SFML代码中打印速度值为何会影响矩形的加减速行为?
SFML加速度模拟程序异常:移除打印语句后速度失控
我编写了一个SFML加速度模拟程序:按下按键时矩形加速,松开按键时矩形减速直至停止。但出现了奇怪的问题——只要保留打印速度值(x_change或y_change)的std::cout语句,程序运行完全正常;一旦删除这些打印语句,矩形就会失控,移动速度远超设定的max_speed。我使用VSCode搭配g++编译器,尝试将max_speed从5降至1也无效果,只有保留打印时程序才正常。
原代码
#include <SFML/Graphics.hpp> #include <iostream> int main() { int width = 600, height = 800; sf::RenderWindow window(sf::VideoMode(width, height), "Testing things"); sf::RectangleShape r1(sf::Vector2f(50, 50)); r1.setFillColor(sf::Color::Blue); float acc_x = 0, acc_y = 0; float x_change = 0, y_change = 0; float x = 300, y = 300; float max_speed = 2; sf::Vector2f rect_pos = sf::Vector2f(x, y); bool run = true; while (run) { sf::Event event; while (window.pollEvent(event)) { if (event.type == sf::Event::Closed) run = false; } acc_x = 0; acc_y = 0; if (sf::Keyboard::isKeyPressed(sf::Keyboard::Left)) acc_x = -0.2; if (sf::Keyboard::isKeyPressed(sf::Keyboard::Right)) acc_x = 0.2; if (sf::Keyboard::isKeyPressed(sf::Keyboard::Up)) acc_y = -0.2; if (sf::Keyboard::isKeyPressed(sf::Keyboard::Down)) acc_y = 0.2; //X axis acceleration x_change += acc_x; //Normalizing the speed. if (abs(x_change) >= max_speed) x_change = x_change / abs(x_change) * max_speed; //Decelerating. if (acc_x == 0) x_change *= 0.99; //The printing lines (necessary for the code to work ??) std::cout << x_change << std::endl; std::cout << y_change << std::endl; rect_pos.x += x_change; //Y axis acceleration y_change += acc_y; if (abs(y_change) >= max_speed) y_change = y_change / abs(y_change) * max_speed; if (acc_y == 0) y_change *= 0.99; rect_pos.y += y_change; r1.setPosition(rect_pos); window.clear(); window.draw(r1); window.display(); } return 0; }
问题根源
你的程序没有**固定帧率或使用时间差(delta time)**计算运动。打印语句会大幅减慢循环执行速度,间接限制了每秒循环次数(帧率);一旦去掉打印,CPU会全力运行循环,每秒循环次数暴增,导致加速度acc_x/acc_y被叠加的次数异常多,速度自然突破max_speed限制。
解决方案
有两种简单的修复方式:
方式1:固定帧率
在创建窗口后,添加一行代码固定帧率(比如60帧/秒),让循环每秒执行固定次数:
window.setFramerateLimit(60);
方式2:使用时间差(delta time)
用SFML的sf::Clock计算每帧的时间间隔,将加速度和速度变化乘以这个时间差,让运动完全独立于帧率,这是更专业的游戏运动处理方式:
修改后的代码示例:
#include <SFML/Graphics.hpp> #include <iostream> #include <cmath> int main() { int width = 600, height = 800; sf::RenderWindow window(sf::VideoMode(width, height), "Testing things"); sf::Clock clock; // 添加时钟对象 sf::RectangleShape r1(sf::Vector2f(50, 50)); r1.setFillColor(sf::Color::Blue); float acc_x = 0, acc_y = 0; float x_change = 0, y_change = 0; float x = 300, y = 300; float max_speed = 200; // 因乘以时间差,速度值可适当调大 sf::Vector2f rect_pos = sf::Vector2f(x, y); bool run = true; while (run) { sf::Time deltaTime = clock.restart(); // 获取从上一帧到当前的时间差 float dt = deltaTime.asSeconds(); // 转换为秒数 sf::Event event; while (window.pollEvent(event)) { if (event.type == sf::Event::Closed) run = false; } acc_x = 0; acc_y = 0; if (sf::Keyboard::isKeyPressed(sf::Keyboard::Left)) acc_x = -100; // 加速度值适配时间差调大 if (sf::Keyboard::isKeyPressed(sf::Keyboard::Right)) acc_x = 100; if (sf::Keyboard::isKeyPressed(sf::Keyboard::Up)) acc_y = -100; if (sf::Keyboard::isKeyPressed(sf::Keyboard::Down)) acc_y = 100; //X axis acceleration x_change += acc_x * dt; // 加速度叠加乘以时间差 //速度限制 if (abs(x_change) >= max_speed) x_change = x_change / abs(x_change) * max_speed; //减速适配时间差 if (acc_x == 0) x_change *= pow(0.99, 1/dt); rect_pos.x += x_change * dt; // 位置更新乘以时间差 //Y axis acceleration y_change += acc_y * dt; if (abs(y_change) >= max_speed) y_change = y_change / abs(y_change) * max_speed; if (acc_y == 0) y_change *= pow(0.99, 1/dt); rect_pos.y += y_change * dt; r1.setPosition(rect_pos); window.clear(); window.draw(r1); window.display(); } return 0; }
内容的提问来源于stack exchange,提问作者kripi
相关产品推荐
相关产品推荐

