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

WebGL中基于Cannon.js的跳跃逻辑实现技术问询

跳跃逻辑实现与代码优化建议

需求回顾

正常状态下玩家碰撞体跟随相机与手部位置;当virtualJumpActive == true时反转逻辑:场景对象与相机在短时间内跟随Cannon.js物理体位置,仅Y轴(对应Cannon.js的Z轴)由物理系统控制,XY轴保留WASD用户控制,同时Y轴始终依赖物理数据以实现跳上其他物体的效果,当前相机Y轴为固定值。

优化后代码

var playerUpdater = {
  UPDATE: () => {
    const cameraEvents = matrixEngine.Events.camera;
    const playerCollider = App.scene.playerCollisonBox.physics.currentBody;
    const playerObj = App.scene[objName];

    // 统一处理Y轴旋转
    playerObj.rotation.rotateY(cameraEvents.yaw + 180);

    // 简化Pitch角度限制计算
    const limit = 2;
    let detPitch = cameraEvents.pitch * 2;
    if (cameraEvents.pitch > limit) {
      detPitch = limit * 2;
    } else if (cameraEvents.pitch < -(limit + 2)) {
      detPitch = -(limit + 2) * 2;
    }

    // 统一处理Pitch位置限制
    let detPitchPos = cameraEvents.pitch;
    detPitchPos = Math.min(detPitchPos, 4);

    if (cameraEvents.virtualJumpActive) {
      // 跳跃状态:物理体驱动相机与场景对象
      playerObj.rotation.rotateX(-detPitch);
      
      // 明确坐标映射:Cannon的X/Y/Z对应场景的X/Z/Y
      const physX = playerCollider.position.x;
      const physY = playerCollider.position.y;
      const physZ = playerCollider.position.z;

      playerObj.position.setPosition(physX, physZ, physY);
      cameraEvents.xPos = physX;
      cameraEvents.zPos = physY;
      cameraEvents.yPos = physZ; // 让相机Y轴跟随物理Z轴,不再固定

      // 锁定物理体旋转,避免倾斜
      playerCollider.angularVelocity.set(0, 0, 0);

      // 避免重复触发定时器:仅在跳跃激活时初始化一次
      if (!cameraEvents.jumpTimer) {
        cameraEvents.jumpTimer = setTimeout(() => {
          cameraEvents.virtualJumpActive = false;
          cameraEvents.virtualJumpY = 2;
          delete cameraEvents.jumpTimer; // 清除定时器标记
        }, 350);
      }

    } else {
      // 正常状态:相机驱动物理体与场景对象
      playerObj.rotation.rotateX(-detPitch);
      playerObj.position.setPosition(
        cameraEvents.xPos,
        cameraEvents.yPos - 0.3 + detPitchPos / 50,
        cameraEvents.zPos
      );

      // 坐标映射:场景X/Y/Z对应Cannon的X/Z/Y
      playerCollider.position.set(
        cameraEvents.xPos,
        cameraEvents.zPos,
        cameraEvents.yPos
      );
      // 锁定物理体速度与旋转,避免漂移
      playerCollider.velocity.set(0, 0, 0);
      playerCollider.angularVelocity.set(0, 0, 0);
    }
  }
};

核心优化点

  • 避免重复定时器触发:原代码在每一帧都会调用setTimeout,导致跳跃结束逻辑被多次触发。新增jumpTimer标记,确保定时器仅初始化一次。
  • 简化变量与重复逻辑:提取重复使用的cameraEvents、playerCollider、playerObj变量,减少重复访问场景对象的开销;统一detPitchPos的限制逻辑,消除代码冗余。
  • 修复相机Y轴固定问题:跳跃状态下让相机yPos直接跟随物理体的Z轴位置,实现Y轴依赖物理数据的需求,解决原固定值无法跳上物体的问题。
  • 明确坐标映射关系:通过变量命名清晰区分Cannon.js与场景的坐标对应关系,避免混淆出错。
  • 优化物理体控制:正常状态下始终锁定物理体速度,避免因物理引擎微小误差导致的位置漂移;跳跃状态下仅锁定旋转,保留Y轴(物理Z轴)的物理运动。

内容的提问来源于stack exchange,提问作者Nikola Lukic

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 18:05:21