4535 Arv med monster

Ett sätt att undvika att skriva samma kod flera gånger är att använda arv. Nedan sker en demonstration med en spelarklass samt några monsterklasser. Monstren flyttar sig på samma vis i båda projekten.

Projekt med monster på GitHub

Projekt med monster som använder arv, på GitHub

Förkunskaper

Tolka klassdiagram.

Valda delar om klassdiagram.

Klassdiagram utan arv

Klasserna Player, Troll, Elf och Phoinx ärver från klassen MonoBehavior. Pilen i klassdiagrammet ovan visar detta.

Snabbguide till klassdiagram

Snabbguide till klassdiagram, se diagram nedan.

I den översta rutan står klassens namn.

I nästa ruta är objektvariablerna uppräknade.

I sista rutan är metoderna uppräknade.

Objektvariabler och metoder föregås av synlighet. Tecknen har följande betydelse.

  • (-) betyder private
  • (#) betyder protected
  • (+) betyder public

Klassens namn

  • -objektvariabel : datatyp
  • -objektvariabel_2: datatyp
  1. +Metod() : returdatatyp
  2. +Metod(parameter: datatyp) : returdatatyp

Steg 1 - Gemensamt

Klasserna Player, Troll, Elf och Phonix har alla objektvariablerna rb och speed gemensamma.

Dessa objektvariabler kommer att flyttas till klassen Actor.

Metoden Start() finns också i klasserna Player, Troll, Elf och Phonix. Innehållet i metoden är delvis gemensamt. Denna metod flyttas också till klassen Actor.

Metoden FixedUpdate() finns också i samtliga klasser men dess innehåll skiljer sig åt så den flyttar vi inte till klassen Actor.

Det nya klassdiagrammet blir som nedan.

Objektvariablerna är protected i Actor istället för private. Detta för att de ska finnas tillgängliga i ärvande klasser. På samma sätt för metoden Start().

Klassen Actor på GitHub

Nya Player med arv på GitHub.

Gamla Player på GitHub

Start() i gamla Player

private void Start()

Start() i Actor

protected virtual void Start()
// samma innehåll som i gamla Player

protected för att metoden ska synas i klasser som ärver från Actor.

virtual för att metoden ska kunna ersättas av en ny i ärvande klasser.

Start i nya Player med arv

protected override void Start()
{
    // call Start() in super class Actor
    base.Start();
    tag = "Player"; 
}

override för att markera att metoden ersätter Start() i superklassen Actor.'

base.Start() för att anropa Start() i Actor.

Steg 2 - gemensamt

I klassdiagrammen för Troll, Elf och Phonix kan man se att de alla har objektvariabeln direction. Därtill har de följande metoder gemensamt: Start(), FixedUpdate(), OnCollisionEnter2D(), OnCollisionStay2D(), SnapToGrid(), SnapToGridX() och SnapToGridY(). Dessa metoder samt objektvariabeln direction flyttar vi till den nya klassen Monster. I Monster ges objektvariabler och metoder synligheten protected för att de skall kunna användas i ärvande klasser.

Lägger också till metoden SelectDiretion() för att OnCollisionEnter2D() och OnCollisionStay2D() ska vara mer lika sina motsvarigheter i Troll, Elf och Phonix.

Fullständigt klassdiagram visas nedan. En metod som finns i en superklass tas bara med i en subklass om den har nytt innehåll.

Koden i gamla Troll har i princip flyttats till Monster.

Det är i huvudsak sättet att välja riktning som skiljer Troll från Elf.

Däremot Phonix skiljer sig mer från både Troll och Elf.

Nya

Kod för Monster på GitHub

Kod för nya Troll på GitHub

Kod för nya Elf på GitHub

Kod för Phonix på GitHub

Gamla

Kod för gamla Troll på GitHub

Kod för gamla Elf på GitHub

Kod för gamla Phonix på GitHub

Intressanta metodanrop

FixedUpdate() i Troll

Följande händer:

Metoden FixedUpdate() anropas på ett objekt av klassen Troll.

FixedUpdate() finns inte implementerad (skriven) i klassen Troll.

Den ärvda metoden från Monster anropas istället.

Detta kallas för sen bindning.

OnCollisionStay2D() i Troll

Följande händer:

Metoden OnCollisionStay2D() anropas på ett objekt av klassen Troll.

OnCollisionStay2D() finns inte implementerad i klassen Troll.

Den ärvda metoden från Monster anropas istället.

Så här långt är det väldigt likt exemplet ovan.

Koden för OnCollisionStay2D() i Monster återges nedan.

protected virtual void OnCollisionStay2D(Collision2D collision)
{
    SelectDirection();
    SnapToGrid();
}

Först anropas metoden SelectDirection(), men inte den i Monster utan den i Troll eftersom anropet började på ett objekt av klassen Troll.

Sedan anropas metoden SnapToGrid() i Monster eftersom den inte finns i Troll.

Övning på arv

Alternativ 1.

Skriv om ett av dina projekt så att arv används i större utsträckning. Ett lämpligt projekt är Cheese Gril.

Alternativ 2.

Lägg till fler monster som rör sig på andra sätt. Antingen i projektet som visats ovan eller i ett eget projekt. Arv ska användas.

Alternativ 3.

Egen idé om projekt med arv.