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

Pixi.js+Electron 2D游戏:拆分碰撞检测为四方向检测问题

解决Pixi.js中玩家与平台的多方向碰撞检测问题

核心思路

要准确判断碰撞方向,必须同时满足两个关键条件:

  • 玩家与平台在垂直于碰撞方向的轴上存在重叠(比如判断上下碰撞时,X轴必须有交叉区域)
  • 结合玩家上一帧的位置校验碰撞发生的时机(避免玩家离开平台后仍误判为持续碰撞)

具体实现

首先在Player类中新增上一帧位置的记录变量(prevX、prevY),在每一帧更新时先保存当前位置,再执行移动逻辑,最后进行碰撞检测。

1. 辅助边界计算

封装统一的边界获取方法,简化重复代码:

// 获取精灵的边界信息(top, bottom, left, right)
getBounds(sprite) {
  return {
    top: sprite.y,
    bottom: sprite.y + sprite.height,
    left: sprite.x,
    right: sprite.x + sprite.width
  };
}

2. 四个方向的碰撞检测函数

// 检测玩家是否从下方碰撞平台顶部
isDownTouching(platform) {
  const playerBounds = this.getBounds(this);
  const prevPlayerBounds = {
    top: this.prevY,
    bottom: this.prevY + this.height,
    left: this.prevX,
    right: this.prevX + this.width
  };
  const platformBounds = this.getBounds(platform);

  // 判定逻辑:X轴重叠 + 上一帧玩家底部未超过平台顶部 + 当前帧玩家底部进入平台范围
  return (
    playerBounds.left < platformBounds.right &&
    playerBounds.right > platformBounds.left &&
    prevPlayerBounds.bottom <= platformBounds.top &&
    playerBounds.bottom > platformBounds.top
  );
}

// 检测玩家是否从上方碰撞平台底部
isUpTouching(platform) {
  const playerBounds = this.getBounds(this);
  const prevPlayerBounds = {
    top: this.prevY,
    bottom: this.prevY + this.height,
    left: this.prevX,
    right: this.prevX + this.width
  };
  const platformBounds = this.getBounds(platform);

  // 判定逻辑:X轴重叠 + 上一帧玩家顶部未低于平台底部 + 当前帧玩家顶部进入平台范围
  return (
    playerBounds.left < platformBounds.right &&
    playerBounds.right > platformBounds.left &&
    prevPlayerBounds.top >= platformBounds.bottom &&
    playerBounds.top < platformBounds.bottom
  );
}

// 检测玩家是否从右侧碰撞平台左侧
isLeftTouching(platform) {
  const playerBounds = this.getBounds(this);
  const prevPlayerBounds = {
    top: this.prevY,
    bottom: this.prevY + this.height,
    left: this.prevX,
    right: this.prevX + this.width
  };
  const platformBounds = this.getBounds(platform);

  // 判定逻辑:Y轴重叠 + 上一帧玩家左侧未超过平台右侧 + 当前帧玩家左侧进入平台范围
  return (
    playerBounds.top < platformBounds.bottom &&
    playerBounds.bottom > platformBounds.top &&
    prevPlayerBounds.left >= platformBounds.right &&
    playerBounds.left < platformBounds.right
  );
}

// 检测玩家是否从左侧碰撞平台右侧
isRightTouching(platform) {
  const playerBounds = this.getBounds(this);
  const prevPlayerBounds = {
    top: this.prevY,
    bottom: this.prevY + this.height,
    left: this.prevX,
    right: this.prevX + this.width
  };
  const platformBounds = this.getBounds(platform);

  // 判定逻辑:Y轴重叠 + 上一帧玩家右侧未超过平台左侧 + 当前帧玩家右侧进入平台范围
  return (
    playerBounds.top < platformBounds.bottom &&
    playerBounds.bottom > platformBounds.top &&
    prevPlayerBounds.right <= platformBounds.left &&
    playerBounds.right > platformBounds.left
  );
}

3. Update函数中的调用逻辑

在Player的update方法中按顺序执行位置保存、移动、碰撞检测:

update(delta) {
  // 1. 保存上一帧位置
  this.prevX = this.x;
  this.prevY = this.y;

  // 2. 执行玩家移动逻辑(根据输入更新x、y或velocity)
  this.handleMovement(delta);

  // 3. 遍历所有平台处理碰撞
  game.platforms.forEach(platform => {
    if (this.isDownTouching(platform)) {
      // 修正玩家位置并重置垂直速度
      this.y = platform.y - this.height;
      this.velocityY = 0;
    }
    if (this.isUpTouching(platform)) {
      this.y = platform.y + platform.height;
      this.velocityY = 0;
    }
    if (this.isLeftTouching(platform)) {
      this.x = platform.x + platform.width;
      this.velocityX = 0;
    }
    if (this.isRightTouching(platform)) {
      this.x = platform.x - this.width;
      this.velocityX = 0;
    }
  });
}

问题根源解释

此前AI提供的isYTouching函数存在两个核心缺陷:

  1. 仅单独检测Y轴位置,未结合X轴的重叠判断,导致玩家与平台在X轴完全分离时,仍可能因Y轴位置重叠误判为碰撞。
  2. 缺少上一帧位置的校验,玩家离开平台后,Y轴位置可能仍处于平台范围内(比如从平台上方跳离时的短暂位置重叠),从而持续返回true。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 01:35:20