【问题标题】:SFML tilemap collisionSFML 瓦片地图碰撞
【发布时间】:2015-03-03 15:13:36
【问题描述】:

我正在用 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;
        }
    }
}

【问题讨论】:

    标签: c++ collision sfml


    【解决方案1】:

    编辑:当碰撞检测返回 false save previous position 时,当你的角色与物体碰撞时,你所要做的就是恢复之前的非碰撞位置。

    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;
    }
    }
    

    类似的东西。

    【讨论】:

      【解决方案2】:

      你的问题本质上是这样的:

      如果你的玩家不是在墙上,他可以向任何方向移动。这包括将他放在墙上的动作。如果你的玩家墙上,他根本无法移动。因此,如果他移动到墙上(因为你允许他这样做),他永远无法摆脱它。

      因此,最明显的解决方法是不要让玩家进入墙壁。一种简单的方法是尝试移动玩家,然后检查与墙壁的碰撞。如果发生碰撞,请将播放器移回原来的位置。

      这应该可以解决您卡在墙上的基本问题。尽管它可能会给您带来其他问题,例如无法直接靠近墙壁。为此,您可以做的是在发生碰撞时准确检查墙壁的位置,然后将玩家向右移动。

      【讨论】:

      • 我无法开始,可能是因为现在是凌晨 3 点。你能不能写一些伪代码?
      • @Wahoozel:我确实写过伪代码。 “尝试移动玩家,然后检查是否与墙壁发生碰撞。如果发生碰撞,请将玩家移回其原始位置。”
      • 非常感谢,我让它工作了。但是现在,如果我试图同时向上和向右走,我就不能沿着墙壁滑动。我只是被卡住了,在我向上或向右松开之前无法移动。
      • 你应该睡觉而不是在凌晨 3 点完成工作。这适得其反。
      • @Wahoozel:尝试将垂直运动与水平运动分开。也就是说,做一些类似于你现在正在做的事情,但是两次。一次用于 x 坐标,一次用于 y 坐标。
      猜你喜欢
      • 2018-07-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-05-06
      • 2014-02-13
      • 1970-01-01
      • 2022-09-27
      • 2022-12-16
      相关资源
      最近更新 更多