Hello, I’ve been working on a scenario to test out the engine and I’ve run into a problem. If I let the frame rate run above ~200 fps the BetterCharacterControl objects seem to stop responding to method calls located in the input listener onAnalog(). I’m wondering if the frame rate is somehow outpacing the event report rate of the listener or if there is some acceleration value to BetterCharacterControl that is being reset with each call to setWalkDirection(). Any insights into what’s going on would be greatly appreciated. Here’s the relevant code:
private TestGame game;
public static void main(String[] args) {
Main app = new Main();
AppSettings cfg = new AppSettings(true);
cfg.setFrameRate(300);
cfg.setVSync(false);
cfg.setFrequency(48);
cfg.setResolution(960, 540);
cfg.setFullscreen(false);
cfg.setSamples(0);
cfg.setTitle("Test Game");
cfg.setUseJoysticks(true);
app.setShowSettings(false);
app.setSettings(cfg);
app.start();
}
@Override
public void simpleInitApp() {
game = new TestGame();
}
@Override
public void simpleUpdate(float tpf) {
game.eventLoop();
}
@Override
public void simpleRender(RenderManager rm) {
game.render();
}
private class TestGame implements ActionListener, AnalogListener {
private final long epoch;
private long AnalogInputTime;
private final Vector3f player1StickDirection, player2StickDirection, isoVector;
private final BulletAppState bulletAppState;
private final Spatial testRoomModel, player1Model, player2Model;
private final BetterCharacterControl player1Phys, player2Phys;
private TestGame() {
//init fields
epoch = currentTimeMillis();
AnalogInputTime = epoch;
player1StickDirection = new Vector3f();
player2StickDirection = new Vector3f();
isoVector = new Vector3f();
bulletAppState = new BulletAppState();
//load models
testRoomModel = assetManager.loadModel(
"Models/test_room/test_room.j3o");
player1Model = assetManager.loadModel(
"Models/test_character/test_character.j3o");
player2Model = player1Model.clone();
//load materials
Material normalMat = new Material(
assetManager, "Common/MatDefs/Misc/ShowNormals.j3md");
//assign materials
testRoomModel.setMaterial(normalMat);
player1Model.setMaterial(normalMat);
player2Model.setMaterial(normalMat);
//register physics with stateManager
stateManager.attach(bulletAppState);
//generate collision geometry
CollisionShape testRoomCollision
= CollisionShapeFactory.createMeshShape((Node) testRoomModel);
//create physics control geometry
RigidBodyControl testRoomPhys = new RigidBodyControl(
testRoomCollision, 0);
player1Phys = new BetterCharacterControl(2f, 6f, 1f);
player2Phys = new BetterCharacterControl(2f, 6f, 1f);
//configure physics
player1Phys.setJumpForce(new Vector3f(0, 12f, 0));
player1Phys.setGravity(new Vector3f(0, 1f, 0));
player2Phys.setJumpForce(new Vector3f(0, 12f, 0));
player2Phys.setGravity(new Vector3f(0, 1f, 0));
//create and configure scene lighting
DirectionalLight sun = new DirectionalLight();
sun.setDirection(new Vector3f(-0.1f, -0.7f, -1.0f));
//configure camera
flyCam.setEnabled(false);
cam.setLocation(new Vector3f(25, 25, 25));
cam.lookAt(Vector3f.ZERO, Vector3f.ZERO);
//configure joystick input
Joystick[] joysticks = inputManager.getJoysticks();
if (joysticks != null) {
joysticks[0].getXAxis().assignAxis("right", "left");
joysticks[0].getYAxis().assignAxis("forward", "backward");
joysticks[0].getButton("2").assignButton("jump");
joysticks[0].getButton("0").assignButton("reset");
if (joysticks.length > 1) {
joysticks[1].getXAxis().assignAxis("right2", "left2");
joysticks[1].getYAxis().assignAxis("forward2",
"backward2");
joysticks[1].getButton("2").assignButton("jump2");
joysticks[1].getButton("0").assignButton("reset2");
inputManager.addListener(this, "left", "right", "forward",
"backward", "left2", "right2", "forward2",
"backward2",
"jump", "jump2", "reset", "reset2");
}
} else {
out.println("No joysticks detected!");
}
//register scene objects
rootNode.attachChild(testRoomModel);
rootNode.attachChild(player1Model);
rootNode.attachChild(player2Model);
rootNode.addLight(sun);
//register physics
bulletAppState.getPhysicsSpace().add(testRoomPhys);
bulletAppState.getPhysicsSpace().add(player1Phys);
bulletAppState.getPhysicsSpace().add(player2Phys);
//bind physics to geometry
testRoomModel.addControl(testRoomPhys);
player1Model.addControl(player1Phys);
player2Model.addControl(player2Phys);
//position players
player1Phys.warp(new Vector3f(-5, 16, 5));
player2Phys.warp(new Vector3f(5, 16, -5));
}
void eventLoop() {
//ensure player stops if analog input stops
if (currentTimeMillis() - AnalogInputTime > .2) {
player1Phys.setWalkDirection(Vector3f.ZERO);
player2Phys.setWalkDirection(Vector3f.ZERO);
}
}
void render() {
}
@Override
public void onAction(String name, boolean isPressed, float tpf) {
if (isPressed) {
switch (name) {
case "jump":
player1Phys.jump();
break;
case "jump2":
player2Phys.jump();
break;
case "reset":
player1Phys.warp(new Vector3f(0, 15, 0));
break;
case "reset2":
player2Phys.warp(new Vector3f(0, 15, 0));
break;
}
}
}
@Override
public void onAnalog(String name, float value, float tpf) {
AnalogInputTime = currentTimeMillis();
//player (1, 2) abstraction
Vector3f stickDirection;
Spatial playerModel;
BetterCharacterControl playerPhys;
if (name.contains("2")) {
stickDirection = player2StickDirection;
playerPhys = player2Phys;
playerModel = player2Model;
} else {
stickDirection = player1StickDirection;
playerPhys = player1Phys;
playerModel = player1Model;
}
switch (name) {
case "left":
case "left2":
stickDirection.x = -value;
break;
case "right":
case "right2":
stickDirection.x = value;
break;
case "forward":
case "forward2":
stickDirection.z = value;
break;
case "backward":
case "backward2":
stickDirection.z = -value;
break;
}
//'dead-zone' input threshold
float deadZone = .005f;
float magnitude = stickDirection.length();
if (magnitude < deadZone) {
return;
}
stickDirection = stickDirection.normalize().mult(
(magnitude - deadZone) / (1
- deadZone));
//cartesian to isometric coordinate conversion
CoordPair isoPair = CoordPair.cartToIso(stickDirection.x,
stickDirection.z);
isoVector.set(isoPair.x, 0, isoPair.y);
//prevent passing -0 to physics methods
if (isoVector.x == 0 || isoVector.x == -0 && isoVector.z == 0
|| isoVector.z == -0) {
playerPhys.setWalkDirection(Vector3f.ZERO);
} else {
playerPhys.setWalkDirection(isoVector.normalize().mult(5));
playerPhys.setViewDirection(isoVector);
playerModel.lookAt(isoVector, Vector3f.UNIT_Y);
}
}
}}