a more sensible way to scan for targets
by Joseph Bosch · in Game Design and Creative Issues · 01/03/2014 (9:18 am) · 5 replies
I am looking for a more sensible way for for units to scan for there next target. What I want to occur i is if the player has not selected a target the unit will shoot at the closet enemy, If the player has selected a target and the target is in range, the unit fires at the target, if the target is out of range the unit should again fire at the closest target. Currently I have this done every time the unit moves it looks at every other unit not on its team and looks to see if any are in range and if so it shoots at the closet one. The problem is associating this with movement makes it happens way to often and is causing a bit of lag in the game. Is there a more sensible way to scan for targets?
#2
01/03/2014 (3:01 pm)
In T2D I think you can use a pick operation, relying on the idea that targets will have collision geometry and box2d can find them. Unfortunately I don't know how to do this off the top of my head.
#3
Not gonna post the whole thing, since most of it's production code (read here: would likely cause more confusion than enlightenment) but the over-arching structure is:
The AIManager setup acts as a bit of a load-balancer, letting me tweak new decision frequency either in batches, or adaptively based on bot count (which is a nice/nasty way of ramping up difficulty on the fly for instance), while the aiDecide allows them to carry on a given action for the duration that I can determine by setting states based on conditions. (and those conditions can set alternate states, ect.)
01/03/2014 (4:34 pm)
I usually use a combination of an aiManager that cycles through bots.Not gonna post the whole thing, since most of it's production code (read here: would likely cause more confusion than enlightenment) but the over-arching structure is:
function startAIManager()
{
new ScriptObject(AIManager){};
MissionCleanup.add(AIManager);
AIManager.think(0);
}
function AIManager::think(%this,%botnum)
{
if (isObject(%this.bots))
{
%num = %this.bots.getCount();
if (($serializeActions)&&(%num>0))
{
%botnum++;
if (%botnum>%num-1) %botnum = 0;
%bot = %this.bots.getObject(%botnum);
if(isObject(%bot)) %bot.aiDecide();
}
else
{
for(%botnum = 0; %botnum<%num;%botnum++)
{
%bot = %this.bots.getObject(%botnum);
if(isObject(%bot)) %bot.aiDecide();
}
}
}
if ($serializeActions) %this.schedule(64, think ,%botnum);
else %this.schedule(500, think ,%botnum);
}
function AIManager::addBot(%this,%bot)
{
if (!isObject(%this.bots))
%this.bots = new SimSet();
%this.bots.add(%bot);
}function AIPlayer::aiDecide(%this)
{
if(!isObject(%this)||(%this.getState() $="Dead")) return;
%this.thinkticks++;
//if we're stuck in the same state to long, pick a new one
if (%this.thinkticks>(%this.botstate+$botStateDuration))
{
%this.thinkticks = 0;
%this.botstate = $botstate_searchForTarget;
}
%this.stopThread(0);
if (%this.confused) %this.botstate = $botstate_Confused;
switch(%this.botstate)
{
case $botstate_Confused:
%this.randomPath();
case $botstate_fire:
%this.aiShoot();
case $botstate_Wander:
%this.randomPath();
case $botstate_PathToNearest:
if(!%this.PathToNearest())
%this.botstate = $botstate_Wander;
case $botstate_PathToInView:
if(!%this.PathToNearestInView())
%this.botstate = $botstate_PathToNearest;
case $botstate_searchForTarget:
if(%this.targetInRange()) %this.botstate = $botstate_fire;
else %this.botstate = $botstate_PathToInView;
default:
%this.botstate = $botstate_searchForTarget;
}
//do we think for ourselves, or let the AIManager do it for us?
if ($individualThinking) %this.schedule(1000, aiDecide);
}The AIManager setup acts as a bit of a load-balancer, letting me tweak new decision frequency either in batches, or adaptively based on bot count (which is a nice/nasty way of ramping up difficulty on the fly for instance), while the aiDecide allows them to carry on a given action for the duration that I can determine by setting states based on conditions. (and those conditions can set alternate states, ect.)
#4
01/04/2014 (6:22 am)
states insides a manager is an interesting idea. originally when i started noticing lag I began to put more and more checking and adding state checks like is the unit reloading or does it already have a target acquired . Some other things I have been thinking of is to divide units based on teams to reduce the amount of checking needing to be done. Lukas very good point, looking back over the previous iteration of this feature it was a unit update function but given there are some units that do not move at all you are correct in that this has to be on some type of timer even though I wanted to avoid that. I think I have settled on the pick radius function along with some state management.
#5
I think T2D has something like Triggers, in that you can have objects register collision without actually colliding. They may be called Sensors. I don't remember well.
01/05/2014 (1:16 am)
Does the player move? You could represent the in range/out of range logic as a Trigger centered at the player's location, which would give you enter/exit callbacks with less performance overhead than iterating through lists repeatedly.I think T2D has something like Triggers, in that you can have objects register collision without actually colliding. They may be called Sensors. I don't remember well.
Torque Owner Lukas Joergensen
WinterLeaf Entertainment
You can use a container search.
But why not only do the search for new targets when the unit fires rather than when the unit moves?
Also what if another unit moves into the range of the player but that player hasn't moved? It would never be assigned as a target then, even though it is clearly in range.