Collision issue at certain spots on terrain

So, I made Jaime follow the third person camera , and hop and run on a terrain I created in the terrain editor. I gave Jaime BetterCharacter Control and used CollisionFactory for the terrain. So far so good. But just at one particular slope, jaime sinks half way into the terrain. There is no issue anywhere else. Just at this one particular spot on the terrain. How do I avoid these?

Untitled

1 Like

Here is the code.

Blockquote

    import com.jme3.animation.AnimChannel;
    import com.jme3.animation.AnimControl;
    import com.jme3.app.Application;
    import com.jme3.app.SimpleApplication;
    import com.jme3.app.state.AbstractAppState;
    import com.jme3.app.state.AppStateManager;
    import com.jme3.asset.AssetManager;
    import com.jme3.bullet.BulletAppState;
    import com.jme3.bullet.collision.shapes.CollisionShape;
    import com.jme3.bullet.control.BetterCharacterControl;
    import com.jme3.bullet.control.RigidBodyControl;
    import com.jme3.bullet.util.CollisionShapeFactory;
    import com.jme3.input.ChaseCamera;
    import com.jme3.input.FlyByCamera;
    import com.jme3.input.InputManager;
    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.math.FastMath;
    import com.jme3.math.Quaternion;
    import com.jme3.math.Vector3f;
    import com.jme3.renderer.Camera;
    import com.jme3.scene.CameraNode;
    import com.jme3.scene.Node;
    import com.jme3.scene.Spatial;
    import com.jme3.scene.control.CameraControl;


    /**
     *
     * @author Abhilash
     */
    public class AnimAppState extends AbstractAppState {
        private SimpleApplication app;
        private Node rootNode;
        private AssetManager assetManager;
        private AnimControl animControl;
        private AnimChannel animChannel;
        private InputManager inputManager;
        private boolean isWalk, isWave, isPunches, isRun, isJumping;
        private Node scene, jaime, pivot, camCharacter, terrain;
        private Camera cam;
        private ChaseCamera chaseCam;
        private CameraNode camNode;
        private FlyByCamera flyCam;
        private AppStateManager stateManager;
        private BulletAppState bulletAppState;
        private BetterCharacterControl jaimeCharacterControl;
        private RigidBodyControl sceneRigidBodyControl,camCharacterControl;
        private Vector3f walkDirection=new Vector3f();


        @Override
        public void initialize(AppStateManager stateManager, Application app) {
            super.initialize(stateManager, app);
            this.app=(SimpleApplication)app;
            this.rootNode=this.app.getRootNode();
            this.assetManager=this.app.getAssetManager();
            inputManager=this.app.getInputManager();
            flyCam=this.app.getFlyByCamera();
            stateManager=this.app.getStateManager();
            cam=this.app.getCamera();

            flyCam.setEnabled(false);
            bulletAppState=new BulletAppState();
            stateManager.attach(bulletAppState);

            bulletAppState.setDebugEnabled(true);
            initScene();
            initPhysicsControls();
            initCam();
            initKeys();
        }


        @Override
        public void update(float tpf) {
            //TODO: implement behavior during runtime

            if(isWave&&!animChannel.getAnimationName().equals("Wave"))
                animChannel.setAnim("Wave");

            if(isWalk&&!animChannel.getAnimationName().equals("Walk")){
                animChannel.setAnim("Walk"); 
            }    

            if(isPunches&&!animChannel.getAnimationName().equals("Punches"))
                animChannel.setAnim("Punches");

            if(isRun&&!animChannel.getAnimationName().equals("Run"))
                animChannel.setAnim("Run");

            if(isJumping&&!animChannel.getAnimationName().equals("Jumping")){        
                animChannel.setAnim("Jumping");
                jaimeCharacterControl.jump();
            }

            if(!isWave&&!isWalk&&!isPunches&&!isRun)
                animChannel.setAnim("Idle");

            moveJaime();

        }

        @Override
        public void cleanup() {
            super.cleanup();
            //TODO: clean up what you initialized in the initialize method,
            //e.g. remove all spatials from rootNode
            //this is called on the OpenGL thread after the AppState has been detached
        }


        private void initScene(){

            scene=(Node)rootNode.getChild("Scene");
            terrain=(Node)rootNode.getChild("terrain-AnimScene");
            jaime=(Node)scene.getChild("Models/Jaime/Jaime.j3o");
            camCharacter=new Node("camcharacter");

            if(scene!=null){
                scene.depthFirstTraversal((Spatial spat)->{
                    if(spat.getName().equals("JaimeGeom-ogremesh")){
                        animControl=spat.getControl(AnimControl.class);
                    }
                });
            }

            animChannel=animControl.createChannel();        
            animChannel.setAnim("Idle");

        }

        private void initPhysicsControls(){
            jaimeCharacterControl=new BetterCharacterControl(0.15f, 0.3f, 30);
            jaimeCharacterControl.setGravity(Vector3f.UNIT_Y.mult(9.8f));
            jaimeCharacterControl.setJumpForce(Vector3f.UNIT_Y.mult(10));
            jaime.addControl(jaimeCharacterControl);
            bulletAppState.getPhysicsSpace().add(jaimeCharacterControl);

            CollisionShape sceneShape=CollisionShapeFactory.createMeshShape(terrain);
            sceneRigidBodyControl=new RigidBodyControl(sceneShape, 0);
            scene.addControl(sceneRigidBodyControl);
            bulletAppState.getPhysicsSpace().add(sceneRigidBodyControl);  

           // bulletAppState.setDebugEnabled(true);
        }

        private void initCam(){
           pivot=new Node("pivot");
           jaime.attachChild(pivot);

           camNode=new CameraNode("Camera Node", cam);

           camNode.setControlDir(CameraControl.ControlDirection.SpatialToCamera);
           pivot.attachChild(camCharacter);


           pivot.attachChild(camNode);
           Vector3f loc=pivot.getLocalTranslation().add(new Vector3f(0, 0.8f, -1.5f));
           camNode.setLocalTranslation(loc);
           camNode.lookAt(pivot.getWorldTranslation(), Vector3f.UNIT_Y);
        }

        private void initKeys(){
            inputManager.addMapping("Walk", new KeyTrigger(KeyInput.KEY_T));
            inputManager.addMapping("Wave", new KeyTrigger(KeyInput.KEY_F));
            inputManager.addMapping("Punches", new KeyTrigger(KeyInput.KEY_G));
            inputManager.addMapping("Run", new KeyTrigger(KeyInput.KEY_H));
            inputManager.addMapping("Move", new KeyTrigger(KeyInput.KEY_W));
            inputManager.addMapping("Jumping", new KeyTrigger(KeyInput.KEY_SPACE));
            inputManager.addMapping("rotateRight", new MouseAxisTrigger(MouseInput.AXIS_X, true));
            inputManager.addMapping("rotateLeft", new MouseAxisTrigger(MouseInput.AXIS_X, false));
            inputManager.addMapping("MoveCamUp", new MouseAxisTrigger(MouseInput.AXIS_Y,true));
            inputManager.addMapping("MoveCamDown", new MouseAxisTrigger(MouseInput.AXIS_Y, false));


            inputManager.addListener(actionListener, "Walk", "Wave", "Punches", "Run", "Jumping");
            inputManager.addListener(analogListener, "Run", "rotateRight", "rotateLeft", "MoveCamUp", "MoveCamDown");
        }

        AnalogListener analogListener=(name, value, tpf)->{
            Quaternion quat=new Quaternion();
            float angle=FastMath.PI*value;

            if (name.equals("rotateRight")) {
                //camNode.rotate(0, 10*tpf, 0);
                quat.fromAngleAxis(FastMath.PI*value, Vector3f.UNIT_Y);
                Vector3f dir = jaimeCharacterControl.getViewDirection();
                jaimeCharacterControl.setViewDirection(quat.mult(dir));

            }
            if (name.equals("rotateLeft")) {

                quat.fromAngleAxis(-FastMath.PI*value, Vector3f.UNIT_Y);
                Vector3f dir = jaimeCharacterControl.getViewDirection();
                jaimeCharacterControl.setViewDirection(quat.mult(dir));
            }

            if (name.equals("MoveCamUp")) {
               calculateAngle(angle);
               //camNode.rotate(tpf, 0, 0);
            }

            if (name.equals("MoveCamDown")) {
                calculateAngle(-angle);
              //  camNode.rotate(-tpf, 0, 0);
            }

        };


        ActionListener actionListener=(name, isPressed, tpf)->{

            isWalk=false;
            isWave=false;
            isPunches=false;
            isRun=false; 
            isJumping=false;

            if(isPressed){
                switch(name){
                    case "Walk":
                        isWalk=isPressed;
                        break;

                    case "Wave":
                        isWave=isPressed;
                        break;

                    case "Punches":
                        isPunches=isPressed;
                        break;

                    case "Run":
                        isRun=isPressed;
                        break;

                    case "Jumping":
                        isJumping=true;
                        break;    

                    default:
                        break;
                }
            } 
        };

        private float ang =0;// 30 * FastMath.DEG_TO_RAD;

        private void calculateAngle(float angle){
            ang+=angle;

            System.out.println(ang);

            if(ang>0.56f){
                ang=0.56f;
            }

            if(ang<-0.18f){
                ang=-0.18f;
            }

            pivot.getLocalRotation().fromAngleAxis(ang, Vector3f.UNIT_X);

        }

        private void moveJaime(){
            walkDirection.set(Vector3f.ZERO);

            if(isRun||isJumping){
                walkDirection.addLocal(jaimeCharacterControl.getViewDirection());
            }

            if(isWalk){
                walkDirection.addLocal(jaimeCharacterControl.getViewDirection()).multLocal(0.5f);
            }

            jaimeCharacterControl.setWalkDirection(walkDirection);

        }
    }