【问题标题】:Tile map collision in SFML game C++SFML 游戏 C++ 中的瓦片地图碰撞
【发布时间】:2018-07-08 18:06:00
【问题描述】:

我正在使用 SFML 库在 C++ 中创建一个游戏,并且在实现瓦片地图冲突期间(我正在从 txt 文件加载地图 - 1 代表平台,0 代表可用空间)。 https://imgur.com/a/tQZc6

我遇到了同时处理所有四种类型的碰撞(从底部,顶部,左侧和右侧)的问题。我的意思是:当没有碰撞时,玩家可以正常移动,但如果我们击中墙壁,碰撞仅出现在第一个编写的 if() 语句中(在我们的示例中,仅发生右侧碰撞,其余部分被省略)。这是我的代码(我只会粘贴必要的东西)

class Player
{
public:
    Player();
    Player(sf::Texture* texture, sf::Vector2u imageCount, sf::Vector2f position, float switchTime, float speed, float jumpSpeed);
    ~Player();

    void UpdatePlayer(float deltaTime);

    float top, right, left, bottom;

private:
    sf::Vector2f _position;
    float groundHeight = 40; //i've added gravity and hardcoded the ground height to create jumping 
    float _jumpSpeed; // later on, it will be replaced with bottom collision
    const float gravity = 981.0f;
    sf::RectangleShape body;
    float _speed;

};

//Player.cpp
void Player::UpdatePlayer(float deltaTime)
{
    sf::Vector2f movement(0.0f, 0.0f);

    if (sf::Keyboard::isKeyPressed(sf::Keyboard::A))
    {
        movement.x -= _speed * deltaTime; //we are using delta time in order to move the object in according to time
    }
    if (sf::Keyboard::isKeyPressed(sf::Keyboard::D))
    {
        movement.x += _speed * deltaTime;
    }

    if (sf::Keyboard::isKeyPressed(sf::Keyboard::W))
    {
        movement.y = -sqrt(5.0f * gravity * _jumpSpeed) * deltaTime;
    }
    if (body.getPosition().y + body.getSize().y < groundHeight || movement.y < 0)
    {
        movement.y += gravity * deltaTime;
    }
    else
    {
        body.setPosition(body.getPosition().x, groundHeight - body.getSize().y);
        movement.y = 0;
    }



    bottom = body.getPosition().y + body.getSize().y;
    left = body.getPosition().x;
    right = body.getPosition().x + body.getSize().x;
    top = body.getPosition().y;


    body.move(movement);

}

//Source.cpp

 void LoadCollisionMap(const char*filename)
{
    std::ifstream openfile(filename);
    std::vector<int> tempMap;
    CollMap.clear();

    if (openfile.is_open())
    {
        while (!openfile.eof())
        {
            std::string str, value;
            std::getline(openfile, str);
            std::stringstream stream(str);

            while (std::getline(stream, value, ' '))
            {
                if (value.length() > 0)
                {
                    int a = atoi(value.c_str());
                    tempMap.push_back(a);
                }
            }
            CollMap.push_back(tempMap);
            tempMap.clear();
        }
    }
}
int main()
{
    LoadCollisionMap("Map2.txt"); //Collision map

Player player(&playerTexture, sf::Vector2u(3, 9),sf::Vector2f(100.0f, 150.0f) ,0.3f, 400.0f, 555.0f);

    for (int i = 0; i < CollMap.size(); i++)
    {
        for (int j = 0; j < CollMap[i].size(); j++)
        {
            if (CollMap[i][j] == 1)
            {

                int CollBottom, CollRight, CollLeft, CollTop;
                CollBottom = i * 32 + 32;
                CollTop = i * 32;
                CollLeft = j * 32;
                CollRight = j * 32 + 32;

                if (player.right < CollLeft || player.left > CollRight || player.top > CollBottom || player.bottom < CollTop)
                {
                    //no collision
                }
                else
                {


                    if (player.right > CollLeft)
                    {
                        std::cout << "collision" << std::endl;
                        player.body.setPosition(player.body.getPosition().x - 1, player.body.getPosition().y);
                        break;

                    }


                    if (player.left < CollRight)
                    {
                        std::cout << "collision 2" << std::endl;
                        player.body.setPosition(player.body.getPosition().x + 1, player.body.getPosition().y);
                        break;
                    }


                    if (player.top < CollBottom)
                    {
                        std::cout << "collision 3" << std::endl;

                        player.body.setPosition(player.body.getPosition().x, player.body.getPosition().y + 1);


                        break;


                    }

                    if (player.bottom > CollTop)
                    {
                        std::cout << "collision 4" << std::endl;

                        player.body.setPosition(player.body.getPosition().x, player.body.getPosition().y - 1);
                        break;
                    }


                }

            }

        }
    }

【问题讨论】:

    标签: c++ sfml


    【解决方案1】:

    运算符break 立即从最嵌套的循环中返回。如果你想检查所有的碰撞,你应该从碰撞检查中删除break,并用 bool 变量替换它。

    bool collisionDetected = false;
    
    if (player.right > CollLeft)
    {
        std::cout << "collision" << std::endl;
        player.body.setPosition(player.body.getPosition().x - 1, player.body.getPosition().y);
    
        collisionDetected = true;
    }
    
    ...
    
    if( collisionDetected ) 
        break;
    

    【讨论】:

    • 我按照你的建议做了,但现在当我撞墙时,玩家只是穿过它。更重要的是,我意识到所有四种类型的碰撞都是同时执行的(无论我从哪一侧碰撞)。
    • @Simon 抱歉,我的错是我从碰撞处理中删除了设置玩家身体的位置。示例已修复。是的,在一次循环迭代期间检查所有碰撞,但我认为这不会造成麻烦。
    • 我也尝试过设置位置,但仍然没有成功。我决定不在 1 个 for 循环中执行所有类型的冲突,而是在 4 个不同的循环中执行所有类型的冲突(例如 (CollMap[i][j] == 1, if (CollMap[i][j] == 2) 等等)。 ..) 但我不得不更改我的 txt 文件,现在它看起来像这样。imgur.com/a/24UAK
    • 1 代表右侧碰撞,2 代表左侧,3 代表底部,4 代表天花板。它有效:)
    猜你喜欢
    • 2015-03-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-06
    • 1970-01-01
    • 2023-04-03
    • 1970-01-01
    相关资源
    最近更新 更多