You need to enable JavaScript to run this app. 基于勾股定理的2D正方形与矩形碰撞检测及物理响应实现求助
优惠活动
大模型
产品
解决方案
定价
更多

基于勾股定理的2D正方形与矩形碰撞检测及物理响应实现求助

问题根因分析
  • 原逻辑基于矩形边中点距离判断碰撞方向,仅对宽高接近的正方形有效。当矩形宽高比例差异大时(比如你代码里宽100高30的平台),边中点距离无法正确反映真实碰撞方向,甚至会出现已经碰撞但中点距离还很大的误判
  • 碰撞响应逻辑错误:静态平台不需要修改位置,原代码同时调整了玩家和平台的坐标,导致碰撞后平台移位、玩家位置异常
  • 执行顺序错误:原代码先做碰撞检测再更新玩家位置,碰撞检测用的是上一帧的玩家坐标,容易出现错位
  • HTML样式错误:body的宽度设置为100vh,应该为100vw,否则画布会出现横向滚动条
修复方案
  1. 修正HTML样式
body {
  height:100vh;
  width:100vw; /* 把原来的100vh改成100vw */
  margin: 0;
  overflow: hidden; /* 新增,隐藏页面滚动条 */
}
  1. 替换碰撞检测逻辑,先做AABB预过滤,再用重叠深度判断碰撞方向,适配任意比例矩形:
function platformDetection(obj, obj2){
  // 第一步:AABB碰撞预检测,没碰撞直接返回,节省性能也避免误判
  if (
    obj.x + obj.w < obj2.x ||
    obj.x > obj2.x + obj2.w ||
    obj.y + obj.h < obj2.y ||
    obj.y > obj2.y + obj2.h
  ) return;

  // 第二步:计算两个矩形的中心坐标差
  const objCenterX = obj.x + obj.w / 2;
  const objCenterY = obj.y + obj.h / 2;
  const obj2CenterX = obj2.x + obj2.w / 2;
  const obj2CenterY = obj2.y + obj2.h / 2;
  const dx = objCenterX - obj2CenterX;
  const dy = objCenterY - obj2CenterY;

  // 第三步:计算x、y轴的重叠深度,重叠更小的轴就是碰撞方向
  const overlapX = (obj.w / 2 + obj2.w / 2) - Math.abs(dx);
  const overlapY = (obj.h / 2 + obj2.h / 2) - Math.abs(dy);

  let val = 0;
  if (overlapX < overlapY) {
    // X轴碰撞
    val = dx > 0 ? 4 : 2; // 4=玩家左撞平台右,2=玩家右撞平台左
  } else {
    // Y轴碰撞
    val = dy > 0 ? 1 : 3; // 1=玩家顶撞平台底,3=玩家底撞平台顶
  }

  // 可以保留你原来的辅助线绘制逻辑,对应val的值绘制即可
  platformAction(obj, obj2, val);
}
  1. 修正碰撞响应逻辑,仅修改玩家坐标,不要改动静态平台的位置:
function platformAction(obj, obj2, val){
  if (val == 1) {
    // 玩家顶部撞平台底部
    obj.y = obj2.y + obj2.h;
    obj.vy = 0;
    obj.jumping = true;
  } else if (val == 2) {
    // 玩家右边撞平台左边
    obj.x = obj2.x - obj.w - 1;
    obj.vx = 0;
  } else if (val == 3) {
    // 玩家底部撞平台顶部
    obj.y = obj2.y - obj.h;
    obj.vy = 0;
    obj.jumping = false;
  } else if (val == 4) {
    // 玩家左边撞平台右边
    obj.x = obj2.x + obj2.w + 1;
    obj.vx = 0;
  }
}
  1. 调整循环执行顺序,先更新玩家位置再做碰撞检测:
function loop() {
  context.clearRect(0, 0, canvas.width, canvas.height); 
  context.fillStyle = 'grey';
  context.fillRect(0, 0, canvas.width, canvas.height);

  // 更新平台
  initObj(platform1);
  initObj(platform2);

  // 先更新玩家位置
  controlPlayer1(player1); 

  // 再执行碰撞检测
  platformDetection(player1, platform1);
  platformDetection(player1, platform2);

  requestAnimationFrame(loop)
}

该方案继承了你原来的“单方向判定、避免多if同时命中”的设计思路,且适配任意比例的矩形碰撞,不需要额外的多条件分支判断。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.22 05:54:08