Я делаю двумерную игру защиты башни для учебных целей и не могу заставить врагов (спрайтов) оказаться в правильном направлении при движении.
Вот как построена карта для уточнения:
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, и когда он достигает третьей плитки, фиксирует и смотрит в правильное направление.
Вы не проверяете, находится ли текущий кадр ниже минимального значения для нужного цикла анимации; вы проверяете его только на максимальное значение. Кроме того, есть некоторые повторения в вашем коде, которые, вероятно, должны быть учтены, чтобы облегчить чтение и работу.
Я бы заменил все ваши методы 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);
lastPosition
? Если это сделано в базе, то вы никогда не будетеlastPosition
в свои методы анимации, потому чтоposition
будет равнаlastPosition
. Что заставляет меня думать, что это так, потому что ваши скриншоты показывают, что он использует первый ряд фреймов, что, я думаю, будет по умолчанию.