Snabbtips OOP-principen om arv

Vi har kommit långt i denna nybörjare guide till objektorienterad programmering, diskuterar principerna för sammanhållning, koppling, inkapsling, och abstraktion. I den här sista artikeln diskuterar vi OOP-principen för arv och dess användningsområden i spelutveckling.

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.


Vad är arv?

Arv är principen om klasshierarkin. Det är möjligheten för ett objekt att ta på sig ett annat objekts tillstånd, beteenden och funktionalitet.

Ett verkligt exempel på arv är genetiskt arv. Vi får alla gener från båda våra föräldrar som då definierar vem vi är. Vi delar kvaliteter hos båda våra föräldrar, men samtidigt är de annorlunda än dem.

Objekt i OOP kan göra samma sak. Föräldraklasser kan ha barnklasser (även kända som superklasser och underklasser), vilka kan ha samma egenskaper hos föräldrarklassen och kan definiera nya stater, beteenden och funktionalitet på egen hand.

Tänk på följande klass som kan användas som förälderklass till olika former:

 offentlig klass Shape protected int height; skyddad int bredd; offentlig form (int h, int w) height = h; bredd = w;  offentligt int område () returhöjd * bredd;  public int getHeight () returhöjd;  public int getWidth () returbredd;  public void setHeight (int h) returhöjd;  public void setWidth (int w) return width; 

För att förlänga den här klassen för att implementera en triangel så skulle det se ut så här:

 Public Class Triangle sträcker Shape public Triangle (int h, int w) super (h, w);  offentligt int område () returnera super.area () / 2; 

Triangel har alla samma tillstånd och funktioner som Form, men omdefinierar område() funktion för att returnera det korrekta området av a Triangel (halv bashöjd).

Nyckelordet super används för att referera till superklassen och någon av dess tillstånd och funktioner. Det är därför vi kan använda super() att ringa superklassens konstruktör och super.area () att ringa område() funktionen av superklassen. Så, i det här fallet, super.area () avkastning höjd bredd.

De skyddad sökord är den sista åtkomstnivåmodifieraren. Det fungerar som den privata åtkomstnivåmodifieraren, men tillåter även att någon underklass har tillgång till variabeln eller funktionen.


Varför är det användbart?

Som du kan se kan arvet i hög grad bidra till att minska kodredundans mellan liknande objekt genom att ta vad de här objekten har gemensamt och sätta dem på ett ställe. Detta skapar också en mer underhållbar kod eftersom det hjälper till att följa principen om DRY och för att förhindra krusningseffekten vid kodändringar.

Om allt detta verkar bekant, är det förmodligen att abstraktion hade mycket liknande fördelar (liksom de flesta andra principerna för OOP). Abstraktion är nära besläktad med arvet eftersom en abstraherad klass kan användas som en superklass för att skapa underklasser. Den enda skillnaden mellan en abstrakt klass och en normal klass är att en abstrakt klass inte kan användas för att skapa ett objekt.


Hur man applicerar det

Låt oss gå tillbaka till våra tre spel en gång till för att beskriva hur man ansöker arv.

asteroider

Minns att vi definierade en abstrakt klass för att flytta objekt över en skärm. Minns också att vi definierade a Fartyg klass för skeppsobjektet. Att tillämpa arv till asteroider kan vi få Fartyg klassen förlänger Rörlig klass enligt följande:

 / ** * Fartygsklassen * / offentlig klass Fartyget sträcker sig Flyttbart (/ ** * Funktion för att rotera skeppet * / public void rotate () // Kod som vänder fartyget / ** * Funktion att branda * / offentlig tomrumsbrand () // Kod att elda

Koden som behövs för att flytta skeppet tas hand om i Rörlig abstrakt klass, så vi kan ta bort den från Fartyg klass. Alla andra föremål för asteroider kan också ärva från Rörlig klass, vilket gör det extremt lätt att ändra hur man flyttar ett objekt.

En sak att notera om arv är förmågan att ha flera arv, eller en klasss förmåga att ärva från flera klasser samtidigt. Vissa språk tillåter det, andra gör det inte.

Java är ett av de språk som inte tillåter flera arv. Därför kan du inte få Ship-objektet från båda a Rörlig klass och a utdragbar klass.

Se till att du är bekant med vad ditt programmeringsspråk tillåter innan du försöker skapa arv i ditt spel.

Tetris

Arv kan tillämpas på Tetris genom att ha Tetrimino och alla spelbilderna ärva från utdragbar klass, som vi definierade i den senaste artikeln.

Pac Man

Minns att för Pac-Man identifierade vi dig föremål: Pac-Man, en Ghost och en pac-punkt. Under hela denna serie har vi bara diskuterat dessa tre objekt och har lagt ner att nämna någonting om det sista kritiska stycket Pac-Man: Power Pellet. Med arv är vi nu redo att prata om det.

En kraftpellett är en speciell pac-punkt som gör att Pac-Man kan äta spöken. Dess tillstånd och beteenden är exakt samma som en pac-punkt, med den enda skillnaden som är dess storlek och möjligheten att blinka (kom ihåg att för att hålla spelet löst kopplat, vill vi att en annan klass ska övervaka när en kraftpellet äts och aktiva changeState () spökens metod). Det här är när arvet kommer till nytta.

Eftersom en pac-dot och power pellet är praktiskt taget samma objekt, kan vi skapa en PowerPellet klass som sträcker sig PacDot klass. De PowerPellet klassen skulle bara behöva ändra några stater för att göra det större och lägga till beteendet att växa och krympa för att skapa en blinkande effekt. Och det är det - vi har nu en kraftpellett med lite extra arbete. Inte så pjåkigt.

Koden för hur detta skulle se ut kan vara som följer:

 / ** * Pac-dot-klassen * / allmän klass PacDot förlänger Drawable protected int size; skyddad int poäng offentlig PacDot () size = 10; poäng = 10;  / ** * Returnerar värdet på pac-punkten för att lägga till spelarens poäng när de ätit * / public int getScore () return score;  / ** * Returnerar storleken på pac-punkten * / public int getSize () return size;  / ** * Power Pellet Class * / public class PowerPellet utökar PacDot private int sizeModifier; // behöver inte definiera storlek och poäng eftersom de är // redan definierade i PacDot - PowerPellet ärver dem. offentlig PowerPellet () size = 20; poäng = 50; sizeModifier = -2;  / ** * Blinkfunktionen som skulle ringas varje gång kraftpelleten * ritas. Ändrar sizeModifier för att simulera en blinkande effekt * / public void blink () size + = sizeModifier; om (storlek < 10 || size > 20) sizeModifier = -sizeModifier; 
Det är värt att nämna att för att hålla reda på alla våra klasser och klassarv för Pac-Man, kan du använda ett klassdiagram för att visuellt se hur allt är relaterat.

Slutsats

Erfarenhet är till stor hjälp för att skapa mer underhållbar kod eftersom det tillåter oss att skapa liknande objekt utan att duplicera koden mellan dem. Det bidrar också till att skapa en organiserad kod genom att visa klasshierarkin.

Och det är allt! Vi är nu färdiga med OOP-serien här på Gamedevtuts +. Jag hoppas att du har haft dessa artiklar och att de har hjälpt dig att bättre förstå hur OOP-principer kan tillämpas på spelutveckling. Var noga med att följa oss på Twitter, Facebook eller Google+ för att hålla dig uppdaterad med de senaste inläggen.