Objektpooler hjälper dig att minska lag i resursintensiva spel

Skyttar och spel som använder partikelsystem måste skapa, manipulera och sedan ta bort många objekt på en gång - kanske till och med hundratals per ram. Detta kan leda till att spelet försvinner eller till och med fryser. I denna handledning ser vi på hur objekt pooler kan hjälpa till med detta problem genom att låta oss återanvända objekt istället för att återskapa dem från början.

Notera: Även om denna handledning skrivs med Java, bör du kunna använda samma tekniker och begrepp i nästan vilken spelutvecklingsmiljö som helst.


Introduktion

En vanlig händelse i skyttar och partikelsystem är att skapa och radera många objekt i snabb följd. Från att skjuta pistoler för att gjuta magiska stavningar, kan skapa och ta bort objekt som behövs vara en dyr operation. När många av dessa operationer utförs snabbt kan det orsaka att spelet släpper eller fryser.

Anledningen är att ett bakgrundsprogram kallat skräp samlare kräver systemresurser för att städa upp det använda minnet. Det är det här rengöringen som kan orsaka att systemet försvinner.

Ett sätt att förhindra detta är att använda en objektpool för att återanvända gamla objekt istället för att radera dem.


Vad är Garbage Collection?

För att förstå varför en objektpool behövs först måste vi förstå hur insamling fungerar.

Sopkollektion är processen med automatisk resurshantering. Det är ansvarigt för att frigöra minnesutrymme för återanvändning när det inte längre behövs.

Ta en titt på följande exempel på en enkel för slinga:

 för (int i = 1; i < 10; i++)  System.out.println(i); 

När ett program kör den här slingan skapas en variabel jag genom att ge tillräckligt med minne för att hålla variabelns data (i det här fallet finns tillräckligt med utrymme för att hålla ett heltal). När slingan är klar, variabeln jag behövs inte längre Programmet kommer så småningom att upptäcka detta och kan sedan frigöra minnet för andra användningsområden.

För det mesta sker sophämtning automatiskt och utan föregående meddelande. Ibland, men om mycket minne måste frigöras på en gång, kan sopkollektion tvinga programmet att använda värdefulla systemresurser för att frigöra det nödvändiga minnet. Detta kan få programmet att laga eller frysa tillfälligt, eftersom det tar tid.

Systemet kan också lagras när det behövs mycket minne på en gång för att skapa nya objekt. Detta beror på att tilldelning av minne kan vara lika resursintensivt som att frigöra det.

På grund av detta blir det viktigt att hantera skräpsamling så att det inte störa ditt program.


Vad är en objektpool?

En objektpool är en datastruktur som återanvändar gamla objekt för att inte kontinuerligt skapa eller ta bort nya. I stället för att ge nytt minne till ett objekt och sedan frigöra det när vi är färdiga med det, fortsätter vi bara att återanvända objektet om och om igen genom att ändra dess värden. På detta sätt behöver inte minnet frigöras, vilket förhindrar skräpsamling.

Sammanslagning av resurser kan erbjuda ett betydande prestationshöjning i situationer där kostnaden för initiering av en klassinstans är hög, hur mycket instansieringen av en klass är hög och antalet instanser som används vid en viss tid är låg.

Tänk på en sådan som en kortlek där däck representerar minne. Varje gång du behöver ett nytt kort (dvs du behöver ett nytt objekt) drar du en från däck och använder den; När du är klar med kortet kastar du den i en liten skräpburk.

Så småningom skulle du gå tom för kort och behöva ett nytt däck, eller soptunnan skulle bli full och måste tas ut (dvs sopor). I båda fallen måste du stoppa vad du gör för att antingen få ett nytt däck eller ta ut papperskorgen.

I en objektpool är varje kort i däcket tomt. När du behöver ett kort skriver du den grundläggande informationen om den som du behöver och använder den. När du är klar med kortet, raderar du informationen och lägger den tillbaka i däcket. På så sätt behövs inga nya kort och du behöver aldrig kasta ett kort i skräpburken. Det är programmerarens sätt att återvinna!


Implementera en objektpool

Att genomföra en objektpool är inte för svårt, men eftersom det krävs ett föremål att agera, visar jag dig också hur man implementerar objektet som objektpoolen ska hålla. Eftersom en objektpool fungerar bäst på objekt som behöver skapas och raderas snabbt, verkar ett partikelsystem som det mest idealiska valet. Det är en två för en speciell!

Vi börjar först genom att implementera Partikel klass. Följande kod är skriven i Java, men samma tekniker kan användas för de flesta andra programmeringsspråk. Jag kommenterar efter varje kodbit.

 offentlig klass Partikel private int framesLeft; privat int posX; privata int posY; privat int xVelocity; privat int yVelocity; / ** * Constructor * / public Particle () framesLeft = 0; posX = 0; posY = 0; xVelocity = 0; yVelocity = 0;  / ** * Initiera alla variabler före användning * / public void init (int pFramesLeft, int pPosX, int pPosY, int pXVelocity, int pYVelocity) framesLeft = pFramesLeft; posX = pPosX; posY = pPosY; xVelocity = pXVelocity; yVelocity = pYVelocity;  / ** * Animate partikeln * / public boolean animera () om (isAlive ()) posX + = xVelocity; posY + = yVelocity; framesLeft--; // Rita objektet till skärmen tillbaka false;  returnera sant;  / ** * Bestäm om en partikel är levande (eller använd) * / offentlig boolean isAlive () returramarLeft> 0; 

Som du kan se är en partikel ett mycket enkelt objekt. Den innehåller några variabler för att hålla reda på var det är på skärmen (posX och bukett), hur fort går det (xVelocity och yVelocity) och hur många ramar den ska dras (framesLeft). En partikel är "levande" om den fortfarande har ramar kvar att dras och "död" annars.

Vid varje ram animera funktionen kallas för att uppdatera partikelns position och rita den till skärmen. Det återvänder falsk om partikeln fortfarande lever, annars returnerar den sanna signifikant partikeln dog.

Notera: Koden för att rita partikeln ligger utanför omfattningen av denna handledning.

Nästa ska vi implementera ObjectPool klass:

 public class ObjectPool private int size; privata listpartiklar; / ** * Constructor * / public ObjectPool (int pSize) size = pSize; partiklar = ny ArrayList (); // Initiera arrayen med partiklar för (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 är också ett relativt enkelt objekt. Den innehåller bara en lista med partiklar och storleken på listan. Effekten av objektpoolen kommer i sina två metoder, skaffa sig och animera.

När objektpoolen behöver få ett nytt objekt för användning, ser det på sista objektet i listan och kontrollerar om det är för närvarande levande eller dött. Om det lever är poolen full, och så måste ett nytt objekt skapas; Om den är död, initierar poolen det sista objektet i listan, poppar det från slutet och trycker det tillbaka på listan framåt. På så sätt har poolen alltid tillgängliga föremål på baksidan och använda föremål i framsidan.

I animera metod, om partikelns animerade funktion returnerar Sann, objektet är klart att återanvändas. Poolen tar bort objektet från listan och trycker det på baksidan. Manipulering av listan på detta sätt gör att skapa och förstöra föremål i poolen konstant och mycket effektiv.

I det här exemplet är objekten som objektpoolen håller partiklar, men för din egen objektpool kan det vara vad du vill. Så länge som samma funktioner finns i objektet som du kommer att använda som i partikelklassen, kommer det att fungera på samma sätt.


Få alltid att falla på plats

Utrustad med en objektpool, är det dags att skapa ett partikelsystem för att ge en gnistrareffekt.

Vi börjar med att skapa objektpoolen för att hålla alla partiklar på skärmen.

 ObjectPool pool = nytt ObjectPool (100);

Vid varje ram genererar vi en ny partikel i mitten av skärmen och tilldelar den en slumpmässig hastighet. Slutligen ska vi animera objektpoolen.

 Slumpmässig randomGenerator = ny slumpmässig (); int velX = randomGenerator.nextInt (5); int velY = randomGenerator.nextInt (5); pool.get (30, 200, 200, velX, velY); pool.animate ();

Slutsats

Att snabbt skapa och ta bort objekt kan potentiellt leda till att ett spel lagras eller fryser. Genom att använda en objektpool kan du spara både systemresurser och användarfrustration.