Nepoužívejte znovu vynalézat stroje konečných států: Jak znovu použít animátor Unity

Konečné stavové stroje jsou jedním z nejpopulárnějších vzorců ve vývoji her z dobrého důvodu. Mohou snížit složitost a vytvářet čitelnější programy tím, že podporují modulární, opakovaně použitelné stavy. Zatímco FSM (konečný stav stroje) nedokážou škálovat na složitější situace, jsou to vynikající řešení pro většinu běžných situací, jako je řešení stavu aplikace nebo vytvoření jednoduché AI. *

* Nevysvětlím základní pojmy a případy použití FSM, protože si myslím, že už je online mnoho dobrých článků, jako je tento článek z knihy Bob Nystrom o vzorcích programování her.

Existují dva hlavní přístupy k vytváření a používání FSM: psaní rychlé a špinavé implementace nebo nákup aktiv z úložiště aktiv k použití. Ale je tu třetí možnost: pomocí vestavěného systému animátorů Unity (Mecanim).

Proč byste měli používat animační systém Unity?

Může se zdát trochu divné znovu použít animační systém k vytvoření konečných stavových strojů, ale animátor je konečný stavový stroj. Přestože má animační funkce, které se mohou dostat do cesty, animátorský systém dělá téměř vše, co byste chtěli. Dodává se s nástroji pro úpravy a vizualizaci stavového stroje během běhu. Je také podporována Unity, testována miliony vývojářů a veškeré zkušenosti s animací Unity, které již máte, jsou použitelné.

Proč místo toho stavět rychlou a špinavou implementaci?

Rychlá a špinavá implementace funguje dobře pro úkol, pro který je určena, ale jakmile budete potřebovat tento vzorec použít jinde, zjistíte, že znovu a znovu přepisujete stejný kód. Animátorský systém může snadno vytvářet různé stavové stroje s opakovaným stavovým chováním.

Co tedy s využitím díla třetí strany?

Existují aktiva třetích stran, která soupeří s animátorským systémem ve složitosti a moci (jako NodeCanvas). Výhodou je také čistší API, protože se nezabývají animacemi. Dokonce jsem si vytvořil vlastní implementaci, kterou jsem nakonec přestal používat ve prospěch opětovného použití animátoru. Protože se chystáte použít animátor k tomu, aby dobře animoval, znovu jej použil pro státní automaty, nemusíte přepínat kontexty mezi dvěma podobnými systémy.

Dobře, jak mám začít?

Nejprve se budu zabývat základními pojmy systému Unity's Animator (Mecanim).

  • V Unity můžete vytvořit dílo zvané Animator Controller. Toto je šablona stavového stroje.
  • Uvnitř vašeho stavového stroje jsou stavy. Pravděpodobně jste zvyklí přiřadit stavy k animacím, ale ve skutečnosti jsou volitelné, pokud chcete vytvořit čistě logický stavový stroj.
  • Chcete-li spustit svůj stavový stroj, přidejte do GameObject komponentu nazvanou Animator a nastavte ji pomocí libovolného ovladače Animator, který jste vytvořili. Toto je nyní instance vašeho státního počítače.
  • Aby bylo možné spustit logiku v každém stavu, musíme vytvořit skript odvozený od třídy StateMachineBehaviour. Jakmile budeme mít toto nové chování, můžeme jej přidat do jakéhokoli stavu uvnitř stavového stroje. **

Více informací o Animátorech si můžete přečíst zde nebo si zde můžete přečíst návod.

** Pamatujte, že to funguje podobně jako MonoBehaviours: skript přijímá předdefinované zprávy, jako je OnEnter, OnExit atd.

Jak používáte StateMachineBehaviours?

Nejčastěji používám stavy pro správu životního cyklu objektů a jejich vlastního chování pomocí zpráv OnStateEnter a OnStateExit, když zdědím od StateMachineBehaviour. Například pokud chci, aby můj stav poslouchal nějaké herní události, obvykle přidávám posluchače při vstupu a při ukončení je odstraňuji. Vyčištěním objektů při ukončení se vyhnete obtížně sledovatelným následkům, jako jsou zbytky herních objektů nebo posluchači zombie. Nechcete, aby váš stát ovlivňoval hru, když není aktivní!

Jeden problém, který jsem našel, je, že OnStateExit není vyvolán, když je Animator deaktivován nebo zničen. Chcete-li řádně vyčistit aktuální stav, musíte se také ujistit, že s OnDisable manipulujete ***.

*** Abych si ušetřil čas, vytvořil jsem úložiště, které importuji do své hry zde umístěné. Neváhejte jej použít ve svých vlastních projektech!

Podívejme se na jednoduchý stavový stroj, který jsem vytvořil pro nepřítele v mé vlastní hře, Jellyquest.

To je rozzlobený úlovek. Otáčí se pomalu, dokud neuvidí hráče, a pak se rychle pohne ve směru hráče.

Pufferfish je prefab nakonfigurovaný pomocí AnimatorController s názvem AngryPufferfish. Existují 3 stavy: Zaměření, Příprava na střelbu a Střelba. Pufferfish začíná ve stavu cílení, který se skládá ze dvou chování státu: RotateFacingDirection a AimInFacingDirection.

RotateFacingDirection otáčí pufferfish na základě konfigurovatelné rychlosti. AimInFacingDirection přijde na to, zda je čertovitý čelem k cíli na základě raycastu.

Ve stavu PreparingToShoot znovu používám chování stavu pojmenované TriggerContinueAfterDelay s parametrem, jak dlouho je zpoždění.

A ve stavu Střelba používám chování stavu MoveInFacingDirection, abych posunul ryby směrem k hráči.

Díky tomu, že každé z těchto chování je obecné a jednoúčelové, mohu je vyladit a znovu použít v jiných státních strojích, abych vytvořil řadu různých typů nepřátel.

Úžasné, něco jiného bych měl vědět?

Existují některé běžné úskalí, na které byste si měli dát pozor. Ty dávají větší smysl, čím více jste seznámeni se systémem animátorů.

  • Buďte unavení z psaní kódu, který může nastavit spoušť mnohokrát ve stejném rámci. Protože spouštěče jsou přechodem spotřebovány pouze jednou, spouštěč by se mohl nastavit poté, co byl spotřebován a přetrvávat kolem současného stavu.
  • OnStateEnter a OnStateExit na počítačích s nižšími stavy pravděpodobně NEBEZPEČÍ, jak byste očekávali. Volají se pouze při zasažení vstupních a výstupních uzlů podřízeného stroje. Tyto uzly však lze omylem obejít tím, že provedou přechody přímo do konkrétního podřízeného stavu nebo ven do vnějšího stavu.
  • Doba přechodu by měla být pravděpodobně vždy nastavena na nulu. Pokud doba trvání přechodu není nula, bude před dalším výstupem OnExit volána funkce OnEnter dalšího stavu.
  • Přechody pomocí triggerů postoupí do dalšího stavu ve stejném rámci. Přechody založené na jiných typech parametrů mají zvláštní rámec.

TL; DR:

  • Stroje pro konečný stav jsou užitečné pro správu životních cyklů objektů
  • Lidé buď psají své vlastní státní stroje v kódu, nebo si kupují aktiva třetí strany z úložiště aktiv. Můžete však použít i Unity Animator.
  • Animator přichází s vestavěnou vizualizací, nástroji, přechody a známým rozhraním.
  • Používání Animátoru je úžasné, ale pozor na některé úskalí, získejte více podrobností výše!

Máte zájem zkrátit čas kompilace? Nebo možná automatickou validaci vaší hry, abyste zabránili rozbitým sestavením? Podívejte se na mé další články!