You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何修复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),这会让角色回到移动前的位置,自然产生间隙。正确的做法是计算角色与墙体的重叠距离,只回退刚好消除重叠的距离,让角色刚好贴紧墙体。

具体修改步骤

  1. 新增计算碰撞重叠量的函数,用于获取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;
}
  1. 修改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;
    }
}
  1. 优化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

火山引擎 最新活动