如何改善3D游戏的角色控制?

由于我从辅助类CharacterControl更改为新的BetterCharacterControl我注意到一些改进,例如推动其他角色正在工作,但我的主角已经开始滑过步骤而无法爬上更高的台阶。

在此处输入图像描述

我必须跳过上面不是正确的比赛方式,它应该只是走过去。 旧的帮助器类CharacterControl有一个默认的不滑动方式,只是走过几步,我认为可以通过改变我创建主角的代码来纠正它。

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

完整的代码是

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

您可以下载我的游戏演示 ,但如何改善步行?

更新

我对jmonkeyforum的跟进也有0回复。

为此,您可以更改最大斜率的值:

 setMaxSlope() 

来自jmonkey网站:

 "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." 

阅读本文我相信它的工作方式类似于,当在世界上移动1个单位时,角色可以体验到的最大高度变化。 如果你将它设置为步长的大小(或安全性的大于<1),你的角色应该能够走上台阶

来源: http ://hub.jmonkeyengine.org/wiki/doku.php/jme3:advance:walking_character #charactercontrol之前为Jmonkey开发