简体   繁体   English

JMonkeyEngine:动态加载模型的碰撞检测

[英]JMonkeyEngine : Collision detection on dynamically loaded models

I am learning JME3 and I managed to create my own height map and modifying some of the example code, etc. Now, I created a very simple 4-wall roofless room with Blender, exported it as a Wavefront .Obj file and loaded it unto my scene (I attacked it to the terrain node. 我正在学习JME3,我设法创建自己的高度图并修改一些示例代码等。现在,我创建了一个非常简单的4墙无屋顶房间,带有Blender,将其导出为Wavefront .Obj文件并将其加载到我的场景(我将它攻击到terrain节点。

Now, my terrain has a collision detection applied so the player can move and jump around, but it can also walk right through the walls of my model. 现在,我的terrain已经应用了碰撞检测,因此玩家可以移动和跳跃,但它也可以穿过模型的墙壁。 All the examples I can find loads an already pre-built scene, and I'm still clueless as to why the player goes right through the loaded model? 我能找到的所有例子都加载了一个已经预先构建的场景,而我仍然无法知道为什么玩家会直接通过加载的模型?

Sorry for the big code, but I couldn't see how else I could do otherwise. 对不起大代码,但我看不出别的怎么办。 The physics is applied at the section /** 6. Add physics: */ : 物理学应用于/** 6. Add physics: */部分/** 6. Add physics: */

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;

    public static void main(String[] args) {
        AppSettings settings = new AppSettings(true);
        settings.setResolution(1366, 768);
        settings.setFullscreen(true);

        Main app = new Main();
        app.setSettings(settings);
        app.setShowSettings(false);
        app.start();
    }

    @Override
    public void simpleInitApp() {
        /** Set up Physics */
        bulletAppState = new BulletAppState();
        stateManager.attach(bulletAppState);
        //bulletAppState.getPhysicsSpace().enableDebug(assetManager);

        flyCam.setMoveSpeed(200);
        setUpKeys();

        /** 1. Create terrain material and load four textures into it. */
        mat_terrain = new Material(assetManager, "Common/MatDefs/Terrain/Terrain.j3md");

        /** 1.1) Add ALPHA map (for red-blue-green coded splat textures) */
        mat_terrain.setTexture("Alpha", assetManager.loadTexture("Textures/terrain/island_1_alpha1.png"));

        /** 1.2) Add GRASS texture into the red layer (Tex1). */
        Texture grass = assetManager.loadTexture("Textures/Terrain/splat/grass.jpg");
        grass.setWrap(WrapMode.Repeat);
        mat_terrain.setTexture("Tex1", grass);
        mat_terrain.setFloat("Tex1Scale", 64f);

        /** 1.3) Add DIRT texture into the green layer (Tex2) */
        Texture dirt = assetManager.loadTexture("Textures/rocks.jpg");
        dirt.setWrap(WrapMode.Repeat);
        mat_terrain.setTexture("Tex2", dirt);
        mat_terrain.setFloat("Tex2Scale", 32f);

        /** 1.4) Add ROAD texture into the blue layer (Tex3) */
        Texture rock = assetManager.loadTexture("Textures/Terrain/splat/dirt.jpg");
        rock.setWrap(WrapMode.Repeat);
        mat_terrain.setTexture("Tex3", rock);
        mat_terrain.setFloat("Tex3Scale", 128f);

        /** 2. Create the height map */
        AbstractHeightMap heightmap = null;
        Texture heightMapImage = assetManager.loadTexture("Textures/terrain/island_1.png");
        heightmap = new ImageBasedHeightMap(heightMapImage.getImage());
        heightmap.load();

        /** 3. We have prepared material and heightmap. 
         * Now we create the actual terrain:
         * 3.1) Create a TerrainQuad and name it "my terrain".
         * 3.2) A good value for terrain tiles is 64x64 -- so we supply 64+1=65.
         * 3.3) We prepared a heightmap of size 512x512 -- so we supply 512+1=513.
         * 3.4) As LOD step scale we supply Vector3f(1,1,1).
         * 3.5) We supply the prepared heightmap itself.
         */
        terrain = new TerrainQuad("my terrain", 65, 513, heightmap.getHeightMap());

        /** 4. We give the terrain its material, position & scale it, and attach it. */
        terrain.setMaterial(mat_terrain);
        terrain.setLocalTranslation(0, -170, 0);
        terrain.setLocalScale(2f, 1f, 2f);
        rootNode.attachChild(terrain);

        /** 4.5. Load some models */
        Spatial building = assetManager.loadModel("Models/building1.obj");
        Material mat_default = new Material(assetManager, "Common/MatDefs/Misc/ShowNormals.j3md");
        building.setMaterial(mat_default);
        building.setLocalTranslation(90, 117, 90);
        building.setLocalScale(5f, 5f, 5f);
        terrain.attachChild(building);


        /** 4.6. Load Sky */
        rootNode.attachChild(SkyFactory.createSky(assetManager, "Textures/Sky/Bright/BrightSky.dds", false));

        /** 4.7. Load water */

        // we create a water processor
        SimpleWaterProcessor waterProcessor = new SimpleWaterProcessor(assetManager);
        waterProcessor.setReflectionScene(rootNode);

        // we set the water plane
        Vector3f waterLocation = new Vector3f(0, -58, 0);
        waterProcessor.setPlane(new Plane(Vector3f.UNIT_Y, waterLocation.dot(Vector3f.UNIT_Y)));
        viewPort.addProcessor(waterProcessor);

        // we set wave properties
        waterProcessor.setWaterDepth(50);         // transparency of water
        waterProcessor.setDistortionScale(0.05f); // strength of waves
        waterProcessor.setWaveSpeed(0.05f);       // speed of waves

        // we define the wave size by setting the size of the texture coordinates
        Quad quad = new Quad(1000, 1000);
        quad.scaleTextureCoordinates(new Vector2f(10f, 10f));

        // we create the water geometry from the quad
        Geometry water = new Geometry("water", quad);
        water.setLocalRotation(new Quaternion().fromAngleAxis(-FastMath.HALF_PI, Vector3f.UNIT_X));
        water.setLocalTranslation(-500, -58, 500);
        water.setShadowMode(ShadowMode.Receive);
        water.setMaterial(waterProcessor.getMaterial());
        rootNode.attachChild(water);

        /** 5. The LOD (level of detail) depends on were the camera is: */
        List<Camera> cameras = new ArrayList<Camera>();
        cameras.add(getCamera());
        TerrainLodControl control = new TerrainLodControl(terrain, cameras);
        terrain.addControl(control);

        /** 6. Add physics: */
        // We set up collision detection for the scene by creating a
        // compound collision shape and a static RigidBodyControl with mass zero.*/
        CollisionShape terrainShape = CollisionShapeFactory.createMeshShape(terrain);
        landscape = new RigidBodyControl(terrainShape, 0);
        terrain.addControl(landscape);
        terrain.addControl(new RigidBodyControl(CollisionShapeFactory.createMeshShape(building), 0));

        // We set up collision detection for the player by creating
        // a capsule collision shape and a CharacterControl.
        // The CharacterControl offers extra settings for
        // size, stepheight, jumping, falling, and gravity.
        // We also put the player in its starting position.
        CapsuleCollisionShape capsuleShape = new CapsuleCollisionShape(1.5f, 6f, 1);
        player = new CharacterControl(capsuleShape, 0.05f);
        player.setJumpSpeed(50);
        player.setFallSpeed(70);
        player.setGravity(100);
        player.setPhysicsLocation(new Vector3f(50, 100, 100));

        // We attach the scene and the player to the rootnode and the physics space,
        // to make them appear in the game world.
        bulletAppState.getPhysicsSpace().add(terrain);
        bulletAppState.getPhysicsSpace().add(player);


    }

    /** We over-write some navigational key mappings here, so we can
     * add physics-controlled walking and jumping: */
    private void setUpKeys() {
        inputManager.addMapping("Left", new KeyTrigger(KeyInput.KEY_A));
        inputManager.addMapping("Right", new KeyTrigger(KeyInput.KEY_D));
        inputManager.addMapping("Up", new KeyTrigger(KeyInput.KEY_W));
        inputManager.addMapping("Down", new KeyTrigger(KeyInput.KEY_S));
        inputManager.addMapping("Jump", new KeyTrigger(KeyInput.KEY_SPACE));
        inputManager.addListener(this, "Left");
        inputManager.addListener(this, "Right");
        inputManager.addListener(this, "Up");
        inputManager.addListener(this, "Down");
        inputManager.addListener(this, "Jump");
    }

    /** These are our custom actions triggered by key presses.
         * We do not walk yet, we just keep track of the direction the user pressed. */
    public void onAction(String binding, boolean value, float tpf) {
        if (binding.equals("Left")) {
            if (value) {
                left = true;
            } else {
                left = false;
            }
        } else if (binding.equals("Right")) {
            if (value) {
                right = true;
            } else {
                right = false;
            }
        } else if (binding.equals("Up")) {
            if (value) {
                up = true;
            } else {
                up = false;
            }
        } else if (binding.equals("Down")) {
            if (value) {
                down = true;
            } else {
                down = false;
            }
        } else if (binding.equals("Jump")) {
            player.jump();
        }
    }

    /**
     * This is the main event loop--walking happens here.
     * We check in which direction the player is walking by interpreting
     * the camera direction forward (camDir) and to the side (camLeft).
     * The setWalkDirection() command is what lets a physics-controlled player walk.
     * We also make sure here that the camera moves with player.
     */
    @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());
    }
}

So, why isn't my model applied to the collision detection? 那么,为什么我的模型不适用于碰撞检测?

I have found the answer, here . 在这里找到了答案。 The solution to the problem is this : 问题的解决方案是这样的:

  1. Create a CollisionShape. 创建一个CollisionShape。 Create a PhysicsControl by supplying the 通过提供来创建PhysicsControl
  2. CollisionShape and mass. 碰撞形状和质量。 Eg com.jme3.bullet.control.RigidBodyControl 例如com.jme3.bullet.control.RigidBodyControl
  3. Add the PhysicsControl to the Spatial. 将PhysicsControl添加到Spatial。 Add the PhysicsControl to the 将PhysicsControl添加到
  4. physicsSpace object. physicsSpace对象。 Attach the Spatial to the rootNode, as usual. 像往常一样将Spatial附加到rootNode。
  5. (Optional) Implement the PhysicsCollisionListener interface to respond to PhysicsCollisionEvents if desired. (可选)如果需要,实现PhysicsCollisionListener接口以响应PhysicsCollisionEvents。

Therefore, replace 因此,更换

terrain.attachChild(building);

by 通过

rootNode.attachChild(building);

and adding 并添加

bulletAppState.getPhysicsSpace().add(building);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM