SFML中可否为单个精灵添加多个可调整大小的包围盒?
SFML吃豆人迷宫多碰撞盒实现方案
完全可以为迷宫背景设置多个碰撞包围盒,这是吃豆人这类网格类2D游戏实现墙壁碰撞的主流方案。
实现原理
SFML的sf::Sprite本身没有内置多包围盒的接口,我们只需要手动定义所有墙壁的碰撞区域,存为碰撞盒列表,每次移动吃豆人前先预判移动后的位置,和所有墙壁碰撞盒做相交校验,碰到墙壁就取消本次移动即可。
具体实现步骤
1. 新增依赖与变量定义
首先引入存储碰撞盒需要的头文件,定义墙壁碰撞盒列表:
#include <vector> // 存储所有墙壁的碰撞包围盒,定义在main函数内部即可 std::vector<sf::FloatRect> wallColliders;
2. 初始化墙壁碰撞盒
你需要根据你的迷宫实际尺寸,把所有墙壁区域拆分成若干个矩形,添加到碰撞盒列表中,注意你的背景精灵缩放了1.25倍,所以原始图上量取的坐标和宽高都要乘以1.25的缩放系数:
// 示例:添加最上方的横向墙壁,你需要自己补全所有墙壁的碰撞盒 // 参数说明:sf::FloatRect(左上角x, 左上角y, 宽度, 高度) wallColliders.emplace_back(0 * 1.25f, 0 * 1.25f, 280 * 1.25f, 10 * 1.25f); // 按照迷宫结构补全其他所有墙壁的碰撞盒...
你使用的迷宫参考图:
3. 修改移动逻辑,新增碰撞校验
不要直接调用move方法,先预判移动后的位置,校验是否和墙壁碰撞后再决定是否执行移动:
// 先拿到吃豆人当前的碰撞盒 sf::FloatRect currentBounds = pacmanMC_sprite.getGlobalBounds(); // 定义本次移动的偏移量 float offsetX = 0.f, offsetY = 0.f; float moveSpeed = 0.015f; // 只计算偏移,不直接移动 if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key::Up)) { offsetY = -moveSpeed; pacmanMC_sprite.setRotation(-90.f); } else if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key::Down)) { offsetY = moveSpeed; pacmanMC_sprite.setRotation(90.f); } else if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key::Left)) { offsetX = -moveSpeed; pacmanMC_sprite.setRotation(-180.f); } else if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key::Right)) { offsetX = moveSpeed; pacmanMC_sprite.setRotation(0.f); } // 预判移动后的碰撞盒 sf::FloatRect nextBounds = currentBounds; nextBounds.left += offsetX; nextBounds.top += offsetY; // 校验是否和墙壁碰撞 bool canMove = true; for (auto& wall : wallColliders) { if (nextBounds.intersects(wall)) { canMove = false; break; } } // 没有碰撞才执行移动 if (canMove) { pacmanMC_sprite.move(offsetX, offsetY); }
优化方案
如果后续觉得遍历所有碰撞盒效率低,你可以用二维网格数组存储迷宫状态:把整个迷宫拆分成固定大小的格子,每个格子标记是「墙壁」还是「通路」,碰撞时只需要检测吃豆人所在格子的相邻格子状态即可,不需要遍历所有墙壁,效率更高。
内容的提问来源于stack exchange,提问作者cindicate
相关产品推荐
相关产品推荐

