Substitutes for CharacterControl in v3.2

I need a substitute for CharacterControl in v3.2, because my player (using CC) has been “sticking” to the ground and messing up my movement.

I have tried using RigidBody instead, and now my player is becoming disbalanced and falling over. It’s really frustrating! :weary:

Is there something else I could use that is supported in jme v3.2?

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.

2 Likes

You can still control the RigidBodyControl with a custom AbstractControl using some forces , here’s a bit of it’s taste :

Vector3f moveForwardForce=new Vector3f(0f,0f,5f);
Vector3f moveBackwardForce=new Vector3f(0f,0f,-5f);
Vector3f moveRTForce=new Vector3f(-5f,0f,0f);
Vector3f moveLTForce=new Vector3f(5f,0f,0f);
Vector3f jumpForce=new Vector3f(0f,20f,0f);

RigidBodyControl rigidBodyControl=new RigidBodyControl(5f,CollisionShapeFactory.createDynamicMeshShape(npcSpatial));

keyBoard.setOnForwardCommand(()->{
rigidBodyControl.applyCentralImpulse(moveForwardForce);
});

keyBoard.setOnBackwardCommand(()->{
rigidBodyControl.applyCentralImpulse(moveBackwardForce);
});

keyBoard.setOnRTCommand(()->{
rigidBodyControl.applyCentralImpulse(moveRTForce);
});

keyBoard.setOnLTCommand(()->{
rigidBodyControl.applyCentralImpulse(moveLTForce);
});

keyBoard.setOnJumpCommand(()->{
rigidBodyControl.applyCentralImpulse(jumpForce);
});

You can also move this npcSpatial by :

  • 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.

1 Like

its rather because of floor CollisionObject or rigid body setting or because of some physics settings.
We would need to know more information.

1 Like

With your forward ray, wouldn’t you have blindspots where a block can pass undetected?

____
|  |        Blindspot
|  |-------------------------> ray
|__|        Blindspot
Player

It seems that any block in those blindspots but not in the ray would be a problem.

I set my RigidBody stuff here:

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.

So it’d be more like this:

_____
|   |---------------> ray
| P |  moving->
|___|        
  |
  |
  |
  |
  V
 ray
1 Like

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.

1 Like

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.

Nevermind, I got it! :grin:

Soooo much better than CharacterControl! Thanks a ton!

Edit: have you had any trouble with becoming stuck inside a block by sneaking in through a corner?

1 Like

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.