Dead Simple Sprite-Sheet Animations

Dead Simple Sprite-Sheet Animations

8 декабря 2022 г.

Я использовал Bevy для личного проекта, и это было восхитительно. По мере роста проекта я превратился в левел-дизайнера, аниматора, иллюстратора, наравне с обычным программистом.

Иногда я натыкаюсь на стены, и кроличьи норы вокруг этих стен слишком привлекательны, чтобы пройти мимо них. Одной из таких кроличьих норок было вычисление циклов анимации спрайтов из одного листа спрайтов. Единственная причина использования одного листа спрайтов заключается в том, что работа разработчика и иллюстратора требует очень много времени, и я хотел, чтобы мой рабочий процесс оставался максимально простым.

Sprite sheet

Animated

Создание анимационных страниц

Страница анимации – это группа кадров, образующих циклическую анимацию. В следующем примере страницы анимации представлены перечислением.

Defining animation loop in an array

Реализация

Определение вариантов анимации в перечислении

<цитата>

Я называю разделы анимации вариантами, а кортеж смещения/размера — страницей

#[derive(Clone, PartialEq)]
pub enum PlayerAnimationVariant {
    Idle,
    Rising,
    Falling,
}

Создание трейта AnimationLoop Черта проста, определяет функцию, которая будет возвращать смещение и размер страницы анимации.

pub trait AnimationLoop {
    fn page(&self) -> (usize, usize);
}

Реализация трейта AnimationLoop для перечисления Черта проста, определяет функцию, которая будет возвращать смещение и размер страницы анимации.

impl AnimationLoop for PlayerAnimationVariant {
    fn page(&self) -> (usize, usize) {
        match self {
            // return values (idx_offset, loop_size) describe the animation loop
            PlayerAnimationVariant::Idle => (0, 3),
            PlayerAnimationVariant::Rising => (2, 2),
            PlayerAnimationVariant::Falling => (4, 4),
        }
    }
}

Переход между кадрами и страницами

looping

Реализация

Реализация диспетчера состояний анимации

В структуре хранится вариант анимации для воспроизведения и текущий индекс кадра.

pub struct PlayerAnimationState {
    pub variant: PlayerAnimationVariant,
    pub idx: usize,
}

Реализация функций перехода

wrapping_next_idx увеличивает idx и выполняет перенос на границе страницы

impl PlayerAnimationState {
    fn wrapping_next_idx(&mut self) -> usize {
        let current_idx = self.idx;
        let (offset, size) = self.variant.page();

        self.idx = offset + (current_idx + 1) % size;

        self.idx
    }
}

transition_variant обновляет диспетчер состояний анимации для воспроизведения варианта, переданного в качестве аргумента

impl PlayerAnimationState {
    ...

    fn transition_variant(&mut self, to: PlayerAnimationVariant) {
        let (offset, _) = to.page();
        self.variant = to;
        self.idx = offset;
    }
}

Это может быть несколько утомительно, поэтому я создал крейт Rust, который упрощает процесс, предоставляя:

  • черты AnimationLoop и AnimationTransition<T: AnimationLoop>
  • удобный макрос AnimationTransitionMacro, реализующий необходимые функции манипулирования индексами для диспетчера состояний анимации

Посмотрите конечный продукт здесь! А вот репозиторий.


Оригинал
PREVIOUS ARTICLE
NEXT ARTICLE