SFML 瓦片地图碰撞
SFML tilemap collision
我正在用 SFML 制作一个 2D 游戏,我正在尝试弄清楚如何与瓦片地图中的瓦片发生碰撞。我已经编写了一些代码,但问题是我卡在了正在碰撞的方块中,如下图所示。我无法向任何方向移动,播放器的大约 5 个像素在墙上。
这是我的碰撞/移动代码
void Player::update(float delta, std::vector<Tile>& tiles) {
canMove = true;
for (int i = 0; i < tiles.size(); i++) {
if (Collision::PixelPerfectTest(sprite, tiles[i].sprite) && tiles[i].collision) {
canMove = false;
}
}
if (canMove) {
move(delta);
}
}
void Player::move(float delta) {
if (sf::Keyboard::isKeyPressed(sf::Keyboard::W) || sf::Keyboard::isKeyPressed(sf::Keyboard::Up) || sf::Joystick::getAxisPosition(0, sf::Joystick::Y) < -20) {
movement.y -= speed * delta;
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::A) || sf::Keyboard::isKeyPressed(sf::Keyboard::Left) || sf::Joystick::getAxisPosition(0, sf::Joystick::X) < -20) {
movement.x -= speed * delta;
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::S) || sf::Keyboard::isKeyPressed(sf::Keyboard::Down) || sf::Joystick::getAxisPosition(0, sf::Joystick::Y) > 20) {
movement.y += speed * delta;
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::D) || sf::Keyboard::isKeyPressed(sf::Keyboard::Right) || sf::Joystick::getAxisPosition(0, sf::Joystick::X) > 20) {
movement.x += speed * delta;
}
sprite.setPosition(movement);
}
这是 PixelPerfectTest 函数(不是我的)
bool PixelPerfectTest(const sf::Sprite& Object1, const sf::Sprite& Object2, sf::Uint8 AlphaLimit) {
sf::FloatRect Intersection;
if (Object1.getGlobalBounds().intersects(Object2.getGlobalBounds(), Intersection)) {
sf::IntRect O1SubRect = Object1.getTextureRect();
sf::IntRect O2SubRect = Object2.getTextureRect();
sf::Uint8* mask1 = Bitmasks.GetMask(Object1.getTexture());
sf::Uint8* mask2 = Bitmasks.GetMask(Object2.getTexture());
// Loop through our pixels
for (int i = Intersection.left; i < Intersection.left + Intersection.width; i++) {
for (int j = Intersection.top; j < Intersection.top + Intersection.height; j++) {
sf::Vector2f o1v = Object1.getInverseTransform().transformPoint(i, j);
sf::Vector2f o2v = Object2.getInverseTransform().transformPoint(i, j);
// Make sure pixels fall within the sprite's subrect
if (o1v.x > 0 && o1v.y > 0 && o2v.x > 0 && o2v.y > 0 &&
o1v.x < O1SubRect.width && o1v.y < O1SubRect.height &&
o2v.x < O2SubRect.width && o2v.y < O2SubRect.height) {
if (Bitmasks.GetPixel(mask1, Object1.getTexture(), (int)(o1v.x) + O1SubRect.left, (int)(o1v.y) + O1SubRect.top) > AlphaLimit &&
Bitmasks.GetPixel(mask2, Object2.getTexture(), (int)(o2v.x) + O2SubRect.left, (int)(o2v.y) + O2SubRect.top) > AlphaLimit)
return true;
}
}
}
}
return false;
}
编辑:这就是我让它工作的方式,以防将来有人需要帮助
void Player::update(float delta, std::vector<Tile>& tiles) {
if (sf::Keyboard::isKeyPressed(sf::Keyboard::W) || sf::Keyboard::isKeyPressed(sf::Keyboard::Up) || sf::Joystick::getAxisPosition(0, sf::Joystick::Y) < -20) {
newPos.y -= speed * delta;
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::A) || sf::Keyboard::isKeyPressed(sf::Keyboard::Left) || sf::Joystick::getAxisPosition(0, sf::Joystick::X) < -20) {
newPos.x -= speed * delta;
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::S) || sf::Keyboard::isKeyPressed(sf::Keyboard::Down) || sf::Joystick::getAxisPosition(0, sf::Joystick::Y) > 20) {
newPos.y += speed * delta;
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::D) || sf::Keyboard::isKeyPressed(sf::Keyboard::Right) || sf::Joystick::getAxisPosition(0, sf::Joystick::X) > 20) {
newPos.x += speed * delta;
}
sf::Vector2f oldPos = sprite.getPosition();
sprite.setPosition(newPos);
for (int i = 0; i < tiles.size(); i++) {
if (Collision::PixelPerfectTest(sprite, tiles[i].sprite) && tiles[i].collision) {
sprite.setPosition(oldPos);
newPos = oldPos;
}
}
}
你的问题本质上是这样的:
如果您的玩家不在墙上,他可以向任何方向移动。这包括会让他撞墙的动作。如果您的玩家 在墙上,他根本无法移动。所以如果他撞到墙上(因为你允许他这样做),他永远无法摆脱它。
所以,最明显的解决方法是不要让玩家撞到墙上。一种简单的方法是尝试移动玩家,然后检查是否与墙壁发生碰撞。如果发生碰撞,将玩家移回原来的位置。
这应该可以解决卡在墙上的基本问题。尽管这可能会给您带来其他问题,例如无法紧靠墙壁。为此,您可以做的是检查发生碰撞时墙的确切位置,然后将玩家移到它旁边。
编辑:当碰撞检测 returns false 保存之前的位置时,当你的角色与一个物体发生碰撞时,你所要做的就是恢复之前的非碰撞位置。
void Player::update(float delta, std::vector<Tile>& tiles) {
for (int i = 0; i < tiles.size(); i++)
Collision::PixelPerfectTest(sprite, tiles[i].sprite) && tiles[i].collision) ? canMove = false : prevpos = sprite.getPosition();
if (canMove) {
move(delta);
}
else
{
sprite.setPosition(prevpos);
canMove = true;
}
}
类似的东西。
我正在用 SFML 制作一个 2D 游戏,我正在尝试弄清楚如何与瓦片地图中的瓦片发生碰撞。我已经编写了一些代码,但问题是我卡在了正在碰撞的方块中,如下图所示。我无法向任何方向移动,播放器的大约 5 个像素在墙上。
这是我的碰撞/移动代码
void Player::update(float delta, std::vector<Tile>& tiles) {
canMove = true;
for (int i = 0; i < tiles.size(); i++) {
if (Collision::PixelPerfectTest(sprite, tiles[i].sprite) && tiles[i].collision) {
canMove = false;
}
}
if (canMove) {
move(delta);
}
}
void Player::move(float delta) {
if (sf::Keyboard::isKeyPressed(sf::Keyboard::W) || sf::Keyboard::isKeyPressed(sf::Keyboard::Up) || sf::Joystick::getAxisPosition(0, sf::Joystick::Y) < -20) {
movement.y -= speed * delta;
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::A) || sf::Keyboard::isKeyPressed(sf::Keyboard::Left) || sf::Joystick::getAxisPosition(0, sf::Joystick::X) < -20) {
movement.x -= speed * delta;
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::S) || sf::Keyboard::isKeyPressed(sf::Keyboard::Down) || sf::Joystick::getAxisPosition(0, sf::Joystick::Y) > 20) {
movement.y += speed * delta;
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::D) || sf::Keyboard::isKeyPressed(sf::Keyboard::Right) || sf::Joystick::getAxisPosition(0, sf::Joystick::X) > 20) {
movement.x += speed * delta;
}
sprite.setPosition(movement);
}
这是 PixelPerfectTest 函数(不是我的)
bool PixelPerfectTest(const sf::Sprite& Object1, const sf::Sprite& Object2, sf::Uint8 AlphaLimit) {
sf::FloatRect Intersection;
if (Object1.getGlobalBounds().intersects(Object2.getGlobalBounds(), Intersection)) {
sf::IntRect O1SubRect = Object1.getTextureRect();
sf::IntRect O2SubRect = Object2.getTextureRect();
sf::Uint8* mask1 = Bitmasks.GetMask(Object1.getTexture());
sf::Uint8* mask2 = Bitmasks.GetMask(Object2.getTexture());
// Loop through our pixels
for (int i = Intersection.left; i < Intersection.left + Intersection.width; i++) {
for (int j = Intersection.top; j < Intersection.top + Intersection.height; j++) {
sf::Vector2f o1v = Object1.getInverseTransform().transformPoint(i, j);
sf::Vector2f o2v = Object2.getInverseTransform().transformPoint(i, j);
// Make sure pixels fall within the sprite's subrect
if (o1v.x > 0 && o1v.y > 0 && o2v.x > 0 && o2v.y > 0 &&
o1v.x < O1SubRect.width && o1v.y < O1SubRect.height &&
o2v.x < O2SubRect.width && o2v.y < O2SubRect.height) {
if (Bitmasks.GetPixel(mask1, Object1.getTexture(), (int)(o1v.x) + O1SubRect.left, (int)(o1v.y) + O1SubRect.top) > AlphaLimit &&
Bitmasks.GetPixel(mask2, Object2.getTexture(), (int)(o2v.x) + O2SubRect.left, (int)(o2v.y) + O2SubRect.top) > AlphaLimit)
return true;
}
}
}
}
return false;
}
编辑:这就是我让它工作的方式,以防将来有人需要帮助
void Player::update(float delta, std::vector<Tile>& tiles) {
if (sf::Keyboard::isKeyPressed(sf::Keyboard::W) || sf::Keyboard::isKeyPressed(sf::Keyboard::Up) || sf::Joystick::getAxisPosition(0, sf::Joystick::Y) < -20) {
newPos.y -= speed * delta;
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::A) || sf::Keyboard::isKeyPressed(sf::Keyboard::Left) || sf::Joystick::getAxisPosition(0, sf::Joystick::X) < -20) {
newPos.x -= speed * delta;
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::S) || sf::Keyboard::isKeyPressed(sf::Keyboard::Down) || sf::Joystick::getAxisPosition(0, sf::Joystick::Y) > 20) {
newPos.y += speed * delta;
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::D) || sf::Keyboard::isKeyPressed(sf::Keyboard::Right) || sf::Joystick::getAxisPosition(0, sf::Joystick::X) > 20) {
newPos.x += speed * delta;
}
sf::Vector2f oldPos = sprite.getPosition();
sprite.setPosition(newPos);
for (int i = 0; i < tiles.size(); i++) {
if (Collision::PixelPerfectTest(sprite, tiles[i].sprite) && tiles[i].collision) {
sprite.setPosition(oldPos);
newPos = oldPos;
}
}
}
你的问题本质上是这样的:
如果您的玩家不在墙上,他可以向任何方向移动。这包括会让他撞墙的动作。如果您的玩家 在墙上,他根本无法移动。所以如果他撞到墙上(因为你允许他这样做),他永远无法摆脱它。
所以,最明显的解决方法是不要让玩家撞到墙上。一种简单的方法是尝试移动玩家,然后检查是否与墙壁发生碰撞。如果发生碰撞,将玩家移回原来的位置。
这应该可以解决卡在墙上的基本问题。尽管这可能会给您带来其他问题,例如无法紧靠墙壁。为此,您可以做的是检查发生碰撞时墙的确切位置,然后将玩家移到它旁边。
编辑:当碰撞检测 returns false 保存之前的位置时,当你的角色与一个物体发生碰撞时,你所要做的就是恢复之前的非碰撞位置。
void Player::update(float delta, std::vector<Tile>& tiles) {
for (int i = 0; i < tiles.size(); i++)
Collision::PixelPerfectTest(sprite, tiles[i].sprite) && tiles[i].collision) ? canMove = false : prevpos = sprite.getPosition();
if (canMove) {
move(delta);
}
else
{
sprite.setPosition(prevpos);
canMove = true;
}
}
类似的东西。