Skyttere og spill som bruker partikkelsystemer må lage, manipulere og fjerne mange gjenstander samtidig - kanskje til og med hundrevis per ramme. Dette kan føre til at spillet forsinker eller til og med fryser. I denne opplæringen ser vi på hvordan objekt bassenger kan hjelpe med dette problemet ved å tillate oss å gjenbruke gjenstander i stedet for å gjenskape dem fra bunnen av.
Merk: Selv om denne opplæringen er skrevet ved hjelp av Java, bør du kunne bruke de samme teknikkene og konseptene i nesten hvilket som helst spillutviklingsmiljø.
En vanlig forekomst i skyttere og partikkelsystemer er å lage og slette mange objekter i rask rekkefølge. Fra skytevåpen til å støpe magiske staver, kan det være en dyr operasjon å skape og slette objekter som trengs. Når mange av disse operasjonene utføres raskt, kan det føre til at spillet lagrer eller fryser.
Årsaken er at et bakgrunnsprogram kalt søppelmann krever systemressurser for å rydde opp brukt minne. Det er dette rydde opp som kan føre til at systemet slår seg.
En måte å forhindre dette på er å bruke et objektbasseng for å gjenbruke gamle objekter i stedet for å slette dem.
For å forstå hvorfor et objektbasseng er nødvendig, må vi først forstå hvordan søppelsamling fungerer.
Søppelsamling er prosessen med automatisk ressursforvaltning. Det er ansvarlig for å frigjøre minneplass for gjenbruk når det ikke lenger er nødvendig.
Ta en titt på følgende eksempel på en enkel til
løkke:
for (int i = 1; i < 10; i++) System.out.println(i);
Når et program kjører denne sløyfen, vil det opprette en variabel Jeg
ved å tildele nok minne til å holde variabelenes data (i dette tilfellet, nok plass til å holde et heltall). Når sløyfen er ferdig, variabelen Jeg
er ikke lenger nødvendig Programmet vil etter hvert oppdage dette, og kan deretter frigjøre minnet til andre bruksområder.
For det meste skjer søppelinnsamling automatisk og uten varsel. Noen ganger, men hvis mye minne må frigjøres på en gang, kan søppelsamling tvinge programmet til å bruke verdifulle systemressurser for å frigjøre det nødvendige minnet. Dette kan føre til at programmet lagres eller fryser midlertidig, da dette tar tid.
Systemet kan også lagres når mye minne er nødvendig på en gang for å lage nye objekter. Dette skyldes at tildeling av minne kan være like ressursintensivt som å frigjøre det.
På grunn av dette blir det viktig å administrere søppelsamling slik at det ikke forstyrrer programmet.
Et objektbasseng er en datastruktur som gjenbruker gamle gjenstander for ikke å kontinuerlig opprette eller slette nye. I stedet for å tildele nytt minne til et objekt og deretter frigjøre det når vi er ferdige med det, holder vi bare gjenbruk av objektet igjen og igjen ved å endre verdiene. På denne måten må ikke minnet frigjøres, og dermed unngå søppelsamling.
Pooling av ressurser kan gi et betydelig ytelsesforhøyelse i situasjoner hvor kostnadene ved å initialisere en klasseeksempel er høy, hvorvidt en klasse er opprettet, er høy og antall forekomster i bruk til enhver tid er lave.
Tenk på det som et kort kort hvor dekket representerer minne. Hver gang du trenger et nytt kort (det vil si at du trenger et nytt objekt), tegner du en fra kortstokken og bruker den. Når du er ferdig med kortet, kaster du det i en liten søppelkasse.
Til slutt vil du gå tom for kort og trenger et nytt dekk, eller søppelkassen blir full og må tas ut (dvs. søppelkolleksjon). I begge tilfeller må du stoppe det du gjør for å enten få et nytt dekk eller ta ut søppelet.
I et objektbasseng er hvert kort i dekket tomt. Når du trenger et kort, skriver du grunnleggende informasjonen om det du trenger og bruker den. Når du er ferdig med kortet, sletter du informasjonen og legger den tilbake i kortstokken. På denne måten er det ikke nødvendig med nye kort, og du trenger aldri å kaste et kort i søppelkassen. Det er programmørens måte å gjenvinne!
Implementering av et objektbasseng er ikke for vanskelig, men siden det krever et objekt å handle på, vil jeg også vise deg hvordan du implementerer objektet objektbassenget vil holde. Siden et objektbasseng fungerer best på objekter som trenger å bli opprettet og slettet raskt, virker et partikkelsystem som det mest ideelle valget. Det er en to for en spesiell!
Vi starter først ved å implementere partikkel~~POS=TRUNC
klasse. Følgende kode er skrevet i Java, men de samme teknikkene kan brukes til de fleste andre programmeringsspråk. Jeg vil kommentere etter hver kodebit.
offentlig klasse Partikkel private int framesLeft; privat int posX; privat int posy; privat int xVelocity; privat int yVelocity; / ** * Constructor * / public Particle () framesLeft = 0; posX = 0; posY = 0; xVelocity = 0; yVelocity = 0; / ** * Initialiser alle variabler før bruk * / public void init (int pFramesLeft, int pPosX, int pPosY, int pXVelocity, int pYVelocity) framesLeft = pFramesLeft; posX = pPosX; posY = pPosY; xVelocity = pXVelocity; yVelocity = pYVelocity; / ** * Animer partikkelen * / offentlige boolean animere () hvis (erAlive ()) posX + = xVelocity; posY + = yVelocity; framesLeft--; // Tegn objektet til skjermen tilbake false; returnere sann; / ** * Bestem om en partikkel er i live (eller i bruk) * / offentlig boolean isAlive () returrammerLeft> 0;
Som du kan se, er en partikkel en veldig enkel gjenstand. Den har noen variabler for å holde oversikt over hvor det er på skjermen (POSX
og Posy
), hvor fort går det (xVelocity
og yVelocity
) og hvor mange rammer det skal tegnes (framesLeft
). En partikkel er "levende" hvis den fremdeles har rammer igjen som skal trekkes, og "død" ellers.
Ved hver ramme, den animere
funksjonen kalles for å oppdatere partikkels posisjon og tegne den på skjermen. Det kommer tilbake falsk
hvis partikkelen fortsatt er i live, ellers returnerer den sanne signifikante partikkelen døde
.
Merk: Koden for å tegne partikkelen ligger utenfor omfanget av denne opplæringen.
Deretter skal vi implementere ObjectPool
klasse:
offentlig klasse ObjectPool private int størrelse; private liste partikler; / ** * Constructor * / public ObjectPool (int pSize) size = pSize; partikler = ny ArrayList (); // Initialiser arrayet med partikler for (int i = 0; i < size; i++) particles.add(new Particle()); /** * Get the first available particle and assign it the new values */ public void get(int pFramesLeft, int pPosX, int pPosY, int pXVelocity, int pYVelocity) if (!particles.get(size-1).isAlive()) particles.get(size-1).init(pFramesLeft, pPosX, pPosY, pXVelocity, pYVelocity); particles.add(0, particles.remove(size-1)); /** * Animate the object pool. Any dead particles will be placed at the front of the list to be reused */ public void animate() for (int i = 0; i < size; i++) if (particles.get(i).animate()) particles.add(size-1, particles.remove(i));
De ObjectPool
klassen er også en relativt enkel gjenstand. Den inneholder bare en liste over partikler og størrelsen på listen. Kraften til objektbassenget kommer i sine to metoder, få
og animere
.
Når objektbassenget trenger å få et nytt objekt for bruk, ser det på det siste elementet i listen og sjekker om det er i live eller død. Hvis det er i live, er bassenget fullt, og det må derfor opprettes et nytt objekt. Hvis den er død, initierer bassenget det siste elementet i listen, popper det fra slutten, og skyver det tilbake på forsiden av listen. På denne måten har bassenget alltid tilgjengelige gjenstander på baksiden og brukte gjenstander på forsiden.
I animere
metode, hvis partikkelens animasjonsfunksjon returnerer ekte
, objektet er klar til å bli gjenbrukt. Bassenget fjerner varen fra listen og skyver den til baksiden. Manipulering av listen på denne måten gjør å skape og ødelegge gjenstander i bassenget konstant og svært effektivt.
I dette eksemplet vil objektene som objektbassenget holder, være partikler, men for ditt eget objektbasseng kan det være hva du vil. Så lenge samme funksjoner eksisterer i objektet du vil bruke som i partikklassen, vil det fungere det samme.
Utstyrt med en objektbasseng, er det på tide å lage et partikkelsystem for å skape en glittereffekt.
Vi starter med å skape objektbassenget for å holde alle partiklene på skjermen.
ObjectPool pool = nytt ObjectPool (100);
Ved hver ramme genererer vi en ny partikkel midt på skjermen og tildeler den en tilfeldig hastighet. Til slutt vil vi animere objektbassenget.
Tilfeldig randomGenerator = ny Tilfeldig (); int velX = randomGenerator.nextInt (5); int velY = randomGenerator.nextInt (5); pool.get (30, 200, 200, velX, velY); pool.animate ();
Hvis du raskt lager og sletter objekter, kan det føre til at et spill lages eller fryses. Ved å bruke et objektbasseng kan du lagre både systemressurser og brukerfrustrasjon.