Когда использовать Spine_Animator против Spine_Instance
Используйте Spine_Animator для всего, что существует в мире (реквизит, NPC, взаимодействуемые объекты).
Используйте Spine_Instance непосредственно, когда вы хотите отрисовать Spine в UI или вам нужен ручной контроль времени жизни.
Если вы вызываете Spine_Instance.create(), вы должны вызвать instance->destroy() когда закончите (иначе будет утечка).
Справочник Spine API (CSL)
Spine_Animator::class:Component{depth_offset:float;layer:s32;instance:Spine_Instance #read_only;}Spine_Instance::class{create::proc()->Spine_Instance;destroy::method();update::method(dt:float);set_skeleton::method(asset:Spine_Asset);get_skeleton::method()->Spine_Asset;set_animation::method(animation:string,loop:bool,track:s64,speed:float=1);// Скиныset_skin::method(skin:string);enable_skin::method(skin:string);disable_skin::method(skin:string);disable_all_skins::method();refresh_skins::method();get_skins::method()->[]string;// Локальные смещения костей (для продвинутых пользователей)get_bone_local_position::method(bone_name:string)->v2;set_bone_local_position::method(bone_name:string,position:v2);// Необязательно: управлять анимациями через машину состоянийset_state_machine::method(new_state_machine:State_Machine,transfer_ownership:bool);// Визуальные настройкиcolor_multiplier:v4;set_color_replace_color::method(color:Color_Replace_Color);}
Добавление анимированных объектов в мир
Существуют 3 способа добавить анимированные объекты в сцену, все они создадут компонент Spine_Animator.
Перетащите любой анимированный ассет из Каталог ассетовв вашу сцену
Создайте новую сущность и добавьте компонент Spine_Animator
Установите Skeleton Data Asset поле на .spine файл в ваших ассетах
Добавьте spine-animator в мир с помощью скриптинга (рассматривается в примерах)
Если ваш код и Spine_Animator находятся на одной сущности и запускаются одновременно, вызовите spine->awaken() перед доступом к spine.instance.
Примеры
Открываемый сундук
Взаимодействуемый сундук, который проигрывает анимацию «open» и затем остается открытым:
Идущая курица
Простой цикл «idle vs walk» на основе движения:
Управляемая машина
Если вы хотите поведение «управляемого» объекта, самый простой подход — управлять движением своей игровой логикой, а управлять анимацией на основе того, движется ли машина.
Если вы переключаетесь только между двумя цикличными анимациями, прямые вызовы set_animation обычно проще, чем построение машины состояний.
Скины (варианты/наряды)
Некоторые спайны не имеют стартового скина по умолчанию. Если ваша сущность «невидима», вероятно, нужно выбрать скин.
Всегда вызывайте refresh_skins() после изменения скинов.
Машины состояний (необязательно, для сложной логики анимаций)
Вы можете упростить логику анимации, вызывая вызовы set_animation напрямую. Если у вас много состояний (idle/run/attack/hit/death), State_Machine помогает определить переходы один раз, а затем просто задавать переменные/триггеры.
Ключевая идея: имена состояний должны совпадать с именами анимаций в вашем Spine-файле.
Что делает машина состояний
Думайте о машине состояний как о маленьком «контроллере анимаций»:
Вы определяете состояния (каждое имя состояния должно совпадать с именем анимации в Spine)
Вы определяете переменные (bool, триггер, int, float)
Вы определяете переходы между состояниями на основе этих переменных
Во время выполнения вы обновляете только переменные (машина состояний выбирает анимацию)
Минимальный пример: idle/walk + триггер атаки
Если вы передаете transfer_ownership = true в set_state_machine, то Spine_Instance уничтожит машину состояний за вас. В противном случае вы должны уничтожить её сами.
Устранение неполадок
В: Я перетащил spine-ассет в сцену и не вижу объект — сущность пустая
О: Убедитесь, что вы нажали «Add Skin» и выбрали вариант скина для применения! Некоторые спайны не имеют скина по умолчанию.
В: Мой скрипт падает, когда я обращаюсь к spine.instance
О: Если ваш скрипт и Spine_Animator запускаются одновременно, вызовите spine->awaken() перед использованием spine.instance.
В: Я сменил скины, но ничего не произошло
О: После любой смены скина (set_skin, enable_skin, disable_skin, disable_all_skins), вы должны вызвать refresh_skins().
Пользовательские скины/анимации игрока
Если вы хотите добавить пользовательские анимации для вашего игрока, вы можете сделать это, объединив базовый Spine-риг игрока All Out с пользовательским ригом, содержащим дополнительные анимации (мы можем предоставить многие из них, просто свяжитесь с намиПоддержка разработчиков)
Формат Spine-рига
Spine-риги состоят из 3 файлов (автоматически загружаются для вас при использовании Каталога ассетов)
Файл скелета (.spine) содержит информацию о костях, скинах и структуре вашего анимированного объекта.
Изображение атласа (.png) содержит текстуры, используемые для отрисовки спайна в мире.
Файл атласа (.atlas) содержит информацию о том, где внутри .png-атласа находится каждая часть анимированного объекта.
Создание собственных анимаций
В настоящее время, чтобы создавать собственные анимации или риги, вам понадобится лицензия Esoteric Spine. Тем не менее, мы предоставляем огромную библиотеку существующих Spine-ригoв и анимаций в составе Каталог ассетовдля вашего использования, и рекомендуем начать оттуда!
Формат экспорта
Чтобы использовать пользовательский Spine-риг в All Out, нужно экспортировать стандартный 3-файловый Spine-бандл в вашу res папку:
something.spine
something.atlas
something.png (текстура атласа)
Если вы не уверены в настройках экспорта, начните с существующего Spine-ассета All Out из Каталога ассетов и повторите его структуру или свяжитесь с нами!
spine := entity->get_component(Spine_Animator);
spine->awaken();
// Вариант A: установить один скин
spine.instance->set_skin("default");
spine.instance->refresh_skins();
// Вариант B: комбинировать несколько скинов
spine.instance->disable_all_skins();
spine.instance->enable_skin("body");
spine.instance->enable_skin("hat");
spine.instance->refresh_skins();
NPC_Anim :: class : Component {
state_machine: State_Machine;
is_moving: bool;
ao_start :: method() {
// 1) Создать машину состояний + переменные
state_machine = State_Machine.create();
moving_var := state_machine->create_variable("is_moving", .BOOL);
attack_var := state_machine->create_variable("attack", .TRIGGER);
// 2) Создать слой (соответствует дорожке Spine, обычно 0)
layer := state_machine->create_layer("main", 0);
// 3) Создать состояния (имена должны совпадать с анимациями в Spine-риге)
idle := layer->create_state("idle", true);
walk := layer->create_state("walk", true);
attack := layer->create_state("attack", false);
layer->set_initial_state(idle);
// 4) Переходы для движения
idle_to_walk := layer->create_transition(idle, walk, false);
idle_to_walk->create_bool_condition(moving_var, true);
walk_to_idle := layer->create_transition(walk, idle, false);
walk_to_idle->create_bool_condition(moving_var, false);
// 5) Атака из любого состояния, затем возврат в idle по завершении
to_attack := layer->create_global_transition(attack, true);
to_attack->create_trigger_condition(attack_var);
attack_to_idle := layer->create_transition(attack, idle, true); // require_state_complete = true
// 6) Прикрепить к экземпляру spine
spine := entity->get_component(Spine_Animator);
spine->awaken();
spine.instance->set_state_machine(state_machine, true); // transfer_ownership = true
}
ao_update :: method(dt: float) {
state_machine->set_bool("is_moving", is_moving);
}
do_attack :: method() {
state_machine->set_trigger("attack");
}
}