[SOLVED] Physics and CameraNode

I made an terrain with a blue box that falls down on the terrain with gravity . I can’t remember if I could move it around. I try to move the blue box around with the camera behind it in 3rd person view. The box is stuck in the sky and won’t fall down if I try to make the camera 3rd person. It will also not move around.
Can anyone help me with the code?

This is my code:

package mygame;

import com.jme3.app.SimpleApplication;
import com.jme3.bullet.BulletAppState;
import com.jme3.bullet.collision.shapes.CapsuleCollisionShape;
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.ChaseCamera;
import com.jme3.input.KeyInput;
import com.jme3.input.MouseInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.input.controls.MouseAxisTrigger;
import com.jme3.input.controls.MouseButtonTrigger;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.renderer.Camera;
import com.jme3.renderer.RenderManager;
import com.jme3.scene.CameraNode;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.control.CameraControl.ControlDirection;
import com.jme3.scene.shape.Box;
import com.jme3.terrain.geomipmap.TerrainLodControl;
import com.jme3.terrain.geomipmap.TerrainQuad;
import com.jme3.terrain.heightmap.AbstractHeightMap;
import com.jme3.terrain.heightmap.ImageBasedHeightMap;
import com.jme3.texture.Texture;
import com.jme3.texture.Texture.WrapMode;
import java.util.ArrayList;
import java.util.List;

public class Main extends SimpleApplication implements ActionListener{
    
    private BulletAppState bulletAppState;
    private RigidBodyControl landscape;
    private CharacterControl player;
    private Vector3f walkDirection = new Vector3f();
    private boolean left = false, right = false, up = false, down = false;
    private TerrainQuad terrain;
    private Material mat_terrain;
    CameraNode camNode;
    boolean rotate = false;
    Vector3f direction = new Vector3f();
    Node boxNode = new Node("Player");
    
    public static void main(String[] args) {
        Main app = new Main();
        app.start();
    }

    @Override
    public void simpleInitApp() {
        
        //flyCam.setEnabled(false);
        
        bulletAppState = new BulletAppState();
        stateManager.attach(bulletAppState);
        
        Box b = new Box(1, 1, 1);
        Geometry geom = new Geometry("Box", b);

        Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
        mat.setColor("Color", ColorRGBA.Blue);
        geom.setMaterial(mat);

        
        
        mat_terrain = new Material(assetManager, "Common/MatDefs/Terrain/Terrain.j3md");
        Texture sand = assetManager.loadTexture("Textures/Terrain/sand.jpg");
        sand.setWrap(WrapMode.Repeat);
        mat_terrain.setTexture("Tex1", sand);
        mat_terrain.setFloat("Tex1Scale", 64f);
        
        AbstractHeightMap heightmap = null;
        Texture heightMapImage = assetManager.loadTexture("Textures/Terrain/heightmap.png");
        heightmap = new ImageBasedHeightMap(heightMapImage.getImage());
        heightmap.load();
        
        int patchSize = 65;
        terrain = new TerrainQuad("my terrain", patchSize, 513, heightmap.getHeightMap());
        
        terrain.setMaterial(mat_terrain);
        terrain.setLocalTranslation(0, -100, 0);
        terrain.setLocalScale(2f, 1f, 2f);
        rootNode.attachChild(terrain);
        
        List<Camera> cameras = new ArrayList<Camera>();
        cameras.add(getCamera());
        TerrainLodControl control = new TerrainLodControl(terrain, cameras);
        terrain.addControl(control);
        
        terrain.addControl(new RigidBodyControl(0));
        
        CapsuleCollisionShape capsuleShape = new CapsuleCollisionShape(1.5f, 6f, 1);
        player = new CharacterControl(capsuleShape, 0.05f);
        player.setJumpSpeed(20);
        player.setFallSpeed(30);

        player.setPhysicsLocation(new Vector3f(-10, 10, 10));
        
        bulletAppState.getPhysicsSpace().add(terrain);
        bulletAppState.getPhysicsSpace().add(player);
        
        player.setGravity(new Vector3f(0,-30f,0));
        
        
        // Disable the default flyby cam
        flyCam.setEnabled(false);
        // Enable a chase cam for this target (typically the player).
        ChaseCamera chaseCam = new ChaseCamera(cam, boxNode, inputManager);
        chaseCam.setSmoothMotion(true);
        
        rootNode.attachChild(boxNode);
        boxNode.attachChild(geom);
        
        
        // Disable the default flyby cam
        flyCam.setEnabled(false);
        //create the camera Node
        camNode = new CameraNode("Camera Node", cam);
        //This mode means that camera copies the movements of the target:
        camNode.setControlDir(ControlDirection.SpatialToCamera);
        //Attach the camNode to the target:
        boxNode.attachChild(camNode);
        //Move camNode, e.g. behind and above the target:
        camNode.setLocalTranslation(new Vector3f(0, 5, -5));
        //Rotate the camNode to look at the target:
        camNode.lookAt(boxNode.getLocalTranslation(), Vector3f.UNIT_Y);
        
        registerInput();
    }
    
    public void registerInput() {

        inputManager.addMapping("moveForward", new KeyTrigger(keyInput.KEY_UP), new KeyTrigger(keyInput.KEY_W));

        inputManager.addMapping("moveBackward", new KeyTrigger(keyInput.KEY_DOWN), new KeyTrigger(keyInput.KEY_S));

        inputManager.addMapping("moveRight", new KeyTrigger(keyInput.KEY_RIGHT), new KeyTrigger(keyInput.KEY_D));

        inputManager.addMapping("moveLeft", new KeyTrigger(keyInput.KEY_LEFT), new KeyTrigger(keyInput.KEY_A));

        inputManager.addMapping("toggleRotate", new MouseButtonTrigger(MouseInput.BUTTON_LEFT));

        inputManager.addMapping("rotateRight", new MouseAxisTrigger(MouseInput.AXIS_X, true));

        inputManager.addMapping("rotateLeft", new MouseAxisTrigger(MouseInput.AXIS_X, false));

        inputManager.addListener(this, "moveForward", "moveBackward", "moveRight", "moveLeft");

        inputManager.addListener(this, "rotateRight", "rotateLeft", "toggleRotate");
    }
    
    public void onAnalog(String name, float value, float tpf) {

        //computing the normalized direction of the cam to move the teaNode

        direction.set(cam.getDirection()).normalizeLocal();

        if (name.equals("moveForward")) {

          direction.multLocal(5 * tpf);

          boxNode.move(direction);

        }

        if (name.equals("moveBackward")) {

          direction.multLocal(-5 * tpf);

          boxNode.move(direction);

        }

        if (name.equals("moveRight")) {

          direction.crossLocal(Vector3f.UNIT_Y).multLocal(5 * tpf);

          boxNode.move(direction);

        }

        if (name.equals("moveLeft")) {

          direction.crossLocal(Vector3f.UNIT_Y).multLocal(-5 * tpf);

          boxNode.move(direction);

        }

        if (name.equals("rotateRight") && rotate) {

          boxNode.rotate(0, 5 * tpf, 0);

        }

        if (name.equals("rotateLeft") && rotate) {

          boxNode.rotate(0, -5 * tpf, 0);

        }
    }    


  


    
    @Override
    public void onAction(String name, boolean keyPressed, float tpf) {

        if (name.equals("displayPosition") && keyPressed) {

          boxNode.move(10, 10, 10);
        }
    }     
    
        

    

    

    @Override
    public void simpleUpdate(float tpf) {
        Vector3f camDir = cam.getDirection().clone().multLocal(0.6f);
        Vector3f camLeft = cam.getLeft().clone().multLocal(0.4f);
        walkDirection.set(0, 0, 0);
        if (left)  { walkDirection.addLocal(camLeft); }
        if (right) { walkDirection.addLocal(camLeft.negate()); }
        if (up)    { walkDirection.addLocal(camDir); }
        if (down)  { walkDirection.addLocal(camDir.negate()); }
        player.setWalkDirection(walkDirection);
        cam.setLocation(player.getPhysicsLocation());
    }
    

    @Override
    public void simpleRender(RenderManager rm) {
        //TODO: add render code
    }
}

When you use physics you manipulate the physics control, not the spatial.

I made adjustements to the code. Now the cube has gravity , it falls down but the camera won’t follow.

package mygame;

import com.jme3.app.SimpleApplication;
import com.jme3.bullet.BulletAppState;
import com.jme3.bullet.collision.shapes.CapsuleCollisionShape;
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.ChaseCamera;
import com.jme3.input.KeyInput;
import com.jme3.input.MouseInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.AnalogListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.input.controls.MouseAxisTrigger;
import com.jme3.input.controls.MouseButtonTrigger;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.renderer.Camera;
import com.jme3.renderer.RenderManager;
import com.jme3.scene.CameraNode;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.control.CameraControl.ControlDirection;
import com.jme3.scene.shape.Box;
import com.jme3.terrain.geomipmap.TerrainLodControl;
import com.jme3.terrain.geomipmap.TerrainQuad;
import com.jme3.terrain.heightmap.AbstractHeightMap;
import com.jme3.terrain.heightmap.ImageBasedHeightMap;
import com.jme3.texture.Texture;
import com.jme3.texture.Texture.WrapMode;
import java.util.ArrayList;
import java.util.List;

/**
 * This is the Main Class of your Game. You should only do initialization here.
 * Move your Logic into AppStates or Controls
 * @author normenhansen
 */
public class Main extends SimpleApplication{
    
    private BulletAppState bulletAppState;
    private RigidBodyControl landscape;
    private TerrainQuad terrain;
    private Material mat_terrain;
    CameraNode camNode;
    boolean rotate = false;
    Vector3f direction = new Vector3f();
    Node boxNode = new Node("Player");
    private boolean isRunning = true;

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

    @Override
    public void simpleInitApp() {
        
           
        bulletAppState = new BulletAppState();
        stateManager.attach(bulletAppState);
        
        Box b = new Box(1, 1, 1);
        Geometry geom = new Geometry("Box", b);

        Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
        mat.setColor("Color", ColorRGBA.Blue);
        geom.setMaterial(mat);

        mat_terrain = new Material(assetManager, "Common/MatDefs/Terrain/Terrain.j3md");
        Texture sand = assetManager.loadTexture("Textures/Terrain/sand.jpg");
        sand.setWrap(WrapMode.Repeat);
        mat_terrain.setTexture("Tex1", sand);
        mat_terrain.setFloat("Tex1Scale", 64f);
        
        AbstractHeightMap heightmap = null;
        Texture heightMapImage = assetManager.loadTexture("Textures/Terrain/heightmap.png");
        heightmap = new ImageBasedHeightMap(heightMapImage.getImage());
        heightmap.load();
        
        int patchSize = 65;
        terrain = new TerrainQuad("my terrain", patchSize, 513, heightmap.getHeightMap());
        
        terrain.setMaterial(mat_terrain);
        terrain.setLocalTranslation(0, -100, 0);
        terrain.setLocalScale(2f, 1f, 2f);
        rootNode.attachChild(terrain);
        /*
        List<Camera> cameras = new ArrayList<Camera>();
        cameras.add(getCamera());
        TerrainLodControl control = new TerrainLodControl(terrain, cameras);
        terrain.addControl(control);
        */
        terrain.addControl(new RigidBodyControl(0));
        
        CollisionShape sceneShape =
            CollisionShapeFactory.createMeshShape(geom);
            landscape = new RigidBodyControl(sceneShape, 0);
            geom.addControl(new RigidBodyControl(1));
        
                
        bulletAppState.getPhysicsSpace().add(terrain);
        bulletAppState.getPhysicsSpace().add(geom);
        
        rootNode.attachChild(boxNode);
        boxNode.attachChild(geom);
                
        // Disable the default flyby cam
        flyCam.setEnabled(false);
        //create the camera Node
        camNode = new CameraNode("Camera Node", cam);
        //This mode means that camera copies the movements of the target:
        camNode.setControlDir(ControlDirection.SpatialToCamera);
        //Attach the camNode to the target:
        boxNode.attachChild(camNode);
        //Move camNode, e.g. behind and above the target:
        camNode.setLocalTranslation(new Vector3f(0, 5, -5));
        //Rotate the camNode to look at the target:
        camNode.lookAt(boxNode.getLocalTranslation(), Vector3f.UNIT_Y);
        
        //registerInput();
        initKeys(); // load my custom keybinding
    }
    
    private void initKeys() {
        // You can map one or several inputs to one named action
        inputManager.addMapping("Pause",  new KeyTrigger(KeyInput.KEY_P));
        inputManager.addMapping("Left",   new KeyTrigger(KeyInput.KEY_J));
        inputManager.addMapping("Right",  new KeyTrigger(KeyInput.KEY_K));
        inputManager.addMapping("Rotate", new KeyTrigger(KeyInput.KEY_SPACE),
                                          new MouseButtonTrigger(MouseInput.BUTTON_LEFT));
        // Add the names to the action listener.
        inputManager.addListener(actionListener, "Pause");
        inputManager.addListener(analogListener, "Left", "Right", "Rotate");
    }
    
    
    private final AnalogListener analogListener = new AnalogListener() {
        @Override
        public void onAnalog(String name, float value, float tpf) {
            if (isRunning) {
                if (name.equals("Rotate")) {
                    boxNode.rotate(0, value * speed, 0);
                }
                if (name.equals("Right")) {
                    Vector3f v = boxNode.getLocalTranslation();
                    boxNode.setLocalTranslation(v.x + value * speed, v.y, v.z);
                }
                if (name.equals("Left")) {
                    Vector3f v = boxNode.getLocalTranslation();
                    boxNode.setLocalTranslation(v.x - value * speed, v.y, v.z);
                }
            } else {
                System.out.println("Press P to unpause.");
            }
        }
    };    


  


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


  
    
        

    

    

    @Override
    public void simpleUpdate(float tpf) {
        
        
    }
    
    

    @Override
    public void simpleRender(RenderManager rm) {
        //TODO: add render code
    }
}

it seems that camNode is attached to boxNode , where the RigidBodyControl is attached to geom
I am not certain, but I believe boxNode stays in place while physics moves geom around, and camNode keeps looking at boxNode still at the initial position.
maybe camNode should be attached to geom, or maybe boxNode should get the RigidBodyControl.
Using the physics debug view setting bulletAppState.setDebugEnabled(true); could help determine what is happening here.

also, this may be trivial but landscape doesn’t look like it is being used, and sceneShape should probably be created from terrain rather than geom.

I fixed the code. Now the box falls and the camera follows the cube but it doesn’t stop on the terrain and keeps falling.

This is my new code:

package mygame;

import com.jme3.app.SimpleApplication;
import com.jme3.bullet.BulletAppState;
import com.jme3.bullet.collision.shapes.CollisionShape;
import com.jme3.bullet.control.RigidBodyControl;
import com.jme3.bullet.util.CollisionShapeFactory;
import com.jme3.input.KeyInput;
import com.jme3.input.MouseInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.AnalogListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.input.controls.MouseButtonTrigger;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.renderer.RenderManager;
import com.jme3.scene.CameraNode;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.control.CameraControl.ControlDirection;
import com.jme3.scene.shape.Box;
import com.jme3.terrain.geomipmap.TerrainQuad;
import com.jme3.terrain.heightmap.AbstractHeightMap;
import com.jme3.terrain.heightmap.ImageBasedHeightMap;
import com.jme3.texture.Texture;
import com.jme3.texture.Texture.WrapMode;

/**
 * This is the Main Class of your Game. You should only do initialization here.
 * Move your Logic into AppStates or Controls
 * @author normenhansen
 */
public class Main extends SimpleApplication{
    
    private BulletAppState bulletAppState;
    private RigidBodyControl landscape, player;
    private TerrainQuad terrain;
    private Material mat_terrain;
    CameraNode camNode;
    boolean rotate = false;
    Vector3f direction = new Vector3f();
    Node boxNode = new Node("Player");
    private boolean isRunning = true;
    float speed = 10f;
    
    
    public static void main(String[] args) {
        Main app = new Main();
        app.start();
    }

    @Override
    public void simpleInitApp() {
        
           
        bulletAppState = new BulletAppState();
        stateManager.attach(bulletAppState);
        
        Box b = new Box(1, 1, 1);
        Geometry geom = new Geometry("Box", b);

        Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
        mat.setColor("Color", ColorRGBA.Blue);
        geom.setMaterial(mat);

        mat_terrain = new Material(assetManager, "Common/MatDefs/Terrain/Terrain.j3md");
        Texture sand = assetManager.loadTexture("Textures/Terrain/sand.jpg");
        sand.setWrap(WrapMode.Repeat);
        mat_terrain.setTexture("Tex1", sand);
        mat_terrain.setFloat("Tex1Scale", 64f);
        
        AbstractHeightMap heightmap = null;
        Texture heightMapImage = assetManager.loadTexture("Textures/Terrain/heightmap.png");
        heightmap = new ImageBasedHeightMap(heightMapImage.getImage());
        heightmap.load();
        
        int patchSize = 65;
        terrain = new TerrainQuad("my terrain", patchSize, 513, heightmap.getHeightMap());
        
        terrain.setMaterial(mat_terrain);
        terrain.setLocalTranslation(0, -100, 0);
        terrain.setLocalScale(2f, 1f, 2f);
        rootNode.attachChild(terrain);
        /*
        List<Camera> cameras = new ArrayList<Camera>();
        cameras.add(getCamera());
        TerrainLodControl control = new TerrainLodControl(terrain, cameras);
        terrain.addControl(control);
        */
        
        CollisionShape terrainShape =
            CollisionShapeFactory.createMeshShape(terrain);
        landscape = new RigidBodyControl(terrainShape, 0);
        
        CollisionShape boxShape =
            CollisionShapeFactory.createMeshShape(boxNode);
        player = new RigidBodyControl(boxShape, 1);
        
        terrain.addControl(landscape);
        boxNode.addControl(player);
        
        //terrain.addControl(new RigidBodyControl(-1f));
        
        //boxNode.addControl(new RigidBodyControl(1f));
        
        bulletAppState.getPhysicsSpace().add(terrain);
        bulletAppState.getPhysicsSpace().add(boxNode);
                
        rootNode.attachChild(boxNode);
        boxNode.attachChild(geom);
                
        // Disable the default flyby cam
        flyCam.setEnabled(false);
        //create the camera Node
        camNode = new CameraNode("Camera Node", cam);
        //This mode means that camera copies the movements of the target:
        camNode.setControlDir(ControlDirection.SpatialToCamera);
        //Attach the camNode to the target:
        boxNode.attachChild(camNode);
        //Move camNode, e.g. behind and above the target:
        camNode.setLocalTranslation(new Vector3f(0, 5, -5));
        //Rotate the camNode to look at the target:
        camNode.lookAt(boxNode.getLocalTranslation(), Vector3f.UNIT_Y);
        
        initKeys();
        
        bulletAppState.setDebugEnabled(true);
    }
    
    private void initKeys() {
        // You can map one or several inputs to one named action
        inputManager.addMapping("Pause",  new KeyTrigger(KeyInput.KEY_P));
        inputManager.addMapping("Left",   new KeyTrigger(KeyInput.KEY_J));
        inputManager.addMapping("Right",  new KeyTrigger(KeyInput.KEY_K));
        inputManager.addMapping("Rotate", new KeyTrigger(KeyInput.KEY_SPACE),
                                          new MouseButtonTrigger(MouseInput.BUTTON_LEFT));
        // Add the names to the action listener.
        inputManager.addListener(actionListener, "Pause");
        inputManager.addListener(analogListener, "Left", "Right", "Rotate");
    }
    
        private final AnalogListener analogListener = new AnalogListener() {
        @Override
        public void onAnalog(String name, float value, float tpf) {
            if (isRunning) {
                if (name.equals("Rotate")) {
                    boxNode.rotate(0, value * speed, 0);
                }
                if (name.equals("Right")) {
                    Vector3f v = boxNode.getLocalTranslation();
                    boxNode.setLocalTranslation(v.x + value * speed, v.y, v.z);
                }
                if (name.equals("Left")) {
                    Vector3f v = boxNode.getLocalTranslation();
                    boxNode.setLocalTranslation(v.x - value * speed, v.y, v.z);
                }
            } else {
                System.out.println("Press P to unpause.");
            }
        }
    };    

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

    @Override
    public void simpleUpdate(float tpf) {
        
        
    }
    
    @Override
    public void simpleRender(RenderManager rm) {
        //TODO: add render code
    }
}

1 Like

I’ll investigate this.

1 Like

You don’t attach the geometry to the box node until after you’ve generated the collision mesh… so there is essentially no collision mesh I guess.

Setting debug to true on the bullet app state probably would have shown this instantly.

Edit: and incidentally, mesh shapes won’t work for anything but static or kinematic objects anyway.

2 Likes

This is true.
Also, a MeshCollisionShape cannot be checked against any other MeshCollisionShape.

For different collision shapes and their uses, you could check the reference table found on this wiki page: https://wiki.jmonkeyengine.org/jme3/advanced/physics.html#create-a-collisionshape

Correct. boxShape refers to a compound shape containing zero child shapes, so player will never collide with anything. You need to re-arrange the code and generate a dynamic shape, like so:

        boxNode.attachChild(geom);
        CollisionShape boxShape =
            CollisionShapeFactory.createDynamicMeshShape(boxNode);
        player = new RigidBodyControl(boxShape, 1);
1 Like

Is your code working now?

I will try later and let you know.

Yes it works now.
I used createDynamicMeshShape(boxNode) instead of createMeshShape(boxNode) and this fixed the problem.
Thanks.

1 Like

Now I have another problem. The cube lands on the terrain. I use The A and D keys to rotate the cube alound the Y axis. The probem is I can’t make the cube move forward in the direction the camera is facing.

This is my code:

package mygame;

import com.jme3.app.SimpleApplication;
import com.jme3.bullet.BulletAppState;
import com.jme3.bullet.collision.shapes.CollisionShape;
import com.jme3.bullet.control.RigidBodyControl;
import com.jme3.bullet.util.CollisionShapeFactory;
import com.jme3.input.KeyInput;
import com.jme3.input.MouseInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.AnalogListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.input.controls.MouseButtonTrigger;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.renderer.RenderManager;
import com.jme3.scene.CameraNode;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.control.CameraControl.ControlDirection;
import com.jme3.scene.shape.Box;
import com.jme3.terrain.geomipmap.TerrainQuad;
import com.jme3.terrain.heightmap.AbstractHeightMap;
import com.jme3.terrain.heightmap.ImageBasedHeightMap;
import com.jme3.texture.Texture;
import com.jme3.texture.Texture.WrapMode;

/**
 * This is the Main Class of your Game. You should only do initialization here.
 * Move your Logic into AppStates or Controls
 * @author normenhansen
 */
public class Main extends SimpleApplication{
    
    private BulletAppState bulletAppState;
    private RigidBodyControl landscape, player;
    private TerrainQuad terrain;
    private Material mat_terrain;
    CameraNode camNode;
    boolean rotate = false;
    Vector3f direction = new Vector3f();
    Node boxNode = new Node("Player");
    private boolean isRunning = true;
    float speed = 10f;
    
    
    public static void main(String[] args) {
        Main app = new Main();
        app.start();
    }

    @Override
    public void simpleInitApp() {
        
           
        bulletAppState = new BulletAppState();
        stateManager.attach(bulletAppState);
        
        Box b = new Box(1, 1, 1);
        Geometry geom = new Geometry("Box", b);

        Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
        mat.setColor("Color", ColorRGBA.Blue);
        geom.setMaterial(mat);

        mat_terrain = new Material(assetManager, "Common/MatDefs/Terrain/Terrain.j3md");
        Texture sand = assetManager.loadTexture("Textures/Terrain/sand2.png");
        sand.setWrap(WrapMode.Repeat);
        mat_terrain.setTexture("Tex1", sand);
        mat_terrain.setFloat("Tex1Scale", 64f);
        
        AbstractHeightMap heightmap = null;
        Texture heightMapImage = assetManager.loadTexture("Textures/Terrain/heightmap.png");
        heightmap = new ImageBasedHeightMap(heightMapImage.getImage());
        heightmap.load();
        
        int patchSize = 65;
        terrain = new TerrainQuad("my terrain", patchSize, 513, heightmap.getHeightMap());
        
        terrain.setMaterial(mat_terrain);
        terrain.setLocalTranslation(0, -100, 0);
        terrain.setLocalScale(2f, 1f, 2f);
        rootNode.attachChild(terrain);
        /*
        List<Camera> cameras = new ArrayList<Camera>();
        cameras.add(getCamera());
        TerrainLodControl control = new TerrainLodControl(terrain, cameras);
        terrain.addControl(control);
        */
        rootNode.attachChild(boxNode);
        boxNode.attachChild(geom);
        
        CollisionShape terrainShape =
            CollisionShapeFactory.createMeshShape(terrain);
        landscape = new RigidBodyControl(terrainShape, 0);
        
        CollisionShape boxShape =
            CollisionShapeFactory.createDynamicMeshShape(boxNode);
        player = new RigidBodyControl(boxShape, 1);
        
        terrain.addControl(landscape);
        boxNode.addControl(player);
        
        //terrain.addControl(new RigidBodyControl(-1f));
        
        //boxNode.addControl(new RigidBodyControl(1f));
        
        bulletAppState.getPhysicsSpace().add(terrain);
        bulletAppState.getPhysicsSpace().add(boxNode);
                
        
                
        // Disable the default flyby cam
        flyCam.setEnabled(false);
        //create the camera Node
        camNode = new CameraNode("Camera Node", cam);
        //This mode means that camera copies the movements of the target:
        camNode.setControlDir(ControlDirection.SpatialToCamera);
        //Attach the camNode to the target:
        boxNode.attachChild(camNode);
        //Move camNode, e.g. behind and above the target:
        camNode.setLocalTranslation(new Vector3f(0, 2, -5));
        //Rotate the camNode to look at the target:
        camNode.lookAt(boxNode.getLocalTranslation(), Vector3f.UNIT_Y);
        
        initKeys();
        
        bulletAppState.setDebugEnabled(true);
    }
    
    private void initKeys() {
        // You can map one or several inputs to one named action
        inputManager.addMapping("Pause",  new KeyTrigger(KeyInput.KEY_P));
        inputManager.addMapping("Left",   new KeyTrigger(KeyInput.KEY_A));
        inputManager.addMapping("Right",  new KeyTrigger(KeyInput.KEY_D));
        inputManager.addMapping("Forward",  new KeyTrigger(KeyInput.KEY_W));
         inputManager.addMapping("Up",  new KeyTrigger(KeyInput.KEY_Q));
        //inputManager.addMapping("Rotate", new KeyTrigger(KeyInput.KEY_SPACE),
        //                                  new MouseButtonTrigger(MouseInput.BUTTON_LEFT));
        // Add the names to the action listener.
        inputManager.addListener(actionListener, "Pause");
        inputManager.addListener(analogListener, "Left", "Right", "Forward", "Up");
    }
    
        private final AnalogListener analogListener = new AnalogListener() {
        @Override
        public void onAnalog(String name, float value, float tpf) {
            if (isRunning) {
                if (name.equals("Right")) {
                    //Vector3f v = boxNode.getLocalTranslation();
                    boxNode.rotate(0,-0.01f,0);
                }
                if (name.equals("Left")) {
                    //Vector3f v = boxNode.getLocalTranslation();
                    boxNode.rotate(0,0.01f,0);
                }
                if (name.equals("Forward")) {
                    Vector3f v = boxNode.getLocalTranslation();
                    boxNode.move(v);
                    //boxNode.setLocalTranslation(1,0,0);
                }
                if (name.equals("Up")) {
                    //Vector3f v = boxNode.getLocalTranslation();
                    boxNode.move(0,1,0);
                    //boxNode.setLocalTranslation(1,0,0);
                }
                else {
                System.out.println("Press P to unpause.");
                }
            }
        }
    };    

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

    @Override
    public void simpleUpdate(float tpf) {
        
        
    }
    
    @Override
    public void simpleRender(RenderManager rm) {
        //TODO: add render code
    }
}

Post can’t be empty so I’m typing text here.

2 Likes