C++ SFML和将对象移动到位置

C++ SFML和将对象移动到位置,c++,animation,sfml,C++,Animation,Sfml,我的SFML棋盘游戏有问题。我得到了在棋盘上移动的标记,棋盘有40个字段,每个字段都定义了位置X和位置Y。然而,有时,这完全是随机发生的,我的代币错过了他的目标位置,在棋盘上进行了额外的回合,然后停止 class Field { protected: int m_positionX; int m_positionY; public: //getters and setters }; 每个玩家都有PositionID目标位置坐标和圆圈形状,这是造成麻烦的标记 clas

我的SFML棋盘游戏有问题。我得到了在棋盘上移动的标记,棋盘有40个字段,每个字段都定义了位置X和位置Y。然而,有时,这完全是随机发生的,我的代币错过了他的目标位置,在棋盘上进行了额外的回合,然后停止

class Field {
protected:  
    int m_positionX;
    int m_positionY;
public:
    //getters and setters
};
每个玩家都有PositionID目标位置坐标和圆圈形状,这是造成麻烦的标记

class Player {
    sf::CircleShape m_token;
    int m_positionID = 0;       
    int m_targetPositionX;
    int m_targetPositionY;
public:
    //getters and setters
}
然后在我的GameEngine类中,我得到了setInMotion函数,它为玩家设置了几个变量,这里调用的函数代码是不相关的,我想,函数名说明了一切

void GameEngine::setInMotion(int number) {  
        m_players[m_activePlayer].startMoving();
        m_players[m_activePlayer].incrementPositionID(number);                          
        m_players[m_activePlayer].setTargetPositionX(m_gameBoard.getField(m_players[m_activePlayer].getPositionID()).getPositionX());
        m_players[m_activePlayer].setTargetPositionY(m_gameBoard.getField(m_players[m_activePlayer].getPositionID()).getPositionY());
}
然后是最重要的功能,实际上是在电路板上移动令牌。 定义令牌\u速度1000

void Player::moveForward(sf::Time dt) {
    if ((int)m_token.getPosition().x >= 240 && (int)m_token.getPosition().y >= 600) {
        this->m_token.move(-TOKEN_SPEED * dt.asSeconds(), 0);       
    }

    if ((int)m_token.getPosition().x <= 240 && (int)m_token.getPosition().y >= 40) {
        this->m_token.move(0, -TOKEN_SPEED * dt.asSeconds());    
    }

    if ((int)m_token.getPosition().x <= 800) && (int)m_token.getPosition().y <= 40) {
        this->m_token.move(TOKEN_SPEED * dt.asSeconds(), 0);    
    }

    if ((int)m_token.getPosition().x >= 800) && (int)m_token.getPosition().y <= 600) {
        this->m_token.move(0, TOKEN_SPEED * dt.asSeconds());        
    }

    if ((int)m_token.getPosition().x >= getTargetPositionX() - 1 && (int)m_token.getPosition().x <= getTargetPositionX() + 1 &&
        (int)m_token.getPosition().y >= getTargetPositionY() - 1 && (int)m_token.getPosition().y <= getTargetPositionY() + 1) {
        this->stopMoving();
    }
}

我想你把事情弄得比要求的复杂多了。你的具体问题很可能是一个时间问题:经过的时间dt可能足够大,你只需跨过目标位置,增加的+1不足以补偿。除非你正在实现一个固定的时间步运动,否则你无法避免这个问题,如果你想知道更多的话,只需查找这个术语

然而,我会以一种完全不同的方式来实现这项运动,这也会使整个实现更容易、更具动态性

首先,我用向量定义我的游戏板和它的位置。如果您想要更复杂的路径,如分支或快捷方式,您可能需要定义自己的链表或类似的内容

回到比赛场地,在我的示例中,我通过一系列位置来定义棋盘,每个位置代表一个球员可能站的可能场地:

std::vector<sf::Vector2f> board;
board.push_back({75, 75});
board.push_back({150, 50});
board.push_back({250, 50});
board.push_back({325, 75});
board.push_back({350, 150});
board.push_back({350, 250});
board.push_back({325, 325});
board.push_back({250, 350});
board.push_back({150, 350});
board.push_back({75, 325});
board.push_back({50, 250});
board.push_back({50, 150});
听起来很奇怪?是的,差不多。数字的整数部分表示索引,而小数点后面的部分表示字段之间的实际位置。例如,值3.75表示令牌在第四个索引3和第五个索引4字段之间为75%

绘制游戏板非常简单,我已将其简化为仅为每个场绘制一些圆形:

for (auto &pos : board) {
    field.setPosition(pos);
    window.draw(field);
}
现在,为了绘制标记,我们必须确定标记前后的点:

const sf::Vector2f playerPosLast = board[static_cast<std::size_t>(playerPos)];
const sf::Vector2f playerPosNext = board[static_cast<std::size_t>(playerPos + 1) % board.size()];
这背后的实际数学在这里并不重要,但由于步长范围为0到1,因此很容易使这成为一个类似抛物线的路径偏移,在点之间从0到-25再回到0

现在,我们只是使用向量数学设置标记的位置,根据计算的步长确定上一个字段和下一个字段之间的点,并添加跳跃偏移:

player.setPosition(playerPosLast + (playerPosNext - playerPosLast) * step + jumpOffset);
window.draw(player);
但是如何移动玩家呢?很简单。如果您希望玩家向前移动4个字段,请在playerPos中添加4个字段。如果要向后移动2个字段,请减去2。只要确保在结束后溢出时回到板的有效范围内

如果您编译并运行以下演示,您将得到一个简单的窗口,其中一个令牌无限期地从一个字段跳到另一个字段:

以下是完整的源代码–未注释,但大多数内容应该是显而易见的,或者在上面解释:

#include <SFML/Graphics.hpp>
#include <vector>

int main()
{
    sf::RenderWindow window({480, 480}, "Board Game");

    std::vector<sf::Vector2f> board;
    board.push_back({75, 75});
    board.push_back({150, 50});
    board.push_back({250, 50});
    board.push_back({325, 75});
    board.push_back({350, 150});
    board.push_back({350, 250});
    board.push_back({325, 325});
    board.push_back({250, 350});
    board.push_back({150, 350});
    board.push_back({75, 325});
    board.push_back({50, 250});
    board.push_back({50, 150});

    sf::CircleShape field(25, 24);
    field.setFillColor(sf::Color::White);
    field.setOutlineColor(sf::Color::Black);
    field.setOutlineThickness(2);
    field.setOrigin({25, 25});

    sf::CircleShape player(20, 3);
    player.setFillColor(sf::Color::Red);
    player.setOutlineColor(sf::Color::Black);
    player.setOutlineThickness(2);
    player.setOrigin({20, 20});

    float playerPos = 0.f;

    while (window.isOpen()) {
        sf::Event event;
        while (window.pollEvent(event)) {
            switch (event.type) {
                case sf::Event::Closed:
                    window.close();
                    break;
                default:
                    break;
            }
        }
        window.clear({0, 127, 127});
        for (auto &pos : board) {
            field.setPosition(pos);
            window.draw(field);
        }

        const sf::Vector2f playerPosLast = board[static_cast<std::size_t>(playerPos)];
        const sf::Vector2f playerPosNext = board[static_cast<std::size_t>(playerPos + 1) % board.size()];
        const float step = playerPos - static_cast<std::size_t>(playerPos);

        const sf::Vector2f jumpOffset(0, 25.f * (2.f * (step - .5)) * (2.f * (step - .5)) - 25.f);
        player.setPosition(playerPosLast + (playerPosNext - playerPosLast) * step + jumpOffset);
        window.draw(player);

        window.display();

        if ((playerPos += .001f) > board.size())
            playerPos -= board.size();
    }
}
const float step = playerPos - static_cast<std::size_t>(playerPos);
const sf::Vector2f jumpOffset(0, 25.f * (2.f * (step - .5)) * (2.f * (step - .5)) - 25.f);
player.setPosition(playerPosLast + (playerPosNext - playerPosLast) * step + jumpOffset);
window.draw(player);
#include <SFML/Graphics.hpp>
#include <vector>

int main()
{
    sf::RenderWindow window({480, 480}, "Board Game");

    std::vector<sf::Vector2f> board;
    board.push_back({75, 75});
    board.push_back({150, 50});
    board.push_back({250, 50});
    board.push_back({325, 75});
    board.push_back({350, 150});
    board.push_back({350, 250});
    board.push_back({325, 325});
    board.push_back({250, 350});
    board.push_back({150, 350});
    board.push_back({75, 325});
    board.push_back({50, 250});
    board.push_back({50, 150});

    sf::CircleShape field(25, 24);
    field.setFillColor(sf::Color::White);
    field.setOutlineColor(sf::Color::Black);
    field.setOutlineThickness(2);
    field.setOrigin({25, 25});

    sf::CircleShape player(20, 3);
    player.setFillColor(sf::Color::Red);
    player.setOutlineColor(sf::Color::Black);
    player.setOutlineThickness(2);
    player.setOrigin({20, 20});

    float playerPos = 0.f;

    while (window.isOpen()) {
        sf::Event event;
        while (window.pollEvent(event)) {
            switch (event.type) {
                case sf::Event::Closed:
                    window.close();
                    break;
                default:
                    break;
            }
        }
        window.clear({0, 127, 127});
        for (auto &pos : board) {
            field.setPosition(pos);
            window.draw(field);
        }

        const sf::Vector2f playerPosLast = board[static_cast<std::size_t>(playerPos)];
        const sf::Vector2f playerPosNext = board[static_cast<std::size_t>(playerPos + 1) % board.size()];
        const float step = playerPos - static_cast<std::size_t>(playerPos);

        const sf::Vector2f jumpOffset(0, 25.f * (2.f * (step - .5)) * (2.f * (step - .5)) - 25.f);
        player.setPosition(playerPosLast + (playerPosNext - playerPosLast) * step + jumpOffset);
        window.draw(player);

        window.display();

        if ((playerPos += .001f) > board.size())
            playerPos -= board.size();
    }
}