Abbiamo fatto molta strada in questa guida per principianti alla programmazione orientata agli oggetti, discutendo i principi di coesione, accoppiamento, incapsulamento, e astrazione. In questo articolo finale, discuteremo il principio OOP di eredità e i suoi usi nello sviluppo del gioco.
Nota: Sebbene questo tutorial sia scritto usando Java, dovresti essere in grado di utilizzare le stesse tecniche e concetti in quasi tutti gli ambienti di sviluppo di giochi.
L'ereditarietà è il principio della gerarchia di classi. È la capacità di un oggetto di assumere gli stati, i comportamenti e la funzionalità di un altro oggetto.
Un esempio di ereditarietà del mondo reale è l'ereditarietà genetica. Tutti riceviamo geni da entrambi i nostri genitori che poi definiscono chi siamo. Condividiamo le qualità di entrambi i nostri genitori, ma allo stesso tempo sono diversi da loro.
Gli oggetti in OOP possono fare la stessa cosa. Le classi parent possono avere classi figlie (note anche come superclassi e sottoclassi rispettivamente) che possono avere le stesse proprietà della classe genitore e possono definire nuovi stati, comportamenti e funzionalità proprie.
Ad esempio, considera la seguente classe che potrebbe essere utilizzata come classe genitore per forme diverse:
Forma di classe pubblica altezza int protetta; larghezza int protetta; forma pubblica (int h, int w) height = h; larghezza = w; public int area () return height * width; public int getHeight () return height; public int getWidth () return width; public void setHeight (int h) return height; public void setWidth (int w) return width;
Per estendere questa classe per implementare un triangolo, sarebbe simile a questa:
public class Triangle estende Shape public Triangle (int h, int w) super (h, w); public int area () return super.area () / 2;
Triangolo
ha tutti gli stessi stati e funzioni di Forma
, ma ridefinisce il la zona()
funzione per restituire l'area corretta di a Triangolo
(metà tempi base altezza).
La parola chiave super
è usato per fare riferimento alla superclasse e ai suoi stati e funzioni. Questo è il motivo per cui possiamo usare super()
chiamare il costruttore della superclasse e super.area ()
chiamare il la zona()
funzione della superclasse. Quindi, in questo caso, super.area ()
ritorna altezza larghezza
.
Il protetta
parola chiave è l'ultimo modificatore del livello di accesso. Funziona come un modificatore di livello di accesso privato, ma consente anche a qualsiasi sottoclasse di accedere alla variabile o alla funzione.
Come puoi vedere, l'ereditarietà può aiutare a ridurre la ridondanza del codice tra oggetti simili prendendo in comune ciò che questi oggetti hanno in comune e mettendoli in un posto. Questo crea anche un codice più gestibile perché aiuta a rispettare il principio di DRY e ad impedire l'effetto a catena nelle modifiche al codice.
Se tutto ciò sembra familiare, è probabilmente perché l'astrazione ha avuto benefici molto simili (così come la maggior parte degli altri principi di OOP). L'astrazione è strettamente correlata all'ereditarietà in quanto una classe astratta può essere utilizzata come una superclasse per creare sottoclassi. L'unica differenza tra una classe astratta e una classe normale è che una classe astratta non può essere utilizzata per creare un oggetto.
Torniamo ai nostri tre giochi ancora una volta per descrivere come applicare l'ereditarietà.
Ricordiamo che abbiamo definito una classe astratta per lo spostamento di oggetti su uno schermo. Ricorda anche che abbiamo definito a Nave
classe per l'oggetto della nave. Per applicare l'ereditarietà agli asteroidi, possiamo avere il Nave
classe estendere il Mobile
classe come segue:
/ ** * La classe nave * / classe pubblica nave estende la funzione Movable / ** * per ruotare la nave * / public void rotate () // Codice che trasforma la nave / ** * Funzione da attivare * / pubblico void fire () // Code to fire
Il codice necessario per spostare la nave è curato nel Mobile
classe astratta, quindi possiamo rimuoverlo dal Nave
classe. Tutti gli altri oggetti per Asteroids potrebbero anche ereditare dal Mobile
classe, rendendo estremamente facile cambiare il modo di spostare un oggetto.
Una cosa da notare sull'ereditarietà è la possibilità di avere ereditarietà multipla o la capacità di una classe di ereditarsi da più classi contemporaneamente. Alcune lingue lo permettono, altri no.
Java è una delle lingue che non consente l'ereditarietà multipla. Pertanto, non è possibile ereditare l'oggetto Ship da entrambi Moveable
classe e a drawable
classe.
L'ereditarietà può essere applicata a Tetris facendo ereditare dal Tetrimino e da tutti gli elementi visivi del gioco drawable
classe, che abbiamo definito nell'ultimo articolo.
Ricorda che per Pac-Man abbiamo identificato gli oggetti: Pac-Man, un Ghost e un Pac-Punto. In tutta questa serie abbiamo discusso solo questi tre oggetti e abbiamo rimandato a menzionare qualcosa sull'ultimo pezzo critico di Pac-Man: il potere pellet. Con l'eredità, ora siamo pronti a parlarne.
Un power pellet è un pac-dot speciale che consente a Pac-Man di mangiare i fantasmi. I suoi stati e comportamenti sono esattamente gli stessi di un pac-dot, con l'unica differenza che è la sua dimensione e la capacità di battere le palpebre (ricordate che per mantenere il gioco liberamente accoppiato, vogliamo che un'altra classe controlli quando si mangia un attivo il changeState ()
metodo dei fantasmi). Questo è quando l'ereditarietà è utile.
Dal momento che un pac-punto e un pellet di potenza sono praticamente lo stesso oggetto, possiamo creare un PowerPellet
classe che estende il PacDot
classe. Il PowerPellet
la classe avrebbe solo bisogno di modificare alcuni stati per renderla più grande e aggiungere il comportamento di crescere e restringersi per creare un effetto lampeggiante. E questo è tutto - ora abbiamo un power pellet con poco lavoro extra. Non troppo malandato.
Il codice per come potrebbe apparire potrebbe essere il seguente:
/ ** * La classe Pac-dot * / public class PacDot estende Drawable dimensione int protetta; punteggio int protetto; public PacDot () size = 10; punteggio = 10; / ** * Restituisce il valore del pac-punto da aggiungere al punteggio del giocatore quando mangiato * / public int getScore () punteggio di ritorno; / ** * Restituisce la dimensione di pac-dot * / public int getSize () return size; / ** * La classe Power Pellet * / public PowerPellet estende PacDot private int sizeModifier; // non è necessario definire la dimensione e il punteggio poiché sono già definiti in PacDot - PowerPellet li eredita. public PowerPellet () size = 20; punteggio = 50; sizeModifier = -2; / ** * La funzione di lampeggiamento che verrebbe chiamata ogni volta che viene visualizzato il blocco di potenza *. Modifica sizeModifier per simulare un effetto lampeggiante * / public void blink () size + = sizeModifier; se (taglia < 10 || size > 20) sizeModifier = -sizeModifier;Vale la pena ricordare che per tenere traccia di tutte le nostre classi e eredità di classe per Pac-Man, è possibile utilizzare un diagramma di classe per vedere visivamente come tutto è correlato.
L'ereditarietà è molto utile per creare codice più gestibile in quanto ci consente di creare oggetti simili senza duplicare il codice tra di essi. Aiuta anche a creare codice organizzato mostrando la gerarchia delle classi.
E questo è tutto! Ora abbiamo finito con la serie OOP qui su Gamedevtuts +. Spero che abbiate apprezzato questi articoli e che vi abbiano aiutato a capire meglio come applicare i principi OOP allo sviluppo del gioco. Assicurati di seguirci su Twitter, Facebook o Google+ per rimanere aggiornato con gli ultimi post.