At a point I also wanted to add physics bounds to a small terrain, so that one couldnt walk off the map.
My approach was to create some simple boxes surrounding the edges of the terrain.
Note that this approach presumes that you have moved your terrain so that 0,0 is the corner of the terrain and the terrain is aligned in positive X/Z to make the world space coordinates in the positive axis ranges.
[java]
public class Terrain extends TerrainQuad implements CollisionGroups {
public Terrain() {
}
public Terrain(final String name, final int patchSize, final int totalSize,
final float[] heightMap) {
super(name, patchSize, totalSize, heightMap);
}
public Terrain(final String name, final int patchSize, final int quadSize,
final Vector3f scale, final float[] heightMap, final int totalSize,
final Vector2f offset, final float offsetAmount) {
super(name, patchSize, quadSize, scale, heightMap, totalSize, offset,
offsetAmount);
}
private RigidBodyControl physicsBoundsControl;
private Geometry physicsGeom;
public void setupPhysicsBounds(final Node worldNode, final PhysicsSpace ps) {
final float terrainSize = getTotalSize() - 1f;
final float size = getTotalSize() + 10;
final float boundWidth = 1f;
final ColorRGBA boundsColor = new ColorRGBA(0f, 0f, 1f, 0.3f);
final Vector3f[] dir = new Vector3f[] { Vector3f.UNIT_Z,
Vector3f.UNIT_Z, Vector3f.UNIT_X, Vector3f.UNIT_X };
final float[] offsetX = new float[] { terrainSize / 2, terrainSize / 2,
0, terrainSize };
final float[] offsetZ = new float[] { 0, terrainSize, terrainSize / 2,
terrainSize / 2 };
for (int i = 0; i < 4; i++) {
final Box q = new Box(size / 2, size / 2, boundWidth / 2);
physicsGeom = new Geometry("physicsBounds" + i, q);
physicsGeom.lookAt(dir[i], Vector3f.UNIT_Y);
physicsGeom.setLocalTranslation(offsetX[i] - 0.5f, size / 2,
offsetZ[i] - 0.5f);
physicsGeom.setQueueBucket(RenderQueue.Bucket.Transparent);
physicsGeom.setShadowMode(RenderQueue.ShadowMode.Off);
physicsGeom.setCullHint(CullHint.Always);
// Lighting
final Material mat = MaterialFactory.LIGHTBLOW
.getInstance(GameClient.getInstance().getAssetManager());
mat.setBoolean("UseMaterialColors", true);
mat.setColor("Diffuse", boundsColor);
// Unshaded
// Material mat = TempCache.unshadedMaterial.clone();
// mat.setColor("Color, boundsColor");
mat.getAdditionalRenderState().setBlendMode(
RenderState.BlendMode.Alpha);
// mat.getAdditionalRenderState().setWireframe(true);
physicsGeom.setMaterial(mat);
// Physics
physicsBoundsControl = new RigidBodyControl(0.0f);
physicsBoundsControl.setCollisionGroup(COLLISION_TERRAIN);
physicsBoundsControl.setCollideWithGroups(COLLISION_PLAYERS);
physicsGeom.addControl(physicsBoundsControl);
worldNode.attachChild(physicsGeom);
ps.add(physicsBoundsControl);
}
}
public void remove(final PhysicsSpace ps) {
physicsGeom.removeControl(physicsBoundsControl);
physicsGeom.removeFromParent();
ps.remove(physicsBoundsControl);
ps.removeAll(this);
removeFromParent();
}
}
[/java]
And my usage (note: It contains some non-core references, but nothing affecting this particular part of it)
[java]
public Terrain createSingleTerrain(final CachedMap map,
final MapDefinition mapDef) {
final Material terrainMat = getMapMat(mapDef);
logger.log(Level.SEVERE, "Loading heightMap: {0} ",
map.getHeightMapPath());
final int patchSize = REGION_SIZE;
final int quadSize = patchSize * map.getWidth();
logger.log(Level.SEVERE, "Loading alphaMap: {0}", map.getAlphaMapPath());
final Terrain terrain = new Terrain("terrain", patchSize + 1,
quadSize + 1, heightmap.getHeightMap());
if (map.getAlphaMap(app.getAssetManager()) != null) {
terrainMat.setTexture("AlphaMap", app.getAssetManager()
.loadTexture(map.getAlphaMapPath()));
}
terrain.setMaterial(terrainMat);
terrain.setShadowMode(ShadowMode.Receive);
terrain.setLocalTranslation(new Vector3f(0.5f * quadSize, 0,
0.5f * quadSize));
...
}
[/java]