Xna добавляет гравитацию в 2D-спрайт

Я пытаюсь смоделировать гравитацию в своей первой игре xna 2d. у меня есть следующее

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

Итак, я пытаюсь переместить спрайт вверх на определенную величину, пока elapsedAirTime ‹ maxAirTime. Однако есть некоторая проблема, когда мой код, кажется, перемещает спрайт вверх только один раз, а не несколько раз в течение этого отрезка времени. вот код в моем классе player.cs или метод обновления класса.

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;
            }
        }

Любая помощь очень ценится, пожалуйста, и спасибо!


person Aziz    schedule 06.02.2011    source источник


Ответы (2)


Чтобы придать вашему спрайту ощущение гравитации, вы должны добавить скорость и ускорение к вашему классу Sprite. Затем создайте метод Update для Sprite и добавляйте ускорение к вашей скорости при каждом обновлении, а скорость добавляйте к положению при каждом обновлении. Позиция не должна основываться на количестве прошедшего эфирного времени. Вы можете установить ускорение на постоянное гравитационное значение, а затем добавлять его к скорости всякий раз, когда вы прыгаете. Это создаст плавный параболический прыжок, который выглядит красиво. Если вы хотите включить синхронизацию, вы можете передать GameTime в метод 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;
}

Я бы предложил использовать более простой метод, пока вы не поймете, как именно работает тайминг и почему вам нужно его реализовать.

person Darkhydro    schedule 07.02.2011
comment
Зачем вычислять timeScalar и хранить старое игровое время? Если эта функция обновления вызывается в каждом игровом цикле (как и должно быть), gt.ElapsedGameTime уже делает всю тяжелую работу за вас. - person John McDonald; 09.02.2011
comment
Причина использования timeScalar: а) если вы хотите изменить частоту кадров по умолчанию или б) если ваш компьютер настолько медленный, что не может поддерживать стандартные 60 UPS/FPS, которые XNA пытается использовать. В любом случае, если вы отстаете от целевой частоты обновления, ваша игра будет выглядеть отстающей без кода timeScalar. - person Darkhydro; 14.02.2011

Похоже, эта строка виновата:

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

Я думаю, вы обнаружите, что это обновляет положение спрайтов быстрее, чем вы думаете, спрайт будет перемещаться на 330 пикселей вверх по экрану за 10 обновлений (при условии, что Game.IsFixedTimeStep == true), что составляет 1 десятую секунды в реальном времени.

Вполне вероятно, что это просто обновляется так быстро, что вы не получаете изменения, чтобы увидеть его рост до того, как сработает условие && 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 обновления), но формула по-прежнему определяет правильную скорость перехода.

person Stuart    schedule 06.02.2011