Slopes and XY axis - Bounding Box Rotation
by Swaroop Reddy · in RTS Starter Kit · 10/22/2007 (4:34 pm) · 7 replies
Does any one have any idea how to get RTS units to rotate along the X and Y axis when ther are one a hill slope. The Racing starter kit shows that the vehicle bounding box rotates in the approrate direction along the X and Y axis when it is on a slope. How can this be implemented on an RTS unit. For bipeds this is not an issue but for animals such as horses it is a MAJOR draw back. Imagine a horse climbing up a hill without rotating its body to match the slope - NOT VERY PLEASANT. I havent seen this addresed anywhere in the forums.
About the author
#2
10/22/2007 (9:00 pm)
Animals follow the slope perfectly in the game Wildlife Tycoon: Venture Africa. Both of the methods above will tell me when and how much to rotate the unit. BUT RTS units DO NOT rotate along the X or Y axis even if you use setTransform(). They only rotate along Z axis. There must tbe some way to rotate them.
#3
10/22/2007 (10:15 pm)
Ahh! now i see what you mean. I didnt know that, if i have time ill try to look around.
#4
www.garagegames.com/index.php?sec=mg&mod=resource&page=view&qid=3148
10/28/2007 (3:34 am)
The link below shows how it is done for the player class. I am not sure how to implement for RTSUnit class.www.garagegames.com/index.php?sec=mg&mod=resource&page=view&qid=3148
#5
Just follow the modifications below for player.cc and player.h
NOW YOUR RTS UNITS WILL LOOK COOL GOING UP THE HILL.
In player.cc
-----------------------------------------------------------------------------------------
At the bottom of PlayerData::PlayerData() add:
conformToGround = true;
At the bottom of PlayerData::initPersistFields() add:
addField("conformToGround", TypeBool, Offset(conformToGround, PlayerData));
At the bottom of PlayerData::packData(BitStream* stream) add:
stream->write(conformToGround);
At the bottom of PlayerData::unpackData(BitStream* stream) add:
stream->read(&conformToGround);
To Player::setPosition(const Point3F& pos,const Point3F& rot) add the following code to the end of the "else" clause:
if (mDataBlock && mDataBlock->conformToGround)
{
RayInfo surfaceInfo;
Point3F above = Point3F(pos.x,pos.y,pos.z + 0.5f);
Point3F below = Point3F(pos.x,pos.y,pos.z - 100.0f);
if (gClientContainer.castRay(above,below,TerrainObjectType | InteriorObjectType,&surfaceInfo))
{
Point3F x,y,z;
z = surfaceInfo.normal;
z.normalize();
mat.getColumn(1,&y);
mCross(y,z,&x);
x.normalize();
mCross(z,x,&y);
mat.setColumn(0,x);
mat.setColumn(1,y);
mat.setColumn(2,z);
}
}
To Player::setRenderPosition(const Point3F& pos, const Point3F& rot, F32 dt) add the following code to the end of the outer else clause:
if (mDataBlock && mDataBlock->conformToGround)
{
RayInfo surfaceInfo;
Point3F above = Point3F(pos.x,pos.y,pos.z + 0.5f);
Point3F below = Point3F(pos.x,pos.y,pos.z - 100.0f);
if (gClientContainer.castRay(above,below,TerrainObjectType | InteriorObjectType,&surfaceInfo))
{
Point3F x,y,z;
z = surfaceInfo.normal;
z.normalize();
mat.getColumn(1,&y);
mCross(y,z,&x);
x.normalize();
mCross(z,x,&y);
mat.setColumn(0,x);
mat.setColumn(1,y);
mat.setColumn(2,z);
}
}
In player.h add the following lines to the bottom of the PlayerData struct:
-------------------------------------------------------------------------------------------
bool conformToGround;
Now you can add the following field to the RTSunit datablock if needed:
conformToGround = 0; // or 1 by default
11/11/2007 (1:04 pm)
IT WORKS!!! I trimmed the above code a bit for the RTS engine. Just follow the modifications below for player.cc and player.h
NOW YOUR RTS UNITS WILL LOOK COOL GOING UP THE HILL.
In player.cc
-----------------------------------------------------------------------------------------
At the bottom of PlayerData::PlayerData() add:
conformToGround = true;
At the bottom of PlayerData::initPersistFields() add:
addField("conformToGround", TypeBool, Offset(conformToGround, PlayerData));
At the bottom of PlayerData::packData(BitStream* stream) add:
stream->write(conformToGround);
At the bottom of PlayerData::unpackData(BitStream* stream) add:
stream->read(&conformToGround);
To Player::setPosition(const Point3F& pos,const Point3F& rot) add the following code to the end of the "else" clause:
if (mDataBlock && mDataBlock->conformToGround)
{
RayInfo surfaceInfo;
Point3F above = Point3F(pos.x,pos.y,pos.z + 0.5f);
Point3F below = Point3F(pos.x,pos.y,pos.z - 100.0f);
if (gClientContainer.castRay(above,below,TerrainObjectType | InteriorObjectType,&surfaceInfo))
{
Point3F x,y,z;
z = surfaceInfo.normal;
z.normalize();
mat.getColumn(1,&y);
mCross(y,z,&x);
x.normalize();
mCross(z,x,&y);
mat.setColumn(0,x);
mat.setColumn(1,y);
mat.setColumn(2,z);
}
}
To Player::setRenderPosition(const Point3F& pos, const Point3F& rot, F32 dt) add the following code to the end of the outer else clause:
if (mDataBlock && mDataBlock->conformToGround)
{
RayInfo surfaceInfo;
Point3F above = Point3F(pos.x,pos.y,pos.z + 0.5f);
Point3F below = Point3F(pos.x,pos.y,pos.z - 100.0f);
if (gClientContainer.castRay(above,below,TerrainObjectType | InteriorObjectType,&surfaceInfo))
{
Point3F x,y,z;
z = surfaceInfo.normal;
z.normalize();
mat.getColumn(1,&y);
mCross(y,z,&x);
x.normalize();
mCross(z,x,&y);
mat.setColumn(0,x);
mat.setColumn(1,y);
mat.setColumn(2,z);
}
}
In player.h add the following lines to the bottom of the PlayerData struct:
-------------------------------------------------------------------------------------------
bool conformToGround;
Now you can add the following field to the RTSunit datablock if needed:
conformToGround = 0; // or 1 by default
#6
11/11/2007 (1:57 pm)
Well done! I'll give it a try as soonas I can.
#7
Novack, if you figure it out how to do it, let me know please.
Thanks.
11/11/2007 (3:38 pm)
I wish I could get the unit to only tilt along the slope on the forward vector. I dont like the way that the unit tilts to the side. Novack, if you figure it out how to do it, let me know please.
Thanks.
Torque 3D Owner Novack
CyberianSoftware
A better idea could be to use some pathfinding mechanism wich in some nodes set a flag to activate the use of the raycasting.
And a second option could be to directly store the angle info in each node of your pathfinding hexagonal grid. You would do the calcs only once, on map generation. Then the units should be rotated accordingly to that stored value.