I’m building my first game using the physics engine and I’ve encountered some odd issues with jump(...)
. Currently, I have inputs settings dirty states that the main update thread uses to trigger jump actions; in my game I’m wanting to jump at an angle, but using the jump function with an angled vector causes the character to trace out a triangle with their flight path instead of a parabola. Finding this odd, I tried to get around the issue by setting the linear velocity at an angle; this cause behavior that is more odd as the unit vector parallel to gravity is completely ignored unless a jump
command has been issues on the given CharacterControl
previously. Below I’ve created a stripped down version of what I’m doing; have I improperly configured my physics space? or are there side effects with jumping and gravity that I’ve missed while reading over the documentation?
import com.jme3.app.SimpleApplication;
import com.jme3.system.AppSettings;
public class Example extends SimpleApplication {
public static void main(String[] args) {
Example example = new Example();
AppSettings appSettings = new AppSettings(false);
appSettings.setFrameRate(60);
example.setSettings(appSettings);
example.start();
}
@Override
public void simpleInitApp() {
ExampleState state = new ExampleState();
stateManager.attach(state);
}
}
import com.jme3.app.Application;
import com.jme3.app.SimpleApplication;
import com.jme3.app.state.AbstractAppState;
import com.jme3.app.state.AppStateManager;
import com.jme3.bullet.BulletAppState;
import com.jme3.bullet.collision.shapes.CollisionShape;
import com.jme3.bullet.control.CharacterControl;
import com.jme3.bullet.control.RigidBodyControl;
import com.jme3.bullet.util.CollisionShapeFactory;
import com.jme3.input.KeyInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.Spatial;
import com.jme3.scene.shape.Box;
public class ExampleState extends AbstractAppState {
private static final String JUMP = "jump";
private static final String UP = "upVector";
private static final String ANGLE_UP = "angleVector";
private CharacterControl control = null;
private SimpleApplication application = null;
private BulletAppState bulletAppState = new BulletAppState();
@Override
public void initialize(AppStateManager stateManager, Application app) {
application = (SimpleApplication) app;
application.getStateManager().attach(bulletAppState);
Spatial character = makePlayerSpatial();
control = makePlayerControl(character);
Spatial floor = makeFloorSpatial();
RigidBodyControl floorControl = makeFloorControl(floor);
application.getRootNode().attachChild(character);
application.getRootNode().attachChild(floor);
bulletAppState.getPhysicsSpace().add(control);
bulletAppState.getPhysicsSpace().add(floorControl);
setupInputs();
}
private Spatial makePlayerSpatial() {
Spatial output = new Geometry("player", new Box(1, 1, 1));
Material material = new Material(application.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
material.setColor("Color", ColorRGBA.DarkGray);
output.setMaterial(material);
return output;
}
private CharacterControl makePlayerControl(Spatial character) {
CollisionShape shape = CollisionShapeFactory.createBoxShape(character);
CharacterControl control = new CharacterControl(shape, 0.2f);
character.addControl(control);
control.setFallSpeed(1000);
control.setPhysicsLocation(new Vector3f(0, 5, -50));
// Changing the gravity's direction has a lot of odd effects.
control.setGravity(new Vector3f(0, -50, 0));
return control;
}
private Spatial makeFloorSpatial() {
Spatial output = new Geometry("floor", new Box(50, 0.1f, 1));
Material material = new Material(application.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
material.setColor("Color", ColorRGBA.Green);
output.setMaterial(material);
return output;
}
private RigidBodyControl makeFloorControl(Spatial floor) {
CollisionShape shape = CollisionShapeFactory.createBoxShape(floor);
RigidBodyControl control = new RigidBodyControl(shape, 0);
floor.addControl(control);
control.setPhysicsLocation(new Vector3f(0, 0, -50));
return control;
}
private void setupInputs() {
application.getInputManager().addMapping(JUMP, new KeyTrigger(KeyInput.KEY_W));
application.getInputManager().addMapping(UP, new KeyTrigger(KeyInput.KEY_S));
application.getInputManager().addMapping(ANGLE_UP, new KeyTrigger(KeyInput.KEY_X));
application.getInputManager().addListener(jumpListener, JUMP, UP, ANGLE_UP);
}
private ActionListener jumpListener = new ActionListener() {
@Override
public void onAction(String name, boolean isPressed, float tpf) {
if (isPressed) {
if (name.equals(JUMP)) jump = true;
if (name.equals(UP)) up = true;
if (name.equals(ANGLE_UP)) angleUp = true;
}
}
};
private boolean jump = false;
private boolean up = false;
private boolean angleUp = false;
@Override
public void update(float tpf) {
if (jump) {
control.jump(new Vector3f(0, 30f, 0));
jump = false;
}
if (up) {
control.setLinearVelocity(new Vector3f(0.1f, 15f, 0));
up = false;
}
if (angleUp) {
control.jump(new Vector3f(40f, 30f, 0));
angleUp = false;
}
}
}