Impuscaturile și jocurile care utilizează sisteme de particule trebuie să creeze, să manipuleze și apoi să elimine mai multe obiecte simultan - poate chiar sute pe cadru. Acest lucru poate duce la întârzierea jocului sau chiar la îngheț. În acest tutorial, vom analiza cum piscine de obiecte pot ajuta cu această problemă, permițându-ne să re-folosim obiectele în loc să le recreăm de la zero.
Notă: Deși acest tutorial este scris folosind Java, ar trebui să puteți folosi aceleași tehnici și concepte în aproape orice mediu de dezvoltare a jocului.
O întâlnire obișnuită în sistemele de împușcături și particule este crearea și ștergerea multor obiecte în succesiune rapidă. De la arme la aruncarea vrăjilor magice, crearea și ștergerea obiectelor necesare poate fi o operație costisitoare. Atunci când multe dintre aceste operații sunt efectuate rapid, pot provoca înghețarea sau înghețarea jocului.
Motivul este că un program de fundal numit colector de gunoi necesită resurse de sistem pentru a curăța memoria utilizată. Este o curățare care poate provoca o întârziere a sistemului.
O modalitate de a preveni acest lucru este utilizarea unei baze de obiecte pentru reutilizarea obiectelor vechi în loc să le ștergeți.
Pentru a înțelege de ce este nevoie de un grup de obiecte, trebuie mai întâi să înțelegem cum funcționează colecția de gunoi.
Colectarea gunoiului este procesul de gestionare automată a resurselor. Acesta este responsabil pentru eliberarea spațiului de memorie pentru reutilizare atunci când nu mai este necesar.
Uitați-vă la următorul exemplu de simplă pentru
buclă:
pentru (int i = 1; i < 10; i++) System.out.println(i);
Când un program execută această buclă, va crea o variabilă eu
prin atribuirea unei cantități suficiente de memorie pentru a ține datele variabilei (în acest caz, suficient spațiu pentru a păstra un număr întreg). Odată ce buclele au terminat, variabila eu
nu mai este nevoie; programul va detecta în cele din urmă acest lucru și poate elibera memoria pentru alte utilizări.
În cea mai mare parte, colectarea gunoiului se face automat și fără notificare. Cu toate acestea, uneori, dacă o mulțime de memorie trebuie să fie eliberată în același timp, colectarea de gunoi poate forța programul să utilizeze resurse valoroase ale sistemului pentru a elibera memoria necesară. Acest lucru poate cauza ca programul să rămână temporar sau înghețat, deoarece este nevoie de timp.
Sistemul poate, de asemenea, să rămână în urmă când este nevoie de o mulțime de memorie pentru a crea obiecte noi. Acest lucru se datorează faptului că atribuirea memoriei poate fi la fel de intensă ca și eliberarea.
Din acest motiv, devine important să gestionați colectarea deșeurilor astfel încât să nu interfereze cu programul dvs..
Un bazin de obiecte este o structură de date care reutilizează obiecte vechi pentru a nu crea sau șterge continuu altele noi. În loc să alocăm o nouă memorie unui obiect și apoi să îl eliberăm odată ce terminăm cu el, vom continua să refolosim obiectul mereu și din nou prin modificarea valorilor. În acest fel, memoria nu trebuie eliberată, evitând astfel colectarea gunoiului.
Împărțirea resurselor poate oferi un impuls semnificativ de performanță în situațiile în care costul inițializării unei instanțe de clasă este ridicat, rata de instanțiere a unei clase este ridicată și numărul de cazuri utilizate în orice moment este scăzut.
Gândește-te la ea ca la un pachet de cărți în care puntea reprezintă memorie. De fiecare dată când aveți nevoie de o nouă carte (adică aveți nevoie de un obiect nou), trageți unul din pachet și îl utilizați; după ce ați terminat cu cardul, îl aruncați într-o cutie mică de gunoi.
În cele din urmă, ați ieșit din cărți și aveți nevoie de o punte nouă, sau dacă gunoi ar putea deveni plin și trebuie eliminat (adică colectarea gunoiului). În ambele cazuri, trebuie să oprești ceea ce faci în prezent pentru a obține o punte nouă sau a scoate gunoiul.
Într-o piscină de obiecte, fiecare carte din pachet este necompletată. Când aveți nevoie de un card, scrieți informațiile de bază de care aveți nevoie și folosiți-o. Odată ce ați terminat cu cardul, ștergeți informațiile și puneți-l înapoi în pachet. În acest fel, nu sunt necesare carduri noi și niciodată nu trebuie să aruncați o carte în cutia de gunoi. Este modul de reciclare al programatorului!
Implementarea unei baze de obiecte nu este prea dificilă, dar deoarece necesită un obiect pentru a acționa, vă voi arăta, de asemenea, cum să implementați obiectul pe care îl va păstra grupul de obiecte. Deoarece un bazin de obiecte funcționează cel mai bine pe obiectele care trebuie create și șterse rapid, sistemul de particule pare a fi cea mai bună alegere. Sunt două pentru una specială!
Vom începe mai întâi prin implementarea particulă
clasă. Următorul cod este scris în Java, însă aceleași tehnici pot fi folosite pentru majoritatea altor limbi de programare. Voi comenta după fiecare fragment de cod.
clasa publică Particle private int framesLeft; private int posX; intuitiv privat; private int xVelocity; private int yVelocity; / ** * Constructor * / public Particle () framesLeft = 0; posX = 0; posY = 0; xVelocity = 0; yVelocity = 0; / ** * Inițializați toate variabilele înainte de a folosi * / void public init (int pFramesLeft, int pPosX, int pPosY, int pXVelocitate, int pYVelocity) framesLeft = pFramesLeft; posX = pPosX; posY = pPosY; xVelocity = pXVelocity; yVelocity = pYVelocity; / ** * Animarea particulelor * / public boolean animate () if (isAlive ()) posX + = xVelocity; posY + = yVelocitate; framesLeft--; // Desenați obiectul la ecranul return false; return true; / ** * Determina dacă o particulă este în viață (sau în uz) * / boolean public isAlive () return framesLeft> 0;
După cum puteți vedea, o particulă este un obiect foarte simplu. Acesta conține câteva variabile pentru a urmări unde este afișat pe ecran (posX
și buchet de flori
), cat de repede merge (xVelocity
și yVelocity
) și câte cadre ar trebui să fie trase (framesLeft
). O particulă este "vie" dacă mai are cadre de tras și "mort" altfel.
La fiecare cadru, anima
funcția este chemată pentru a actualiza poziția particulei și a trage-o pe ecran. Se întoarce fals
în cazul în care particula este încă în viață, altfel se întoarce adevărat semnificând particula decedat
.
Notă: Codul pentru desenarea particulei este dincolo de scopul acestui tutorial.
Apoi, vom implementa ObjectPool
clasă:
clasa publică ObjectPool private int size; private particule din listă; / ** * Constructor * / ObjectPool public (int pSize) size = pSize; particule = noul ArrayList (); // Inițializați matricea cu particule pentru (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));
ObjectPool
clasa este, de asemenea, un obiect relativ simplu. Pur și simplu deține o listă de particule și dimensiunea listei. Puterea bazinului de obiecte vine în cele două metode, obține
și anima
.
Când grupul de obiecte trebuie să obțină un obiect nou pentru utilizare, acesta privește ultimul element din listă și verifică dacă acesta este în prezent viu sau mort. Dacă este viu, piscina este plină, deci trebuie să fie creat un obiect nou; dacă este mort, piscina inițializează ultimul element din listă, îl afișează de la capăt și îl împinge înapoi în partea din față a listei. În acest fel, piscina are întotdeauna obiecte disponibile în spate și obiecte folosite în față.
În anima
, dacă funcția animată a particulei revine Adevărat
, obiectul este gata de reutilizare. Piscina elimină articolul din listă și îl împinge în spate. Manipularea listei în acest mod face ca crearea și distrugerea obiectelor din piscină să fie constante și foarte eficiente.
În acest exemplu, obiectele bazate pe piscinele de obiecte vor fi Particule, dar pentru propria piscină de obiecte poate fi orice doriți. Atâta timp cât există aceleași funcții în obiectul pe care îl veți folosi ca și în clasa Particule, va funcționa la fel.
Echipat cu o piscină de obiecte, este timpul să creați un sistem de particule care să facă un efect de scânteie.
Începem prin crearea bazei de obiecte pentru a ține toate particulele de pe ecran.
ObjectPool pool = ObjectPool nou (100);
La fiecare cadru, vom genera o nouă particulă în centrul ecranului și vom atribui o viteză aleatorie. În cele din urmă, vom anima fondul de obiecte.
Random generator aleator = nouă Random (); int velX = randomGenerator.nextInt (5); int velY = aleatorGenerator.nextInt (5); pool.get (30, 200, 200, velx, velY); pool.animate ();
Crearea rapidă și ștergerea obiectelor pot determina întârzierea sau înghețarea unui joc. Prin utilizarea unei baze de obiecte, puteți salva atât resursele de sistem, cât și frustrarea utilizatorilor.