【问题标题】:C++ SFML Sprite movement not working as intendedC++ SFML Sprite 移动未按预期工作
【发布时间】:2019-05-21 22:27:09
【问题描述】:

我正在使用带有 C++ 的 SFML 来尝试移动应用了特定纹理的精灵,但它并没有像我想要的那样移动。

我是 SFML 新手,我在 sfml 网站上阅读了有关运动的教程,并在 Youtube 上观看了许多关于此的教程。我看到的东西要么非常基础,要么目前已经足够复杂(主要是游戏开发的东西)

#include <SFML/Graphics.hpp>

#include <thread>
#include <chrono>

#include<iostream>

using namespace sf;
using namespace std;

    int main()
    {
        sf::RenderWindow window(sf::VideoMode(600, 600), "test!");

        Texture t;
        t.loadFromFile("/*texture directory*/");

        Sprite s(t);
        s.setScale(Vector2f(0.25f, 0.25f));

        float temp = 0;

        while (window.isOpen())
        {
            sf::Event event;
            while (window.pollEvent(event))
            {
                if (event.type == sf::Event::Closed)
                    window.close();
            }

            window.clear(Color::White);
            window.draw(s);
            window.display();

            s.move(Vector2f(temp, temp));


            for (int i = 0; i < 3; i++) {
                if (i == 0) {
                    this_thread::sleep_for(chrono::milliseconds(1000));
                    temp = 10;
                }
                else if (i == 1) {
                    this_thread::sleep_for(chrono::milliseconds(1000));
                    temp = 20;
                }
                else {
                    this_thread::sleep_for(chrono::milliseconds(1000));
                    temp = -10;
                }
            }
        }
        return 0;
    }

我希望精灵移动到 (10,10),然后在一秒钟后,(20,20),然后在一秒钟后,移动回 (10,10)。 相反,精灵每三秒只移动一次 (-10,-10),所以它只在循环结束时获取 temp 的值。 setPosition 也是如此。

这里有一些非常基本的东西在起作用,但研究让我得到的问题比答案还要多,这就是我来这里的原因。

【问题讨论】:

    标签: c++ sfml


    【解决方案1】:

    最外层的while 循环管理绘图。您在其中放置了另一个 for 循环。内部循环必须完成,然后外部循环才能继续其迭代,即绘制另一帧。执行不会异步发生,因此带有std::this_thread::sleep_for 调用的for 循环总共会阻塞渲染循环3 秒。它使其更改为temp,最后无条件为-10

    您想要做的是创建 state,它在渲染循环中持续存在并创建一个小型状态机。此状态将是您的i。在temp 附近声明并初始化它(好吧,您也可以在if 语句中使用temp)并删除for 循环。如果您想继续动画,请不要忘记将temp 设置为-10 时将i 设置回0

    另一种可能但较差的方法是:

    1. 将渲染(以及可能的事件处理)代码放入函数中;
    2. 每次你想刷新图形时调用这个函数,即在你每次设置temp之后,但记得事先更新s

    最后,我相信sf::Sprite 具有访问状态的成员函数,而不仅仅是修改,所以你应该能够只使用s,而不需要temp。保持简单并从控制流的角度进行思考。

    【讨论】:

    • 请稍等片刻,我想我已经达到目的了。我尝试按照您的指示进行操作,结果如下:codepile.net/pile/8nzG6BdY 我可以看到精灵以 (20,20) 的增量移动,这是正确的,但我没有看到前两个动作。
    • @hulululu 该代码与原始代码存在相同的问题。当state0 时,递增state 使其在之后立即匹配第二个条件,依此类推。因此,应该有一个点(毕竟ifs)用于修改状态(state = state == 2 ? 0 : state + 1;)。但是,如果您计划添加更多刷新率高于 1/3Hz 的动画或逻辑,您应该根据时间来制作动画,而不是控制它(如其他答案所示)。
    • 非常感谢。读我昨晚的所作所为,我觉得有点愚蠢。我现在使用了你的第二种,次等的方法,重要的是它有效。
    【解决方案2】:

    避免在渲染线程上使用睡眠。

    相反,您将测量经过的时间并按比例移动:

    #include <SFML/Graphics.hpp>
    
    #include <thread>
    #include <chrono>
    
    #include<iostream>
    
    using namespace sf;
    using namespace std;
    
        int main()
        {
            sf::RenderWindow window(sf::VideoMode(600, 600), "test!");
    
            Texture t;
            t.loadFromFile("/*texture directory*/");
    
            Sprite s(t);
            s.setScale(Vector2f(0.25f, 0.25f));
    
            float speed = 10.0;
            sf::Clock clock;
    
            while (window.isOpen())
            {
                sf::Event event;
    
                while (window.pollEvent(event))
                {
                    if (event.type == sf::Event::Closed)
                        window.close();
                }
    
                float time = clock.getElapsedTime().asSeconds();
                s.move(Vector2f(speed*time, speed*time));
                clock.restart();
    
                window.clear(Color::White);
                window.draw(s);
                window.display();
    
    
            }
            return 0;
        }
    

    此代码允许您的精灵以固定速度移动。您可以使用额外的 sf::clock 更改速度

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-03-09
      • 2023-03-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多