有没有办法让我在 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 使用一个时间戳并将自上一个时间戳以来经过的时间传递给所有移动例程。