Skip to content

203. 综合实战:开放世界(四)

Published:

上节实现了人遇到障碍物会停:

2025-12-07 21.20.16.gif

这节继续实现按空格跳跃的功能。

在地面上,移动速度是 10,但是跳起来以后,速度应该减小,比如往前跳,肯定速度不如走的快。

单独设置一个跳的时候的速度:

首先监听空格按下状态:

image.png

const keyPressed = {
  w: false,
  a: false,
  s: false,
  d: false,
  space: false
};

window.addEventListener('keydown', (e) => {
  const key = e.key.toLowerCase();
  if (key === ' ') {
    keyPressed.space = true;
  } else if (key in keyPressed) {
    keyPressed[key] = true;
  }
});

window.addEventListener('keyup', (e) => {
  const key = e.key.toLowerCase();
  if (key === ' ') {
    keyPressed.space = false;
  } else if (key in keyPressed) {
    keyPressed[key] = false;
  }
});

定义下空中的移动速度,以及往上跳的力。

image.png

加一下是否在地面的检测,用数值方向的速度判断就行。

const airControlSpeed = 1.5;
const jumpForce = 1000;
// 检测是否在地面或物体上
const physicsVelocity = playerBody.velocity;
const velocityY = Math.abs(physicsVelocity.y);
const isOnGround = velocityY < 1.0;

然后后面移动的时候,根据是否在地面来计算不同的速度:

image.png

地面上的移动速度快,空中慢一点。

if (isMoving) {
    moveDirection.normalize();
    if (isOnGround) {
      // 地面上
      playerBody.velocity.x = moveDirection.x * moveSpeed;
      playerBody.velocity.z = moveDirection.z * moveSpeed;
    } else {
      // 空中
      playerBody.velocity.x = moveDirection.x * airControlSpeed;
      playerBody.velocity.z = moveDirection.z * airControlSpeed;
    }
} else if (isOnGround) {
    playerBody.velocity.x = 0;
    playerBody.velocity.z = 0;
}

并且按住空格的时候,如果是在地面,就给物体加一个向上跳的力:

  if (keyPressed.space) {
    const physicsVelocity = playerBody.velocity;
    const velocityY = Math.abs(physicsVelocity.y);

    if (velocityY < 1.0) {
      playerBody.applyImpulse(new CANNON.Vec3(0, jumpForce, 0), playerBody.position);
    }
  }

试下效果:

2025-12-07 22.20.44.gif

可以看到,能跳跃,并且能跳到立方体上。

然后从立方体上走下来:

2025-12-07 22.22.49.gif

这样,跳跃功能就完成了。

我们走到灰色的墙边看一下:

2025-12-07 22.24.34.gif

没问题,同样也无法穿墙。

案例代码上传了小册仓库

总结

这节我们加上了跳跃功能,人物可以跳跃,跳到平台上,然后走下来。

跳跃的时候我们单独处理了下空中的移动速度。

当然,如果模型有跳跃的动画更好,会显得更真实。

下节,我们在这个开放世界中加入更多内容。

评论