有没有办法让我在 C++ 游戏中保持恒定的速度?
Is there a way I can keep something at a constant speed in C++ game?
我目前有一款游戏,其中有玩家、敌人和射弹。用户可以产生射弹来伤害敌人。但是,我遇到的问题是,敌人会加速用户连续生成的更多射弹。我尝试使用游戏时钟来保持一切不变,我的游戏循环如下。
while (window.isOpen())
{
std::chrono::high_resolution_clock::time_point begin = std::chrono::high_resolution_clock::now();
for (int i = 0; i < enemies.size(); i++)
{
enemies[i].move(begin, HEIGHT, WIDTH, player);
}
for (size_t i = 0; i < player.projectiles.size();)
{
if (player.projectiles[i].move(begin, WIDTH))
{
player.projectiles.erase(player.projectiles.begin() + i);
}
else
{
i++;
}
}
for (int i = 0; i < enemies.size();)
{
for (int j = 0; j < player.projectiles.size();)
{
if (enemies[i].hit(player.projectiles[j]))
{
player.projectiles.erase(player.projectiles.begin() + j);
}
else
{
j++;
}
}
if (enemies[i].hp <= 0)
{
enemies.erase(enemies.begin() + i);
}
else
{
i++;
}
}
sf::Event event;
while (window.pollEvent(event))
{
if (event.type == sf::Event::Closed)
{
window.close();
break;
}
if (sf::Mouse::isButtonPressed(sf::Mouse::Right))
{
enemies.push_back(Enemy(100.0, 1.0, Mouse::getPosition().x, Mouse::getPosition().y, Color::White));
}
if (event.type == Event::KeyPressed)
{
if (event.key.code == player.up)
{
player.moving_up = true;
}
else if (event.key.code == player.down)
{
player.moving_down = true;
}
else if (event.key.code == player.right)
{
player.moving_right = true;
}
else if (event.key.code == player.left)
{
player.moving_left = true;
}
else if (event.key.code == player.shoot)
{
player.shooting = true;
}
if (event.key.code == player.exit)
{
window.close();
}
}
if (event.type == Event::KeyReleased)
{
if (event.key.code == player.up)
{
player.moving_up = false;
}
else if (event.key.code == player.down)
{
player.moving_down = false;
}
else if (event.key.code == player.right)
{
player.moving_right = false;
}
else if (event.key.code == player.left)
{
player.moving_left = false;
}
else if (event.key.code == player.shoot)
{
player.shooting = false;
}
}
player.input(begin, HEIGHT, WIDTH);
for (int i = 0; i < enemies.size();)
{
for (int j = 0; j < player.projectiles.size();)
{
if (enemies[i].hit(player.projectiles[j]))
{
player.projectiles.erase(player.projectiles.begin() + j);
}
else
{
j++;
}
}
if (enemies[i].hp <= 0)
{
enemies.erase(enemies.begin() + i);
}
else
{
i++;
}
}
}
window.clear();
player.draw(window);
for (int i = 0; i < enemies.size(); i++)
{
enemies[i].draw(window);
}
window.display();
}
enemy.move 函数如下所示,其中速度设置为 1.0:
void Enemy::move(std::chrono::high_resolution_clock::time_point begin, float height, float width, Player player)
{
std::chrono::high_resolution_clock::time_point end = std::chrono::high_resolution_clock::now();
if (player.x < this->x)
{
if (this->x - (enemy_speed * (std::chrono::duration_cast<std::chrono::microseconds>(end - begin).count()) / 1000.0) < 0)
{
this->x = 0;
}
else
{
this->x = this->x - (enemy_speed * (std::chrono::duration_cast<std::chrono::microseconds>(end - begin).count()) / 1000.0);
}
if (player.y < this->y)
{
if (this->y - (enemy_speed * (std::chrono::duration_cast<std::chrono::microseconds>(end - begin).count()) / 1000.0) < 0)
{
this->y = 0;
}
else
{
this->y = this->y - (enemy_speed * (std::chrono::duration_cast<std::chrono::microseconds>(end - begin).count()) / 1000.0);
}
}
else
{
if (this->y + (enemy_speed * (std::chrono::duration_cast<std::chrono::microseconds>(end - begin).count()) / 1000.0) > (height - double(this->sprite.getSize().y)))
{
this->y = height - double(this->sprite.getSize().y);
}
else
{
this->y = this->y + (enemy_speed * (std::chrono::duration_cast<std::chrono::microseconds>(end - begin).count()) / 1000.0);
}
}
}
else
{
if (this->x + (enemy_speed * (std::chrono::duration_cast<std::chrono::microseconds>(end - begin).count()) / 1000.0) > (width - double(this->sprite.getSize().x)))
{
this->x = width - double(this->sprite.getSize().x);
}
else
{
this->x = this->x + (enemy_speed * (std::chrono::duration_cast<std::chrono::microseconds>(end - begin).count()) / 1000.0);
}
if (player.y < this->y)
{
if (this->y - (enemy_speed * (std::chrono::duration_cast<std::chrono::microseconds>(end - begin).count()) / 1000.0) < 0)
{
this->y = 0;
}
else
{
this->y = this->y - (enemy_speed * (std::chrono::duration_cast<std::chrono::microseconds>(end - begin).count()) / 1000.0);
}
}
else
{
if (this->y + (enemy_speed * (std::chrono::duration_cast<std::chrono::microseconds>(end - begin).count()) / 1000.0) > (height - double(this->sprite.getSize().y)))
{
this->y = height - double(this->sprite.getSize().y);
}
else
{
this->y = this->y + (enemy_speed * (std::chrono::duration_cast<std::chrono::microseconds>(end - begin).count()) / 1000.0);
}
}
}
this->sprite.setPosition(this->x, this->y);
}
对于较长的代码段,我深表歉意,但这些是相关的部分,我不知道具体您可能需要哪些代码段。非常感谢任何帮助。
基本上,要以恒定的速度移动某物,您需要根据自从您之前移动该对象以来所经过的时间来确定移动的距离,而不是自从移动该对象以来所经过的时间当前周期的开始,就像你在这里做的那样。
所以你的移动函数应该是这样的:
void Enemy::move(float height, float width, Player player) {
std::chrono::high_resolution_clock::time_point now = std::chrono::high_resolution_clock::now();
// various code that moves by enemy_speed * (now - prev_time)
prev_time = now;
}
其中 prev_time
是敌人对象中的一个字段,您可以在其中存储之前的移动时间戳。您需要确保将其正确初始化为初始时间,否则第一步会意外“跳跃”。
您可以减少查询时钟的次数,方法是为所有 enemies/objects 使用一个时间戳并将自上一个时间戳以来经过的时间传递给所有移动例程。
我目前有一款游戏,其中有玩家、敌人和射弹。用户可以产生射弹来伤害敌人。但是,我遇到的问题是,敌人会加速用户连续生成的更多射弹。我尝试使用游戏时钟来保持一切不变,我的游戏循环如下。
while (window.isOpen())
{
std::chrono::high_resolution_clock::time_point begin = std::chrono::high_resolution_clock::now();
for (int i = 0; i < enemies.size(); i++)
{
enemies[i].move(begin, HEIGHT, WIDTH, player);
}
for (size_t i = 0; i < player.projectiles.size();)
{
if (player.projectiles[i].move(begin, WIDTH))
{
player.projectiles.erase(player.projectiles.begin() + i);
}
else
{
i++;
}
}
for (int i = 0; i < enemies.size();)
{
for (int j = 0; j < player.projectiles.size();)
{
if (enemies[i].hit(player.projectiles[j]))
{
player.projectiles.erase(player.projectiles.begin() + j);
}
else
{
j++;
}
}
if (enemies[i].hp <= 0)
{
enemies.erase(enemies.begin() + i);
}
else
{
i++;
}
}
sf::Event event;
while (window.pollEvent(event))
{
if (event.type == sf::Event::Closed)
{
window.close();
break;
}
if (sf::Mouse::isButtonPressed(sf::Mouse::Right))
{
enemies.push_back(Enemy(100.0, 1.0, Mouse::getPosition().x, Mouse::getPosition().y, Color::White));
}
if (event.type == Event::KeyPressed)
{
if (event.key.code == player.up)
{
player.moving_up = true;
}
else if (event.key.code == player.down)
{
player.moving_down = true;
}
else if (event.key.code == player.right)
{
player.moving_right = true;
}
else if (event.key.code == player.left)
{
player.moving_left = true;
}
else if (event.key.code == player.shoot)
{
player.shooting = true;
}
if (event.key.code == player.exit)
{
window.close();
}
}
if (event.type == Event::KeyReleased)
{
if (event.key.code == player.up)
{
player.moving_up = false;
}
else if (event.key.code == player.down)
{
player.moving_down = false;
}
else if (event.key.code == player.right)
{
player.moving_right = false;
}
else if (event.key.code == player.left)
{
player.moving_left = false;
}
else if (event.key.code == player.shoot)
{
player.shooting = false;
}
}
player.input(begin, HEIGHT, WIDTH);
for (int i = 0; i < enemies.size();)
{
for (int j = 0; j < player.projectiles.size();)
{
if (enemies[i].hit(player.projectiles[j]))
{
player.projectiles.erase(player.projectiles.begin() + j);
}
else
{
j++;
}
}
if (enemies[i].hp <= 0)
{
enemies.erase(enemies.begin() + i);
}
else
{
i++;
}
}
}
window.clear();
player.draw(window);
for (int i = 0; i < enemies.size(); i++)
{
enemies[i].draw(window);
}
window.display();
}
enemy.move 函数如下所示,其中速度设置为 1.0:
void Enemy::move(std::chrono::high_resolution_clock::time_point begin, float height, float width, Player player)
{
std::chrono::high_resolution_clock::time_point end = std::chrono::high_resolution_clock::now();
if (player.x < this->x)
{
if (this->x - (enemy_speed * (std::chrono::duration_cast<std::chrono::microseconds>(end - begin).count()) / 1000.0) < 0)
{
this->x = 0;
}
else
{
this->x = this->x - (enemy_speed * (std::chrono::duration_cast<std::chrono::microseconds>(end - begin).count()) / 1000.0);
}
if (player.y < this->y)
{
if (this->y - (enemy_speed * (std::chrono::duration_cast<std::chrono::microseconds>(end - begin).count()) / 1000.0) < 0)
{
this->y = 0;
}
else
{
this->y = this->y - (enemy_speed * (std::chrono::duration_cast<std::chrono::microseconds>(end - begin).count()) / 1000.0);
}
}
else
{
if (this->y + (enemy_speed * (std::chrono::duration_cast<std::chrono::microseconds>(end - begin).count()) / 1000.0) > (height - double(this->sprite.getSize().y)))
{
this->y = height - double(this->sprite.getSize().y);
}
else
{
this->y = this->y + (enemy_speed * (std::chrono::duration_cast<std::chrono::microseconds>(end - begin).count()) / 1000.0);
}
}
}
else
{
if (this->x + (enemy_speed * (std::chrono::duration_cast<std::chrono::microseconds>(end - begin).count()) / 1000.0) > (width - double(this->sprite.getSize().x)))
{
this->x = width - double(this->sprite.getSize().x);
}
else
{
this->x = this->x + (enemy_speed * (std::chrono::duration_cast<std::chrono::microseconds>(end - begin).count()) / 1000.0);
}
if (player.y < this->y)
{
if (this->y - (enemy_speed * (std::chrono::duration_cast<std::chrono::microseconds>(end - begin).count()) / 1000.0) < 0)
{
this->y = 0;
}
else
{
this->y = this->y - (enemy_speed * (std::chrono::duration_cast<std::chrono::microseconds>(end - begin).count()) / 1000.0);
}
}
else
{
if (this->y + (enemy_speed * (std::chrono::duration_cast<std::chrono::microseconds>(end - begin).count()) / 1000.0) > (height - double(this->sprite.getSize().y)))
{
this->y = height - double(this->sprite.getSize().y);
}
else
{
this->y = this->y + (enemy_speed * (std::chrono::duration_cast<std::chrono::microseconds>(end - begin).count()) / 1000.0);
}
}
}
this->sprite.setPosition(this->x, this->y);
}
对于较长的代码段,我深表歉意,但这些是相关的部分,我不知道具体您可能需要哪些代码段。非常感谢任何帮助。
基本上,要以恒定的速度移动某物,您需要根据自从您之前移动该对象以来所经过的时间来确定移动的距离,而不是自从移动该对象以来所经过的时间当前周期的开始,就像你在这里做的那样。
所以你的移动函数应该是这样的:
void Enemy::move(float height, float width, Player player) {
std::chrono::high_resolution_clock::time_point now = std::chrono::high_resolution_clock::now();
// various code that moves by enemy_speed * (now - prev_time)
prev_time = now;
}
其中 prev_time
是敌人对象中的一个字段,您可以在其中存储之前的移动时间戳。您需要确保将其正确初始化为初始时间,否则第一步会意外“跳跃”。
您可以减少查询时钟的次数,方法是为所有 enemies/objects 使用一个时间戳并将自上一个时间戳以来经过的时间传递给所有移动例程。