TGB turret behavior
by Shaderman · 04/25/2009 (9:45 am) · 13 comments
Hi,
I just want to share this small TGB turret behavior. The video below shows it in action with a slightly modified Behavior Shooter project.
This behavior uses functions written by Tom Ogburn and James Ford (thank you guys!). Some parameters can be tweaked to suit your needs. I didn't comment the code to avoid confusing myself :)
I just want to share this small TGB turret behavior. The video below shows it in action with a slightly modified Behavior Shooter project.
This behavior uses functions written by Tom Ogburn and James Ford (thank you guys!). Some parameters can be tweaked to suit your needs. I didn't comment the code to avoid confusing myself :)
//---------------------------------------------------------------------------------------------
// TGB Turret behavior
// Put together by Shaderman
// This behavior uses code written by Tom Ogburn and James Ford
//---------------------------------------------------------------------------------------------
if (!isObject(TurretBehavior))
{
%template = new BehaviorTemplate(TurretBehavior);
%template.friendlyName = "Turret";
%template.behaviorType = "AI";
%template.description = "Shoots automatically at a target";
%template.addBehaviorField(target, "The target object to face and shoot at", object, "", t2dSceneObject);
%template.addBehaviorField(angularSpeed, "The rotation speed", float, "45.0");
%template.addBehaviorField(tickFreq, "The delay in ms between rotation updates", integer, "200");
%template.addBehaviorField(range, "The activity range (rotate and shoot when the target is within this range). 0 means there's no limit.", integer, "20");
%template.addBehaviorField(projectile, "The projectile to shoot", object, "", t2dSceneObject);
%template.addBehaviorField(projectileLayer, "The projectile layer (0-31)", integer, "", "0");
%template.addBehaviorField(projectileEff, "The projectile effect", object, "", t2dSceneObject);
%template.addBehaviorField(speed, "The projectile speed", float, "10.0");
%template.addBehaviorField(angle, "Objects within this angle will be shot", integer, "45");
%template.addBehaviorField(numShots, "The number of shots fired in a row", integer, "3");
%template.addBehaviorField(shotDelay, "The delay between shots fired in a row", integer, "3000");
%template.addBehaviorField(reloadTime, "The reload time", integer, "5000");
}
function TurretBehavior::onLevelLoaded(%this, %scenegraph)
{
if (!isObject(%this.target) || !%this.target.getVisible())
return;
%this.isReloaded = true;
%this.rotationSchedule = %this.schedule(%this.tickFreq, "rotate");
}
function TurretBehavior::reload(%this)
{
%this.isReloaded = true;
}
function TurretBehavior::rotate(%this)
{
if (!isObject(%this.target) || !%this.target.getVisible())
{
%this.rotationSchedule = %this.schedule(%this.tickFreq, "rotate");
return;
}
if(%this.range $= 0)
%this.dist = %this.range;
else
%this.dist = t2dVectorDistance(%this.owner.getPosition(), %this.target.getPosition());
if(%this.dist <= %this.range)
{
%rotateDir = shortestDirection(%this.owner.getRotation(), %this.target.getRotation());
%directionVectorX = %this.target.getpositionX() - %this.owner.getpositionX();
%directionVectorY = %this.target.getpositionY() - %this.owner.getpositionY();
%angle = 180 - mRadtoDeg(maTan(%directionVectorX , %directionVectorY));
%this.owner.rotateTo(%angle, %this.angularSpeed * %rotateDir, true, true, true, 2);
}
%this.rotationSchedule = %this.schedule(%this.tickFreq, "rotate");
}
function TurretBehavior::onRotationTarget(%this)
{
cancel(%this.rotationSchedule);
%this.shotsFired = 0;
%this.schedule(%this.shotDelay, "shoot");
}
function TurretBehavior::shoot(%this)
{
if(!%this.isReloaded)
{
%this.rotationSchedule = %this.schedule(%this.tickFreq, "rotate");
return;
}
if(%this.shotsFired >= %this.numShots)
{
%this.shotsFired = 0;
%this.isReloaded = false;
%this.schedule(%this.reloadTime, "reload");
%this.rotationSchedule = %this.schedule(%this.tickFreq, "rotate");
return;
} else {
%origin = %this.owner.getPosition();
%fvec = rotationToVector( %this.owner.getRotation() );
%targetPos = %this.target.getPosition();
%inRange = pointInSight( %origin, %fvec, %targetPos, %this.angle );
if(!%inRange)
return;
%pro = %this.projectile.cloneWithBehaviors();
%pro.position = %this.owner.getPosition();
%pro.rotation = %this.owner.getRotation();
%pro.scenegraph = %this.owner.getScenegraph();
%pro.setLayer(%this.projectileLayer);
if(isObject(%this.projectileEff))
{
%effect = %this.projectileEff.cloneWithBehaviors();
%effect.scenegraph = %this.owner.getScenegraph();
%effect.setLayer(%this.projectileLayer);
%effect.mountToLinkpoint(%pro, 1, 0, true , true, true, true);
}
%force = VectorScale(%fvec, %this.speed);
%pro.setConstantForce(getWord(%force, 0), getWord(%force, 1), false);
%this.shotsFired++;
%this.schedule(%this.shotDelay, "shoot");
}
}
// This function was written by Tom Ogburn
// http://www.garagegames.com/community/forums/viewthread/37261
function shortestDirection(%currentAngle, %targetAngle)
{
//Default to clockwise if equi-distant or if it is shorter
%direction = 1;
%angleDifference1 = mabs(%currentAngle - %targetAngle);
%angleDifference2 = mabs((%currentAngle + 360) - %targetAngle);
if (%angleDifference1 > %angleDifference2)
{
//Go counter-clockwise
%direction = -1;
}
return %direction;
}
// The following code was written by James Ford
// http://www.garagegames.com/community/forums/viewthread/77232
//
// origin@ The position of the agent (t2dVector)
// fvec@ The forward vector of the agent (t2dVector)
// point@ The point to test (t2dVector)
// maxAngle@ The agent's max view angle in degrees (F32)
function pointInSight( %origin, %fvec, %point, %maxAngle )
{
%toPoint = t2dVectorNormalise( t2dVectorSub( %point, %origin ) );
%dot = t2dVectorDot( %toPoint, %fvec );
%angle = mRadToDeg( mAcos( %dot ) );
return %angle < %maxAngle;
}
function rotationToVector( %rotation )
{
// "0 -1" is the vector straight up in TGB eg. it corresponds to a rotation of zero,
// so rotate it by your objects rotation and you get your objects forward vector.
%fvec = rotateVector( "0 -1", %rotation );
return %fvec;
}
function rotateVector( %vector, %angle )
{
%angle = mDegToRad(%angle);
%x = getWord(%vector,0);
%y = getWord(%vector,1);
%nx = mCos(%angle) * %x - mSin(%angle) * %y;
%ny = mSin(%angle) * %x + mCos(%angle) * %y;
return %nx SPC %ny;
}
#2
04/25/2009 (5:55 pm)
very nice sman as always!
#3
to
I've updated the original code above as well.
@Andrew thanks as always ;)
04/25/2009 (11:48 pm)
@Johnny sorry, never noticed that. Just change the code between the lines 56-65 fromif(%this.dist > %this.range)
return;
%rotateDir = shortestDirection(%this.owner.getRotation(), %this.target.getRotation());
%directionVectorX = %this.target.getpositionX() - %this.owner.getpositionX();
%directionVectorY = %this.target.getpositionY() - %this.owner.getpositionY();
%angle = 180 - mRadtoDeg(maTan(%directionVectorX , %directionVectorY));
%this.owner.rotateTo(%angle, %this.angularSpeed * %rotateDir, true, true, true, 2);to
if(%this.dist <= %this.range)
{
%rotateDir = shortestDirection(%this.owner.getRotation(), %this.target.getRotation());
%directionVectorX = %this.target.getpositionX() - %this.owner.getpositionX();
%directionVectorY = %this.target.getpositionY() - %this.owner.getpositionY();
%angle = 180 - mRadtoDeg(maTan(%directionVectorX , %directionVectorY));
%this.owner.rotateTo(%angle, %this.angularSpeed * %rotateDir, true, true, true, 2);
}I've updated the original code above as well.
@Andrew thanks as always ;)
#4
04/27/2009 (7:39 am)
Cool behavior ;) If you have time you should add it to the TDN behavior list.
#5
04/27/2009 (9:14 am)
Works like a charm! Thanks again, Shaderman!
#6
@Johnny you're welcome :)
04/27/2009 (9:32 am)
@Joe thanks, I was only able to add a link on TDN to this resource page. AFAIK Michael Perry and others are still working on TDN and uploads / TDN templates don't seem to work at the moment.@Johnny you're welcome :)
#7
cool resource!
BTW is there any way to shoot at different targerts? if this comes across as a stupid q then pls xcuse as am a noob!
10/03/2009 (8:11 am)
hi,cool resource!
BTW is there any way to shoot at different targerts? if this comes across as a stupid q then pls xcuse as am a noob!
#8
Sorry, not with this behavior - you'd need to extend it.
10/03/2009 (11:08 am)
Quote:BTW is there any way to shoot at different targerts?
Sorry, not with this behavior - you'd need to extend it.
#9
10/05/2009 (12:49 am)
hmmm...thought as much...thanks anyways.
#10
Create Simset
$globalset = new SimSet(TargetList);
Example, you tell the objects you want as a target
$globalset.add(%this.owner);
change the behavior's target to
%this.target = $globalset.getobject(n);
Plus, you can have it cycle through potential targets by
n++
Once I work out all of the kinks I'll post up the modified behavior. BTW, this behavior rocks.
11/26/2009 (10:20 pm)
If you create a behavior or class that adds the owner object to a globally accessible simset, you can modify this behavior to pick its targets from the simset.Create Simset
$globalset = new SimSet(TargetList);
Example, you tell the objects you want as a target
$globalset.add(%this.owner);
change the behavior's target to
%this.target = $globalset.getobject(n);
Plus, you can have it cycle through potential targets by
n++
Once I work out all of the kinks I'll post up the modified behavior. BTW, this behavior rocks.
#11
For multiple targets I'd either add a behavior field holding a classname of targets or write a separate turret target behavior and assign it to the target objects (something like the deal damage / take damage behavior).
11/27/2009 (7:32 am)
I've made a small change to the behavior because there was a static setLayer(3) call used for the projectiles. I've added a behavior field projectileLayer which affects the projectile (and its effect if there is one assigned) and defaults to 0.For multiple targets I'd either add a behavior field holding a classname of targets or write a separate turret target behavior and assign it to the target objects (something like the deal damage / take damage behavior).
#12
08/31/2011 (3:07 pm)
Is there any way to use this with the platformer starter kit? I have been trying without much success.
#13
thanks!
-nic
10/09/2011 (10:49 pm)
I'm trying to figure out how I get objects in the behavior drop down. For instance how do I add an object I made: $pball to be tracked by the turret? and added to the drop down of objects.thanks!
-nic
Torque Owner Johnny Sprada
Thank you for sharing this! It works fantastic!
One thing I noticed is that if the target starts or exits outside of the turret range, it won't start tracking, when the target enters that range.
I'm trying to see if I can figure out how to make it pick the target up again, upon entering the range.
Thanks again, this is GREAT stuff!