Сделать базовый эффект бегущего спрайта - PullRequest
1 голос
/ 01 декабря 2011

Я создаю свою самую первую игру с XNA и пытаюсь запустить мой спрайт.Все отлично работает для первого спрайта.Например: если я иду направо (D), мой спрайт смотрит вправо, если я иду налево (A), мой спрайт смотрит налево, и если я ничего не трогаю, мой спрайт является по умолчанию.Теперь, что я хочу сделать, это если спрайт идет вправо, я хочу альтернативно изменить спрайты (левая нога, правая нога, левая нога и т. Д.)* - это первый запущенный Sprite, а xRunRight1 - это тот, который должен поменяться с xRunRight при правильном запуске.Вот что у меня сейчас:

    protected override void Update(GameTime gameTime)
    {
        float timer = 0f;
        float interval = 50f;
        bool frame1 = false ;
        bool frame2 = false;
        bool running = false;

        KeyboardState FaKeyboard = Keyboard.GetState();
        // Allows the game to exit
        if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
            this.Exit();


            if ((FaKeyboard.IsKeyUp(Keys.A)) || (FaKeyboard.IsKeyUp(Keys.D)))
            {
                xCurrent = xDefault;
            }

            if (FaKeyboard.IsKeyDown(Keys.D))
            {

                timer += (float)gameTime.ElapsedGameTime.TotalMilliseconds;
                if (timer > interval)
                {
                    if (frame1)
                    {
                        xCurrent = xRunRight;
                        frame1 = false;
                    }
                    else
                    {
                        xCurrent = xRunRight1;
                        frame1 = true;

                    }
                }

                xPosition += xDeplacement;


            }

Есть идеи ...?Я застрял на этом некоторое время .. Заранее спасибо и дайте мне знать, если вам нужна какая-либо другая часть из кода.

Ответы [ 3 ]

2 голосов
/ 01 декабря 2011

Вы забыли сбросить таймер, вы можете сделать это, когда достигнете условия timer interval. Кроме того, 50 мс кажется слишком малым для интервала, может быть, вы могли бы сделать как 400 мс?

Кроме того, выглядит хорошо, он будет делать то, что вы хотите.

Кроме того, вы можете посмотреть анимированных спрайтов для ходьбы. То, что вы делаете, - это создаете изображение с шагающими анимационными спрайтами один рядом с другим, одинакового размера. Вы рисуете только часть этого изображения (один спрайт) и перемещаетесь по ним в зависимости от времени.

Вот краткий код для анимированной текстуры:

class AnimatedTexture2D : Texture2D
{
    int _numberOfImages;
    int _currentImage = 0;

    int _timeInterval;
    int _spriteWidth;

    public Rectangle DrawFromRectangle
    {
        get
        {
            return new Rectangle(_currentImage * _spriteWidth, 0, _spriteWidth, this.Height);
        }
    }

    public AnimatedTexture2D(Texture2D entireImage, int spriteWidth, int numberOfImages, int timeInterval)
        : base(entireImage.GraphicsDevice, entireImage.Width, entireImage.Height)
    {
        _numberOfImages = numberOfImages;
        _timeInterval = timeInterval;
        _spriteWidth = spriteWidth;

        Color[] data = new Color[entireImage.Width * entireImage.Height];
        entireImage.GetData<Color>(0, new Rectangle(0, 0, entireImage.Width, entireImage.Height), data, 0, entireImage.Width * entireImage.Height);

        this.SetData<Color>(data);
    }

    public void Animate(GameTime gameTime)
    {
        int totalImageTime = _timeInterval * _numberOfImages;
        int currentPoint = (int)gameTime.TotalGameTime.TotalMilliseconds % totalImageTime;

        _currentImage = currentPoint / _timeInterval;
    }
}

Использование довольно просто:

1) объявить где-нибудь:

AnimatedTexture2D animatedTexture;

2) запустите его с вашей текстурой (у меня была последовательность 2560x64 из 40 64 * 64 изображений), где отдельные изображения расположены рядом друг с другом по горизонтали:

animatedTexture = new AnimatedTexture2D(Content.Load<Texture2D>(@"Textures\Loading"), 64, 40, 20);

3) в вашем методе Update () вызовите

animatedTexture.Animate(gameTime);

4) в вашем методе Draw () вызовите:

SpriteBatch.Draw(animatedTexture, new Rectangle(20, 20, 64, 64), animatedTexture.DrawFromRectangle, Color.White);

Не забудьте про DrawFromRectangle в части 4! (обратите внимание, что целевой прямоугольник использует объявленную ширину отдельной детали, а не всю ширину текстуры, которая в моем тесте составляет 2560 пикселей)

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

Кроме того, если вам не нравится мой временный код (он очень прост, но отсутствует способ сброса анимации), измените его так, чтобы у вас была переменная истекшего времени, и добавьте к ней, как вы делаете в своем собственном коде, и используйте это, чтобы изменить _currentImage. Вы даже можете сделать эту переменную общедоступной, чтобы использовать ее для сброса анимации (или для ее установки в указанной точке).

Конечно, вы также можете сделать по умолчанию анимированную текстуру с одним кадром, чтобы вы могли использовать один и тот же код везде. Надеюсь, это поможет!

1 голос
/ 01 декабря 2011

Если вы знаете, что каждая анимация будет иметь одинаковое количество кадров, вы можете сохранить 3 переменные на спрайт (инкапсулировать в класс для достижения наилучших результатов).BaseFrame - это целое число для хранения глобального номера анимации.SubFrame - это смещение анимации, в котором содержится текущий кадр.FrameAccumulator для хранения информации о времени.

Каждый раз, когда вызывается обновление, добавляйте количество мс с момента последнего обновления к аккумулятору.Как только аккумулятор превысит время анимации, увеличьте значение SubFrame и перезагрузите аккумулятор.Проверьте, не превышает ли подкадр количество кадров для каждой анимации, и, если это так, установите его обратно в 0. Вы можете получить реальный индекс кадра из этого, добавив BaseFrame + Subframe.Когда вам нужно отобразить другую анимацию, просто измените BaseFrame.

Допустим, у каждой анимации есть 3 кадра, а у вас всего 2 анимации.Всего у вас будет 6 кадров.RunLeft будет BaseFrame 0, а RunRight будет BaseFrame 3. Это должно легко дать вам номер кадра для рисования.

1 голос
/ 01 декабря 2011

Вам нужно сохранить последний раз, когда вызывался Update (..), и интервал должен быть ... ну ... интервал, то есть разница между ElapsedGameTime и последним вызовом для обновления ElapsedGameTime.Сделайте это с новым членом вашего класса (LastElapsedGameTimeUpdateCalled) или статическим членом вашего подчиненного.

...