Unity3D Design Patterns – State – Construirea unei mașini de stat Unity3D

  • Acasă /
  • Unity3D
  • / Unity3D Design Patterns – State – Construirea unei mașini de stat Unity3D
De Jason Weimann /May 26, 2017

Programele de proiectare sunt soluții reutilizabile la probleme comune întâlnite în proiectele software. Utilizarea unor modele de proiectare bune în Unity poate ajuta la menținerea proiectului dvs. curat, ușor de întreținut și ușor de extins. De asemenea, le face mai ușor de construit.. Astăzi, voi acoperi modelul State și elementele de bază ale construirii unei mașini de stare în Unity3D.

Patronul State este un model de proiectare software comportamental care implementează o mașină de stare într-un mod orientat pe obiecte. … Acest model este utilizat în programarea calculatoarelor pentru a încapsula comportamente diferite pentru același obiect pe baza stării sale interne.

O implementare care nu-mi place..

Există câteva moduri în care puteți implementa un model de stare în Unity. Una dintre metodele comune pe care le văd se face prin utilizarea instrucțiunii switch. În general, arată cam așa.

Probleme

În timp ce acest lucru funcționează din punct de vedere tehnic, există câteva probleme serioase care vor apărea în timp.

În primul rând, toată logica noastră este acum în interiorul acestei singure clase. Atacul, apărarea, întoarcerea acasă și orice altă stare pe care dorim să o creăm, toate trebuie adăugate aici. Acest lucru va duce la o clasă principală mare și umflată pentru AI-ul nostru. De asemenea, va crește probabilitatea ca codul nostru să se strice, deoarece modificăm aceeași clasă pentru fiecare tip de logică. În scurt timp, această clasă s-ar putea transforma cu ușurință într-un dezastru de peste 1000 de linii.

De asemenea, nu există o modalitate foarte bună de a trata evenimentele care au loc la intrarea și ieșirea dintr-o stare. Destul de des, dorim ca un personaj sau un obiect să facă ceva atunci când intră într-o stare, să repete o acțiune în timp ce se află în acea stare și să facă ceva total diferit atunci când părăsește starea.

Cu această configurație, ar trebui să adăugăm mai multe comutatoare pentru intrarea și ieșirea din stare, umflând și mai mult clasa și făcând totul mai greu de înțeles.

O implementare mai bună

O abordare mai bună este ca fiecare stare să fie o clasă proprie, în general cu o clasă de bază „state” din care să moștenească.

În acest fel, personajul sau obiectul trebuie să aibă doar o referință la starea sa curentă și un apel pentru a face actualizarea acelei stări. Atunci când dorim să adăugăm o nouă stare, trebuie doar să creăm o nouă clasă.

Utilizând această metodă, clasa noastră de personaje arată puțin diferit:

Puteți observa că clasele au aproximativ aceeași dimensiune… dar asta doar pentru că prima versiune nu face de fapt nimic (în principal pentru a o menține digerabilă). Dacă acea primă clasă ar face tot ceea ce face sistemul pe care am să vi-l arăt, ar fi imensă.

Cum funcționează?

Dacă vă uitați la metoda Update, veți vedea că pur și simplu apelează metoda Tick() asupra stării curente. Cu acest apel, starea controlează ceea ce va face personajul în fiecare cadru.

Avem, de asemenea, o metodă SetState care ne permite să transmitem o stare în care dorim ca personajul să intre. Apelând SetState și trecând diferite stări, putem schimba complet comportamentul acestui personaj, fără a schimba nimic în clasa personajului în sine.

În funcție de configurația dumneavoastră, ar putea fi recomandabil să păstrați stările și să treceți de la una la alta pentru a evita colectarea gunoiului. Pentru ca acest lucru să fie ușor de înțeles, am sărit peste acest aspect, dar merită ținut minte dacă schimbările de stare sunt rapide și dacă sunteți pe o platformă unde contează.

Ce este clasa State?

Clasa State este o clasă de bază abstractă pe care o vom folosi pentru toate stările pe care le creăm. Ea definește un contract foarte de bază pentru ceea ce trebuie să implementeze un stat și alte lucruri pe care le poate implementa opțional.

Referința de caracter este, de asemenea, adăugată la această clasă de bază State, deoarece toate statele noastre din acest exemplu vor avea o interfață cu un caracter într-un fel sau altul. Luăm caracterul în constructorul clasei noastre de stare și îl păstrăm într-o variabilă protejată, astfel încât să fie disponibil pentru clasele noastre de stare.

Avem, de asemenea, metoda abstractă Tick(). Făcând-o abstractă înseamnă că clasele noastre de stat sunt obligate să o implementeze.

În schimb, avem două metode virtuale pentru OnStateEnter() & OnStateExit() care sunt opționale. Deoarece sunt virtuale, ele au o implementare implicită care nu face nimic și nu este necesar să fie implementate.

Aceasta este întreaga clasă State… destul de simplu, nu-i așa?

Crearea unei stări – Return Home

Acum că avem elementele de bază, să creăm o implementare a unei stări pe care să o putem conecta la personajul nostru.

Starea Return Home face pur și simplu ca personajul să se întoarcă la locația sa de origine. Din moment ce nu definim de fapt destinația pentru home, aceasta este implicit Vector3.zero.

Tick

Metoda Tick îi spune personajului să se deplaseze spre destinația (0, 0, 0).

Metoda MoveToward se află pe o versiune a personajului de la sfârșitul acestei postări. Într-un proiect real, această mișcare ar fi probabil controlată de o altă componentă, cum ar fi o clasă ‘CharacterMovement’ sau altceva.

Apoi verifică dacă personajul a ajuns acasă, iar dacă da, îi spune personajului să treacă la o stare ‘wander’. Observați că trecem personajul în momentul creării noii stări. Acest lucru se datorează faptului că starea noastră este concepută pentru a necesita un personaj.

EnterState

De asemenea, schimbăm culoarea personajului atunci când se intră în starea de întoarcere acasă prin OnStateEnter. Astfel, când un personaj se întoarce acasă, acesta este albastru.

Crearea unei alte stări – Wander

Pentru ca o mașină de stare să aibă sens, avem nevoie de mai mult de o stare. De fapt, starea noastră de întoarcere acasă vrea de fapt să treacă personajul într-o stare de rătăcire odată ce a terminat, așa că trebuie să creăm acea stare de rătăcire.

Starea de rătăcire va alege o locație aleatorie și va muta personajul spre acea poziție. Când ajunge în acea poziție, va alege un alt loc spre care să se plimbe.

Acesta va continua să facă acest lucru până când se va plimba timp de 5 secunde (pe baza variabilei noastre wanderTime). În acel moment, îi va spune personajului să se întoarcă la starea ReturnHome (linia 43).

Starea de rătăcire schimbă, de asemenea, culoarea personajului nostru în verde prin intermediul metodei OnStateEnter.

Să vedem cum arată

Aici, am creat o scenă cu o duzină de „personaje” reprezentate sub formă de cuburi.

Vă veți vedea cum se plimbă de colo-colo cât timp sunt verzi, apoi se duc din nou acasă când sunt albastre și repetă procesul.

Caracterul complet

Am menționat mai sus că întreaga clasă de caractere este aici cu metoda MoveToward. Din nou, într-un proiect real, v-aș recomanda să păstrați mișcarea de bază separată într-o altă componentă, dar pentru a păstra acest lucru simplu, aici este în clasa Character.

Concluzii

Patronul de stare este uimitor de puternic. Puteți construi sisteme de inteligență artificială, meniuri și multe altele cu ușurință, odată ce vă simțiți confortabil cu acest model.

Acest aparat de stare este, de asemenea, foarte simplu și poate fi extins pentru a face lucruri cum ar fi caching state (pentru a evita noi alocări de memorie) sau personalizat mai mult în funcție de nevoile dumneavoastră.

O altă modalitate excelentă de a construi aparate de stare este prin intermediul obiectelor scriptabile. O mașină de stare configurată folosind scriptableobjects poate fi configurată cu ușurință în editor/inspector de către proiectanți fără a atinge vreodată codul, dar acesta este un subiect puțin mai complicat în care s-ar putea să mă scufund mai târziu.

Când aveți nevoie să construiți puțină logică de joc, încercați să configurați o mașină de stare proprie (sau copiați-o pe aceasta ca punct de plecare), sunt sigur că vă va ajuta și vă veți bucura de noul model.

.

Lasă un răspuns

Adresa ta de email nu va fi publicată.