Xna给2D精灵添加重力

6

我正在尝试在我的第一个XNA 2D游戏中模拟重力。我有以下代码:

        //Used for Jumping
    double elapsedAirTime = 0.0;
    double maxAirTime = 8.35;
    //End Jumping

我正在尝试在elapsedAirTime < maxAirTime期间将精灵向上移动一定量。然而,我的代码存在问题,只能在此时间段内将精灵向上移动一次,而不是多次。以下是我“player.cs”类中的代码,即该类的update方法。

if (newState.IsKeyDown(Keys.Space))
        {
            if(oldState.IsKeyUp(Keys.Space))
            {
                //if we are standing or jumping then change the velocity
                if (playerState == PlayerStates.Standing)
                {
                    playerState = PlayerStates.Jumping;
                    this.position.Y -= (float)(30.0 + ((1.2)*elapsedAirTime)*elapsedAirTime);
                }
            }
        }
        //if we are jumping give it some time
        if (playerState == PlayerStates.Jumping)
        {
            if ((elapsedAirTime < maxAirTime) && position.Y < 3)
            {
                this.position.Y -= (float)(30.0 + ((1.2) * elapsedAirTime)*elapsedAirTime);
                elapsedAirTime += gameTime.ElapsedGameTime.TotalSeconds;
            }
            //otherwise time to fall
            else
            {
                playerState = PlayerStates.Falling;
            }

        }

        //add gravity to falling objects
        if (playerState == PlayerStates.Falling || playerState == PlayerStates.Standing)
        {
            //if we are above the ground
            if (this.position.Y < windowBot - 110)
            {
                //chnage state to falling
                playerState = PlayerStates.Falling;
                this.position.Y += 3.0f + ((float)(gameTime.ElapsedGameTime.TotalSeconds));
            }
            else
            {
                playerState = PlayerStates.Standing;
                elapsedAirTime = 0.0f;
            }
        }

任何帮助都非常感激,请和谢谢您!
2个回答

11
为使你的精灵具有重力感,应在Sprite类中添加速度和加速度。然后为Sprite创建一个Update方法,在每次更新时,将加速度添加到速度中,并将速度添加到位置中。位置不应基于经过的时间。您可以将加速度设置为恒定的重力值,然后在跳跃时增加精灵的速度。这将创建一个流畅的抛物线跳跃效果。如果想要包括时间控制,可以将GameTime传递给Sprite的Update方法,并在速度上使用它作为修饰符。以下是示例Update方法:

void Update(GameTime gt)
{
    int updateTime = gt.ElapsedGameTime.TotalMilliseconds - oldgt.ElapsedGameTime.TotalMilliseconds;
    float timeScalar = updateTime / AVG_FRAME_TIME;
    this.velocity += this.acceleration * timeScalar;
    this.position += this.velocity;
    oldgt = gt;
}

如果使用时间控制,此方法会稍微复杂一些。您必须追踪更新所需的时间量,然后将其除以更新或帧所需的平均时间量,以获得您应该调整速度的量。不使用时间控制时,该方法非常简单:

void Update()
{
    this.velocity += this.acceleration;
    this.position += this.velocity;
}

我建议在了解时间控制的工作原理以及为什么需要实现它之前先使用更简单的方法。

为什么要计算timeScalar并存储旧的游戏时间?如果这个更新函数每次游戏循环都被调用(应该是这样),gt.ElapsedGameTime已经为您完成了所有繁重的工作。 - John McDonald
2
使用timeScalar的原因是a)如果您想更改默认帧速率,或b)如果您的计算机太慢而无法跟上XNA尝试的默认60 UPS / FPS。在任何情况下,如果您落后于目标更新速率,没有timeScalar代码,您的游戏将看起来像是滞后的。 - Darkhydro

2

看起来这一行有问题:

this.position.Y -= (float)(30.0 + ((1.2) * elapsedAirTime)*elapsedAirTime);

我认为您会发现,这比您想象的更快地更新了精灵的位置,在10个更新中,精灵将在屏幕上向上移动330像素(假设Game.IsFixedTimeStep == true),即实时时间的1/10秒。

很可能是因为更新得太快了,以至于在&& position.Y < 3条件触发并改变playerState之前,您没有看到它上升。

看起来您想说的是 - 每秒跳x个像素,最多8.5秒,只要按住空格键。

您需要改变计算方式为this.position.y -= (float) (30 * gameTime.ElapsedGameTime.TotalSeconds),这将使跳跃动作的移动非常线性,但这意味着精灵以确切的每秒30个像素跳跃。

如果Game.IsFixedTimeStep == true - 这是默认设置 - 更新每秒调用60次,因此gameTime.ElapsedGameTime.TotalSeconds每次更新大约为0.1。如果发生某些事情导致更新跳过(例如渲染问题),则更新将延迟,gameTime.ElapsedGameTime.TotalSeconds可能为0.3(跳过2次更新),但公式仍然可以计算出正确的跳跃速率。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接