Someone else may give you a better solution that uses jme’s physics, but I stopped using CharacterControl or BetterCharacterControl for character movement in my projects 3 years ago when I had similar problems getting it to function right, and even still I got extremely low framerate when I’d get near 20 character controls. Unless anything has changed, I would personally say that those 2 classes are not viable outside of test cases.
As an alternative, I wrote my own very simple physics system that uses as little as 2 rays for moving a character every frame: one ray points down and determines the y position, and another ray points in the direction the character has moved in order to detect collisions. You can also check the contact normal of the downward facing ray to see if the player has moved onto a steep surface and use that to stop players from glitching up walls and big mountains.
I still use jme’s physics (minie specifically) for occasions where I need advanced physics functionality, like for ragdolls and dynamic knockback effects, but when the players or npcs are just walking around normally and playing animations, using a full fledged physics system seems to be overkill. I went from having 20 character control lagging out my cpu, to being able to have 100+ npcs without any noticeable fps drop on the cpu. And it looks/feels much better than the normal character control. I could never find a realistic sweet spot with the character control’s values like friction, mass, and jump height without causing some weird new buggy behavior to pop up every time I thought I got it right.
rigidBody.setGravity(moveForward); which basically creates a continuous pulling force towards the vector3f specified in your physicsSpace ,
rigidBody.applyCentralForce(moveForward); which is the same as impulse but this gets cleared after being applied .
NB: applyCentralForce or applyCentralImpulse is basically applying a force on the object assuming it’s effective center is the object center ie (0,0,0) w/ respect to the object node.
if , you need to change the effective center for this object during the application of the force , use :
applyForce(force,offset);
applyImpulse(force,offset);
Where offset is a vector3f instance , that’s used as an effective center for perception of that force.
protected void build(AssetManager manager) {
guy = new RigidBodyControl();
//guy.setJumpSpeed(jumpVel);
//guy.setFallSpeed(fallForce);
body = new Geometry(bodyName, new Box(1, height*0.5f, 1));
body.setLocalTranslation(pos);
Material mat = new Material(manager, "Common/MatDefs/Light/Lighting.j3md");
mat.setBoolean("UseMaterialColors", true);
mat.setColor("Diffuse", ColorRGBA.Blue);
body.setMaterial(mat);
body.addControl(guy);
guy.setPhysicsLocation(pos);
guy.setMass(500); // a very heavy dude lol
//guy.setGravity(new Vector3f(0, -20, 0)); deactivated, gravity applied elsewhere
guyNode.attachChild(body);
}
and I do my movement here:
protected void move(Camera cam) {
Vector3f camDir = cam.getDirection().multLocal(0.5f);
Vector3f camLeft = cam.getLeft().multLocal(0.2f);
Vector3f walkDirect = new Vector3f(0, 0, 0);
if (up) walkDirect.addLocal(camDir.x, 0, camDir.z);
if (down) walkDirect.addLocal(-camDir.x, 0, -camDir.z);
if (left) walkDirect.addLocal(camLeft);
if (right) walkDirect.addLocal(camLeft.negate());
//guy.setWalkDirection(walkDirect);
//pos = pos.add(walkDirect);
//guy.setPhysicsLocation(guy.getPhysicsLocation().add(walkDirect));
guy.setLinearVelocity(grav.add(walkDirect.mult(100)));
//guy.applyCentralForce(walkDirect);
}
A block in your lower blind spot would be detected by the downward facing ray, and then you can determine whether to let the player step up that block by comparing the y value gap to their step height. And to avoid an upper blind spot, I cast the ray from the top of the player, rather than the center.
Yes that’s how I do it. If you wanted to make it even better and don’t need a really high number of NPCs, then you could add another downward ray or also cast rays to the left and right to avoid any parts of the spatial’s limbs from clipping when walking parallel to a wall.
For larger NPCs you’d likely want to have your system use more rays like that to minimize the clipping so it will look better visually. But you could still get by with just a forward and downward facing ray without any game breaking issues.
If I detect a collision using a horizontal ray, how do I know where to move the player to get out of the block?
If I just stop the player from moving farther in that direction, it would result in sticky collisions.
I don’t think I have, I think I’m able to avoid this since running straight into anything always has a small amount of pushback to the player, and if they run into something at an angle then the pushback code will cause then to slide against it in the direction they’re going (by crossing the ray’s direction with the collision’s contactNormal), and this prevents sticky physics and a lot of other issues.
I’ve had issues with phasing through walls when there’s a sudden drop in fps. But the order of the ray cast and the movement can help fix this. Each frame, Its important to first do the ray cast in the desired walk direction and then apply the move once the results of the ray have confirmed it to be valid.