问题描述
我正在用SFML制作2D游戏,并且试图弄清楚如何与tilemap中的图块发生碰撞。我已经写了一些代码,但是问题是我陷入了与之碰撞的图块中,如下面的图片所示。我无法向任何方向移动,并且播放器的大约5个像素在墙上。
I'm making a 2D game in SFML and I'm trying to figure out how to collide with tiles in a tilemap. I've written some code but the problem is that I get stuck in the tile I'm colliding with as you can see in the picture below. I cannot move in any direction and around 5 pixels of the player is in the wall.
此是我的碰撞/运动代码
This is my collision / movement code
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函数(不是我的)
This is the PixelPerfectTest function (it's not mine)
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;
}
编辑:这是我的工作方式,以防将来有人需要帮助
This is how I got it working in case anyone from the future needs help
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;
}
}
}
推荐答案
您的问题本质上是这样的:
Your problem is essentially this:
如果您的玩家不在墙壁上,则他可以朝任何方向移动。这包括会使他陷入困境的动作。如果您的玩家 在墙上,那么他根本无法移动。因此,如果他进入墙壁(因为您允许他这样做),他将永远无法摆脱。
If your player is not in a wall, he can move in any direction. This includes movements which would put him in a wall. If your player is in a wall, he cannot move at all. So if he moves into a wall (because you allowed him to do so), he can never get out of it.
因此,最明显的解决办法是不要让玩家进入墙壁。一种简单的方法是尝试移动播放器,然后检查与墙壁的碰撞。如果发生碰撞,请将播放器移回其原始位置。
So, the most obvious fix is to not let the player move into a wall. One simple way to do that is to attempt to move the player, then check for a collision with the wall. If there is a collision, move the player back to its original position.
这应该可以解决您卡在墙上的基本问题。尽管这可能会给您带来其他问题,例如无法直立在墙旁。为此,您可以做的就是检查发生碰撞时墙的确切位置,并将玩家向右移动。
That should fix your basic problem of getting stuck in walls. Though it may leave you with other problems, such as not being able to get right up next to the wall. For that, what you can do is check exactly where the wall is when a collision happens, and move the player right to it.
这篇关于SFML tilemap碰撞的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!