I post here a controller which allow to move a physics component with only gravity (no torque/force) and catch collisions with other StaticPhysicsNode.
Good idea to move character in physics environnement!
Jme-jbullet do that, but actually i didn't see that on jmephysics!
import com.jme.input.InputHandler;
import com.jme.input.action.InputAction;
import com.jme.input.action.InputActionEvent;
import com.jme.math.Vector3f;
import com.jme.scene.Controller;
import com.jmex.physics.DynamicPhysicsNode;
import com.jmex.physics.PhysicsNode;
import com.jmex.physics.StaticPhysicsNode;
import com.jmex.physics.contact.ContactInfo;
import com.jmex.physics.material.Material;
/**
* Control a ghost physic node to be moved without physic interaction,
* like no physic, but catch collision with other StaticPhysicNode
*
* @author anykeyh@gmail.com
*/
public class CharacterController extends Controller {
private static final long serialVersionUID = 3152691286715564793L;
private int contactPointCount = 0;
private DynamicPhysicsNode nodeToControl;
private boolean onGround = false;
private Vector3f physicDecal = new Vector3f();
private InputHandler inputHandler = new InputHandler();
private Vector3f tmpVec = new Vector3f();
private class CollisionHandler extends InputAction {
@Override
public void performAction(InputActionEvent evt) {
ContactInfo info = (ContactInfo )evt.getTriggerData();
DynamicPhysicsNode self;
PhysicsNode other;
self = nodeToControl;
if(info.getNode1() == self) {
other = info.getNode2();
} else {
other = info.getNode1();
}
if(other instanceof StaticPhysicsNode) {
contactPointCount++;
info.getContactNormal(tmpVec);
if(other != info.getNode2()) {
tmpVec.negateLocal();
}
if(tmpVec.y > groundTriggerValue) {
onGround = true;
self.clearDynamics(); //Clear gravity
}
tmpVec.multLocal(info.getPenetrationDepth());
physicDecal.addLocal(tmpVec);
}
}
}
private float groundTriggerValue = 0.3f;
private void resetGathering() {
onGround = false;
contactPointCount = 0;
physicDecal.set(0,0,0);
}
private void applyTranslation() {
if(contactPointCount > 0) {
physicDecal.divideLocal(contactPointCount);
physicDecal.addLocal(nodeToControl.getLocalTranslation());
nodeToControl.getLocalTranslation().set(
physicDecal
);
}
}
public DynamicPhysicsNode getNodeToControl() {
return nodeToControl;
}
public void setNodeToControl(DynamicPhysicsNode nodeToControl) {
if(nodeToControl!=this.nodeToControl) {
if(this.nodeToControl!=null) {
inputHandler.clearActions();
}
this.nodeToControl = nodeToControl;
nodeToControl.setMaterial(Material.GHOST);
inputHandler.addAction(new CollisionHandler(), nodeToControl.getCollisionEventHandler() , false);
}
}
public boolean isOnGround() {
return onGround;
}
public float getGroundTriggerValue() {
return groundTriggerValue;
}
/**
* Set the value of the up vector to see if player is on ground
* @param groundTriggerValue
*/
public void setGroundTriggerValue(float groundTriggerValue) {
this.groundTriggerValue = groundTriggerValue;
}
@Override
public void update(float time) {
if(nodeToControl!=null) {
resetGathering();
inputHandler.update(time);
applyTranslation();
}
}
public CharacterController(DynamicPhysicsNode node) {
setNodeToControl(node);
}
}
You just have to add this controller on a dynamic physic node:
physicNode.addController(new CharacterController(physicNode));
It seems to work properly. Thanks to return here any issues you found ;)
And enjoy!