Как связать релиз пули с анимацией стрельбы

15

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

РЕДАКТИРОВАТЬ: Я думаю, что у меня проблемы с формулировкой вопроса должным образом.

Мой вопрос

tp0w3rn
источник
Благодарность! Многие хорошие идеи от всех вас, мне нравится идея использования обратного вызова. Я думаю, что я попытаюсь реализовать это, я действительно не хотел полагаться на отслеживание времени.
tp0w3rn

Ответы:

8

По сути, вы на правильном пути - вам нужно знать, как долго длится анимация, чтобы делать подобные вещи. Анимации - это больше, чем просто набор кадров, вокруг них есть всякая другая информация, которая вам нужна. Например, сколько кадров, цикл анимации, как быстро он воспроизводится (например, 10 кадров анимации в секунду, или 25, или 60?). Каждая анимация может быть определена в виде нескольких фрагментов данных, которые некоторый обобщенный код анимации может просматривать и воспроизводить. Вы должны инкапсулировать часть анимации в свой собственный фрагмент кода, который ничего не знает, кроме этих определений анимации и способов отображения отдельных кадров изображения. Это значит, что у вас есть анимационный объект, который вы можете загрузить, начать воспроизведение, остановить воспроизведение и указать рендеринг в определенном месте на экране.

Гибкий подход заключается в использовании своего рода определения анимации для инкапсуляции информации такого рода. Поэтому вместо того, чтобы просто сказать «анимация Х - это все эти кадры, просто играть через них», вы получите что-то более сложное.

Например, с каким-то смоделированным форматом данных

анимации =
{
  {name = "walk", files = "walk * .png", frameCount = "12", loop = "true"},
  {name = "fire" files = "fire * .png" frameCount = "6",
       события = {
           {name = "bulletLeavesGun", frame = "4", param1 = "43", param2 = "30"}
       }
  }
}

Итак, ваш код говорит что-то вроде:

currentAnimation = animations.Get("fire");
currentAnimation.Play();

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

List<Event> events = currentAnimation.EventsSinceLastCheck();
foreach (AnimationEvent event in events)
{
    if (event.name == "bulletLeavesGun")
    {
        Vector2 bulletPosition = new Vector2(event.param1, event.param2);
        Vector2 actualBulletPosition = new Vector2(
                 character.x + bulletPosition.x, 
                 character.y + bulletPosition.y);
        CreateBulletAt(actualBulletPosition);
    }
}

Примечания к сведению:

  • Код анимации должен существовать отдельно от кода игры. Вы действительно не хотите, чтобы ваш игровой код был слишком тесно связан с болтами при воспроизведении анимации.
  • Код анимации знает, следует ли выполнять цикл на основе определения анимации
  • Код анимации знает, когда анимация завершена, и может перезвонить другому коду, чтобы сказать: «Эй, анимация под названием« огонь »только что закончилась, что вы хотите сделать сейчас?»
  • Код анимации ничего не знает о событиях, кроме того, что у них есть имя и некоторые произвольные данные, связанные с ними (param1 и param2)
  • Код анимации знает, в каком кадре он находится в данный момент, и когда он меняется на новый, он может проверить и сказать: «О, я сейчас на 4 кадре, это означает, что это событие под названием« огонь »только что произошло, добавьте это к мой список недавних событий, чтобы я мог рассказать любому, кто спрашивает об этом ».

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

MrCranky
источник
Я не согласен с сохранением логики анимации (сейчас на кадре 4 это означает, что это событие под названием «огонь» только что произошло). Анимации должны быть слепыми и тупыми. Я должен был сделать некоторые логики на стороне сервера и вырвать анимацию, а пользовательский интерфейс из игры - это то, что я больше не хочу делать. Я бы действительно рекомендовал использовать очень короткие и сегментированные анимации, воспроизводить их параллельно логике, чтобы логика запускала последовательности анимации со скоростью, определяемой логикой. Никогда не проверяйте логику на наличие анимации.
Койот
Разделение анимации на части кажется довольно ненужным. Я бы согласился не опрашивать статус анимации, но это все еще оставляет его первую рекомендацию. Я не знаю, имел ли он в виду отдельную систему событий, чтобы отделить код анимации от остальной части игры (шаблон наблюдателя?), Но я так и сделал. Ни «логика», как вы ее выразили, не должна знать о коде анимации, или наоборот.
Джоккинг
@ Койот, я бы сказал, что вы смешиваете две разные вещи. Да, логика на стороне сервера всегда должна быть независимой от визуальных элементов (потому что вам не нужно запускать систему анимации, чтобы просто выяснить, когда запускается пуля), но это не поможет вам построить систему анимации на клиенте , На клиенте вы абсолютно не хотите, чтобы визуальные эффекты были бездумно подчинены серверу, потому что это выглядело бы ужасно - пули появлялись в нечетное время и не синхронно с персонажем, потому что между игрой и сервером был скачок отставания , Там нет причин, вы не можете иметь оба (продолжение ...)
MrCranky
@Coyote (продолжение ...), игровой процесс может управляться сервером, отделенным от визуальных эффектов. Таким образом, пуля запускается в момент X на сервере, и клиент отражает это действие, сразу же начав воспроизводить анимацию огня, при этом визуальный эффект запуска пули отстает на несколько кадров от симуляции геймплея пули. Нужны компромиссы между визуальной точностью и симуляцией игрового процесса, поэтому сказать, что «анимация должна быть слепой и тупой», просто наивно. Иногда события абсолютно необходимо привязать к кадрам анимации, потому что никакой другой метод не заставит их выглядеть или звучать правильно.
MrCranky
@Coyote На самом деле, теперь я думаю об этом, стрельба пулями является ужасным примером для этого, в основном из-за ответа от thedaian ниже. Увольнение должно произойти сразу. Лучшим примером будет запуск пыльной VFX при приземлении персонажа - сервер и клиент синхронизируются относительно того, когда персонаж начинает прыгать, но визуальное отображение остается за клиентом. И когда анимация попадает в правильный кадр, где нога падает на землю, событие VFX должно срабатывать. Аналогично, события необходимы, если необходимо принять решение для определенного кадра анимации, переходить ли на другую анимацию.
MrCranky
3

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

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

В зависимости от вашей платформы разработки, у вас может быть какая-то функция обновления анимации или обратный вызов, который позволит вам точно ответить, когда анимация достигнет желаемой точки. Вот как я бы сделал это с Flixel, например.

Грегори Эйвери-Вейр
источник
1
addAnimationCallbackМетод Flixel может быть использован на объекте обжига. В функции обратного вызова вы можете увидеть, является ли текущий кадр анимации стрельбы кадром, который должен создать объект маркера. Если это так, вы можете добавить пулю на экран.
Снег слепой
2

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

Ответ альтернативного игрового дизайна: если нет действительно веской причины для этого, я бы избежал задержки с нажатием кнопки «огонь» и появлением маркера. Если анимация не очень-очень короткая (один или два кадра, макс, в основном дульная вспышка), это заставит реагировать на нажатие кнопки огня медленно, и это будет раздражать обычного игрока. Даже если вы решите использовать анимацию до того, как появятся пули (пошаговые RPG и тактические игры были бы приемлемыми причинами для этого), я бы подумал о включении где-нибудь опции «отключить анимацию», чтобы позволить игра, чтобы двигаться быстрее, если игрок хочет.

thedaian
источник
Да, не заставляйте огонь реагировать медленно. Это как общая проблема с прыжками; аниматоры добились большого успеха, но игроки ожидают, что они окажутся в воздухе, как только они нажмут на кнопку.
Джоккинг
2

Как говорит мистер Крэнки; держите анимацию и логику отдельно.

Но самое главное, логика должна оставаться главной частью.

  • Когда кнопка огня нажата, вы должны запустить « действие » розыгрыша в состоянии вашего персонажа (логика).
  • Это действие должно запустить анимацию рисования со всеми параметрами (время жизни и т. Д.).
  • После розыгрыша действие завершится , вы можете вызвать пожар действие (может выстрелить еще раз , или в зависимости от оружия)
  • Это действие может генерировать пули и запускать анимацию огня .

Имейте в виду, что управление пользовательским интерфейсом из логики - единственный способ гарантировать, что вы сможете сохранить, повторно использовать и поделиться своей логикой позже (новый рендер, новая игра, версия сервера без рендерера ...)

койот
источник
1

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

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

{
  animation: {
    name: shoot,
    length: 12,
    spritesheet: shoot.png
    event: {
      frame: 4,
      name: bulletLeavesGun,
    },
  },
}

Читайте данные при загрузке анимации, и пусть код анимации отправляет событие, когда оно находится в этом кадре во время воспроизведения.

jhocking
источник