[Solved] Gravity for the BetterCharacterControl does not use mass

I have a simple application spawns a model controled with a BetterCharacterControl on top of a static floor.

However how high I spawn the model or how heavy it is, it will always fall at the same speed.

My question is : how can I make the gravity realistic? It’s as if my model was a giant heavy feather falling slowly.

Here’s my code :

package com.chevreuilgames.retroflashyrpg;

import com.chevreuilgames.retroflashyrpg.assets.AssetHierarchy;
import com.jme3.app.SimpleApplication;
import com.jme3.bullet.BulletAppState;
import com.jme3.bullet.control.BetterCharacterControl;
import com.jme3.bullet.control.RigidBodyControl;
import com.jme3.input.KeyInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.light.AmbientLight;
import com.jme3.light.DirectionalLight;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.post.FilterPostProcessor;
import com.jme3.post.ssao.SSAOFilter;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.shape.Box;

public class Game_Main extends SimpleApplication {

    private BulletAppState bulletAppState;
    private Node manModel;
    private Node manNode;
    private BetterCharacterControl manCharControl;
    private Material manMaterial;

    public static void main(String[] args) {
        SimpleApplication app = new Game_Main();
        app.start();
    }

    @Override
    public void simpleInitApp() {
        bulletAppState = new BulletAppState();
        stateManager.attach(bulletAppState);
        bulletAppState.getPhysicsSpace().setGravity(new Vector3f(0, -9.81f, 0));

        setupCamera();
        initFloor();
        initManMaterial();
        initManModel();
        initLights();
        initKeys();
    }

    private void setupCamera() {
        flyCam.setMoveSpeed(flyCam.getMoveSpeed() * 40f);
        cam.setLocation(Vector3f.UNIT_XYZ.mult(50));
        cam.lookAt(Vector3f.ZERO.clone(), Vector3f.UNIT_Y.clone());
    }

    private void initKeys() {
        inputManager.addMapping("Jump", new KeyTrigger(KeyInput.KEY_SPACE));
        inputManager.addListener(actionListener, "Jump");
    }

    private void initFloor() {
        Material floorMaterial = new Material(assetManager,
                "Common/MatDefs/Light/Lighting.j3md");
        floorMaterial.setBoolean("UseMaterialColors", true);
        floorMaterial.setColor("Ambient", ColorRGBA.LightGray);
        floorMaterial.setColor("Diffuse", ColorRGBA.LightGray);
        floorMaterial.setColor("Specular", ColorRGBA.LightGray);
        floorMaterial.setFloat("Shininess", 64f);  // [0,128]

        Box floorShape = new Box(new Vector3f(-100, -1, -100), new Vector3f(100, 1, 100));
        Geometry floorGeometry = new Geometry("floor", floorShape);
        floorGeometry.setLocalTranslation(0, -1, 0);

        floorGeometry.setMaterial(floorMaterial);
        rootNode.attachChild(floorGeometry);

        RigidBodyControl floorPhysics = new RigidBodyControl(0);
        floorGeometry.addControl(floorPhysics);
        floorPhysics.setFriction(10f);
        bulletAppState.getPhysicsSpace().add(floorPhysics);
    }

    private void initManMaterial() {
        manMaterial = new Material(assetManager,
                "Common/MatDefs/Light/Lighting.j3md");
        manMaterial.setBoolean("UseMaterialColors", true);
        manMaterial.setColor("Ambient", ColorRGBA.Cyan);
        manMaterial.setColor("Diffuse", ColorRGBA.Cyan);
        manMaterial.setColor("Specular", ColorRGBA.White);
        manMaterial.setFloat("Shininess", 64f);  // [0,128]
    }

    private void initManModel() {
        manModel = (Node) assetManager.loadModel(AssetHierarchy.Man.getPath());
        manModel.setLocalTranslation(0, 11.5f, 0);
        manModel.setMaterial(manMaterial);
        rootNode.attachChild(manModel);

        manNode = new Node();
        manNode.attachChild(manModel);
        rootNode.attachChild(manNode);

        manCharControl = new BetterCharacterControl(5f,
                11.5f,
                5f); // construct character. (If your character bounces, try increasing height and weight.)
        manNode.addControl(manCharControl);

        manCharControl.setJumpForce(new Vector3f(0, 50f, 0));
        manCharControl.warp(new Vector3f(0, 10, 0));

        bulletAppState.getPhysicsSpace().add(manCharControl);
        bulletAppState.getPhysicsSpace().addAll(manNode);
    }

    private void initLights() {
        DirectionalLight directionalLight = new DirectionalLight();
        directionalLight.setDirection(Vector3f.UNIT_XYZ.mult(-1).normalizeLocal());
        directionalLight.setColor(ColorRGBA.White);
        rootNode.addLight(directionalLight);

        AmbientLight ambientLight = new AmbientLight();
        ambientLight.setColor(ColorRGBA.White.mult(0.1f));
        rootNode.addLight(ambientLight);

        FilterPostProcessor fpp = new FilterPostProcessor(assetManager);
        SSAOFilter ssaoFilter = new SSAOFilter(12.94f, 43.92f, 0.33f, 0.61f);
        fpp.addFilter(ssaoFilter);
        viewPort.addProcessor(fpp);
    }

    private final ActionListener actionListener = new ActionListener() {
        @Override
        public void onAction(String name, boolean keyPressed, float tpf) {
            if (name.equals("Jump") && !keyPressed) {
                manCharControl.jump();
            }
        }
    };
}

In the absence of air resistance, light and massive objects fall at the same speed.

Either setGravity() on the physics space or else setGravity() on the control.

3 Likes

It seems that I should have failed all my physics classes.

On another note, even when I set the gravity to something like -2000, it still falls extremely slowly.

manCharControl = new BetterCharacterControl(5f, 11.5f, 5f);
manNode.addControl(manCharControl);

manCharControl.setJumpForce(new Vector3f(0, 50f, 0));
manCharControl.setGravity(new Vector3f(0, -20000.81f, 0));
manCharControl.warp(new Vector3f(0, 20, 0));

EDIT : I think I got it : the “local” gravity doesn’t do anything but the global gravity actually affects the model. It works now.

1 Like

I suspect there’s an ordering issue. If you setGravity() on the rigid body and then add it to the physics space, the physics space gravity will override the rigid body’s setting.

2 Likes