Enhet Nå tenker du med komponenter

Mens Unity er en fantastisk gamedev-plattform, blir det vant til å begynne å jobbe, da du sannsynligvis trenger å skifte dine kognitive cogs for å forstå det komponentbasert arkitektur.

Selv om klassisk Objektorientert Programmering (OOP) kan brukes og brukes, bygger Unity-arbeidsflyten seg svært godt på strukturen av komponenter - som krever komponentbasert tenkning. Hvis du er kjent med komponenter, er det bra; Hvis ikke, det er ikke et problem. Her vil jeg gi deg et krasj kurs på komponenter i Unity.

Forhåndsvis bilde: Old Cogs av Emmanuel Huybrech.


Hva er en komponent?

Før vi fortsetter med hvordan vi jobber og tenker med komponenter, la oss sørge for at vi forstår hva de egentlig er.

I programmeringsplanen går konseptene for komponenter og avkobling hånd i hånd. En komponent kan betraktes som et mindre stykke større maskin. Hver komponent har sin egen spesifikke jobb, og kan generelt (og optimalt) oppnå sin oppgave eller sin hensikt uten hjelp av eksterne kilder. I tillegg tilhører komponenter sjelden en enkelt maskin, og kan knyttes sammen med forskjellige systemer for å oppnå deres spesifikke oppgave, men oppnår forskjellige resultater når det gjelder det større bildet. Dette skyldes at komponenter ikke bare bryr seg om det større bildet, men også vet ikke engang det eksisterer.

Et klassisk eksempel på komponenter er brikkene i en bil, men det er kjedelig, for jeg er ikke også inn i biler. I stedet betrakt en Xbox 360-kontroller. Tt har to analoge pinner, forskjellige knapper, triggere og så videre. Ikke bare er hele kontrolleren selv en komponent, men hvert enkelt aspekt av kontrolleren er en komponent.

Bilde av Futurilla.

X-knappen kan: trykkes på; send av informasjonen den er blitt trykket på; bli løslatt; og send av informasjon som er den er utgitt. Det har ingen anelse om at det er forskjellige andre knapper rett ved siden av det, og det bryr seg heller ikke.

Kontrolleren selv er en komponent som består av andre komponenter (alle knapper, joysticks og triggere), fordi det kan sende data til hva det er koblet til, men det bryr seg ikke hva det objektet er (Xbox, PC, noen Arduino skapelse, eller hva som helst). Verken X-knappen, eller selve kontrolleren selv, trenger å vite hvilket spill du spiller, da det fortsatt vil gjøre jobben sin uavhengig av mottakeren av informasjonen. 

Funksjonen til kontrolleren er en enveiskast, og oppgaven vil aldri endre på grunn av hva den er koblet til. Dette gjør det til en vellykket komponent, både fordi den kan gjøre jobben sin som en frittstående enhet, men også fordi den kan gjøre jobben sin med flere enheter.


Hvordan og hvorfor har Unity Favor Components?

Enhet ble bygget med komponenter i tankene, og det viser. En av de mest verdifulle og særegne aspektene av Enhet er at det er et veldig visuelt program. Jeg har jobbet i spillutvikling i mange år nå, og bortsett fra mine veldig tidlige Flash IDE-dager har jeg for det meste jobbet med PNG-sprite-ark og en kodeditor som FlashDevelop-som ikke er visuell i det hele tatt.

Enhet er det motsatte. Enhet lar deg se alt du jobber med, og i sanntid. Dette betyr at du kan teste prosjektet ditt, se prosjektet som kjører i et eget vindu, foreta endringer i koden eller spillobjekter, og se de endringene som reflekteres live. Mengden kraft dette systemet gir til en utvikler er enorm, og er nå, etter min mening, et viktig aspekt av moderne spillutvikling. Alt dette er gjort mulig av Unitys komponentbaserte arkitektur.

Inspektøren

Hvis du ikke er kjent med Unity, skal jeg forklare inspektøren. Dette er et panel i Unity som viser deg alle egenskapene til et spillobjekt. Hvis du klikker på spilleren din i verden (enten på kjøretid eller før) kan du se alt om det aktuelle objektet.

Hvis spillerens avatar har seks komponenter på dem, vil hver bli oppført i en egen fane, og hver offentlig variabel vil være tilgjengelig for deg å se og justere. Hvis spilleren din har en beholdning, vil du ikke bare se at han har en oversikt, du vil også kunne se elementene i den beholdningen, og hvilken indeks i listen eller arrayen som hvert bestemt element opptar. Hvis du henter et nytt element i spillet mens du prøver, ser du det lagt til i inventar-live. Du kan til og med legge til eller fjerne elementer fra den beholdningen, noe som gjør at du raskt kan teste nye elementer, som du selv kan skape mens spillet går.

Enhetsinspektøren.

Mens levende redigering er sinnsykt kraftig, er det ikke akkurat avhengig av bruk av komponenter. Du kan endre et skript, og se disse endringene gjenspeiles live, men det er begrenset i forhold til hvilke komponenter du kan gjøre.

Tenk på en vertikal space shooter. Når du tester prosjektet ditt i de fleste andre miljøer, ser du hvordan spillet ditt spiller, tar notater, går deretter tilbake til koden og justerer ting, bare for å kompilere prosjektet igjen og teste disse punktene. Hvis du har et liveoppsett, kan du finjustere koden på fly, og se de endringene mens du spiller, noe som er enda bedre. Når det blir sagt, hvis du ikke bruker komponenter, må du bytte mye kode for å se noen større effekter, noe som tar tid, og dette slår i stedet for formålet med live redigering.

Hvis du jobber med komponenter, kan du legge til nye komponenter på to sekunder flatt. Du kan bytte ut skipets våpen for våpenene som en sjef bruker (forutsatt at du programmerte komponentene til å fungere alene, som gode komponenter burde gjøre), kan du bytte ditt fem-treffes helsesystem til den kule Halo-lignende lade skjermen du programmert for et annet spill. Du kan legge til en rekke staver til en av dine tegn, og alt om sekunder.

Du trenger ikke å endre noen kode, du trenger ikke å kompilere, du bare dra og slipp, eller velg ønsket komponent fra en rullegardinliste, og den er lagt til. Den slags kraft er uvurderlig for spillbalansering, og det sparer enorme mengder tid.


Bytter til komponentbasert tenkning

Den vanskeligste delen om å jobbe med komponenter er å lære å strukturere prosjektene dine når du bruker dem. For de fleste programmører vil dette trolig bety at du skal skape mye flere skript, med hver enkelt mindre og mer spesifikke oppgaver.

Hvordan du kommuniserer mellom skript er også en anstendig hindring, da du har mye flere stykker og færre gigantiske klasser hvor hvert objekt vet om hvert annet objekt. Det er åpenbart måter rundt dette, for eksempel statiske variabler for kjernekomponenter i spillet ditt (spillere, score osv.), Men det fungerer sjelden for alt (og anbefales ikke), og det finnes avanserte metoder for å strukturere komponentene dine riktig. , og å holde seg avkoblet.

Heldigvis, siden Unity ble bygget med komponenter i tankene, har den en rekke innebygde funksjoner som hjelper oss å oppnå dette. Det er funksjoner for å få referanser til en bestemt komponent, for å kontrollere alle objekter for å se hvilke som inneholder en bestemt komponent etc. Med disse ulike funksjonene kan du enkelt hente den informasjonen som trengs for å lage den magiske enveisgade kunnskapen der komponenter kan kommunisere med objekter de påvirker, men komponenten selv har ingen anelse om hva akkurat den objekten er. Kombiner dette med bruk av grensesnitt, og du har nok programmeringsevne til å ta noen tilnærming til saken, enkel eller kompleks.

Eksempel: Enemy typer

I et OOP arvssystem kan du ha en base Fiende klasse som inneholdt alle funksjoner som de fleste av dine fiender ville bruke, og da kunne du utvide det for å legge til spesifikk funksjonalitet.

Hvis du noen gang har faktisk implementert et slikt system, er du klar over det mellom din base Fiende klasse, og kanskje din base GameObject (eller tilsvarende) klasse, kommer du til slutt med mye unødvendig rot av å ha variabler og funksjoner som noen klasser trenger, men mange gjør det ikke. grensesnitt kan hjelpe med dette, men de er ikke alltid løsningen.

Nå, la oss ta en titt på det samme oppsettet, men tenker med komponenter. Du har fortsatt forskjellige fiender, som alle deler mye felles funksjonalitet, men hver har unike egenskaper.

Det første trinnet er å bryte all funksjonalitet i stykker. Man kan tro det ha helse og døende er en del av det samme systemet, men selv det eksempelet kan brytes opp i en helsekomponent og en dødssystemkomponent. Dette er fordi helsen din er din helse, og ingenting mer. Når det når null, er det ikke opp til helsesystemet å bestemme hva som skjer neste, det er bare opp til helsesystemet å vite at det faktisk er null. Andre systemer, et slikt dødssystem, kan lese denne informasjonen, og deretter velge å gjøre som de ønsker.

Kanskje vil dødssystemet gyte en ny fiende (tenk på en stor fiende som bryter inn i biter); kanskje det vil slippe en power-up; kanskje det vil legge til en eksplosjonseffekt på skjermen. Uansett hva som skjer, er helsystemet ikke en del av det, og det er slik vi lager rene og nyttige komponenter.

Når vi tenker på bevegelse, kan vi tro at all bevegelse må være i et enkelt skript. Men noen fiender i noen spill kan ikke gå; de kan bare hoppe. Noen fiender kan gå, men kan ikke hoppe. Å tenke på disse tingene er hvordan vi ser hvor komponenter kan, og bør eksistere. Når det gjelder mobilitet, kan vi skille hoppet fra å gå eller løpe, å flytte, og så videre, så vil vi gi oss renere kode og mer allsidighet.

Komponenter gjør koden renere (ingen unødvendige variabler og funksjoner), men de gjør også prosessen med å skape fiender langt mer fleksibel og hyggelig. Med hvert stykke fiendtlig funksjonalitet satt opp som en komponent, kan vi dra og slippe aspekter av fiender, og se hvordan de oppfører seg - og til og med i sanntid, hvis vi bruker Unity.

La oss anta at alle de følgende egenskapene allerede er programmert. Under vår fiendskapelsesprosess kunne vi skape tre blanke fiender, som alle er bare tomme prefabs i Unity. Vi kan da trekke på et helsesystem, et elementdråpesystem og et dødssystem, som vi vet at alle våre fiender, uavhengig av forskjeller, vil ha helse, dø og slippe et objekt. Vi kan faktisk velge alle tre prefabsene samtidig, og dra og slipp disse komponentene i Inspektørpanelet, og oppdater alle tre samtidig..

Deretter vet vi at en fiende vil kunne fly, så vi velger den ene fienden, og drar a flying komponent på den. En annen kan se et mål i spillet, og brann på det, så vi kaster på en brann på målet komponent script. Den tredje kan kaste opp en barriere som blokkerer alle angrep i en kort varighet, så vi kaster på barriere komponent.

Vi har nå tre unike fiender, alle deler visse komponenter, men alle har også komponenter som bare gjelder dem. Den hyggelige delen er at det å gjøre disse fiender er enkelt, og å eksperimentere med nye variasjoner er like enkelt som å dra og slippe. Vil du ha en flygende fiende med en barriere som kan målrette mot en fiende og brann på den? Dra alle ovennevnte komponenter til en enkelt fiende, og du har nettopp det!


Konklusjon

Å tenke på komponenter kan ikke være lett, men det har sikkert fordelene. Du vil fortsette å bruke både komponenter og arv i fremtidig programmering, men det er ekstremt verdifullt å utvide mengden måter å nærme seg det samme problemet ved å se ulike perspektiver.

Når det gjelder Unity, kan du bruke hvilken metode du helst foretrekker, men komponenter er definitivt favoriserte, og det er bare ikke fornuftig å kjempe mot en slik fantastisk arbeidsflyt. Å lære enhet og bytte måte å tenke på å jobbe med komponenter har vært en moderat vanskelig hindring for å overvinne, men nå som jeg er her, ser jeg ikke meg selv tilbake snart.