Normen, I have spent several hours on trying to get a vehicle to work without controls (only using PhysicsVehicle), starting from a stable working situation with a vehicle that did use the control, but I can’t get it to work, although I think I am 99% there. The wheels are positioned correctly and react to steering commands (they turn) but collision detection does not work.
I am going back to my original approach for now, using controls and copying the spatial coordinates back to the ES, but if you are interested in the control-less version, I can post a link to the project here.
I have a factory class it creates ControlDrivers based on entity CollisionShape and PhysicsControl component.
for HeightMap based terrains i just use the HeightfieldCollisionShape as you can see below.
public class BulletDriverFactory extends AbstractGameSystem implements PhysicsDriverFactory{
static Logger log = LoggerFactory.getLogger(BulletDriverFactory.class);
private EntityData ed;
private AssetManager assetManager;
@Override
protected void initialize() {
log.info("onInitialize()");
this.ed = getSystem(EntityData.class);
if (ed == null) {
throw new RuntimeException("PhysicsDriverFactory requires an EntityData object.");
}
assetManager = getSystem(AssetManager.class);
if (assetManager == null) {
throw new RuntimeException("PhysicsDriverFactory requires an AssetManager.");
}
}
@Override
public void start() {
log.info("start()");
}
@Override
public void stop() {
log.info("stop()");
}
@Override
protected void terminate() {
assetManager.clearCache();
}
@Override
public PhysicsControlDriver createDriver(EntityData ed, EntityId entityId) {
PhysicDriver driverInfo = ed.getComponent(entityId, PhysicDriver.class);
PhysicsControlDriver driver = null;
switch (driverInfo.getPhysicsShape()) {
case BulletDriverTypes.COLLISION_SHAPE_HEIGHTFIELD:
TerrainQuad terrainQuad = TerrainCreator.createNonMatTerrainQuad(assetManager, ed, ed.getComponent(entityId, Terrain.class));
switch (driverInfo.getPhysicsControl()) {
case BulletDriverTypes.CONTROL_RIGID_BODY:
log.info("Create physic driver:[CONTROL_RIGID_BODY, COLLISION_SHAPE_HEIGHTFIELD]");
driver = new RigidBodyDriver(new RigidBodyControl(new HeightfieldCollisionShape(terrainQuad.getHeightMap(), terrainQuad.getLocalScale()), 0));
break;
}
break;
case BulletDriverTypes.COLLISION_SHAPE_BOX:
switch (driverInfo.getPhysicsControl()) {
case BulletDriverTypes.CONTROL_RIGID_BODY:
log.info("Create physic driver:[CONTROL_RIGID_BODY, COLLISION_SHAPE_BOX]");
BoxShape shape = ed.getComponent(entityId, BoxShape.class);
BoxCollisionShape box = new BoxCollisionShape(shape.getHalfExtents());
MassProperties mass = ed.getComponent(entityId, MassProperties.class);
driver = new RigidBodyDriver(new RigidBodyControl(box, mass.getMass()));
break;
}
break;
case BulletDriverTypes.COLLISION_SHAPE_CAPSULE:
switch (driverInfo.getPhysicsControl()) {
case BulletDriverTypes.CONTROL_BETTER_CHARACTER:
log.info("Create physic driver:[CONTROL_BETTER_CHARACTER, COLLISION_SHAPE_CAPSULE]");
CapsuleShape shape = ed.getComponent(entityId, CapsuleShape.class);
MassProperties mass = ed.getComponent(entityId, MassProperties.class);
driver = new BetterCharacterDriver(new PhysicsCharacterControl(shape.getRadius(), shape.getHeight(), mass.getMass()));
break;
}
break;
case BulletDriverTypes.COLLISION_SHAPE_COMPOUND:
break;
case BulletDriverTypes.COLLISION_SHAPE_CONE:
break;
case BulletDriverTypes.COLLISION_SHAPE_CYLINDER:
break;
case BulletDriverTypes.COLLISION_SHAPE_GIMPACT:
break;
case BulletDriverTypes.COLLISION_SHAPE_HULL:
break;
case BulletDriverTypes.COLLISION_SHAPE_MESH:
break;
case BulletDriverTypes.COLLISION_SHAPE_PLANE:
break;
case BulletDriverTypes.COLLISION_SHAPE_SPHERE:
switch (driverInfo.getPhysicsControl()) {
case BulletDriverTypes.CONTROL_RIGID_BODY:
driver = new PhysicShipDriver();
break;
}
break;
}
if (driver == null) {
log.error("Unsuported Physics Driver !");
}
return driver;
}
}
for example this my RigidBodyDriver which wraps a RigidBodyControl inside.
And then the mechanics work just like the SimplePhysicState from sim-eth-es example.
public class RigidBodyDriver implements PhysicsControlDriver {
static Logger log = LoggerFactory.getLogger(RigidBodyDriver.class);
private RigidBodyControl control;
private Vector3f physicsLocation;
private Quaternion physicsRotation;
public RigidBodyDriver() {
}
public RigidBodyDriver(RigidBodyControl control) {
this.control = control;
}
@Override
public void addToPhysicSpace(PhysicsSpace physicsSpace) {
physicsSpace.add(control);
}
@Override
public void removeFromPhysicSpace(PhysicsSpace physicsSpace) {
physicsSpace.remove(control);
}
@Override
public void update(double stepTime, Body body) {
// Grab local versions of the player settings in case another
// thread sets them while we are calculating.
// Quaternion rot = physicsRotation;
// Vector3f loc = physicsLocation;
// control.setPhysicsRotation(rot);
// control.setPhysicsLocation(loc);
// Setup the current world rotation of the body
Quaternion rot = control.getPhysicsRotation();
body.orientation.set(rot.getX(), rot.getY(), rot.getZ(), rot.getW());
// Apply the accelerated velocity oriented into world space
Vector3f temp = control.getPhysicsLocation();
Vec3d pos = new Vec3d(temp.x, temp.y, temp.z);
body.pos.set(pos);
Vector3f temp2 = control.getLinearVelocity();
Vec3d v = new Vec3d(temp2.x, temp2.y, temp2.z);
body.velocity.set(v);
}
@Override
public void updatePhysicComponents(EntityData ed, EntityId entityId) {
log.info("updatePhysicComponents() :" + entityId.toString());
MassProperties mass = ed.getComponent(entityId, MassProperties.class);
Position pos = ed.getComponent(entityId, Position.class);
control.setMass(mass.getMass());
control.setPhysicsLocation(pos.getLocation().toVector3f());
PhysicsType physicType = ed.getComponent(entityId, PhysicsType.class);
if(physicType.getPhysicType() == PhysicsType.KINEMATIC)
control.setKinematic(true);
else
control.setKinematic(false);
}
public void applyMovementState(Vector3f location, Quaternion rotation) {
this.physicsLocation = location;
this.physicsRotation = rotation;
}
public RigidBodyControl getControl() {
return control;
}
}