Rom Nyttige spillobjektbeholdere

Hele poenget med a rom er å holde spillobjekter. Spillobjektene i ett rom burde ikke ha noen måte å kommunisere med spillobjektene i et annet rom, slik at mellomrom gir en enkel måte å skille forskjellige grupper av spillobjekter. I denne artikkelen lærer du fordelene ved en slik arkitektur.

Hvis du vil se et eksempel på implementering av mellomrom, vennligst se åpen kildekode spillmotor SEL. Jeg selv er aktivt forfatter SEL og er stolt over å presentere den som en fullt funksjonell ressurs for leserne av denne artikkelen.

Jeg vil gjerne takke Sean Middleditch for å lære meg om fordelene med Spaces.

Tips: Begrepet rom i sammenheng med denne artikkelen refererer til en spesiell beholder med spillobjekter. Jeg er egentlig ikke klar over et klart definert offisielt begrep. Hvis du vet om en, vær så snill å kommentere!


Konvensjonell objekthåndtering

I en konvensjonell spillmotor lagres spillobjekter vanligvis i en enkelt beholder. En slik beholder kan være en fordeler sammen med en håndtakshåndterer. Noen ganger er beholderen bare en koblet liste. Uansett hva den faktiske implementeringen er, kan det være bare en enkelt beholder som holder alle spillobjekter, og hvert spillobjekt er alltid i denne beholderen.

Dette er greit og fungerer helt, men det har noen organisatoriske problemer. For eksempel, tenk en tradisjonell spilltilstandsfører. Ofte, mellom overgangen fra en stat til en annen, blir alle nåværende spillobjekter frigjort og nye leses inn fra disken. Som en optimalisering kan spillobjekter for den neste tilstanden (eller nivået) lastes på en separat tråd på forhånd slik at tilstandsoverganger er øyeblikkelige.

Det er imidlertid et irriterende problem som ofte oppstår: Hvordan representerer vi GUI-elementer for menyer? Kanskje spilleren HUD er kodet ved hjelp av spillobjekter og skript knyttet til disse spillobjektene. En naiv implementering av statlig ledelse vil kreve at alle HUD-elementer blir ødelagt og gjenopprettet ved overgang av staten. Dette betyr at egendefinert kode vil være nødvendig for å håndtere overgangen til bestemte objekter fra en stat til en annen.

Eller kanskje et spilldesign krever gal bakgrunnsområde der noe stort slag skjer - men dette slaget må ikke forstyrre forgrunnen (eller spilleren) på noen måte.

Ofte oppstår rare, raske løsninger for slike ting, som for eksempel å representere HUD-elementer som ekstremt langt unna resten av spillingen i verden. Pause-menyer og lignende blir bare flyttet til visning når det trengs, og flyttes ellers. Vanligvis er egendefinert kode kreves for å administrere og organisere spillobjekter, da de alle ligger på en enkelt fabrikk eller container.


Flere spillobjektbeholdere

En akseptabel løsning på dette problemet ville være å benytte mellomrom (se den ekstra videobeskrivelsen av min kollega Sean Middleditch). Siden alle spillobjekter i hvert mellomrom har null interaksjon, blir mellomrom en naturlig måte å nærme seg organisering av spillobjekter. Dette kan i stor grad redusere behovet for spesiell kode for å opprettholde en separat logisk beholder innenfor en faktisk container (som nevnt i forrige avsnitt).

La oss ta en rask titt på et eksempel på hva en plassimplementering kan se ut på et språk som ligner på C ++:

 klasse Space public: GameObject CreateObject (strengnavn); const streng GetName (void) const; privat: streng m_name; // Kan være noen form for tildeler, kanskje bare en std :: vektor Container m_objects; ;

Det er ofte nyttig å kunne slå opp et mellomrom ved navn. Dette er spesielt flott for skript der et skript kan bruke kode som dette:

 // Kjør litt logikk for bakgrunnen lokal plass = GetSpace ("Bakgrunn") tornado = space.CreateObject ("Tornado") // Ellers kan vi gjøre noe helt isolert fra bakgrunnen, // som å hente spilleren (som for noen grunnen døde) og spiller en // død animasjon over toppen av spilleren lokal plass = GetSpace ("CurrentLevel") player = space.GetPlayer () space.CreateObjectAt ("DeathAnimation", spiller)
Diagram som viser den enkle organisasjonen av spillobjekter i isolerte beholdere. Ikke alle mellomrom har like mange spillobjekter, eller til og med de samme spillobjektene.

Hvilke objekter går inn i rom?

Svaret på dette spørsmålet er: alle av dem! Enhver type spillobjekt vil bli plassert i et mellomrom. Hvis du er kjent med aggregering (eller komponentbasert design), vil et spillobjekt og tilhørende komponenter alle ligge innenfor samme rom.

Tanken er å skape en arkitektonisk funksjon for å tillate en enkel og effektiv måte å gruppere spillobjekter sammen og isolere dem fra andre grupper.

Terminologi

Spaces er ganske liknende noen andre begreper som har vært flytende rundt for en stund nå. Det har blitt sagt at mellomrom er relatert til visningslisten i Flash. Hvis du er kjent med portaler for gjengjøring (spesielt viktig i 3D-spill med mange interiørrom), er ideen ganske lik her også.

Det er imidlertid et viktig skille å gjøre her. Rom er ikke en form for romlig partisjonering som gjøres med portaler eller annen mellomrom (f.eks. det populære BSP-treet) for å gjøre okklusjon. Rom er en arkitektonisk funksjon for å tillate isolasjon av generelle spillobjekter.

Personlig liker jeg å tenke på mellomrom som Photoshop-lag: alle lagene kan vises (eller høres) samtidig, men når de maler på et lag, blir ingen andre lag noen gang direkte berørt; hvert lag er unikt og isolert.

Systemer og rom

Konseptet med a system, i forbindelse med denne artikkelen kan beskrives som et sett med funksjonalitet (funksjoner eller metoder) som opererer på spillobjektene til et mellomrom. På denne måten blir et rom levert til et system for å utføre noen handlinger; et bestemt system er globalt for hele spillet.

Diagram som eksemplifiserer enkelheten ved å tillate et system å operere på et mellomrom som input.

Tenk deg et grafikksystem som inneholder en void Graphics :: DrawWorld (Space space) funksjon. Dette DrawWorld funksjonen ville sløyfe over objektene innenfor den oppgitte plassen som kan gjengis og tegne dem på skjermen.

Tanken er nå å skrive kode (systemer) som opererer på en gitt inngang av spillobjekter. Ingen spesiell sporing eller styring av spillobjekter må skje innen slike systemer. Et system bør ikke gjøre noe unntatt utføre operasjoner på spillobjekter.

Denne stilen gir deg noen flotte fordeler, som beskrevet i neste avsnitt.


Fordeler med rom

Den mest umiddelbare fordelen med å implementere mellomrom i en motor er at håndteringen av GUI-elementer eller -menyer blir trivial. Vi kan konstruere en plass dedikert til en bestemt meny, og når denne menyen er inaktiv, trenger systemene ganske enkelt ikke å fungere på innholdet i rommet. Når en meny er inaktiv, sitter den i minnet (spillobjektene som består av minnet sitter i menyplassen) og gjør ingenting; det blir heller ikke oppdatert av et logisk system eller gjengitt av et grafikksystem.

Når denne menyen blir aktiv igjen, kan den enkelt overlates til de aktuelle systemene. Menyen kan da oppdateres og gjengis på riktig måte. Samtidig kan spillingen som foregår bak menyen, opphøre å bli oppdatert på noen måte, selv om det kanskje fortsatt er overført til grafikksystemet som skal gjengis. Dette implementerer trivielt en elegant og robust pause og gjenopptatt type funksjonalitet som bare kommer implisitt på grunn av måten mellomrom er definert.

Isolerte nivåer

Ofte, i RPG-spill som Pokémon, vil spilleren komme inn og forlate hus og hytter. Når det gjelder gameplay er disse forskjellige husene vanligvis helt isolerte; Små hus eller grotter er et ideelt scenario for å søke mellomrom. En hel plass kan bygges for å inneholde spillobjektene til et bestemt hus, og disse kan lastes og initialiseres i minnet og hvile til det er nødvendig. Øyeblikkelige overganger kan oppnås ved å bytte ut hvilken plass som blir overlevert til de ulike motorsystemene.

En kul ide for 2D-spill som plattformspillere (eller til og med 3D-spill) kan være å simulere faktiske nivåer og fiender fra spillet i bakgrunnen. Dette kan bringe verden til liv på en måte som faktisk ikke krever noe ekstra innhold, og neppe noen ekstra utviklingstid. Det beste eksempelet jeg kunne finne av dette er Rayman Legends:


Faktiske fiender, det samme som spilleren ser normalt, kan hoppe rundt eller krype på veggene i det fjerne. Overganger mellom disse forskjellige "lagene" kan gi noen svært interessante designmuligheter.

Disse mulighetene er egentlig ganske sjeldne å finne eksempler på, og ideen om mellomrom er egentlig ikke omfavnet av moderne AAA-studioer eller -motorer. Imidlertid er designen solid og fordelene er ekte.

Lokalt multiplayer

I mange spill med multiplayer-støtte der begge spillerne spiller med samme spillklient, er det noen begrensninger. Ofte kan spillerne ikke gå til et nytt område uten å være i nærheten av hverandre. Noen ganger kan spillerne ikke engang forlate hverandres skjerm. Dette kan skyldes spilldesign, men jeg har en mistanke om at det ofte skyldes arkitektoniske begrensninger.

Med mellomrom kan vi støtte to spillere, kanskje med splittede skjermer, reise fra ett nivå eller bygge til en annen. Hver spiller kan bo i samme rom, eller i to separate mellomrom. Når hver spiller er i en annen bygning, kan de begge være i to separate mellomrom. En de konvergerer på samme område, kan motoren overføre en av spillerens spillobjekter til det motsatte rommet.

Editor Support

Dette er definitivt min favoritt eksempel på hvordan mellomrom er kjempebra. I redaktører er det ofte seksjoner der du kan utvikle en ny type objekt. Dette objektet i opprettelsen vil vanligvis ha et visningsport for å forhåndsvise opprettelsen som en utvikling av hums sammen.

Det kan være umulig for de fleste motorer å naturlig støtte en slik redaktør. Hva om brukeren endrer posisjonen og det plutselig kolliderer med simuleringen og banker ting over, eller aktiverer noen AI? Tilpasset kode må opprettes for å kunne håndtere objektet i minnet på en eller annen måte. Enten spesiell isolasjonskode, eller noen formidlingsformat, må redigeres og oversettes fra redaktøren til den faktiske simuleringen. Intermediære trinn kan være noen form for serialisering, eller komplisert ikke-påtrengende dummy "proxy objekt". Proxy objekter kan ofte kreve avansert kodeintrospeksjon å bli implementert på en nyttig måte. Disse alternativene kan være dyre eller unødvendige for mange prosjekter.

Men hvis man har rom til disposisjon, kan en kamerobjekt og objektet i skapelsen plasseres i et isolert rom. Denne plassen kan da overlates til hvilke systemer som er nødvendige og håndteres isolert grasiøst. Ingen spesiell sakskode eller ytterligere forfatterskap ville være nødvendig i et slikt scenario.

Flere nivåer kan opprettholdes innenfor redaktører med letthet. Flere visningsportaler og simuleringer kan kjøre i isolasjon samtidig. Hva om en utvikler ønsket å dele skjermbildet for utvikling av to nivåer for å bytte frem og tilbake raskt? Dette kan være en vanskelig programvare engineering-oppgave, eller redaktørarkitekturen kan implementere noen form for mellomrom.


Implementeringsideer

Space Management

Hva håndterer alle mellomrom? Mange spillutviklere kan ha det i deres praksis at alt må kunne eies av noen leder. Alle mellomrom må kunne styres av denne ene enheten, ikke sant? Faktisk er denne typen paradigme bare ikke nødvendig hele tiden.

I SEL-motoren er mellomrom konstruert fra ett sted, og det kan søkes etter navn med en ordliste, men det kan være best for de fleste prosjekter å bare la mellomrom administreres i hvert enkelt tilfelle. Ofte er det bare fornuftig å skape et mellomrom innenfor noen tilfeldig skript, hold deg til det en stund, og slipp deretter ut plass. Andre ganger opprettes et mellomrom og setter i minnet hele varigheten av spillets kjøretid.

En god anbefaling ville være å bare la brukeren tildele en plass og frigjøre den etter ønske. Det ville trolig være bra å bruke en enkelt tildeler for denne oppførselen. Imidlertid kan forvaltningen av rominstansen selv, som funnet gjennom erfaring, være best ikke bekymret for; la det være til brukeren.

Merk: Når et rom er ødelagt, skal det rydde opp alle gjenstandene i! Ikke forveksle mangelen på en leder med mangel på livstidsadministrasjon.

Komponenter og underrom

Komponenter registreres ofte med sine respektive systemer i en komponentbasert motor. Men med mellomrom blir dette unødvendig. I stedet bør hvert mellomrom inneholde det som kalles a underrom. Et underrom kan være veldig trivielt å implementere-si, som en vektor av komponentobjekter. Tanken er å bare inneholde ulike typer komponentbeholdere innenfor hvert rom. Når en komponent er konstruert, spør den om hvilken plass den skal tilknyttes, og registrerer seg med underrommet.

Et mellomrom trenger ikke nødvendigvis å ha hver enkelt type underrom i seg selv. For eksempel vil et menyrom trolig ikke trenge noen fysisk simulering, og kan derfor ikke ha en hel forekomst av en fysikkverden som representerer et fysisk underrom.

Til slutt skal det bemerkes at i en komponentbasert arkitektur må spillobjektene ha et håndtak eller en peker til det rommet de bor i. På denne måten blir plassen en del av den unike identifikatoren til selve spilletobjektet.


Konklusjon

Rom er svært enkle å implementere og gir mange viktige fordeler. For stort sett alle spill og spillmotor i eksistens, vil tillegg av mellomrom være en positiv på grunn av den enkle implementeringen. Bruk mellomrom, selv for svært små prosjekter og veldig små spill!

Som en ressurs er min egen implementering av mellomrom åpen kilde for offentlig visning i spillmotor SEL.