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?
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
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.
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:
Add this to the body of your turret with an always sensor (ie Always -> Python (module mode, the turretAI function)
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.
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)