平台游戏对象碰撞处理解析:代码逻辑求助
我跟着教程写了Player类里的onCollision方法,教程讲得还行,但我还是没完全搞懂代码的运行逻辑。其中Vector2类型的mid代表碰撞区域的中点,示意图如下:
我能直觉理解要计算重叠部分的长度(图中的x),然后把这个值加到玩家的位置Vector2上,防止玩家穿过Platform。但Vector2相关的一些数学运算我搞不明白。我看过面向游戏开发者的线性代数文章,里面讲了归一化这些概念,但没法把这些概念套到下面的具体代码里:
Vector2 collisionNormal = absoluteCenter - mid; final seperationDist = (size.x / 2) - collisionNormal.length; collisionNormal.normalize(); if (Vector2(0, -1).dot(collisionNormal) > 0.9) { _isOnGround = true; } position += collisionNormal.scaled(seperationDist);
有人能帮我拆解这段代码的逻辑,或者讲讲平台游戏里处理这类碰撞问题的通用方法吗?
我的Player类(核心为onCollision方法)
class Player extends SpriteAnimationGroupComponent with HasGameRef<Gain>, KeyboardHandler, CollisionCallbacks { String character; Player({pos, this.character = "Ninja Frog"}) : super(position: pos); final double stepTime = 0.05; ... @override void onCollision(Set<Vector2> intersectionPoints, PositionComponent other) { if (other is Platform) { if (intersectionPoints.length == 2) { Vector2 mid = (intersectionPoints.elementAt(0) + intersectionPoints.elementAt(1)) / 2; Vector2 collisionNormal = absoluteCenter - mid; final seperationDist = (size.x / 2) - collisionNormal.length; collisionNormal.normalize(); if (Vector2(0, -1).dot(collisionNormal) > 0.9) { _isOnGround = true; } position += collisionNormal.scaled(seperationDist); } } super.onCollision(intersectionPoints, other); } }
代表游戏墙体、地面、天花板的Platform类
class Platform extends PositionComponent with CollisionCallbacks { bool canJumpThrough; Platform({required Vector2 position, required Vector2 size, this.canJumpThrough = false}) : super(position: position, size: size); @override FutureOr<void> onLoad() { add(RectangleHitbox(collisionType: CollisionType.passive)); return super.onLoad(); } }
代码逐行拆解
Vector2 collisionNormal = absoluteCenter - mid;
计算从碰撞区域中点mid指向玩家中心absoluteCenter的向量,这个向量的方向就是玩家需要被推开的大致方向——因为玩家是从mid所在的碰撞区域,往自己中心的反方向侵入了平台。final seperationDist = (size.x / 2) - collisionNormal.length;size.x / 2是玩家矩形碰撞盒的半宽,collisionNormal.length是玩家中心到碰撞区域中点的直线距离。两者相减得到的就是玩家侵入平台的深度(也就是你说的图中x),这个值就是需要把玩家推开的距离,能让玩家刚好离开碰撞区域。collisionNormal.normalize();
归一化是把向量转换成长度为1的单位向量,只保留方向信息。这样后续用它乘以seperationDist时,就能得到一个方向正确、长度刚好等于推开距离的位移向量。if (Vector2(0, -1).dot(collisionNormal) > 0.9) { _isOnGround = true; }
这里用到向量点积运算:Vector2(0, -1)是指向正上方的单位向量(游戏中通常y轴向下,所以(0,-1)代表向上)。点积结果可以判断两个向量的夹角:结果接近1时,两个向量方向几乎一致;接近-1则方向完全相反。这里判断点积大于0.9,说明碰撞法线方向接近向上,也就是玩家踩在了平台顶部,因此设置_isOnGround为true,用于后续跳跃等逻辑判断。position += collisionNormal.scaled(seperationDist);
最后把归一化后的方向向量乘以推开距离,得到精准的位移值,加到玩家位置上,让玩家被推回到与平台无重叠的位置,避免穿模。
平台游戏碰撞处理通用思路
- 碰撞检测:先检测玩家与平台是否发生碰撞,获取碰撞交点或重叠区域信息。
- 碰撞响应:
- 计算碰撞法线(推开方向),确定玩家需要被修正的方向;
- 计算重叠深度,确定需要推开的距离;
- 根据碰撞方向判断碰撞类型(踩地面、撞墙、碰天花板),更新玩家状态;
- 应用位移修正,将玩家移至碰撞外的安全位置。
- 多数游戏引擎会提供内置碰撞响应系统,但手动实现的核心逻辑就是方向判断+深度计算+位移修正这三步。
内容的提问来源于stack exchange,提问作者Squinnb

