You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JMonkeyEngine中车辆碰撞形状与模型、车轮不同步问题求助

JMonkeyEngine中车辆碰撞形状与模型、车轮不同步问题求助

嘿,我最近在JMonkeyEngine里基于testFancyCar示例做一个驾驶游戏,换了自定义的赛车模型后遇到了几个棘手的问题,折腾好一阵都没解决,想请教下社区的大佬们:

  • 车身的CollisionShape和生成它的模型偏移了90度,我试过在生成碰撞形状前后旋转模型,但完全没效果;
  • 车轮不仅和原模型的位置对齐得不准,旋转方向还完全错了。

我用的模型里,车轮节点分别命名为FER_TIRE_LF_4、FER_TIRE_LR_5、FER_TIRE_RF_6、FER_TIRE_RR_7,车身节点是car_1。以下是我的完整代码:

public class Main extends SimpleApplication implements ActionListener {
    private BulletAppState bAppState;
    private Spatial car;
    private VehicleControl player;
    private float steeringValue = 0;
    private float accelerationValue = 0;

    public static void main(String[] args) {
        Main app = new Main();
        app.start();
    }

    private void setupKeys() {
        inputManager.addMapping("Lefts", new KeyTrigger(KeyInput.KEY_H));
        inputManager.addMapping("Rights", new KeyTrigger(KeyInput.KEY_K));
        inputManager.addMapping("Ups", new KeyTrigger(KeyInput.KEY_U));
        inputManager.addMapping("Downs", new KeyTrigger(KeyInput.KEY_J));
        inputManager.addMapping("Reset", new KeyTrigger(KeyInput.KEY_RETURN));
        inputManager.addListener(this, "Lefts");
        inputManager.addListener(this, "Rights");
        inputManager.addListener(this, "Ups");
        inputManager.addListener(this, "Downs");
        inputManager.addListener(this, "Reset");
    }

    @Override
    public void simpleInitApp() {
        bAppState = new BulletAppState();
        stateManager.attach(bAppState);
        bAppState.setDebugEnabled(true);

        viewPort.setBackgroundColor(new ColorRGBA(0.7f, 0.8f, 1f, 1f));
        flyCam.setMoveSpeed(10);

        createCar();
        createTrack();
        setUpLights();
        setupKeys();
    }

    @Override
    public void simpleUpdate(float tpf) {
    }

    @Override
    public void simpleRender(RenderManager rm) {
    }

    private void createTrack() {
        Material material = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
        material.setColor("Color", ColorRGBA.Blue);
        Box floorBox = new Box(140, 0.25f, 140);
        Geometry floorGeometry = new Geometry("Floor", floorBox);
        floorGeometry.setMaterial(material);
        floorGeometry.setLocalTranslation(0, -1, 0);
        floorGeometry.addControl(new RigidBodyControl(0));
        rootNode.attachChild(floorGeometry);
        bAppState.getPhysicsSpace().add(floorGeometry);
    }

    /**
     * Wheels are named "FER_TIRE_LF_4" "FER_TIRE_LR_5" "FER_TIRE_RF_6" "FER_TIRE_RR_7"
     */
    private void createCar() {
        float stiffness = 120.0f;//200=f1 car
        float compValue = 0.2f; //(lower than damp!)
        float dampValue = 0.3f;
        final float mass = 400;

        car = assetManager.loadModel("Models/racecar_rc-14/scene.gltf");
        Spatial chassis = findSpatial(car, "car_1");
        CollisionShape carHull = CollisionShapeFactory.createDynamicMeshShape(chassis);
        player = new VehicleControl(carHull, mass);
        car.addControl(player);

        Vector3f wheelDirection = new Vector3f(0,-1,0);
        Vector3f wheelAxle = new Vector3f(1, 0, 0);

        Spatial wheel_fr = findSpatial(car, "FER_TIRE_RF_6");
        BoundingBox box = toRootBound(wheel_fr);
        float wheelRadius = box.getYExtent();
        player.addWheel(wheel_fr, wheel_fr.getLocalTranslation(), wheelDirection, wheelAxle, 0.2f, wheelRadius, true);

        Spatial wheel_fl = findSpatial(car, "FER_TIRE_LF_4");
        player.addWheel(wheel_fl, wheel_fl.getLocalTranslation(), wheelDirection, wheelAxle, 0.2f, wheelRadius, true);

        Spatial wheel_br = findSpatial(car, "FER_TIRE_RR_7");
        player.addWheel(wheel_br, wheel_br.getLocalTranslation(), wheelDirection, wheelAxle, 0.2f, wheelRadius, false);

        Spatial wheel_bl = findSpatial(car, "FER_TIRE_LR_5");
        player.addWheel(wheel_bl, wheel_bl.getLocalTranslation(), wheelDirection, wheelAxle, 0.2f, wheelRadius, false);

        player.setSuspensionCompression(compValue * 2.0f * FastMath.sqrt(stiffness));
        player.setSuspensionDamping(dampValue * 2.0f * FastMath.sqrt(stiffness));
        player.setSuspensionStiffness(stiffness);
        player.setMaxSuspensionForce(10000);
        player.getWheel(2).setFrictionSlip(4);
        player.getWheel(3).setFrictionSlip(4);

        player.setPhysicsLocation(new Vector3f(0, 0, 0));
        player.setPhysicsRotation(new Matrix3f());

        rootNode.attachChild(car);
        bAppState.getPhysicsSpace().add(player);
    }

    private void setUpLights() {
        DirectionalLight l1 = new DirectionalLight();
        l1.setDirection(new Vector3f(-0.1f, -0.7f, -1.0f).normalizeLocal());
        rootNode.addLight(l1);

        DirectionalLight l2 = new DirectionalLight();
        l2.setDirection(new Vector3f(1, 0, 0).normalizeLocal());
        rootNode.addLight(l2);
    }

    private Spatial findSpatial(Spatial spatial, String name) {
        if (spatial.getName().startsWith(name)) {
            return spatial;
        }
        if (spatial instanceof Node) {
            Node node = (Node) spatial;
            for (int i = 0; i < node.getQuantity(); i++) {
                Spatial child = node.getChild(i);
                Spatial result = findSpatial(child, name);
                if (result != null) {
                    return result;
                }
            }
        }
        return null;
    }

    private BoundingBox toRootBound(Spatial sp) {
        BoundingBox bbox = (BoundingBox) sp.getWorldBound();
        return bbox;
    }

    @Override
    public void onAction(String name, boolean isPressed, float tpf) {
        if (name.equals("Lefts")) {
            steeringValue = isPressed ? -1 : 0;
            player.setSteeringValue(steeringValue, 0, 1);
        } else if (name.equals("Rights")) {
            steeringValue = isPressed ? 1 : 0;
            player.setSteeringValue(steeringValue, 0, 1);
        } else if (name.equals("Ups")) {
            accelerationValue = isPressed ? 1 : 0;
            player.applyForce(new Vector3f(0, 0, accelerationValue * 1000), Vector3f.ZERO);
        } else if (name.equals("Downs")) {
            accelerationValue = isPressed ? -1 : 0;
            player.applyForce(new Vector3f(0, 0, accelerationValue * 500), Vector3f.ZERO);
        } else if (name.equals("Reset")) {
            if (isPressed) {
                player.setPhysicsLocation(new Vector3f(0, 0, 0));
                player.setPhysicsRotation(new Matrix3f());
                player.setLinearVelocity(Vector3f.ZERO);
                player.setAngularVelocity(Vector3f.ZERO);
                steeringValue = 0;
                accelerationValue = 0;
            }
        }
    }
}

我尝试过在加载模型后旋转chassis节点再生成碰撞形状,但偏移问题依然存在;对于车轮问题,我怀疑是不是wheelDirection和wheelAxle的向量设置和模型坐标系不匹配,但调整向量后还是没解决。有没有大佬遇到过类似的问题,或者能帮我分析下问题出在哪?

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.09 03:04:31