Efficient way to tell if object is within range?
by Tyler Slabinski · in Torque Game Builder · 01/12/2011 (10:43 pm) · 15 replies
I'm setting up a small prototype, and I'm trying to get a turret in my game (think of a tower defense turret) to "lock on" to another object when it comes within a certain range. I can't really think very well how this could be done efficiently, or if it is even possible to do efficiently. The only way I can think of doing this is to make a loop to check every single target constantly to find out if the distance is less than a number.
Is there a way to do this without using a loop/update/schedule type function?
Is there a way to do this without using a loop/update/schedule type function?
About the author
#2
@Patrick - wouldn't that still require a schedule loop
01/13/2011 (1:16 am)
Use a trigger and if an object enters the trigger then start using the loop to check. When the object gets out of the trigger stop the loop.@Patrick - wouldn't that still require a schedule loop
#3
Just for clarification though, the pickRadius function returns an array, right? I just want to make sure I can loop through the objects and find the closest object nearby.
01/13/2011 (3:24 am)
I don't think it would be too bad, since it will only need to play the schedule loop while there isn't an object in the radius (which would be pretty rare during the middle of a level).Just for clarification though, the pickRadius function returns an array, right? I just want to make sure I can loop through the objects and find the closest object nearby.
#4
01/13/2011 (6:41 am)
Spawn a transparent t2dObject with the size that you want for your range, mount it on the turret. Use 'onCollision' of your t2dObject now.
#5
It certainly would but you could break from it immediately if there were no results returned and the masking is quite fast. Essentially, alleviating the problem of looping through all the object but not really eliminating the use of onUpdate.
Aun's method is quite good - especially using triggers rather than using straight collisions. Collisions tend to stop some objects when they collide or cause them to stutter.
@Tyler, pickRadius returns a space separated list of ObjectID's so loop like so (untested):
01/13/2011 (4:53 pm)
@Aun,It certainly would but you could break from it immediately if there were no results returned and the masking is quite fast. Essentially, alleviating the problem of looping through all the object but not really eliminating the use of onUpdate.
Aun's method is quite good - especially using triggers rather than using straight collisions. Collisions tend to stop some objects when they collide or cause them to stutter.
@Tyler, pickRadius returns a space separated list of ObjectID's so loop like so (untested):
for($i = 0; %i < getWordCount(%result), %i++)
{
%curDist = t2dVectorDistance(%turrent.getPosition() SPC %result.getWord(%i));
//TODO: track previous dist's and compare.
}
#6
But yeah, I think triggers would work great because of those onEnter/onLeave callbacks. Mount those triggers.
01/14/2011 (8:39 am)
As far as I know, those are caused by physics, not collisions. You can disable physics altogether.But yeah, I think triggers would work great because of those onEnter/onLeave callbacks. Mount those triggers.
#7
Now I am fairly certain that this should work, but I am worried specifically about the pickRadius function itself. I am not sure how to pass the arguments it needs. Using the documentation, I tried this:
The arguments passed were:
Center of radius = %turret.getPosition()
Radius size = 75
Group Mask? = BIT(1)
Layer Mask? = BIT()
Search invisible = true
Exclude objects = 0
I am confused about the group mask and layer mask. In the game, the enemies are all set into group #1, so I want to narrow the search to that. The documentation example shows BIT(1) as an example, so I used that, which I am assuming will work. However, I could care less about the layer mask, so I set that to just BIT(), which I hope means it is defaulting to everything.
Any idea?
01/16/2011 (1:28 am)
I like Patrick's method because it gives a list that will give me more control. It would also save the game work for building each individual trigger.function findClosestEnemy(%turret)
{
%result = pickRadius(%turret.getPosition(), 75, BIT(), BIT(1), true, 0);
%prevDist = 75;
for(%i = 0; %i < getWordCount(%result), %i++)
{
%curDist = t2dVectorDistance(%turret.getPosition() SPC %result.getWord(%i));
if (%curDist < %prevDist)
{
%prevDist = %curDist;
%enemy = %result.getWord(%i);
}
}
return %enemy;
}Now I am fairly certain that this should work, but I am worried specifically about the pickRadius function itself. I am not sure how to pass the arguments it needs. Using the documentation, I tried this:
pickRadius(%turret.getPosition(), 75, BIT(), BIT(1), true, 0);
The arguments passed were:
Center of radius = %turret.getPosition()
Radius size = 75
Group Mask? = BIT(1)
Layer Mask? = BIT()
Search invisible = true
Exclude objects = 0
I am confused about the group mask and layer mask. In the game, the enemies are all set into group #1, so I want to narrow the search to that. The documentation example shows BIT(1) as an example, so I used that, which I am assuming will work. However, I could care less about the layer mask, so I set that to just BIT(), which I hope means it is defaulting to everything.
Any idea?
#8
Doesn't seem wrong to me, anyone else know?
01/16/2011 (4:24 pm)
Well, I solved that, but I keep getting an 'unable to find function pickRadius' error in the console.function findClosestEnemy(%turret)
{
%result = pickRadius(%turret.getPosition(), 75, BIT(0), BIT(1), true, %turret);
%prevDist = 75;
for (%i = 0; %i < getWordCount(%result); %i++)
{
%curDist = t2dVectorDistance(%turret.getPosition() SPC %result.getWord(%i));
if (%curDist < %prevDist)
{
%prevDist = %curDist;
%enemy = %result.getWord(%i);
}
}
return %enemy;
}Doesn't seem wrong to me, anyone else know?
#9
01/16/2011 (11:23 pm)
pickRadius is a method of the t2dSceneGraph object, so try calling it like so:function findClosestEnemy(%turret)
{
%result = %turret.getSceneGraph().pickRadius(%turret.getPosition(), 75, BIT(0), BIT(1), true, %turret);
%prevDist = 75;
for (%i = 0; %i < getWordCount(%result); %i++)
{
%curDist = t2dVectorDistance(%turret.getPosition() SPC %result.getWord(%i));
if (%curDist < %prevDist)
{
%prevDist = %curDist;
%enemy = %result.getWord(%i);
}
}
return %enemy;
}
#10
I get this error:
The blank space is there, so the echo function is not outputting anything. I've tried getField, getWord, and getRecord to try retrieving it.
I can't seem to get the object to be outputted by it. I may be looking into this wrong, but it doesn't seem to be outputting a list of objects.
EDIT: I seem to be able to output the ObjectID by just typing:
However, I have yet to test it on multiple objects at once.
01/20/2011 (6:04 pm)
Okay, I was able to get pickRadius to work, however I can't seem to open up any of it's fields. For example, if I simplify this for a single enemy:function findClosestEnemy(%turret)
{
%result = $Scene.pickRadius(%turret.getPosition(), 75, BIT(1));
echo(getField(%result, 1).getPosition());
}I get this error:
game/scripts/Turret.cs (87): Unable to find object: '' attempting to call function 'getPosition'
The blank space is there, so the echo function is not outputting anything. I've tried getField, getWord, and getRecord to try retrieving it.
I can't seem to get the object to be outputted by it. I may be looking into this wrong, but it doesn't seem to be outputting a list of objects.
EDIT: I seem to be able to output the ObjectID by just typing:
echo(%result);
However, I have yet to test it on multiple objects at once.
#11
Then try:
01/20/2011 (6:08 pm)
That code assumes that the objects you're trying to get with pickRadius are in group 1 as designated by the BIT(1) part. Are you sure they are in group 1?Then try:
echo(getWord(%result, 0).getPosition());
#12
Everything works now. Here is completed code for reference:
Thank you for helping me anyways.
EDIT: Typo in code, fixed though.
01/20/2011 (6:37 pm)
I'm sorry, that was a waste of time. I apparently just had to delete my DSO.Everything works now. Here is completed code for reference:
function getAngle(%this)
{
%enemy = findClosestEnemy(%this);
%enemyPos = %enemy.getPosition();
%turretPos = %this.getPosition();
%x = %enemyPos.x - %turretPos.x;
%y = %enemyPos.y - %turretPos.y;
return mRadToDeg(mAtan(%x, %y));
}
function findClosestEnemy(%turret)
{
%result = $Scene.pickRadius(%turret.getPosition(), 75, BIT(1));
%prevDist = 75;
for (%i = 0; %i < getWordCount(%result); %i++)
{
%curDist = t2dVectorDistance(%turret.getPosition(), getWord(%result, %i));
if (%curDist < %prevDist)
{
%prevDist = %curDist;
%enemy = getWord(%result, %i);
}
}
return %enemy;
}
function BasicTurret::onUpdate(%this)
{
%angle = getAngle(%this);
%this.setRotation(-%angle + 180);
}Thank you for helping me anyways.
EDIT: Typo in code, fixed though.
#13
01/21/2011 (7:10 am)
Very nice! Let's see some video!
#14
However, I will post a video once I get a full working prototype.
01/21/2011 (10:52 am)
Can't post a video now since I don't have the correct software needed.However, I will post a video once I get a full working prototype.
#15
01/30/2011 (12:26 pm)
Hi, this thread caught my attention because I built a tower defense game using T2D/iTorque. Sort of off subject, but what software do you guys recommend to screen capture video to demo the game?
Torque Owner RollerJesus
Dream. Build. Repeat.