Dette er den andre delen av søket vårt for å skape et 3D-romskytespill. I første del så vi på hvordan du oppretter et grunnleggende PlayCanvas-spill, med fysikk og kollisjon, våre egne modeller og et kamera.
Til referanse, her er en live demo av vårt endelige resultat igjen.
I denne delen skal vi fokusere på dynamisk opprettelse av enheter med skript (for å gyte kuler og asteroider), samt hvordan du legger til ting som en FPS-teller og tekst i spillet. Hvis du allerede har fulgt den forrige delen og er fornøyd med det du har, kan du begynne å bygge fra det og hoppe over følgende minimumoppsett. Ellers, hvis du trenger å starte om fra begynnelsen:
var Fly = pc.createScript ('fly'); Fly.attributes.add ('speed', type: 'nummer', standard: 50); // initialiser kode kalt en gang per enhet Fly.prototype.initialize = function () ; // oppdateringskode kalt hver ramme Fly.prototype.update = function (dt) // Trykk Z for å stryke hvis (this.app.keyboard.isPressed (pc.KEY_Z)) // Flytt i retningen den vender var force = this.entity.forward.clone (). skala (this.speed); this.entity.rigidbody.applyForce (kraft); // Roter opp / ned / venstre / høyre hvis (this.app.keyboard.isPressed (pc.KEY_UP)) var force_up = this.entity.right.clone (). Skala (1); this.entity.rigidbody.applyTorque (force_up); hvis (this.app.keyboard.isPressed (pc.KEY_DOWN)) var force_down = this.entity.right.clone (). skala (-1); this.entity.rigidbody.applyTorque (force_down); hvis (this.app.keyboard.isPressed (pc.KEY_RIGHT)) // Roter til høyre var force_right = this.entity.up.clone (). skala (-1); this.entity.rigidbody.applyTorque (force_right); hvis (this.app.keyboard.isPressed (pc.KEY_LEFT)) var force_left = this.entity.up.clone (). skala (1); this.entity.rigidbody.applyTorque (force_left); ; // swap-metode kreves for manuell opplasting av skript // arve skriptstatus her Fly.prototype.swap = function (old) ; // for å lære mer om manuskriptanatomi, vennligst les: // http://developer.playcanvas.com/no/user-manual/scripting/
Test at alt fungerte. Du bør kunne fly med Z til trykk og piltastene for å rotere!
Dynamisk skape objekter er avgjørende for nesten alle typer spill. I den demoen jeg opprettet, gyter jeg to slags asteroider. Den første typen flyter bare rundt og fungerer som passive hindringer. De respawn når de kommer for langt unna for å skape et konsekvent tett asteroidfelt rundt spilleren. Den andre typen gyter fra lenger unna og beveger seg mot spilleren (for å skape en følelse av fare selv om spilleren ikke beveger seg).
Vi trenger tre ting for å gyte våre asteroider:
Opprett en ny enhet ut av en modell du velger. Dette kan være noe ut av PlayCanvas-butikken, eller noe fra BlendSwap, eller bare en grunnleggende form. (Hvis du bruker dine egne modeller, er det god praksis å åpne den opp i Blender først for å sjekke antall ansikter som brukes og optimalisere det hvis det er nødvendig.)
Gi den en passende kollisjonsform og en stiv kroppsdel (sørg for at den er dynamisk). Når du er fornøyd med det, fjerner du merket av aktivert eske:
Når du deaktiverer et objekt som dette, svarer det til å fjerne det fra verden så langt som spilleren er bekymret. Dette er nyttig for midlertidig å fjerne objekter, eller i vårt tilfelle, for å beholde et objekt med alle dens egenskaper, men ikke å ha det i spillet.
Opprett et nytt skript kalt AsteroidSpawner.js og legg det til Rot objekt i hierarkiet. (Merk at roten bare er et normalt objekt som kan ha noen komponenter som er koblet til det, akkurat som kameraet.)
Åpne nå skriptet du nettopp har opprettet.
Den generelle måten å klone en enhet på og legge den til verden via skript ser slik ut:
// Opprett klonen var newEntity = oldEntity.clone (); // Legg det til rotobjektet this.app.root.addChild (newEntity); // Gi det et nytt navn, ellers blir det også OldEntitys navn newEntity.name = "ClonedEntity"; // Aktiver det, forutsatt at oldEntity er satt til deaktivert newEntity.enabled = true;
Slik kloner du et objekt hvis du allerede hadde et "oldEntity" -objekt. Dette etterlater ett spørsmål ubesvart: Hvordan får vi tilgang til AsteroidModel vi opprettet?
Det er to måter å gjøre dette på. Den mer fleksible måten er å opprette et skriptattributt som inneholder hvilken enhet som skal klones, slik at du enkelt kan bytte modeller uten å berøre skriptet. (Dette er akkurat hvordan vi gjorde kameraet se et script tilbake i trinn 7.)
Den andre måten er å bruke funksjonen findByName. Du kan ringe denne metoden på en hvilken som helst enhet for å finne noen av sine barn. Så vi kan kalle det på rotobjektet:
var oldEntity = this.app.root.findByName ("AsteroidModel");
Og så vil dette fullføre koden ovenfra. Det fulle AsteroidSpawner-skriptet ser nå slik ut:
var AsteroidSpawner = pc.createScript ('asteroidSpawner'); // initialiser kode kalt en gang per enhet AsteroidSpawner.prototype.initialize = function () var oldEntity = this.app.root.findByName ("AsteroidModel"); // Opprett klonen var newEntity = oldEntity.clone (); // Legg det til rotobjektet this.app.root.addChild (newEntity); // Gi det et nytt navn, ellers blir det også OldEntitys navn newEntity.name = "ClonedEntity"; // Aktiver det, forutsatt at oldEntity er satt til deaktivert newEntity.enabled = true; // Sett sin posisjon newEntity.rigidbody.teleport (ny pc.Vec3 (0,0,1)); ; // oppdateringskode kalt hver ramme AsteroidSpawner.prototype.update = function (dt) ;
Test at dette arbeidet ved å starte og se for å se om din asteroidmodell eksisterer.
Merk: Jeg brukte newEntity.rigidbody.teleport
i stedet for newEntity.setPosition
. Hvis en enhet har en stiv kropp, vil den stive kroppen overstyre enhetens posisjon og rotasjon, så husk å sette disse egenskapene på stivbygden og ikke på enheten selv.
Før du går videre, må du prøve å lage ti eller flere asteroider rundt spilleren, enten tilfeldig eller på en systematisk måte (kanskje til og med i en sirkel?). Det ville bidra til å sette all din gytekode inn i en funksjon slik at det ville se slik ut:
AsteroidSpawner.prototype.initialize = function () this.spawn (0,0,0); this.spawn (1,0,0); this.spawn (1,1,0); // etc… ; AsteroidSpawner.prototype.spawn = funksjon (x, y, z) // Gytekode her ...
Du bør være komfortabel å legge til nye skript nå. Opprett et nytt skript (kalt Asteroid.js) og legg det til AsteroidModel. Siden alle våre fremspringte asteroider er kloner, vil de alle ha det samme skriptet knyttet til dem.
Hvis vi lager mange asteroider, vil det være en god ide å sørge for at de blir ødelagt når vi ikke lenger trenger dem eller når de er langt nok unna. Her er en måte du kan gjøre dette på:
Asteroid.prototype.update = function (dt) // Få spilleren var spilleren = this.app.root.findByName ("Ship"); // Erstatt "Ship" med hva spilleren din heter. // Klone asteroidenes posisjon var avstand = this.entity.getPosition (). Klone (); // Trekk spillers posisjon fra denne asteroidens posisjon distance.sub (player.getPosition ()); // Få lengden på denne vektoren hvis (distance.length ()> 10) // Noen vilkårlig grense this.entity.destroy (); ;
Feilsøkingstips: Hvis du vil skrive ut noe, kan du alltid bruke nettleserens konsoll som om dette var en vanlig JavaScript-app. Så du kan gjøre noe sånt console.log (distance.toString ());
å skrive ut avstandsvektoren, og det vil dukke opp i konsollen.
Før du går videre, må du kontrollere at asteroiden forsvinner når du beveger deg bort fra den.
Spawning kuler vil være omtrent den samme ideen som gyte asteroider, med ett nytt konsept: Vi vil oppdage når kulen treffer noe og fjerner den. For å skape vårt kulsystem trenger vi:
Du kan bruke hvilken som helst form for kulen din. Jeg brukte en kapsel bare for å få en ide om hvilken retning kulen stod overfor. Akkurat som før, lag din enhet, skala den ned, og gi den en dynamisk, stiv kropp og en passende kollisjonskasse. Gi det navnet "Bullet", så det blir lett å finne.
Når du er ferdig, må du passe på å deaktivere den (med avmerkingsboksen Aktivert).
Lag et nytt skript og legg det til spillerens skip. Denne gangen skal vi bruke et attributt for å få en referanse til kuleenheten vår:
Shoot.attributes.add ('bullet', type: 'entity');
Gå tilbake til redigeringsprogrammet og klikk på "parse" for det nye attributtet som skal vises, og velg kuleenheten du opprettet.
Nå i oppdateringsfunksjonen, vil vi:
Du har allerede blitt introdusert til alle disse konseptene. Du har sett hvordan du klonerer asteroider, hvordan du bruker en kraft i en retning for å få skipet til å bevege seg, og hvordan du posisjonerer ting. Jeg vil la implementeringen av denne delen være en utfordring. (Men hvis du sitter fast, kan du alltid se på hvordan jeg implementerte mitt eget Shoot.js-skript i prosjektet mitt).
Her er noen tips som kan spare deg for noen hodepine:
keyboard.wasPressed
i stedet for keyboard.isPressed
. Når du oppdager når X-tasten trykkes for å skyte et skudd, er det førstnevnte en enkel måte å gjøre det bare på når du trykker i motsetning til avfyring så lenge knappen holdes.rotateLocal
i stedet for å sette en absolutt rotasjon. For å sikre at kulen alltid springer parallelt med skipet, var det vondt å beregne vinklene riktig. En mye enklere måte er å bare sette kulens rotasjon til skipets rotasjon, og deretter rotere kulen i sitt lokale rom med 90 grader på X-aksen. På dette punktet bør kulene dine gyte, trykke på asteroider, og bare ricocheting inn i tomt rom. Antall kuler kan raskt bli overveldende, og å vite hvordan å oppdage kollisjon er nyttig for alle slags ting. (For eksempel kan du ha lagt merke til at du kan lage objekter som bare har en kollisjonskomponent, men ingen stiv kropp. Disse vil fungere som utløsere, men vil ikke reagere fysisk.)
Opprett et nytt skript kalt Bullet og legg det til din Bullet-modell som blir klonet. PlayCanvas har tre typer kontaktarrangementer. Vi skal lytte til collisionend, som brenner når objektene skiller seg (ellers vil kula bli ødelagt før asteroiden har en sjanse til å reagere).
For å høre inn på en kontakthendelse, skriv dette inn i init-funksjonen din:
this.entity.collision.on ("collisionend", this.onCollisionEnd, dette);
Og så opprett lytteren selv:
Bullet.prototype.onCollisionEnd = function (result) // Destroy kule hvis den treffer en asteroide hvis (result.name == "Asteroid") this.entity.destroy (); ;
Dette er hvor navnet du ga til asteroiderne dine når du kom til dem, blir relevant. Vi vil at kulen bare skal bli ødelagt når den kolliderer med en asteroid. resultat
Er enheten det ferdig med å kollidere med.
Alternativt kan du fjerne den sjekken og bare få den ødelagt på kollisjon med noe.
Det er sant at det ikke er noen andre objekter i verden å kollidere med, men jeg har noen problemer tidlig med spilleren som utløser kollens kollisjon for en ramme og den forsvinner før den kan starte. Hvis du har mer kompliserte kollisionsbehov, støtter PlayCanvas kollisjonsgrupper og masker, men det er ikke veldig godt dokumentert når du skriver.
Vi er i hovedsak ferdig med spillet selv på dette punktet. Selvfølgelig er det mange små polske ting jeg la til den endelige demoen, men det er ingenting der du ikke kan gjøre med det du har lært så langt.
Jeg ønsket å vise deg hvordan du lager en FPS meter (selv om PlayCanvas allerede har en profiler, du kan svinge over spillknappen og sjekke profilerboksen) fordi det er et godt eksempel på å legge til et DOM-element som er utenfor PlayCanvas-motoren.
Vi skal bruke dette slanke FPSMeter-biblioteket. Det første du må gjøre er å gå over til bibliotekets nettside og laste ned den reduserte produksjonsversjonen.
Gå tilbake til PlayCanvas-editoren, opprett et nytt skript, og kopier over fpsMeter.min.js-koden. Fest dette skriptet til rotobjektet.
Nå som biblioteket er lastet opp, opprett et nytt skript som vil initialisere og bruke biblioteket. Kaller det meter.js, og fra brukseksemplet på bibliotekets nettside har vi:
var meter = pc.createScript ('meter'); Meter.prototype.initialize = function () this.meter = ny FPSMeter (document.body, graph: 1, heat: 1); ; Meter.prototype.update = funksjon (dt) this.meter.tick (); ;
Legg også målerskriptet til rotobjektet og start. Du bør se FPS-telleren øverst til venstre på skjermen!
Til slutt, la oss legge til litt tekst i vår verden. Denne er litt involvert siden det er ulike måter å gjøre det på. Hvis du bare vil legge til statisk brukergrensesnitt, er det enkelt å jobbe med DOM, og overlegger brukergrensesnittene dine på toppen av PlayCanvas lerretelement. En annen metode er å bruke SVGer. Dette innlegget diskuterer noen av disse forskjellige måtene.
Siden disse er alle standard måter å håndtere tekst på nettet, har jeg valgt i stedet å se på hvordan man lager tekst som eksisterer innenfor spillverdenen. Så tenk på det som tekst som ville gå på et skilt i miljøet eller et objekt i spillet.
Måten vi gjør dette på er å skape en materiale for hvert stykke tekst vi vil gjengi. Vi lager deretter en usynlig lerret at vi gjør teksten til å bruke det kjente lerretet fillText-metoden. Til slutt, vi gjør lerretet på materialet å få det til å vises i spillet.
Merk at denne metoden kan brukes til mer enn bare tekst. Du kan dynamisk tegne teksturer eller gjøre alt et lerret kan gjøre.
Lag et nytt materiale og kaller det noe som "TextMaterial". Sett sin diffuse farge til svart siden teksten vår blir hvit.
Lag en plan enhet og legg ved dette materialet til det.
Du kan finne hele text.js-skriptet i dette nettverket:
https://gist.github.com/OmarShehata/e016dc219da36726e65cedb4ab9084bd
Du kan se hvordan det setter opp tekstur for å bruke lerretet som kilde, spesielt på linjen: this.texture.setSource (this.canvas);
Lag dette skriptet og legg det til flyet ditt. Legg merke til hvordan det skaper to attributter: tekst og skriftstørrelse. På denne måten kan du bruke det samme skriptet for ethvert tekstobjekt i spillet ditt.
Start simuleringen, og du bør se den store "Hello World" -teksten et sted rundt. Hvis du ikke ser det, må du kontrollere at a) den har en lyskilde i nærheten, og b) du ser på den rette siden av den. Teksten blir ikke gjengitt hvis du ser på den bakfra. (Det hjelper også å plassere et fysisk objekt i nærheten av flyet for å finne det først.)
Når du har satt sammen din fantastiske prototype, kan du klikke på PlayCanvas-ikonet øverst til venstre på skjermen og velge "Publisering". Her kan du publisere nye bygg som skal være vert på PlayCanvas og dele dem med verden!
Det er det for denne demonstrasjonen. Det er mye mer å utforske i PlayCanvas, men forhåpentligvis blir denne oversikten komfortabel nok med det grunnleggende for å begynne å bygge dine egne spill. Det er en veldig fin motor som jeg tror flere folk skal bruke. Mye av det som er opprettet med det, har vært teknologiske demoer fremfor fulle spill, men det er ingen grunn til at du ikke kan bygge og publisere noe gøy med det.
En funksjon jeg ikke snakket om, men kanskje har vært tydelig, er at PlayCanvas redaktør lar deg oppdatere spillet ditt i sanntid. Dette gjelder for design, ved at du kan flytte ting i redigeringsprogrammet, og de vil oppdatere i lanseringsvinduet hvis du har det åpent, så vel som for kode, med hot-reloading.
Til slutt, mens redaktøren er veldig praktisk, kan alt du kan gjøre med det, gjøres med ren kode. Så hvis du trenger å bruke PlayCanvas på et budsjett, er en god referanse til bruk eksemplermappen på GitHub. (Et godt sted å starte ville være dette enkle eksempelet på en spinnende kube.)
Hvis noe er forvirrende i det hele tatt, vennligst gi meg beskjed i kommentarene! Eller bare hvis du har bygget noe kul og vil dele, eller funnet ut en enklere måte å gjøre noe, vil jeg gjerne se!