Jak poprawić kontrolę postaci w mojej grze 3D?

Odkąd zmieniłem klasę pomocnikówCharacterControl do nowegoBetterCharacterControl Zauważam pewne usprawnienia, takie jak pchanie innych postaci, ale moja główna postać zaczęła przesuwać się po schodach i nie może wspinać się na wyższe stopnie.

Muszę przeskoczyć krok powyżej, który nie jest właściwym sposobem grania, powinien po prostu iść. Stara klasa pomocniczaCharacterControl miał domyślny sposób, aby nie przesuwać, po prostu chodząc po schodach i myślę, że można to poprawić, zmieniając kod, w którym tworzę głównego bohatera.

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();
}

Pełny kod to

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;
    }

}

Możesz pobrać apróbny mojej gry, ale jak mogę poprawić chodzenie?

Aktualizacja

Mójkontynuacja w jmonkeyforum również było 0 odpowiedzi.

questionAnswers(1)

yourAnswerToTheQuestion