How to improve character control for my 3D game?

一个人想着一个人 提交于 2019-12-06 05:57:54

问题


Since I changed from the helper class CharacterControl to the new BetterCharacterControl I notice some improvements such as pushing other characters is working but my main character has started sliding over steps and can't climb higher steps.

I must jump the step above which is not the right way of playing, it should be just walking over. The old helper class CharacterControl had a default way of not sliding, just walking over steps and I think it can be corrected by altering the code where I create the main character.

private void createNinja() {
    ninjaNode = (Node) assetManager
        .loadModel("Models/Ninja/Ninja.mesh.xml");
    ninjaNode.setShadowMode(RenderQueue.ShadowMode.CastAndReceive);
    ninjaNode.setLocalScale(0.06f);
    ninjaNode.setLocalTranslation(new Vector3f(55, 3.3f, -60));
    ninjaControl = new BetterCharacterControl(2, 4, 0.5f);
    ninjaControl.setJumpForce(new Vector3f(6, 6, 6));

    ninjaNode.addControl(ninjaControl);
    rootNode.attachChild(ninjaNode);
    bulletAppState.getPhysicsSpace().add(ninjaControl);
    getPhysicsSpace().add(ninjaControl);
    animationControl = ninjaNode.getControl(AnimControl.class);
    animationChannel = animationControl.createChannel();
}

The complete code is

package adventure;

import com.jme3.system.AppSettings;
import java.io.File;

import com.jme3.renderer.queue.RenderQueue;
import com.jme3.renderer.queue.RenderQueue.ShadowMode;
import com.jme3.animation.AnimChannel;
import com.jme3.animation.AnimControl;
import com.jme3.animation.AnimEventListener;
import com.jme3.animation.LoopMode;
import com.jme3.app.SimpleApplication;
import com.jme3.asset.BlenderKey;
import com.jme3.asset.plugins.HttpZipLocator;
import com.jme3.asset.plugins.ZipLocator;
import com.jme3.bullet.BulletAppState;
import com.jme3.bullet.PhysicsSpace;
import com.jme3.bullet.collision.shapes.CapsuleCollisionShape;
import com.jme3.bullet.control.BetterCharacterControl;
import com.jme3.bullet.control.CharacterControl;
import com.jme3.bullet.control.RigidBodyControl;
import com.jme3.input.ChaseCamera;
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.MaterialList;
import com.jme3.math.ColorRGBA;
import com.jme3.math.FastMath;
import com.jme3.math.Quaternion;
import com.jme3.math.Vector3f;
import com.jme3.post.FilterPostProcessor;
import com.jme3.post.filters.BloomFilter;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.scene.plugins.ogre.OgreMeshKey;
import com.jme3.input.controls.MouseButtonTrigger;
import com.jme3.input.MouseInput;

public class PyramidLevel extends SimpleApplication implements ActionListener,
        AnimEventListener {
    private Node gameLevel;
    private static boolean useHttp = false;
    private BulletAppState bulletAppState;
    private AnimChannel channel;
    private AnimControl control;
    // character
    private BetterCharacterControl goblinControl; 
    private BetterCharacterControl ninjaControl;
    private Node ninjaNode;
    boolean rotate = false;
    private Vector3f walkDirection = new Vector3f(0, 0, 0);
    private Vector3f viewDirection = new Vector3f(1, 0, 0);
    private boolean leftStrafe = false, rightStrafe = false, forward = false,
            backward = false, leftRotate = false, rightRotate = false;
    private Node goblinNode;
    Spatial goblin;
    RigidBodyControl terrainPhysicsNode;

    // animation
    AnimChannel animationChannel;
    AnimChannel shootingChannel;
    AnimControl animationControl;
    float airTime = 0;
    // camera
    private boolean left = false, right = false, up = false, down = false,
            attack = false;

    ChaseCamera chaseCam;
    private boolean walkMode = true;
    FilterPostProcessor fpp;
    private Spatial sceneModel;

    private RigidBodyControl landscape;

    public static void main(String[] args) {

        File file = new File("quake3level.zip");
        if (!file.exists()) {
            useHttp = true;
        }
        PyramidLevel app = new PyramidLevel();
        AppSettings settings = new AppSettings(true);
        settings.setTitle("Dungeon World");
        settings.setSettingsDialogImage("Interface/splash.png");
        app.setSettings(settings);
        app.start();
    }

    @Override
    public void simpleInitApp() {
        this.setDisplayStatView(false);
        bulletAppState = new BulletAppState();
        bulletAppState.setThreadingType(BulletAppState.ThreadingType.PARALLEL);
        stateManager.attach(bulletAppState);
        bulletAppState.setDebugEnabled(false);
        setupKeys();
        DirectionalLight dl = new DirectionalLight();
        dl.setColor(ColorRGBA.White.clone().multLocal(2));
        dl.setDirection(new Vector3f(-1, -1, -1).normalize());
        rootNode.addLight(dl);
        AmbientLight am = new AmbientLight();
        am.setColor(ColorRGBA.White.mult(2));
        rootNode.addLight(am);

        if (useHttp) {
            assetManager
                    .registerLocator(
                            "http://jmonkeyengine.googlecode.com/files/quake3level.zip",
                            HttpZipLocator.class);
        } else {
            assetManager.registerLocator("quake3level.zip", ZipLocator.class);
        }

        // create the geometry and attach it
        MaterialList matList = (MaterialList) assetManager
                .loadAsset("Scene.material");
        OgreMeshKey key = new OgreMeshKey("main.meshxml", matList);
        gameLevel = (Node) assetManager.loadAsset(key);
        gameLevel.setLocalScale(0.1f);
        gameLevel.addControl(new RigidBodyControl(0));
        getPhysicsSpace().addAll(gameLevel);
        rootNode.attachChild(gameLevel);
        getPhysicsSpace().addAll(gameLevel);
        createCharacters();
        setupAnimationController();
        setupChaseCamera();
        setupFilter();
    }

    private void setupFilter() {
        FilterPostProcessor fpp = new FilterPostProcessor(assetManager);
        BloomFilter bloom = new BloomFilter(BloomFilter.GlowMode.Objects);
        fpp.addFilter(bloom);
        viewPort.addProcessor(fpp);
    }

    private PhysicsSpace getPhysicsSpace() {
        return bulletAppState.getPhysicsSpace();
    }

    private void setupKeys() {
        inputManager.addMapping("wireframe", new KeyTrigger(KeyInput.KEY_T));
        inputManager.addListener(this, "wireframe");
        inputManager.addMapping("CharLeft", new KeyTrigger(KeyInput.KEY_A));
        inputManager.addMapping("CharRight", new KeyTrigger(KeyInput.KEY_D));
        inputManager.addMapping("CharUp", new KeyTrigger(KeyInput.KEY_W));
        inputManager.addMapping("CharDown", new KeyTrigger(KeyInput.KEY_S));
        inputManager
                .addMapping("CharSpace", new KeyTrigger(KeyInput.KEY_SPACE));
        inputManager.addMapping("CharShoot", new MouseButtonTrigger(
                MouseInput.BUTTON_LEFT));
        inputManager.addListener(this, "CharLeft");
        inputManager.addListener(this, "CharRight");
        inputManager.addListener(this, "CharUp");
        inputManager.addListener(this, "CharDown");
        inputManager.addListener(this, "CharSpace");
        inputManager.addListener(this, "CharShoot");
    }

    private void createNinja() {
        ninjaNode = (Node) assetManager
                .loadModel("Models/Ninja/Ninja.mesh.xml");
        ninjaNode.setShadowMode(RenderQueue.ShadowMode.CastAndReceive);
        ninjaNode.setLocalScale(0.06f);
        ninjaNode.setLocalTranslation(new Vector3f(55, 3.3f, -60));
        ninjaControl = new BetterCharacterControl(2, 4, 0.5f);
        ninjaControl.setJumpForce(new Vector3f(6, 6, 6));

        ninjaNode.addControl(ninjaControl);
        rootNode.attachChild(ninjaNode);
        bulletAppState.getPhysicsSpace().add(ninjaControl);
        getPhysicsSpace().add(ninjaControl);
        animationControl = ninjaNode.getControl(AnimControl.class);
        animationChannel = animationControl.createChannel();
    }

    private void createGoblin() {
        goblinNode = (Node) assetManager
                .loadModel("objects/goblin.j3o");
        goblinNode.setShadowMode(RenderQueue.ShadowMode.CastAndReceive);
        goblinNode.setLocalScale(4f);
        goblinNode.setLocalTranslation(new Vector3f(51.5f, 3.3f, -60));
        goblinControl = new BetterCharacterControl(2, 4, 0.5f);
        goblinControl.setJumpForce(new Vector3f(6, 6, 6));

        goblinNode.addControl(goblinControl);
        rootNode.attachChild(goblinNode);
        bulletAppState.getPhysicsSpace().add(goblinControl);
        getPhysicsSpace().add(goblinControl);
        animationControl = goblinNode.getControl(AnimControl.class);
        animationChannel = animationControl.createChannel();
    }

    private void createCharacters() {
        CapsuleCollisionShape capsule = new CapsuleCollisionShape(0.05f, 0.05f);
        createNinja();
        ninjaControl.setViewDirection(new Vector3f(0, 0, 1));
        //getPhysicsSpace().add(ninjaControl);
        createGoblin();
        BlenderKey blenderKey = new BlenderKey("Models/Oto/Oto.mesh.xml");
        Spatial man = (Spatial) assetManager.loadModel(blenderKey);
        man.setLocalTranslation(new Vector3f(69, 15, -60));
        man.setShadowMode(ShadowMode.CastAndReceive);
        rootNode.attachChild(man);
        //goblin = assetManager.loadModel("objects/goblin.j3o");
        //goblin.scale(4f, 4f, 4f);

        //goblinControl = new BetterCharacterControl(2,3,0.5f);
        //goblin.addControl(goblinControl);

        //goblinControl.setPhysicsLocation(new Vector3f(60, 3.5f, -60));
        //goblin.setLocalTranslation(new Vector3f(150,70.5f, -5));
        //control = goblin.getControl(AnimControl.class);
        //control.addListener(this);
        //channel = control.createChannel();

        // for (String anim : control.getAnimationNames())
        // System.out.println("goblin can:"+anim);
        //channel.setAnim("walk");
        //goblin.setLocalTranslation(new Vector3f(51.5f, 3, -55));

        //rootNode.attachChild(goblin);
        //getPhysicsSpace().add(goblinControl);
        Spatial monster = assetManager
                .loadModel("objects/creatures/monster/monster.packed.j3o");

        Spatial monster2 = assetManager.loadModel("Models/Jaime/Jaime.j3o");
        monster2.scale(5f, 5f, 5f);
        monster.scale(2f, 2f, 2f);
        monster.setLocalTranslation(new Vector3f(53, 3, -55));
        monster2.setLocalTranslation(new Vector3f(48, 3, -55));

        rootNode.attachChild(monster2);
        rootNode.attachChild(monster);

    }

    private void setupChaseCamera() {
        flyCam.setEnabled(false);
        chaseCam = new ChaseCamera(cam, ninjaNode, inputManager);
        chaseCam.setDefaultDistance(37);

    }

    private void setupAnimationController() {
        animationControl = ninjaNode.getControl(AnimControl.class);
        animationControl.addListener(this);
        animationChannel = animationControl.createChannel();

    }

    @Override
    public void simpleUpdate(float tpf) {
        //goblinControl.setWalkDirection(goblin.getLocalRotation()
            //  .mult(Vector3f.UNIT_Z).multLocal(0.4f));
        Vector3f camDir = cam.getDirection().clone().multLocal(8f);
        Vector3f camLeft = cam.getLeft().clone().multLocal(8f);
        camDir.y = 0;
        camLeft.y = 0;
        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());
        }
        // if (attack) {
        // animationChannel.setAnim("Attack1");
        // animationChannel.setLoopMode(LoopMode.DontLoop);
        // }
        if (!ninjaControl.isOnGround()) {
            airTime = airTime + tpf;
        } else {
            airTime = 0;
        }
        if (walkDirection.length() == 0) {
            if (!"Idle1".equals(animationChannel.getAnimationName())) {
                animationChannel.setAnim("Idle1", 1f);
            }
        } else {
            ninjaControl.setViewDirection(walkDirection.negate());
            if (airTime > .3f) {
                if (!"stand".equals(animationChannel.getAnimationName())) {
                    animationChannel.setAnim("Idle1");
                }
            } else if (!"Walk".equals(animationChannel.getAnimationName())) {
                animationChannel.setAnim("Walk", 1f);
            }
        }
        ninjaControl.setWalkDirection(walkDirection);
    }

    /*
     * Ninja can: Walk Ninja can: Kick Ninja can: JumpNoHeight Ninja can: Jump
     * Ninja can: Spin Ninja can: Attack1 Ninja can: Idle1 Ninja can: Attack3
     * Ninja can: Idle2 Ninja can: Attack2 Ninja can: Idle3 Ninja can: Stealth
     * Ninja can: Death2 Ninja can: Death1 Ninja can: HighJump Ninja can:
     * SideKick Ninja can: Backflip Ninja can: Block Ninja can: Climb Ninja can:
     * Crouch
     */

    public void onAction(String binding, boolean value, float tpf) {

        if (binding.equals("CharLeft")) {
            if (value) {
                left = true;
            } else {
                left = false;
            }
        } else if (binding.equals("CharRight")) {
            if (value) {
                right = true;
            } else {
                right = false;
            }
        } else if (binding.equals("CharUp")) {
            if (value) {
                up = true;
            } else {
                up = false;
            }
        } else if (binding.equals("CharDown")) {
            if (value) {
                down = true;
            } else {
                down = false;
            }
        } else if (binding.equals("CharSpace")) {
            // character.jump();
            ninjaControl.jump();
        } else if (binding.equals("CharShoot") && value) {
            // bulletControl();
            Vector3f origin = cam.getWorldCoordinates(
                    inputManager.getCursorPosition(), 0.0f);
            Vector3f direction = cam.getWorldCoordinates(
                    inputManager.getCursorPosition(), 0.0f);
            // direction.subtractLocal(origin).normalizeLocal();
            // character.setWalkDirection(location);
            System.out.println("origin" + origin);
            System.out.println("direction" + direction);
            // character.setViewDirection(direction);
            animationChannel.setAnim("Attack3");
            animationChannel.setLoopMode(LoopMode.DontLoop);
        }
    }

    public void onAnimCycleDone(AnimControl control, AnimChannel channel,
            String animName) {
        if (channel == shootingChannel) {
            channel.setAnim("Idle1");
        }
    }

    public void onAnimChange(AnimControl control, AnimChannel channel,
            String animName) {
    }

    public Node getGameLevel() {
        return gameLevel;
    }

    public void setGameLevel(Node gameLevel) {
        this.gameLevel = gameLevel;
    }

    public static boolean isUseHttp() {
        return useHttp;
    }

    public static void setUseHttp(boolean useHttp) {
        PyramidLevel.useHttp = useHttp;
    }

    public BulletAppState getBulletAppState() {
        return bulletAppState;
    }

    public void setBulletAppState(BulletAppState bulletAppState) {
        this.bulletAppState = bulletAppState;
    }

    public AnimChannel getChannel() {
        return channel;
    }

    public void setChannel(AnimChannel channel) {
        this.channel = channel;
    }

    public AnimControl getControl() {
        return control;
    }

    public void setControl(AnimControl control) {
        this.control = control;
    }

    public BetterCharacterControl getGoblincharacter() {
        return goblinControl;
    }

    public void setGoblincharacter(BetterCharacterControl goblincharacter) {
        this.goblinControl = goblincharacter;
    }

    public BetterCharacterControl getCharacterControl() {
        return ninjaControl;
    }

    public void setCharacterControl(BetterCharacterControl characterControl) {
        this.ninjaControl = characterControl;
    }

    public Node getCharacterNode() {
        return ninjaNode;
    }

    public void setCharacterNode(Node characterNode) {
        this.ninjaNode = characterNode;
    }

    public boolean isRotate() {
        return rotate;
    }

    public void setRotate(boolean rotate) {
        this.rotate = rotate;
    }

    public Vector3f getWalkDirection() {
        return walkDirection;
    }

    public void setWalkDirection(Vector3f walkDirection) {
        this.walkDirection = walkDirection;
    }

    public Vector3f getViewDirection() {
        return viewDirection;
    }

    public void setViewDirection(Vector3f viewDirection) {
        this.viewDirection = viewDirection;
    }

    public boolean isLeftStrafe() {
        return leftStrafe;
    }

    public void setLeftStrafe(boolean leftStrafe) {
        this.leftStrafe = leftStrafe;
    }

    public boolean isRightStrafe() {
        return rightStrafe;
    }

    public void setRightStrafe(boolean rightStrafe) {
        this.rightStrafe = rightStrafe;
    }

    public boolean isForward() {
        return forward;
    }

    public void setForward(boolean forward) {
        this.forward = forward;
    }

    public boolean isBackward() {
        return backward;
    }

    public void setBackward(boolean backward) {
        this.backward = backward;
    }

    public boolean isLeftRotate() {
        return leftRotate;
    }

    public void setLeftRotate(boolean leftRotate) {
        this.leftRotate = leftRotate;
    }

    public boolean isRightRotate() {
        return rightRotate;
    }

    public void setRightRotate(boolean rightRotate) {
        this.rightRotate = rightRotate;
    }

    public Node getModel() {
        return goblinNode;
    }

    public void setModel(Node model) {
        this.goblinNode = model;
    }

    public Spatial getGoblin() {
        return goblin;
    }

    public void setGoblin(Spatial goblin) {
        this.goblin = goblin;
    }

    public RigidBodyControl getTerrainPhysicsNode() {
        return terrainPhysicsNode;
    }

    public void setTerrainPhysicsNode(RigidBodyControl terrainPhysicsNode) {
        this.terrainPhysicsNode = terrainPhysicsNode;
    }

    public AnimChannel getAnimationChannel() {
        return animationChannel;
    }

    public void setAnimationChannel(AnimChannel animationChannel) {
        this.animationChannel = animationChannel;
    }

    public AnimChannel getShootingChannel() {
        return shootingChannel;
    }

    public void setShootingChannel(AnimChannel shootingChannel) {
        this.shootingChannel = shootingChannel;
    }

    public AnimControl getAnimationControl() {
        return animationControl;
    }

    public void setAnimationControl(AnimControl animationControl) {
        this.animationControl = animationControl;
    }

    public float getAirTime() {
        return airTime;
    }

    public void setAirTime(float airTime) {
        this.airTime = airTime;
    }

    public boolean isLeft() {
        return left;
    }

    public void setLeft(boolean left) {
        this.left = left;
    }

    public boolean isRight() {
        return right;
    }

    public void setRight(boolean right) {
        this.right = right;
    }

    public boolean isUp() {
        return up;
    }

    public void setUp(boolean up) {
        this.up = up;
    }

    public boolean isDown() {
        return down;
    }

    public void setDown(boolean down) {
        this.down = down;
    }

    public boolean isAttack() {
        return attack;
    }

    public void setAttack(boolean attack) {
        this.attack = attack;
    }

    public ChaseCamera getChaseCam() {
        return chaseCam;
    }

    public void setChaseCam(ChaseCamera chaseCam) {
        this.chaseCam = chaseCam;
    }

    public boolean isWalkMode() {
        return walkMode;
    }

    public void setWalkMode(boolean walkMode) {
        this.walkMode = walkMode;
    }

    public FilterPostProcessor getFpp() {
        return fpp;
    }

    public void setFpp(FilterPostProcessor fpp) {
        this.fpp = fpp;
    }

    public Spatial getSceneModel() {
        return sceneModel;
    }

    public void setSceneModel(Spatial sceneModel) {
        this.sceneModel = sceneModel;
    }

    public RigidBodyControl getLandscape() {
        return landscape;
    }

    public void setLandscape(RigidBodyControl landscape) {
        this.landscape = landscape;
    }

}

You can download a demo of my game but how do I improve the walking?

Update

My followup at the jmonkeyforum also had 0 replies.


回答1:


To do this you change the value of the max slope:

setMaxSlope()

From the jmonkey site:

"How steep the slopes and steps are that the character can climb without considering them    
an obstacle. Higher obstacles need to be jumped. Vertical height in world units."

Reading this I believe it works in a way similar to, when moving 1 unit in the world what is the maximum change in height a character can experience. If you set this to the size of the steps (or a larger by <1 for safety) you'r character should be able to walk up steps

Sources: http://hub.jmonkeyengine.org/wiki/doku.php/jme3:advanced:walking_character#charactercontrol Developing for Jmonkey before



来源:https://stackoverflow.com/questions/16782375/how-to-improve-character-control-for-my-3d-game

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!