RTS Kit Pathfinding
by Robert Stewart · in RTS Starter Kit · 02/17/2006 (6:27 pm) · 11 replies
Well I have created a simple pathfinding feature for the RTS Kit, first I explain what it does.
Basically when you move a unit from Point A to Point B, it will send a ray and find any objects from A to B. If the ray collides it will find the side of the bounding box that the ray collided against, from there it will find the closest corner of the BB to the clicked position. Then it projects another ray from the units destination to the clicked position to find if any more objects are in the way.
This version was done completly in script and could benifit from been ported to the engine, I will probrally work on this fairly soon.
Here are the changes you have to make, + is the added/changed lines.
engine\game\rts\rtsunit.cc
engine\game\rts\rtsunit.h
Basically when you move a unit from Point A to Point B, it will send a ray and find any objects from A to B. If the ray collides it will find the side of the bounding box that the ray collided against, from there it will find the closest corner of the BB to the clicked position. Then it projects another ray from the units destination to the clicked position to find if any more objects are in the way.
This version was done completly in script and could benifit from been ported to the engine, I will probrally work on this fairly soon.
Here are the changes you have to make, + is the added/changed lines.
engine\game\rts\rtsunit.cc
if(goalDelta.len() < .1)
{
stopMove();
mVelocity.set(0,0,0);
setActionThread(PlayerData::RootAnim,true,false,false);
+if (this->mNextPos.x <= 10000 && this->mNextPos.x >= -10000 && this->mNextPos.z != 154)
+{
char bufs[48];
+dSprintf(bufs, sizeof(bufs), "%0.2f %0.2f %0.2f", this->mNextPos.x, this->mNextPos.y, this->mNextPos.z);
+Con::executef(this, 2, "NextNode", bufs);
+}
+else
+{
+Con::executef(this, 1, "onReachDestination");
+}engine\game\rts\rtsunit.h
S32 getTeam() const { return mTeam; }
+Point3F getNextPos() const { return mNextPos; }About the author
#2
02/17/2006 (8:03 pm)
I'll try it out as soon as I get an inch of free time!
#3
02/18/2006 (7:28 am)
One thing you should know is that it works with only one unit, the unit is defined $player at startup. However it would be easy to apply this to all units in a selection, or to AI controlled players. Ill update this fairly quik with those addidtions.
#4
02/18/2006 (9:24 am)
Well to save energy it would probably be best to just have everybody follow the player that did the initial pathfinding.
#5
*edit
02/18/2006 (9:55 am)
You're right that is why I was only using one unit in my code, because I have a form of flocking in my* game.*edit
#6
and put
under
you must of overlooked that
03/04/2006 (9:14 am)
Errors ahoy all about mNextPos; To fix them go to RTSunit.hand put
Point3F mNextPos;
under
Point3F mAimLocation; // Point to look at
you must of overlooked that
#7
function GuiRTSTSCtrl::onRightMouseDownTerrain(%this, %x, %y, %z){
needs one more }
and once I do that the raycheck always returns 0 did you add collision? because I don't have it right now.
03/04/2006 (9:32 am)
More problems the end of function GuiRTSTSCtrl::onRightMouseDownTerrain(%this, %x, %y, %z){
needs one more }
and once I do that the raycheck always returns 0 did you add collision? because I don't have it right now.
#8
My CPU fried and I'm not able to really look at my code right now, I'll get back to you in a couple days.
03/08/2006 (8:12 am)
Sorry for the long delay, please email me if you don't get a fast response.My CPU fried and I'm not able to really look at my code right now, I'll get back to you in a couple days.
#9
03/08/2006 (5:16 pm)
Ok thanks
#10
I'm getting the following information in the console window
"
starter.RTS/client/scripts/inputHandler.cs (148): Unable to find object: '' attempting to call function 'getTransform'
Current Unit's Postion 1368
Clicked Position 15 25 249
RayCast Information 0
Normal
"
The line it's having trouble with is "%unitPos = $player.gettransform();". It can't seem to find $player.
Anyone have any ideas?
-Nick
04/05/2006 (10:00 am)
Has anyone been able to get this pathfinding to work? My units are still walking they're default straight line path.I'm getting the following information in the console window
"
starter.RTS/client/scripts/inputHandler.cs (148): Unable to find object: '' attempting to call function 'getTransform'
Current Unit's Postion 1368
Clicked Position 15 25 249
RayCast Information 0
Normal
"
The line it's having trouble with is "%unitPos = $player.gettransform();". It can't seem to find $player.
Anyone have any ideas?
-Nick
#11
04/18/2006 (4:40 am)
I have the same problem i have corrected the errors stated by Master Treb and i have nothing working...
Torque Owner Robert Stewart
Change you're onRightMouseDownTerrain to this.
function GuiRTSTSCtrl::onRightMouseDownTerrain(%this, %x, %y, %z) { if(%this.selectionIncludesTeam) { %searchMasks = ($TypeMasks::InteriorObjectType | $TypeMasks::StaticShapeObjectType | $TypeMasks::VehicleObjectType | $TypeMasks::ForceFieldObjectType | $TypeMasks::PhysicalZoneObjectType | $TypeMasks::StaticTSObjectType); %unitPos = $player.gettransform(); %clickPos = (%x SPC %y SPC %z); %target = ContainerRayCast (%unitPos, %clickPos, %searchMasks); echo ("Current Unit's Positon" SPC %unitPos); echo ("Clicked Position" SPC %clickPos); echo ("RayCast Information" SPC %target); if (%target) { %unit = getWord(%target, 0); %type = %unit.getname(); %xx = getWord(%target, 1); %yy = getWord(%target, 2); %zz = getWord(%target, 3); %spawnPoint = (%xx SPC %yy SPC 250); %nodePos = %xx SPC %yy; %unitCornerA = (getword(%unit.getworldbox(), 0) SPC getword(%unit.getworldbox(), 1)); %unitCornerB = (getword(%unit.getworldbox(), 3) SPC getword(%unit.getworldbox(), 4)); %unitCornerC = (getword(%unit.getworldbox(), 0) SPC getword(%unit.getworldbox(), 4)); %unitCornerD = (getword(%unit.getworldbox(), 3) SPC getword(%unit.getworldbox(), 1)); if (%xx == getword(%unit.getworldbox(), 0)) { //commandToServer('IssueMove', getword(%unit.getworldbox(), 0) + 2, getword(%unit.getworldbox(), 1) - 1, %z); if(VectorDist(%clickPos, %unitCornerA) < VectorDist(%clickPos, %unitCornerC)) { commandToServer('IssueMove', getword(%unit.getworldbox(), 0), getword(%unit.getworldbox(), 1) - 1, %z); echo ("Heading to corner A X"); $player.setnextpos(%x SPC %y SPC %z); } if(VectorDist(%clickPos, %unitCornerA) > VectorDist(%clickPos, %unitCornerC)) { commandToServer('IssueMove', getword(%unit.getworldbox(), 0), getword(%unit.getworldbox(), 4) + 1, %z); $player.setnextpos(%x SPC %y SPC %z); echo ("Heading to corner C X"); } } if (%xx == getword(%unit.getworldbox(), 3)) { if(VectorDist(%clickPos, %unitCornerB) < VectorDist(%clickPos, %unitCornerD)) { commandToServer('IssueMove', getword(%unit.getworldbox(), 3), getword(%unit.getworldbox(), 4) + 1, %z); echo ("Heading to corner B X"); $player.setnextpos(%x SPC %y SPC %z); } if(VectorDist(%clickPos, %unitCornerB) > VectorDist(%clickPos, %unitCornerD)) { commandToServer('IssueMove', getword(%unit.getworldbox(), 3), getword(%unit.getworldbox(), 1) - 1, %z); echo ("Heading to corner D X"); $player.setnextpos(%x SPC %y SPC %z); } } if (%yy == getword(%unit.getworldbox(), 1)) { if(VectorDist(%clickPos, %unitCornerA) < VectorDist(%clickPos, %unitCornerD)) { commandToServer('IssueMove', getword(%unit.getworldbox(), 0) - 1, getword(%unit.getworldbox(), 1), %z); echo ("Heading to corner A Y"); $player.setnextpos(%x SPC %y SPC %z); } if(VectorDist(%clickPos, %unitCornerA) > VectorDist(%clickPos, %unitCornerD)) { commandToServer('IssueMove', getword(%unit.getworldbox(), 3) + 1, getword(%unit.getworldbox(), 1), %z); echo ("Heading to corner D Y"); $player.setnextpos(%x SPC %y SPC %z); } } if (%yy == getword(%unit.getworldbox(), 4)) { if(VectorDist(%clickPos, %unitCornerB) < VectorDist(%clickPos, %unitCornerC)) { commandToServer('IssueMove', getword(%unit.getworldbox(), 3) + 1, getword(%unit.getworldbox(), 4), %z); echo ("Heading to corner B Y"); $player.setnextpos(%x SPC %y SPC %z); } if(VectorDist(%clickPos, %unitCornerB) > VectorDist(%clickPos, %unitCornerC)) { commandToServer('IssueMove', getword(%unit.getworldbox(), 0) - 1, getword(%unit.getworldbox(), 4), %z); echo ("Heading to corner C Y"); $player.setnextpos(%x SPC %y SPC %z); } } echo ("PathManager"); } else { echo ("Normal"); commandToServer('IssueMove', %x, %y, %z); } }Thats it, there are so many ways to implement pathfinding, I have created a few different types over the last week, this is the one I found to work best for me.
In it's current stage this is kinda like a hack, in an attempt to make it more permanent I have moved parts to the engine already, the next move should probrally be to move code from input handler to guiRTSCtrl.