Layer based traversability for Torque3D terrains
by Konrad Kiss · 06/03/2009 (3:12 am) · 35 comments
My second resource regarding Torque3D terrains lets you set up terrain layers that can not be walked upon by your player (and/or your vehicles). This provides a very easy way to paint traversable terrain for your game.
I'm using it to restrict movement onto cliffs and riverbeds / ocean floors and other places where the player shouldn't wander off to. Use responsibly. ;)
In the end, your already cluttered terrain material editor will look like this: (I've marked the new feature with a red box)

Ok, let's get to work.
terrain/terrData.h
add before the last #endif
This is needed to be able to use this global function outside terrData
terrain/terrMaterial.h
add as a protected member
add as a public member function
terrain/terrMaterial.cpp
change the class constructor
add in initPersistFields, after the other fields
T3D/shapeBase.h
add as a protected member to the ShapeBase class
add as public members functions to the ShapeBase class
T3D/shapeBase.cpp
add after other includes
add at the end of the ShapeBase constructor
add at the end of the file
I decided to add helper functions to ShapeBase, but do the actual checks in derived classes where needed...
T3D/player.cpp - and any other class where you need per layer traversability (ie. wheeledvehicle?)
In Player::processTick after
That's it for the engine changes, now we need to modify tools scripts to be able to use this within the terrain material editor.
tools/missionEditor/gui/guiTerrainMaterialDlg.ed.gui
overwrite the code for the control with the internalName attribute "sideProjectionCtrl" with the following
tools/missionEditor/scripts/interfaces/terrainMaterialDlg.ed.cs
a) after
b) after
c) after
d) finally, after
This is it. If your player doesn't move right away, make sure you set the layer below your player to passable. You need to save your mission in order to save the changes you make to your terrain layers, so don't forget that!
Enjoy!
Update: The Player::processTick code was made more stable for AI.
Update (07/30/2009):
For this to work in a networked environment, make sure the server loads the terrain materials - it needs to know about them to decide if a terrain material is traversable or not.
Include this in, say, scripts/server/init.cs in initServer(), at the end of the function:
I'm using it to restrict movement onto cliffs and riverbeds / ocean floors and other places where the player shouldn't wander off to. Use responsibly. ;)
In the end, your already cluttered terrain material editor will look like this: (I've marked the new feature with a red box)

Ok, let's get to work.
terrain/terrData.h
add before the last #endif
This is needed to be able to use this global function outside terrData
TerrainBlock* getTerrainUnderWorldPoint(const Point3F & wPos); // >>> <<< Per-layer traversability
terrain/terrMaterial.h
add as a protected member
bool mTraversable; // >>> <<< Per-layer traversability
add as a public member function
bool isTraversable() const { return mTraversable; } // >>> <<< Per-layer traversabilityterrain/terrMaterial.cpp
change the class constructor
TerrainMaterial::TerrainMaterial()
: mSideProjection( false ),
mDetailScale( 32.0f ),
mDetailStrength( 1.0f ),
mDetailDistance( 50.0f ),
mTraversable( true ), // >>> <<< Per-layer traversability
mParallaxScale( 0.0f )
{
}add in initPersistFields, after the other fields
addField( "traversable", TypeBool, Offset( mTraversable, TerrainMaterial ) ); // >>> <<< Per-layer traversability
T3D/shapeBase.h
add as a protected member to the ShapeBase class
// >>> Per-layer traversability Point3F mLastTraversablePosition; // <<< Per-layer traversability
add as public members functions to the ShapeBase class
// >>> Per-layer traversability
bool ShapeBase::isOnTraversableTerrain();
Point3F getLastTraversablePosition() { return mLastTraversablePosition; }
// <<< Per-layer traversabilityT3D/shapeBase.cpp
add after other includes
// >>> Per-layer traversability #include "terrain/terrData.h" #include "terrain/terrMaterial.h" // <<< Per-layer traversability
add at the end of the ShapeBase constructor
// >>> Per-layer traversability mLastTraversablePosition = Point3F(0,0,0); // <<< Per-layer traversability
add at the end of the file
I decided to add helper functions to ShapeBase, but do the actual checks in derived classes where needed...
// >>> Per-layer traversability
bool ShapeBase::isOnTraversableTerrain() {
if (mLastTraversablePosition != getRenderPosition()) {
// check terrain type below and see if it can be traversed
// get the terrain block beneath
TerrainBlock * terr = getTerrainUnderWorldPoint(getPosition());
if (terr) {
// now let's find our grid position
Point3F pos = getRenderPosition();
Point2I gridPos = terr->getGridPos(pos);
// and get the material's properties at that grid position
// Beta 5 - matIndex: (use this if you have a version of Torque 3D before Beta 5
//U8 matIndex = terr->getMaterialIndex(gridPos.x, gridPos.y);
// Beta 5 + matIndex:
U8 matIndex = terr->getFile()->getLayerIndex(gridPos.x, gridPos.y);
TerrainMaterial * terrMat = terr->getMaterial(matIndex);
if (terrMat) {
// we now can check if this material is traversable or not
if (!terrMat->isTraversable()) {
// this is not traversable
return false;
} else {
mLastTraversablePosition = getRenderPosition();
}
}
}
}
return true;
}
// <<< Per-layer traversabilityT3D/player.cpp - and any other class where you need per layer traversability (ie. wheeledvehicle?)
In Player::processTick after
// If we're not being controlled by a client, let the
// AI sub-module get a chance at producing a move.
Move aiMove;
if (!move && isServerObject() && getAIMove(&aiMove))
move = &aiMove;add the following:// >>> Per-layer traversability
if (isServerObject() && !isOnTraversableTerrain()) {
Move tMove;
tMove = NullMove;
tMove.x = 0;
tMove.y = 0;
tMove.z = 0;
Point3F cPos = getPosition();
Point3F tPos = getLastTraversablePosition();
Point3F iPos = tPos - cPos;
iPos.normalize();
setPosition(cPos+(iPos*0.1f), getRotation());
if (move) {
tMove.yaw = move->yaw;
tMove.pitch = move->pitch;
tMove.roll = move->roll;
tMove.freeLook = move->freeLook;
for (U32 i=0; i<MaxTriggerKeys; i++) {
tMove.trigger[i] = move->trigger[i];
}
move = &tMove;
}
// let's stop here
mVelocity.x = 0;
mVelocity.y = 0;
}
// <<< Per-layer traversabilityThat's it for the engine changes, now we need to modify tools scripts to be able to use this within the terrain material editor.
tools/missionEditor/gui/guiTerrainMaterialDlg.ed.gui
overwrite the code for the control with the internalName attribute "sideProjectionCtrl" with the following
// >>> Per-layer traversability
new GuiCheckBoxCtrl() {
internalName = "sideProjectionCtrl";
canSaveDynamicFields = "0";
isContainer = "0";
Profile = "GuiCheckBoxProfile";
HorizSizing = "right";
VertSizing = "bottom";
Position = "55 35";
Extent = "54 16";
MinExtent = "8 2";
canSave = "1";
Visible = "1";
tooltipprofile = "GuiToolTipProfile";
hovertime = "1000";
alpha = "1";
color = "255 255 255 255";
unitClip = "0 0 1 1";
text = "Side Prj";
groupNum = "-1";
buttonType = "ToggleButton";
useMouseEvents = "0";
useInactiveState = "0";
};
new GuiCheckBoxCtrl() {
internalName = "traversableCtrl";
canSaveDynamicFields = "0";
isContainer = "0";
Profile = "GuiCheckBoxProfile";
HorizSizing = "right";
VertSizing = "bottom";
Position = "116 35";
Extent = "59 16";
MinExtent = "8 2";
canSave = "1";
Visible = "1";
tooltipprofile = "GuiToolTipProfile";
hovertime = "1000";
alpha = "1";
color = "255 255 255 255";
unitClip = "0 0 1 1";
text = "Passable";
groupNum = "-1";
buttonType = "ToggleButton";
useMouseEvents = "0";
useInactiveState = "0";
};
// <<< Per-layer traversabilitytools/missionEditor/scripts/interfaces/terrainMaterialDlg.ed.cs
a) after
%this-->sideProjectionCtrl.setValue( %mat.useSideProjection );add
%this-->traversableCtrl.setValue( %mat.traversable ); // >>> <<< Per-layer traversability
b) after
%useSideProjection = %this-->sideProjectionCtrl.getValue();add
%traversable = %this-->traversableCtrl.getValue(); // >>> <<< Per-layer traversability
c) after
%mat.useSideProjection != %useSideProjection ||add
%mat.traversable != %traversable || // >>> <<< Per-layer traversability
d) finally, after
%mat.useSideProjection = %useSideProjection;add
%mat.traversable = %traversable; // >>> <<< Per-layer traversability
This is it. If your player doesn't move right away, make sure you set the layer below your player to passable. You need to save your mission in order to save the changes you make to your terrain layers, so don't forget that!
Enjoy!
Update: The Player::processTick code was made more stable for AI.
Update (07/30/2009):
For this to work in a networked environment, make sure the server loads the terrain materials - it needs to know about them to decide if a terrain material is traversable or not.
Include this in, say, scripts/server/init.cs in initServer(), at the end of the function:
exec("art/terrains/materials.cs");About the author
Lead Developer at Bitgap Games (www.bitgap.com) currently working on Xenocell (www.xenocell.com) a massively multiplayer action strategy game based on Torque 3D technology.
#2
06/03/2009 (3:55 am)
@Max: Yes, that's exactly what this is for. You can easily switch any terrain material in the editor to become (or cease to be) walkable. By default, every material is walkable.
#3
Also makes me think that terrain types could do other things, like a terrain surface that does damage if the player steps on it.
06/03/2009 (6:50 am)
Konrad - what a brilliant idea!Also makes me think that terrain types could do other things, like a terrain surface that does damage if the player steps on it.
#4
06/03/2009 (6:56 am)
@Steve: Thanks! Damage, yes! Or slippery surfaces! Or surfaces that speed you up! (not such a good idea for my game, but it'd definitely rock for others). This new system is marvelous. It is just so much easier to add your ideas to.
#5
06/03/2009 (7:49 am)
ooh, I like the slippery surface idea, think of driving on an oil patch, or an ice hockey sports game, or getting stuck in quicksand.
#6
06/03/2009 (7:53 am)
:) Best of all: new terrain system is just ideal for some mesh based pathfinding.
#7
06/03/2009 (8:03 am)
pray tell more?
#8
I've found this page which might tell you more about what they are for and how they are used in games. Also this one is very informative about what it is and how it could be implemented.
If you had automatically created and optimized nav meshes in your game, you would not have to worry about a gazillion of nodes, since nav meshes can in general be better optimized. Also, large traversable areas take very little resources from the engine. Furthermore, there are many gains with handling traversable areas instead of traversable lines.
06/03/2009 (8:37 am)
Well, you see, the new terrain uses the concept that materials do not overlay. When a material is either traversable or not, the entire terrain grid perfectly specifies a walkable - navigation - mesh which is often used for pathfinding as an alternative to nodes. Actually, it is a lot better than using nodes. I've found this page which might tell you more about what they are for and how they are used in games. Also this one is very informative about what it is and how it could be implemented.
If you had automatically created and optimized nav meshes in your game, you would not have to worry about a gazillion of nodes, since nav meshes can in general be better optimized. Also, large traversable areas take very little resources from the engine. Furthermore, there are many gains with handling traversable areas instead of traversable lines.
#9
06/03/2009 (8:41 am)
Very handy indeed.
#10
06/03/2009 (8:59 am)
Pretty darn cool.
#11
06/03/2009 (9:15 am)
Seems like you could use this same approach to control placement of plants. Grass in grassy material areas, etc.
#12
06/03/2009 (11:20 am)
Nice one Konrad!
#13
@Tim: Yes, the concept could be used to paint objects, but the drawback is that only one kind of object could be spawned on one terrain grid square. A system where paint overlays are possible would probably fit the task of painting objects on terrain better. Also, the GroundCover that's currently in Torque3D Beta 2 already has this built in, so you can place objects per layer, which would work really well for placing grass objects on grassy terrain.
06/03/2009 (12:44 pm)
@J, Russell, Michael: Thanks guys!@Tim: Yes, the concept could be used to paint objects, but the drawback is that only one kind of object could be spawned on one terrain grid square. A system where paint overlays are possible would probably fit the task of painting objects on terrain better. Also, the GroundCover that's currently in Torque3D Beta 2 already has this built in, so you can place objects per layer, which would work really well for placing grass objects on grassy terrain.
#14
06/03/2009 (12:54 pm)
This is awesome. Useful for slowing down movement to represent thick mud or snow.
#16
Even though I had sworn to my self to create our project in TGEA and avoid the last 5 years engine creepings, your ressources are some of the main reasons Im thinking about porting to T3D as soon as I have a 100% working prototype.
Keep up the spirit ;)
06/03/2009 (2:35 pm)
Extremely handy Konrad!Even though I had sworn to my self to create our project in TGEA and avoid the last 5 years engine creepings, your ressources are some of the main reasons Im thinking about porting to T3D as soon as I have a 100% working prototype.
Keep up the spirit ;)
#17
and why arent they here yet?
:))
06/03/2009 (4:48 pm)
ok... so who hands out the seals of awsomeness?and why arent they here yet?
:))
#18
06/03/2009 (11:54 pm)
Man this should be in the release version of T3D this is hardcore!
#19
@Infinitium3D: You're right, that would be a much more down-to-earth use too. Cool idea!
@Afan: Thanks man! Hope you can use it!
@Christian: Thanks. I'm just a clone, will forward that. :) And if you can, definitely come over to the dark side (= better shadows). I'll ask for a cut from GG, too. ;)
@Bloodknight: That's the best comment I've ever got! :) Thanks!
@OmegaDog: Thanks! I've made hints to including this in the final, but even if it doesn't make it, it's not too hard to add. It could still use a little work when "colliding" with non-passable materials. Maybe the navigation mesh could be the next step here, in handling that collision as well.
06/04/2009 (12:55 am)
Thanks guys, I'm glad it turned out to be so useful! :)@Infinitium3D: You're right, that would be a much more down-to-earth use too. Cool idea!
@Afan: Thanks man! Hope you can use it!
@Christian: Thanks. I'm just a clone, will forward that. :) And if you can, definitely come over to the dark side (= better shadows). I'll ask for a cut from GG, too. ;)
@Bloodknight: That's the best comment I've ever got! :) Thanks!
@OmegaDog: Thanks! I've made hints to including this in the final, but even if it doesn't make it, it's not too hard to add. It could still use a little work when "colliding" with non-passable materials. Maybe the navigation mesh could be the next step here, in handling that collision as well.
#20
Actually Caylo was working on the same idea (ground friction via an icy material) and he never did a resource.
06/04/2009 (12:41 pm)
Cool!Actually Caylo was working on the same idea (ground friction via an icy material) and he never did a resource.
Torque Owner Maximillian Brewer
I don't actually have T3D, but do plan on upgrading very soon. But just a question about what looks like a very useful resource...
So you can make it so that based on what texture has been applied, you can or can't walk on it???
From Max