Hvordan bygge et Prince-of-Persia-Style Time-Rewind System, del 1

Hva du skal skape

I denne opplæringen bygger vi et enkelt spill hvor spilleren kan spole fremgang i enhet (det kan også tilpasses til arbeid i andre systemer). Denne første delen vil gå inn i systemets grunnleggende, og neste del vil kutte den ut og gjøre den mye mer allsidig.

Først, selv om vi tar en titt på hvilke spill som bruker dette. Da ser vi på de andre bruksområdene for dette tekniske oppsettet, før du til slutt lager et lite spill som vi kan spole tilbake, noe som burde gi deg et grunnlag for din egen.

En demonstasjon av grunnleggende funksjonalitet

Du trenger den nyeste versjonen av Unity for dette, og bør ha litt erfaring med det. Kildekoden er også tilgjengelig for nedlasting hvis du vil sjekke din egen fremgang mot den.

Klar? La oss gå!

Hvordan har dette vært brukt før?

Prince of Persia: Sands of Time er et av de første spillene som virkelig integrerer en tidssvingende mekaniker i sin gameplay. Når du dør, trenger du ikke bare å laste på nytt, men kan heller spole om spillet i noen sekunder til hvor du levde igjen, og prøv igjen igjen.

Prince of Persia: The Forgotten Sands. De Sands Of Time Trilogi integrerer tidspoling vakkert inn i sin gameplay og unngår nedsenkende hurtigopplasting.

Denne mekanikeren er ikke bare integrert i gameplayet, men også fortellingen og universet, og er nevnt gjennom historien.

Andre spill som bruker disse systemene er Flette, for eksempel, som også er sentrert rundt tidenes vikling. Helten Tracer i Watch har en kraft som tilbakestiller henne til en stilling for noen få sekunder siden, hovedsakelig tilbakespoling hennes tid, selv i et multiplayer spill. De NETT-serie racer spill har også en snapshot-mekaniker, hvor du har et lite basseng med tilbakevending under et løp, som du kan få tilgang til når du har en kritisk krasj. Dette forhindrer frustrasjon forårsaket av krasjer nær slutten av rase, noe som kan være spesielt irriterende.


Når du har en dødelig krasj i NETT du får sjansen til å spole spillet til et punkt før krasj.

Andre bruksområder

Men dette systemet kan ikke bare brukes til å erstatte hurtigbesparende. En annen måte dette er ansatt er spøkelse i racing spill og asynkron multiplayer.

replays

Replays er en annen morsom måte å benytte denne funksjonen på. Dette kan ses i spill som SUPER VARMT, de orm serien, og stort sett flertallet av sportsspill.

Sports-replays fungerer på samme måte som de presenteres på TV, hvor en handling vises igjen, muligens fra en annen vinkel. For dette er ikke en video innspilt, men snarere handlinger av brukeren, slik at replayen kan benytte forskjellige kameravinkler og bilder. The Worms-spillene bruker dette på en humoristisk måte, hvor svært komiske eller effektive drep vises i et øyeblikkelig replay.

SUPERHOT registrerer også bevegelsen din. Når du er ferdig med å spille rundt, blir hele fremgangen din igjen, og viser noen få sekunder av den faktiske bevegelsen som skjedde.

Super Meat Boy bruker dette på en morsom måte. Når du er ferdig med et nivå, ser du et replay av alle dine tidligere forsøk på toppen av hverandre, som kulminerer med ferdigkjøringen din som den siste venstre stående.

End-of-level replay i Super Meat Boy. Hver en av dine tidligere forsøk er innspilt og deretter spilt samtidig.

Time-Trial Ghosts

Race-Ghosting er en teknikk hvor du kjører for den beste tiden på et tomt spor. Men samtidig løp du mot a spøkelse, som er en spøkelsesaktig, gjennomsiktig bil, som kjører den nøyaktige måten du kjørte før på ditt beste forsøk. Du kan ikke kollidere med det, noe som betyr at du fortsatt kan konsentrere deg om å få den beste tiden.

I stedet for å kjøre alene kommer du til konkurrere mot deg selv, noe som gjør tidforsøk mye morsommere. Denne funksjonen vises i de fleste racing spill, fra Behov for fart serie til Diddy Kong Racing.

Kjører et spøkelse i Trackmania Nations. Denne har sølvproblemet, noe som betyr at jeg vil få sølvmedaljen hvis jeg slår dem. Legg merke til overlappingen i bilmodeller, slik at spøkelsen ikke er kroppslig og kan kjøres gjennom.

Multiplayer-Ghosts

Asynkron Multiplayer-Ghosting er en annen måte å bruke dette oppsettet på. I denne sjelden brukte funksjonen blir multiplayer-kamper oppnådd ved å registrere dataene til en spiller, som deretter sender kjøringen til en annen spiller, som senere kan kjempe imot den første spilleren. Dataene blir brukt på samme måte som et tidsforsøk-spøkelse ville være, bare at du kjører mot en annen spiller.

En form for dette dukker opp i Trackmania-spill, hvor det er mulig å løpe mot visse vanskeligheter. Disse innspilte racerne vil gi deg en motstander til å slå for en viss belønning.

Film-redigering

Få spill tilbyr dette fra get-go, men brukt riktig, det kan være et morsomt verktøy.Team Fortress 2 tilbyr en innebygd replay-editor, som du kan lage egne klipp til.

Replay editor fra Team Fortress 2. Når det er registrert, kan en kamp sees fra ethvert perspektiv, ikke bare spilleren.

Når funksjonen er aktivert, kan du registrere og se tidligere kamper. Det viktige elementet er det alt er registrert, ikke bare visningen din. Dette betyr at du kan bevege deg rundt den spillte spillverdenen, se hvor alle er, og har kontroll over tid.

Hvordan bygge den

For å teste dette systemet trenger vi et enkelt spill der vi kan teste det. La oss lage en!

Spilleren

Lag en kube i din scene, dette vil være vår spiller-karakter. Deretter oppretter du et nytt C # -script-anrop Player.cs og tilpasse Oppdater()-funksjon for å se slik ut:

ugyldig oppdatering () transform.Translate (Vector3.forward * 3.0f * Time.deltaTime * Input.GetAxis ("Vertikal")); transform.Rotate (Vector3.up * 200.0f * Time.deltaTime * Input.GetAxis ("Horizontal")); 

Dette vil håndtere enkel bevegelse via piltastene. Fest dette skriptet til spillerens terning. Når du nå treffer spill, bør du allerede kunne flytte rundt.

Vink deretter kameraet slik at det ser kuben ovenfra, med plass på siden der vi kan flytte den. Til slutt, opprett et fly for å fungere som gulv og tilordne noen forskjellige materialer til hver gjenstand, slik at vi ikke beveger den inn i et tomrom. Det skal se slik ut:

Prøv det, og du bør kunne flytte kuben din med WSAD og piltastene.

TimeController

Opprett nå et nytt C # -script kalt TimeController.cs og legg det til en ny, tom GameObject. Dette vil håndtere selve opptaket og påfølgende spoling av spillet.

For å gjøre dette arbeidet, registrerer vi bevegelsen av spillerens karakter. Når vi trykker på tilbakespolingsknappen, vil vi tilpasse spillerens koordinater. For å gjøre det, begynn å opprette en variabel for å holde spilleren slik som denne:

offentlig GameObject-spiller;

Og tilordne spillerobjektet til den resulterende sporet på TimeController, slik at den kan få tilgang til spilleren og dens data.

Da må vi lage en matrise for å holde spillerdataene:

offentlig ArrayList playerPositions; void Start () playerPositions = new ArrayList (); 

Det vi skal gjøre neste gang, registrerer spillerenes posisjon. Vi vil ha posisjonen lagret der spilleren var i den siste rammen, stillingen hvor spilleren var 6 bilder siden, og stillingen hvor spilleren var 8 sekunder siden (eller hvor lenge du vil sette den på record). Når vi senere treffer en knapp, går vi bakover gjennom vårt utvalg av stillinger og tildeler det ramme for ramme, noe som resulterer i en tidsavspoling av funksjonen.

La oss først lagre dataene:

void FixedUpdate () playerPositions.Add (player.transform.position); 

I FixedUpdate ()-funksjon vi registrerer dataene. FixedUpdate () brukes som det kjører med konstant 50 sykluser per sekund (eller hva du setter det til), noe som gjør det mulig for et fast intervall å registrere og sette dataene. De Oppdater()-funksjonen kjører i mellomtiden avhengig av hvor mange rammer CPUen håndterer, noe som vil gjøre tingene vanskeligere.

Denne koden lagrer spillerposisjonen til hver ramme i matrisen. Nå må vi søke det!

Vi legger til en sjekk for å se om tilbakespolingsknappen ble trykket. For dette trenger vi en boolsk variabel:

offentlig bool erReversing = false;

Og en innsjekking i Oppdater()-funksjonen til å stille det i henhold til om vi vil spole tilbake spillingen:

ugyldig oppdatering () if (Input.GetKey (KeyCode.Space)) isReversing = true;  else isReversing = false; 

For å få spillet til å løpe bakover, Vi vil bruke dataene i stedet for opptakDen nye koden for innspilling og bruk av spillerens stilling skal se slik ut:

void FixedUpdate () if (! isReversing) playerPositions.Add (player.transform.position);  ellers player.transform.position = (Vector3) playerPositions [playerPositions.Count - 1]; playerPositions.RemoveAt (playerPositions.Count - 1); 

Og hele TimeController-skript slik:

bruker UnityEngine; bruker System.Collections; offentlig klasse TimeController: MonoBehaviour offentlig GameObject player; offentlig ArrayList playerPositions; offentlig bool erReversing = false; void Start () playerPositions = new ArrayList ();  ugyldig oppdatering () hvis (Input.GetKey (KeyCode.Space)) isReversing = true;  else isReversing = false;  void FixedUpdate () hvis (! erReversing) playerPositions.Add (player.transform.position);  ellers player.transform.position = (Vector3) playerPositions [playerPositions.Count - 1]; playerPositions.RemoveAt (playerPositions.Count - 1); 

Også, ikke glem å legge til en sjekk til spiller-klasse for å se om TimeController er for øyeblikket tilbakespoling eller ikke, og bare bevege seg når den ikke går tilbake. Ellers kan det opprette buggy atferd:

bruker UnityEngine; bruker System.Collections; offentlig klasse Spiller: MonoBehaviour privat TimeController timeController; void Start () timeController = FindObjectOfType (typeof (TimeController)) som TimeController;  ugyldig oppdatering () hvis (! timeController.isReversing) transform.Translate (Vector3.forward * 3.0f * Time.deltaTime * Input.GetAxis ("Vertical")); transform.Rotate (Vector3.up * 200.0f * Time.deltaTime * Input.GetAxis ("Horizontal"));  

Disse nye linjene vil automatisk finne TimeController-objekt i scenen ved oppstart og sjekk det under kjøretid for å se om vi for øyeblikket spiller spillet eller spoler det. Vi kan bare kontrollere tegnet når vi for øyeblikket ikke er reverseringstid.

Nå skal du kunne bevege deg rundt i verden, og spole bevegelsen din ved å trykke på mellomrom. Hvis du laster ned byggepakken som er vedlagt denne artikkelen og åpnes TimeRewindingFunctionality01 du kan prøve det ut!

Men vent, hvorfor fortsetter vår enkle spiller-kube i den siste retningen vi forlot dem? Fordi vi ikke kom seg rundt for å også registrere rotasjonen!

For det trenger du en annen matrise for å beholde rotasjonsverdiene, for å instantiere den i begynnelsen, og for å lagre og bruke dataene på samme måte som vi håndterte posisjonsdata.

bruker UnityEngine; bruker System.Collections; offentlig klasse TimeController: MonoBehaviour offentlig GameObject player; offentlig ArrayList playerPositions; offentlig ArrayList playerRotations; offentlig bool erReversing = false; void Start () playerPositions = new ArrayList (); playerRotations = ny ArrayList ();  ugyldig oppdatering () hvis (Input.GetKey (KeyCode.Space)) isReversing = true;  else isReversing = false;  void FixedUpdate () hvis (! erReversing) playerPositions.Add (player.transform.position); playerRotations.Add (player.transform.localEulerAngles);  ellers player.transform.position = (Vector3) playerPositions [playerPositions.Count - 1]; playerPositions.RemoveAt (playerPositions.Count - 1); player.transform.localEulerAngles = (Vector3) playerRotations [playerRotations.Count - 1]; playerRotations.RemoveAt (playerRotations.Count - 1); 

Prøv det! TimeRewindingFunctionality02 er den forbedrede versjonen. Nå kan vår spiller-kube bevege seg bakover i tid, og vil se på samme måte som den gjorde da det var i det øyeblikket.

Konklusjon

Vi har bygget et enkelt prototypespill med et allerede brukbart tidsavspolingssystem, men det er langt fra ferdig ennå. I neste del av denne serien vil vi gjøre den mye mer stabil og allsidig, og legge til noen pene effekter. 

Her er det vi fortsatt trenger å gjøre:

  • Bare ta opp hver 12. ramme og interpolere mellom de opptakene som er lagret på den store datalasten
  • Bare skriv inn de siste ~ 75 spillernes posisjoner og rotasjoner for å sikre at arrayet ikke blir for uhåndterlig og spillet ikke krasjer

Vi vil også se på hvordan du utvider dette systemet forbi bare spillerkarakteren:

  • Spill inn mer enn bare spilleren
  • Legg til en effekt som betyr at tilbakespoling skjer (som VHS-uskarphet)
  • Bruk en egendefinert klasse for å holde spillerens posisjon og rotasjon i stedet for arrays