2D анимация движения для спрайтов с использованием одного листа спрайта с четырьмя направлениями

1

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

Вот как построена карта для уточнения:

http://i.imgur.com/ivO8kWe.png

И вот лист спрайтов, который я использую для тестирования:

http://i.imgur.com/2h4fSL3.png

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

Сказал, что у каждого спрайта, у которого есть нереста, будет определенный путь для ходьбы, из которого я пытаюсь найти направление, с которым спрайт сталкивается, проверяя последнее положение X или Y и текущую позицию X или Y, при этом я выбираю, какую строку листа спрайта, который я буду использовать для анимации ходьбы. Например, скажем, спрайт движется на юг, он должен использовать спрайты внизу листа спрайта (рамки с 15 по 19), но он не работает.

Это класс анимации, который я использую для врагов:

 public class AnimatedSprite : Sprite
    {
        public int Lines { get; set; }
        public int Columns { get; set; }
        protected int currentFrame;
        protected int totalFrames;
        protected int timeSinceLastFrame = 0;
        protected int milisecondsPerFrame = 50;


        public AnimatedSprite(Texture2D texture, int lines, int columns, Vector2 position)
            : base ( texture, position)
        {
            this.texture = texture;
            this.position = position;
            Lines = lines;
            Columns = columns;
            totalFrames = Lines * Columns;
        }

        public override void Update(GameTime gameTime)
        {
            base.Update(gameTime);

           //Here i check if the sprite sheet have more than 1 line because if it have, 
           //it must use a different update method.
            if (Lines > 1)
            {
                // Down
                if (lastPostion.Y < position.Y)
                {
                    AnimateDown(gameTime);
                }
                // Up
                if (position.Y < lastPosition.Y)
                {
                    AnimateUp(gameTime);
                }

                // Right
                if (position.X > lastPosition.X)
                {
                    AnimateRight(gameTime);
                }

                // Left
                if (position.X < lastPosition.X)
                {
                    AnimateLeft(gameTime);
                }
            }

            if (Lines == 1) {
            timeSinceLastFrame += gameTime.ElapsedGameTime.Milliseconds;
            if (timeSinceLastFrame > milisecondsPerFrame)
            {
                timeSinceLastFrame -= milisecondsPerFrame;
                currentFrame++;
                if (currentFrame == totalFrames)
                {
                    currentFrame = 0;
                }
            }
        }                        
           center = new Vector2(position.X + texture.Width / Columns, position.Y + texture.Height / Lines);
        }

        public void AnimateUp(GameTime gameTime)
        {
            timeSinceLastFrame += gameTime.ElapsedGameTime.Milliseconds;
            if (timeSinceLastFrame > milisecondsPerFrame)
            {
                timeSinceLastFrame -= milisecondsPerFrame;
                currentFrame++;
                if (currentFrame > 14)
                    currentFrame = 10;
            }
        }

        public void AnimateDown(GameTime gameTime)
        {
            timeSinceLastFrame += gameTime.ElapsedGameTime.Milliseconds;
            if (timeSinceLastFrame > milisecondsPerFrame)
            {
                timeSinceLastFrame -= milisecondsPerFrame;
                currentFrame++;
                if (currentFrame > 19)
                    currentFrame = 15;
            }
        }           

        public void AnimateLeft(GameTime gameTime)
        {
            timeSinceLastFrame += gameTime.ElapsedGameTime.Milliseconds;
                if (timeSinceLastFrame > milisecondsPerFrame)
            {
                timeSinceLastFrame -= milisecondsPerFrame;
                currentFrame++;
                if (currentFrame > 4)
                    currentFrame = 0;
            }
        }

     public void AnimateRight(GameTime gameTime)
        {
            timeSinceLastFrame += gameTime.ElapsedGameTime.Milliseconds;
                if (timeSinceLastFrame > milisecondsPerFrame)
            {
                timeSinceLastFrame -= milisecondsPerFrame;
                currentFrame++;
                if (currentFrame > 9)
                    currentFrame = 5;
            }
        }


        public override void Draw(SpriteBatch spriteBatch)
        {
            int width = texture.Width / Columns;
            int height = texture.Height / Lines;
            int line = (int)((float)currentFrame / (float)Columns);
            int column = currentFrame % Columns;

            Rectangle originRectangle = new Rectangle(width * column, height * line, width, height);
            Rectangle destinationRectangle = new Rectangle((int)position.X, (int)position.Y, width, height);          

            spriteBatch.Draw(texture, destinationRectangle, originRectangle, Color.White);
        }
    }
}

Редактирование: я провел тест на прямолинейном уровне (начальная точка слева), он начинает смотреть влево (рамка 0), но когда он достигает третьей коричневой черепицы, он фиксируется и смотрит в правильное направление:

i.imgur.com/3FsGhuY.png

Edit2: Я провел тест с линейными линиями по всем четырем направлениям (начиная с самого начала и вверх, начинаю направо и направо налево и наоборот), и во всех них он начинается с кадра 0, и когда он достигает третьей плитки, фиксирует и смотрит в правильное направление.

  • 0
    А что не работает?
  • 1
    Когда / где установлена lastPosition ? Если это сделано в базе, то вы никогда не будете lastPosition в свои методы анимации, потому что position будет равна lastPosition . Что заставляет меня думать, что это так, потому что ваши скриншоты показывают, что он использует первый ряд фреймов, что, я думаю, будет по умолчанию.
Показать ещё 6 комментариев
Теги:
2d
xna

1 ответ

1
Лучший ответ

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

Я бы заменил все ваши методы AnimateXXXX одним методом:

public void AnimateLoop(GameTime gameTime, int loopFirstFrame, int loopLastFrame)
{
    timeSinceLastFrame += gameTime.ElapsedGameTime.Milliseconds;
    if (timeSinceLastFrame > milisecondsPerFrame)
    {
        timeSinceLastFrame -= milisecondsPerFrame;
        currentFrame++;
    }
    if (currentFrame > loopLastFrame || currentFrame < loopFirstFrame)
        currentFrame = loopFirstFrame;
}

И затем назовите их так:

// Down
if (lastPostion.Y < position.Y)
    AnimateLoop(gameTime, 15, 19);
// Up
if (position.Y < lastPosition.Y)
    AnimateLoop(gameTime, 10, 14);
// Right
if (lastPosition.X < position.X)
    AnimateLoop(gameTime, 5, 9);
// Left
if (position.X < lastPosition.X)
    AnimateLoop(gameTime, 0, 4);
  • 0
    Это сработало! Теперь это выглядит так просто, вы не представляете, сколько времени я потратил, пытаясь решить его самостоятельно. Большое спасибо, мистер!

Ещё вопросы

Сообщество Overcoder
Наверх
Меню