特定场景下玩家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
相关产品推荐
相关产品推荐

