You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

特定场景下玩家Y轴碰撞失效问题排查

玩家碰撞检测穿模问题

以下是我的玩家update函数:

void update() {
    IsOnWall = false;
    IsOnFloor = false;
    int collide[4] = { collidelist(Rect{pos.x, pos.y + vel.y, hitbox.width, vel.y + 1}, Stillbodies),
                        collidelist(Rect{pos.x, pos.y + hitbox.height, hitbox.width, vel.y - 1}, Stillbodies),
                        collidelist(Rect{pos.x + vel.x, pos.y + 1, vel.x - 1, hitbox.height - 1}, Stillbodies),
                        collidelist(Rect{pos.x + hitbox.width, pos.y + 1, vel.x + 1, hitbox.height - 1}, Stillbodies) };
    if (collide[0] >= 0 && vel.y <= 0) {
        vel.y = 0;
        pos.y = Stillbodies[collide[0]].y + Stillbodies[collide[0]].height;
        IsOnFloor = true;
    }
    if (collide[1] >= 0 && vel.y > 0) {
        vel.y = 0;
        pos.y = Stillbodies[collide[1]].y - Stillbodies[collide[1]].height;
    }
    if (collide[2] >= 0 && vel.x <= 0) {
        vel.x = 0;
        pos.x = Stillbodies[collide[2]].x + Stillbodies[collide[2]].width;
        IsOnWall = true;
    }
    if (collide[3] >= 0 && vel.x > 0) {
        vel.x = 0;
        pos.x = Stillbodies[collide[3]].x - hitbox.width;
        IsOnWall = true;
    }
    IsOnWallOnly = (IsOnWall && !IsOnFloor);
    IsOnFloorOnly = (IsOnFloor && !IsOnWall);
    pos.x += vel.x;
    pos.y += vel.y;
    hitbox.x = pos.x;
    hitbox.y = pos.y;
}

其中if collide[0]分支大部分情况正常,但当玩家的y速度恰好等于碰撞物体的高度时,会出现一帧的穿模情况。其余if分支在相同场景下均能正常工作。

最小复现示例

复现代码

#include <iostream>
#include <deque>
class Rect {
public:
    int x;
    int y;
    int width;
    int height;
    Rect(int X, int Y, int WIDTH, int HEIGHT) {
        x = X;
        y = Y;
        width = WIDTH;
        height = HEIGHT;
    }
};
class Spot {
public:
    int x;
    int y;
    Spot(int x1, int y1) {
        x = x1;
        y = y1;
    }
};
bool colliderect(Rect rect1, Rect rect2) {
    return (rect1.x < rect2.x + rect2.width &&
        rect1.x + rect1.width > rect2.x &&
        rect1.y < rect2.y + rect2.height &&
        rect1.y + rect1.height > rect2.y);
}
int collidelist(Rect rect, std::deque<Rect> rects) {
    for (float rec = 0; rec < rects.size(); rec++) {
        if (colliderect(rect, rects[rec])) {
            return rec;
        }
    }
    return -1;
}
std::deque<Rect> Stillbodies = { {0, 0, 50, 50} };
int main() {
    Spot pos = Spot(0, 50);
    Rect hitbox = Rect(pos.x, pos.y, 50, 50);
    Spot vel = Spot(0, 0);
    while (true) {
        char move;
        std::cin >> move;
        if (move == 'u') {
            vel.y = -50;
        }
        else if (move == 'd') {
            vel.y = 50;
        }
        else {
            vel.y = 0;
        }
        int collide[4] = { collidelist(Rect{pos.x, pos.y + vel.y, hitbox.width, vel.y + 1}, Stillbodies),
                                collidelist(Rect{pos.x, pos.y + hitbox.height, hitbox.width, vel.y - 1}, Stillbodies),
                                collidelist(Rect{pos.x + vel.x, pos.y + 1, vel.x - 1, hitbox.height - 1}, Stillbodies),
                                collidelist(Rect{pos.x + hitbox.width, pos.y + 1, vel.x + 1, hitbox.height - 1}, Stillbodies) };
        //broken collision (other ones that look same work)
        if (collide[0] >= 0 && vel.y <= 0) {
            vel.y = 0;
            pos.y = Stillbodies[collide[0]].y + Stillbodies[collide[0]].height;
        }
        //this one works
        if (collide[1] >= 0 && vel.y > 0) {
            vel.y = 0;
            pos.y = Stillbodies[collide[1]].y - hitbox.height;
        }
        pos.x += vel.x;
        pos.y += vel.y;
        hitbox.x = pos.x;
        hitbox.y = pos.y;
        std::cout << pos.x << " " << pos.y << std::endl;
    }
    return 0;
}

输入/输出(附注释)

n //n代表无操作
0 50 //无变化
u //u代表向上移动
0 0 //玩家上移但进入了方块内部
n //无操作
0 50 //被推出方块
u //向上移动
0 0 //重复上述情况
u //向上移动
0 -50 //现在处于方块上方,实际游戏中可穿过方块
d //向下移动
0 -50 //碰撞生效
d //向下移动
0 -50 //再次验证碰撞生效

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 05:14:53