如何修复AABB碰撞下平台游戏角色与物体碰撞产生的间隙
平台游戏角色碰撞墙体产生间隙的修复方案
问题描述
开发平台游戏时遇到角色无法完全贴近墙体的问题,原因是碰撞检测触发后直接将dx从角色位置中减去,导致角色与墙体之间产生间隙。以下是当前的MovePlayer函数代码:
void MovePlayer() { float dx = 0; if(keys.right) dx += (plr.speed * g_deltaTime); if(keys.left) dx -= (plr.speed * g_deltaTime); plr.myCollider->position.x += dx; Collider *temp = collider_head.next; while(temp != NULL) { Collider *next = temp->next; if(temp != plr.myCollider && temp->type == COLLIDER_STATIC && isColliding(plr.myCollider, temp)) { plr.myCollider->position.x -= dx; } temp = next; } plr.y_velocity += GRAVITY * g_deltaTime; float dy = plr.y_velocity * g_deltaTime; plr.myCollider->position.y += dy; temp = collider_head.next; while(temp != NULL) { Collider *next = temp->next; if(temp != plr.myCollider && temp->type == COLLIDER_STATIC && isColliding(plr.myCollider, temp)) { plr.myCollider->position.y -= dy; if(plr.y_velocity > 0) { plr.grounded = TRUE; } plr.y_velocity = 0; } temp = next; } if(keys.up && plr.grounded) { plr.y_velocity = -110; plr.grounded = FALSE; } if(keys.up && plr.y_velocity < 0) { plr.y_velocity += -90.0f * g_deltaTime; } }
修复思路
当前代码在碰撞后直接将角色位置回退整个dx(或dy),这会让角色回到移动前的位置,自然产生间隙。正确的做法是计算角色与墙体的重叠距离,只回退刚好消除重叠的距离,让角色刚好贴紧墙体。
具体修改步骤
- 新增计算碰撞重叠量的函数,用于获取x、y轴的重叠数值:
typedef struct { float x; float y; } CollisionOverlap; CollisionOverlap CalculateCollisionOverlap(Collider* a, Collider* b) { CollisionOverlap overlap = {0}; // 计算x轴重叠 float aRight = a->position.x + a->width; float bRight = b->position.x + b->width; float aLeft = a->position.x; float bLeft = b->position.x; overlap.x = fmin(aRight, bRight) - fmax(aLeft, bLeft); // 计算y轴重叠 float aBottom = a->position.y + a->height; float bBottom = b->position.y + b->height; float aTop = a->position.y; float bTop = b->position.y; overlap.y = fmin(aBottom, bBottom) - fmax(aTop, bTop); return overlap; }
- 修改x轴碰撞处理逻辑,替换原有的直接回退
dx的代码:
// 原x轴碰撞判断块替换为: if(temp != plr.myCollider && temp->type == COLLIDER_STATIC && isColliding(plr.myCollider, temp)) { CollisionOverlap overlap = CalculateCollisionOverlap(plr.myCollider, temp); // 根据移动方向调整位置,只消除重叠部分 if(dx > 0) { // 向右移动撞墙,左移重叠量 plr.myCollider->position.x -= overlap.x; } else if(dx < 0) { // 向左移动撞墙,右移重叠量 plr.myCollider->position.x += overlap.x; } }
- 优化y轴碰撞处理,同样用重叠量替代回退整个
dy:
// 原y轴碰撞判断块替换为: if(temp != plr.myCollider && temp->type == COLLIDER_STATIC && isColliding(plr.myCollider, temp)) { CollisionOverlap overlap = CalculateCollisionOverlap(plr.myCollider, temp); if(dy > 0) { // 下落撞地面,上移重叠量 plr.myCollider->position.y -= overlap.y; plr.grounded = TRUE; } else if(dy < 0) { // 跳跃撞天花板,下移重叠量 plr.myCollider->position.y += overlap.y; } plr.y_velocity = 0; }
关键说明
- 核心逻辑是只回退碰撞产生的重叠距离,而非整个移动量,这样角色会刚好贴合墙体/地面,不会出现间隙。
- 必须根据移动方向判断重叠量的调整方向,确保角色向正确的方向移动以消除碰撞。
内容的提问来源于stack exchange,提问作者greg04




