I det första inlägget i denna serie diskuterade vi varför objektorienterad programmering (OOP) var till hjälp för spelutveckling och lärde sig att identifiera objekt, deras stater och deras beteenden. I den här artikeln ska vi titta på den specifika OOP-principen för sammanhållning och hur det gäller spel.
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.
Sammanhållning är principen att vara eller göra en sak bra. Med andra ord betyder sammanhållning gruppering av kod som bidrar till en enda uppgift.
Ett bra icke-programmeringsexempel på denna princip var täckt av en av de första Gamedevtuts + artiklarna som pratade om Covert Action Rule:
Försök inte göra för många spel i ett paket ... Individuellt kunde de ha varit bra spel. Tillsammans kämpade de med varandra.
Samma regel gäller objektorienterad programmering. Varje objekt borde bara ha ett ansvar. Varje beteende hos det objektet bör bara göra en uppgift. Något mer än det och du kommer att ha en mycket svårare tid att ändra koden.
Kod som är organiserad av funktionalitet och endast en uppgift sägs ha hög sammanhållning. Mycket sammanhängande kod är återanvändbar, enkel och lätt att förstå. Det skapar också objekt som är små och fokuserade.
Kod som är ordentligt ordnad och har flera uppgifter sägs ha låg sammanhållning. Sådan kod är svår att förstå, underhålla och återanvända, och är ofta komplex. Det skapar också objekt som är stora och ofokuserade.
Att ha hög sammanhållning är generellt bra, medan det är allmänt dåligt att ha låg sammanhållning. När du skriver kod, strävar du alltid efter att skriva mycket sammanhängande kod.
Så hur tillämpar vi detta på objektorienterad programmering? Bra för att börja med, att organisera kod till objekt hjälper till att öka sammanhållningen i spelet i allmänhet. Varje enskilt objekt bör dock också ha hög sammanhållning. Låt oss hänvisa till våra tre exempel för att se hur det fungerar.
Minns från den sista artikeln att vi definierade skeppsobjektet som att ha uppförande av att vrida, flytta och skjuta.
Om vi skulle skriva en enda kod som gjorde alla tre beteenden på en gång skulle det bli ganska rörigt. I stället bör vi skilja varje beteende i vad som är kända som funktioner. Funktioner gör det möjligt för oss att skilja funktionalitet och gruppera samma kod tillsammans, vilket bidrar till att skapa en hög kohesiv kod.
Vid programmering definieras ett objekt genom att skapa en klass. I Java kodas en klass enligt följande:
/ ** * Skeppsklassen * / allmänklassen Skepp / ** * Funktion - utför beteendet (uppgift) för att vrida skeppet * / public void rotate () // Kod som vänder skeppet / ** * Funktion - utför uppförandet (uppgift) för att flytta Ship * / public void move () // Kod som rör fartyget / ** * Funktion - utför uppträdandet (uppgift) för att skjuta fartygets pistol * / allmän tomrumsbrand ) // Kod som gör fartyget en kula
Som du kan se får varje beteende sin egen funktion, och koden är ganska välorganiserad bara i denna skelettstruktur.
Oroa dig inte för mycket om exakt syntaxen just än; vi kommer att diskutera det mer detaljerat när vi går längre fram i serien.För Tetris, kom ihåg att beteendet hos en tetromino faller, rör sig (sidled) och roterar. Grundklassstrukturen är följande:
/ ** * Tetromino-klassen * / offentlig klass Tetromino / ** * Funktion - uppdatera en Tetrominos position * / public void fall () // Kod som uppdaterar Tetrominos position / ** * Funktion - flytta en Tetromino * / public void move () // Kod som flyttar Tetromino sidledes / ** * Funktion - rotera en Tetromino * / public void rotate () // Kod som roterar Tetromino med 90 grader
Igen separeras beteenden i sina egna funktioner. För falla
metod, men märker att uppgiften är att uppdatera tetrominos position. Detta beror på att tetromino alltid faller, så vi kan inte bara göra uppgiften "för att tetromino ska falla".
Istället flyttar en fallande tetromino bara ett visst antal rader åt gången på skärmen - så vi måste uppdatera tetromino-positionen för att återspegla denna fallande hastighet.
För spökeobjektet med beteenden att flytta och byta tillstånd, måste vi göra lite mer arbete för att få det att vara mycket sammanhängande.
/ ** * Ghostklassen * / offentlig klass Ghost / ** * Function - flyttar Ghost * / public void move () // Kod som flyttar spöket i den aktuella riktningen / ** * Funktion - ändra Ghost direction * / public void changeDirection () // Kod som ändrar Ghosts riktning / ** * Funktion - ändra Ghost speed * / public void changeSpeed () // Kod som ändrar Ghosts hastighet / ** * Funktion - ändra Ghost color * / public void changeColor () // Kod som ändrar Ghosts färg / ** * Funktion - ändra Ghost state * / public void changeState () // Kod som ändrar Ghosts tillstånd // Denna funktion också kommer att ringa de tre funktionerna changeDirection, changeSpeed och changeColor
Ghost-staten har tre extra funktioner tillagt den: Byt riktning
, ändra färg
, och changeSpeed
. Dessa var inte i vår ursprungliga beteendelista eftersom de inte är beteenden. I stället är dessa funktioner som är kända som hjälpfunktioner och finns där för att hjälpa oss att upprätthålla hög sammanhållning.
Förändringen av tillståndet (vad som händer när Pac-Man äter en kraftpellets) kräver tre olika uppgifter som ska utföras: Vrid djupblå, bakåtriktad och rör sig långsammare. För att upprätthålla sammanhållning vill vi inte ha en funktion att göra alla tre av dessa uppgifter, så vi delar upp dem i tre deltakar som funktionen kommer att kräva för att slutföra sin enda huvuduppgift.
Användningen av ordet och När vi beskriver vad ett beteende / en funktion betyder brukar vi skapa mer än en funktion.
Sammanhållning är principen att gruppera som kod tillsammans och se till att varje funktion utför endast en enda uppgift. Sammanhållning bidrar till att skapa kod som är underhållbar och återanvändbar.
I nästa Snabbtips diskuterar vi principen om koppling och hur den relaterar till sammanhållning. Följ oss på Twitter, Facebook eller Google+ för att hålla dig uppdaterad med de senaste inläggen.