Tracking to an object without the TrackTo actuator?

How would one go about tracking to an object without using the TrackTo actuator? The reason I don’t want to use the actuator is because the turrets on my ships have a specific “tracking speed” to add game balance to the larger, hard-hitting weapons.

I currently have them set up to use the keyboard to turn… but I’d really like to be able to specify an object and then figure out how to implement the tracking speed to that. I thought maybe raycasting would work, but then how would you get the angle/axis that it needs to rotate in order for the ray to collide with the target?

https://youtu.be/IkVCxj_7C6A

Cones my friend !

Attach multiple “Collider cones” and use them to torque :slight_smile:

Attachments

DetectorAi.blend (498 KB)


NM accidental post

You can use the handy alignAxisToVect method and specify a factor less than 1 so the turret doesn’t immediately snap to its target.

targetVec = targetObj.worldPosition - turretObj.worldPosition
axis = 1  # assuming your turret fires along its y-axis
factor = .5  # cover half the distance each frame
turretObj.alignAxisToVect(targetVec, axis, factor)

If you want the turret to only rotate a fixed maximum angle rather than a fraction of the angle between it and the target. You can get the current angle using the Vector.angle method and calculating what factor you need to specify to get the desired angle change.

from mathutils import Vector

MAX_ANGLE = 0.087  # maximum angle to rotate per frame in radians

targetVec = targetObj.worldPosition - turretObj.worldPosition

# get turret's current vector
axis = 1  # assuming your turret fires along its y-axis
turretVec = Vector([0, 0, 0])
turretVec[axis] = 1
turretVec.rotate(turretObj.worldOrientation)

# get the angle between the turret vector and target vector
angle = turretVec.angle(targetVec)

# calculate the appropriate factor, the try statement catches when the angle is zero
try:
    factor = MAX_ANGLE / angle
except ZeroDivisionError:
    factor = 1
if factor > 1:
    factor = 1

# align the turret
turretObj.alignAxisToVect(targetVec, axis, factor)

cones dont always work, they are messy, dirty, and almost always interfer with rays and “mouse over” sensors
i would go with a python solution instead, like the one that Mobious posted

???
they have never not worked for me,

Mouse over? for selecting a target?

that is what the cone is for…

I keep hearing “don’t trust physics”

It has never failed me,
What is the issue with it?

After watching the video again, I noticed the turrets consist of two parts that rotate separately on different axis. If those are what you’re using in your setup, then things get a bit trickier since you have to rotate each part separately and kept the rotation constrained to a specific axis. The code still follows the same general outline of what I posted above though.

just use 6dof rigid bodies :slight_smile:

Here is a example of a 2 part 6dof controller,

Turret

Die cube die

Attachments

DetectorRet (1).blend (525 KB)

thank you! just what I needed :slight_smile:

I needed to write this for my own project, so I took some of Mobious’ code, and modified it.

Changes:

  • Separate Elevation and Rotation (ie a barrel).
  • You can specify the max turn speed in radians (ie 0.02 rad per frame) or the number of frames to track over (5 frames)

How to use:

  1. Add this to the body of your turret with an always sensor (ie Always -> Python (module mode, the turretAI function)
  2. Add to the turret the property ‘max speed.’ If the number is less than 1, this will be it’s maximum turn speed, if it is greater than 1, then it will be the number of frames to completely target the enemy.
  3. Add a barrel, parent it to the turret body, and give it the property ‘barrel’

This will currently track the object named ‘target’ but you can probably write your own code to chose an enemy. If you can’t, have a look at my AI snippets in the resources section, which has a function for that.

def turretAI(cont):    target = bge.logic.getCurrentScene().objects['target']
    aimPos = lead(target)
    turret = cont.owner
    barrel = [chi for chi in turret.children if 'barrel' in chi][0]
    aimAt(aimPos, turret, barrel)
    
def lead(target):
    #Will contain the necessary logic to lead ahead of a target
    return target.worldPosition


def aimAt(aimPos, turret, barrel):
    maxTurn = turret['maxTurn']
      
    #Z axis stuff
    turVec = turret.getAxisVect([0,1,0])  
    aimVec = aimPos - turret.worldPosition
    aimVec.z = 0    
    angle = turVec.angle(aimVec)
    if angle > 0:
        if maxTurn > 1:
            factor = 1/maxTurn
        else:
            factor = maxTurn/turVec.angle(aimVec)
        turret.alignAxisToVect(aimVec, 1, factor)
    
    #X Axis Stuff
    barVec = barrel.getAxisVect([0,1,0])
    aimVec = barrel.getVectTo(aimPos)[1]
    aimVec[0] = turret.getAxisVect([0,1,0]).x  
    aimVec[1] = turret.getAxisVect([0,1,0]).y
    angle = barVec.angle(aimVec)
    if angle > 0:
        if maxTurn > 1:
            factor = 1/maxTurn
        else:
            factor = maxTurn/turVec.angle(aimVec)
        barrel.alignAxisToVect(aimVec, 1, factor)

yep I already have everything set up to be able to target new enemies and such. thanks for the code :slight_smile: