☰
从圆到碰撞:游戏物理的入门真相
2026/10/17 1:42:55 网站建设 项目流程

一、碰撞检测要回答什么问题?

游戏里每一帧,都要问一句:

“这两个东西碰到了没有?”

比如:

  • 子弹打中敌人没有?
  • 玩家踩到地面没有?
  • 角色撞到墙没有?
  • 玩家走进宝箱的范围没有?

碰到之后要做什么(扣血、停下、弹开、播放音效),那是碰撞响应,是另一件事。

碰撞检测只负责回答:碰到了吗?


二、最简单的两种方法

游戏里大部分物体,其实都可以用圆或者方框来近似。

1. 圆和圆:看距离

两个圆,圆心之间的距离 ≤ 两个半径加起来,就碰到了。

没碰到: 碰到了: ( A ) ( B ) ( A )( B ) ←── 距离 ──→ 距离 ≤ 半径和

例子:

  • A 圆心 (0, 0),半径 1
  • B 圆心 (3, 0),半径 1
  • 距离 = 3,半径和 = 2
  • 3 > 2 →没碰到
boolHit(Vector2a,floatra,Vector2b,floatrb){returnVector2.Distance(a,b)<=ra+rb;}

适合:子弹、球、角色的大致范围。


2. 方框和方框:看左右、看上下

两个不旋转的方框(叫AABB),要同时满足:

  • 左右方向有重叠
  • 上下方向有重叠

只要有一个方向分开了,就没碰到。

左右重叠,上下也重叠 → 碰到 左右重叠,但上下分开 → 没碰到 ┌────┐ ┌────┐ │ A ┌┼───┐ │ A │ └────┼┘ B │ └────┘ └────┘ ┌────┐ │ B │ └────┘
boolHit(Recta,Rectb){bool左右重叠=a.xMin<=b.xMax&&a.xMax>=b.xMin;bool上下重叠=a.yMin<=b.yMax&&a.yMax>=b.yMin;return左右重叠&&上下重叠;}

适合:平台跳跃游戏、俯视角游戏里的墙、地块、箱子。

很多 2D 小游戏,只用这两种方法就够了。


三、东西多了怎么办?先粗筛,再细查

假如场景里有 1000 个物体,两两检测就是约 50 万次,太慢。

所以真实的游戏都分两步:

阶段做什么比喻
粗检测快速排除明显离得很远的物体先看是不是在同一个房间
细检测对靠得近的物体,精确判断碰没碰到再看是不是真的撞上了

粗检测常用的方法:把地图划成格子,只检测同一个格子里的物体。

┌────┬────┬────┐ │ ● │ │ │ │ ● │ │ ● │ 只有左上格子里的两个点需要互相检测 ├────┼────┼────┤ │ │ ● │ │ └────┴────┴────┘

四、形状复杂了怎么办?

如果物体是旋转的方框、三角形、多边形,圆和 AABB 的方法就不够用了。这时候才需要更高级的方法:

方法一句话
SAT(分离轴)找一个方向,如果在这个方向上两个形状分开了,就没碰到
GJK前面讲的那个,用 Support 函数,能处理任意凸形状

前面卡住的地方,其实属于**“进阶内容”**。不先掌握圆和方框,直接看 GJK 当然会很难。


五、游戏里常见的碰撞问题

问题现象常见解决办法
穿墙子弹太快,一帧就跳过了墙检测"移动路线"而不是只看位置(射线检测)
卡墙 / 抖动角色贴着墙一直抖碰撞后把角色推出来一点
太慢物体多了掉帧先粗检测,用格子划分

六、如果你用 Unity

Unity 已经帮你做好了大部分工作,你只需要:

  1. 给物体加Collider(BoxCollider2D、CircleCollider2D 等)
  2. 至少一方加Rigidbody2D
  3. 写回调函数:
voidOnCollisionEnter2D(Collision2Dother){Debug.Log("撞到了:"+other.gameObject.name);}

GJK、SAT 这些,引擎内部已经实现了,平时做游戏不需要自己写。


需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询