- Kursmaterial
- Planering
- Arbete
- Kunskapsdokument
- Tutorials
- Andra kurser
- Om Kursolle
2. Moment02 - Objektorientering
I detta moment skall vi kika på objektorientering, OOP (object-oriented programming), och hur vi kan använda denna teknik för att bygga tydligare och mer generella applikationer. Vi kommer lära oss att bygga klasser och skapa objekt vilket är grunden inom den objektorienterade programmeringen.
Objektorientering är en viktig del av de objektorienterade programmeringsspråken. Det är ett sätt att försöka anpassa programmeringen mot den riktiga
världen där helt andra datatyper finns än just de datatyper som finns inbyggt i programmeringsspråket. När vi skall sätta samman information om någon person eller en bil så räcker det inte att bara förlita sig på bara de enkla variabler som finns i en applikation. Det är då vi vill använda oss av objekt.
Momentet börjar med en teorigenomgång frikopplad från något specifikt programmeringsspråk innan vi kikar på hur OOP fungerar i programmeringsspråket C#. Detta gör vi genom att följa en tutorial och bygga en klass och lär oss använda denna i en applikation. Slutligen så börjar vi med den tutorial som vi skall jobba med i stora delar av kursen. Den tutorial som bygger oss ett spel i C#.
2.1 Teori
Vi börjar med en allmän genomgång av OOP. Denna presentation är bortkopplad från något specifikt programmeringsspråk. Senare i momentet kommer vi kika på hur vi jobbar med objektorientering specifikt i C#.
2.2 OOP & C# genom två tutorials
2.2.1 Objektorienteringens grunder
För att lära dig objektorientering i C# så har jag byggt en tutorial där du skall skapa klassen Car och sedan jobba med denna klass genom objektorienteringens grunder.
Uppgift m02u01
Genomför tutorial ovan och redovisa sedan ditt arbete enligt instruktionerna under punkten Redovisning
nedan.
2.2.2 Att lagra objekt i en samling
Dags för nästa tutorial, denna gången bygger vi vidare med klassen Car och nu skall vi bygga en applikation kring våra bilar så att de går att lagra i en lista, lägga till, ta bort och tömma listan. Klicka här för att jobba med tutorialen.
Uppgift m02u02
Genomför tutorial ovan och lämna sedan in ditt projekt i Classroom. Packa hela projektet så att jag kan köra det på min dator.
2.3 Speltutorial
Vi kommer arbeta med ett läromedel, skriven av Krister Trangius, som har en bra tutorial för hur spel tillverkas. Även om boken är skriven till en tidigare kursplan, före HT-17, så finns det många saker som är bra och som vi kan dra nytta av.
Boken
Boken är beställd och kommer förhoppningsvis levereras inom kort. I Classroom finns de kapitel som behövs i väntan på boken.
2.3.1 Spelets grundstruktur
Introduktion till spelutveckling och hur våra projekt ser ut finns i boken men jag kommer här gå igenom det viktigaste. Numreringen härifrån kommer följa bokens kapitelnumrering.
Kapitel 5. Komma igång med XNA och MonoGame
Monogame är ett ramverk för att skapa spel för olika plattformar. Det finns flera liknande ramverk som underlättar för dig att skapa spel där, Godot, Unity och Unreal kan nämnas bland de större.
Tidigare fanns XNA, utvecklat av MicroSoft, men sedan 2013 vidareutvecklas inte detta ramverk och främst MonoGame har ersatt. Att MonoGame har ersatt beror på att koden för dessa båda är lika och det skall gå att kompilera gamla spel som utvecklats för XNA i MonoGame.
Vi kommer utveckla våra spel i Visual Studio och med hjälp av MonoGames hemsida så behöver installera och konfigurera Visual Studio något. Följer du min lista här nedan så är det snart gjort;
- Jag utgår ifrån att du redan har installerat Visual Studio 2022, då kan du börja med att följa guiden Install MonoGame extension for Visual Studio 2022.
- Nästa steg är att skapa ditt första spelprojekt. Det gör du via guiden Creating a Project with Visual Studio 2022. Alla texter och bilder är inte identiska i min version av VS 2022 mot bilderna i guiden men ni borde lösa vilken av projektstyperna som skall skapas.
- När projektet är skapat så fick jag upp en varning om att
This project is targeting a version of .NET which is not installed.
Jag installerade inte denna version och det gick ändå att köra projektet. Jag vet dock inte om vi får problem senare, så det kan vara läge att installera det som önskas.
Kapitel 6. Introduktion till spelutveckling
När du skapar ett nytt spelprojekt i MonoGame så kommer du att få lite grundläggande kod som behövs för att spelet skall fungera. I denna koden så finns det några förskapade metoder som vi behöver bekanta oss med.
Kapitel 6.1 Att skapa ett första projekt
har du inte redan skapat ditt första projekt så hittar du guiden precis här ovanför.
Kapitel 6.2 Spel-loopen
När vi utvecklar spel så kommer vi jobba med något som kallas händelsebaserad programmering, vilket innebär att det är händelser som styr vad skall ske i spelet. Vi har tidigare sett detta i Python/Turtle då vi kan styra en figur, eller när vi byggde GUI i Python och på det sättet kunde aktivera olika händelser genom att klicka på knappar eller skriva in en text i ett formulär.
Inom spelprogrammering så kan inte spelet endast vänta på att vi skall göra något, då skulle ju spelet stå helt still tills vi väljer att flytta vår figur. Det skulle ju bli tråkiga spel om inget hände under tiden.
Därför så finns det en spel-loop (game loop) som ser till att spelet hela tiden fortsätter. Denna spel-loop har en viss frekvens då den uppdaterar vårt spel. För MonoGame så kommer den att uppdatera spelet ca 60 gånger per sekund så det som vi egentligen ser är 60 utritade stillbilder per sekund, enheten för detta är fps (frames per second). Hastigheten på dessa bilder gör att vi ser det som ett rörligt spel.
Kapitel 6.3 Metoden Main()
Koden
Nu skall jag gå igenom startkoden och som vi tidigare har sett så utvecklas C#, koden förändras något och samma gäller MonoGame. Jag kommer utgå från bokens kod och där jag ser att det behövs förtydligande kommer jag göra detta. Troligtvis kommer ni efter ett tag bli sams med koden som automatgenereras och den koden som skrivs i boken.
Det blir lite knas direkt då jag pratar om metoden Program.cs
då denna kod visas enligt Top Level Statement
vilket vi gått igenom tidigare. Du kommer inte göra så mycket i just den filen så det spelar nog ingen roll om den visas med Top Level Statement
eller inte.
I metoden
skapas ett objekt av typen Game1 och sedan anropas metoden . Run är metoden som kommer se till att spelet körs med hastigheten 60 fps och att spelet hela tiden kommer fortgå. Varför objektet game skapas på detta sätt beskrivs kort i boken för den som är intresserad. För kommande arbete är det inte så viktigt.Kapitel 6.4 Livscykeln för ett spel i MonoGame
Metoden
är viktig för spelet men det är samtidigt ingen metod som vi kommer skriva kod i. Metoden har som uppgift att se till att spelet loopas 60 ggr/s, att alla kontroller görs och att spelet ritas ut som det är tänkt. Vi kan se denna metoden som vår spelmotor som sköter allt som vi förväntar oss skall fungera.Det intressanta med denna metoden är att den i sin tur anropar fem andra metoder som vi kan påverka och som kommer driva spelet framåt.
Metoderna
och används för att sätta upp variabler och allt vi behöver förbereda inför spelet.och är själva spel-loopen, och dessa metoder kommer köras 60 ggr var per sekund så länge spelet pågår.
är metoden som rensar upp efter oss när spelet är slut.
Kapitel 6.4.1 Klassen Game1
Ändrad namngivning i koden
MonoGame har ändrat sättet som de skapar sina variabelnamn. I boken heter medlemsvariabeln för spelets SpriteBatch till
medan i den automatgenereade koden döper numera variabeln till . Det gör ingen skillnad, men antingen döper du om variablerna til bokens standard från början eller så kommer ud ihåg att du behöver namnge allt i boken enligt den nya namngivningen.I klassen Game1 finns det två variabler och datatyper som vi behöver hålla koll på.
GraphicsDeviceManager graphics; SpriteBatch spriteBatch;
är en klass som tar hand om kopplingen mellan spelet och grafikkortet.
är klassen som vi använder oss av för att skriva ut bilder i spelet.
public Game1() { graphics = new GraphicsDeviceManager(this); Content.RootDirectory = "Content"; }
I konstruktorn så kopplas objektet
talar om vart vi kommer lägga de filer som vi vill använda i vårt spel, tex bilder och ljud.
Ändringar i koden
I klassen
så har det skapats en ny medlem, , som borde vara självförklarande.Kapitel 6.4.2 Initialize()
I metoden
initierar vi de objekt som vi kommer behöva under spelet. Metoden ligger utanför spel-loopen så denna metod kommer endast köras en gång.protected override void Initialize() { // TODO: Add your initialization logic here base.Initialize(); }
anropar metoden från den ärvda klassen . Här skriver vi vår egna kod före anropet till basklassens metod. Mer om arv kommer i nästa moment.
Kapitel 6.4.3 LoadContent()
I metoden
så laddas content (innehåll) in, här tänker vi oss att bilder, ljud, fonter och annat innehåll skall läsas in. Denna metod ingår heller inte i spel-loopen så den körs också en gång. Det är lite flytande vad som skall göras i denna metod och vad som skall/kan göras i .protected override void LoadContent() { // Create a new SpriteBatch, which can be used to draw textures. spriteBatch = new SpriteBatch(GraphicsDevice); //TODO: use this.Content to load your game content here }
Här skapas objektet
som använder för att kunna rita ut sprites (bilder) på skärmen.Kapitel 6.4.4 Update()
Metoden
är den första metoden som körs inne i spel-loopen, här kommer alla händelser fångas upp och alla beräkningar att göras. Eftersom denna körs 60 ggr/s så finns det 60 möjligheter per sekund att läsa av en tangent som trycks ner, en musrörelse eller en kollision mellan två objekt i vårt spel. Sedan måste alla beräkningar göras så att objekten flyttar på sig, något händer när två objekt kolliderar som påverkar dessa och andra objekt.protected override void Update(GameTime gameTime) { // For Mobile devices, this logic will close the Game when the Back button is pressed // Exit() is obsolete on iOS #if !__IOS__ && !__TVOS__ if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape)) Exit(); #endif // TODO: Add your update logic here base.Update(gameTime); }
Koden här är ett exempel på hur den metoden kan se ut. Den kod som finns där för tillfället är kod som avbryter spelet på flera olika sätt, beroende på vilken plattform som spelet skall köras på.
Här anropar vi även den ärvda metoden
när vi har gjort våra specifika anrop. Detta fungerar på samma sätt som i .Ändringar i koden
I den automatgenererade koden så har hela blocket med stängknappen i IOS och TVOS.
Kapitel: 6.4.5 Draw()
Metoden rör sig
.
Det är när spelet inte hinner göra alla beräkningar eller rita ut allt som skall ritas ut innan spel-loopens nästa varv börjar som vi upplever att spelet laggar. Datorn hinner helt enkelt inte med allt som skall göras. Då får vi ge mer hårdvaruresurser, skriva effektivare kod eller helt enkelt ta bort delar av spelets detaljer.
protected override void Draw(GameTime gameTime) { graphics.GraphicsDevice.Clear(Color.CornflowerBlue); //TODO: Add your drawing code here base.Draw(gameTime); }
anropas här på samma sätt som tidigare.
Kapitel 6.4.6 UnloadContent()
Metoden
ligger utanför spel-loopen och körs först när spelet avslutas. Här rensar vi upp och släpper resurser som inte behöver finnas kvar när spelet avslutats. Oftast löser detta sig själv, objekt ligger inte kvar och skräpar i minnet när spelet är slut. Däremot är det viktigt att stänga filer som vi har kopplingar till, kanske en fil där data sparas och där den fortfarande är “öppen”. Det är också viktigt att stänga alla eventuella anslutningar ifall vi bygger spel som fungerar över nätverk.protected override void UnloadContent() { // TODO: Unload any non ContentManager content here }
Ändringar i koden
I den automatgenererade koden så skapas inte denna metoden alls.
Kapitel 6.5 Att rita ut på skärmen.
Bilder som används inom spelprogrammering kallas för sprite. Det finns en historik kring hur man använde sprite på ett speciellt sätt tidigare då våra datorer hade mindre kapacitet. Då var det väldigt viktigt att sprites var i exakta storlekar och så optimerade i storlek som det var möjligt. Ofta byggdes större bilder upp av flera mindre sprites för att optimera datorns arbete. Idag har datorerna en helt annan kapacitet och då behöver vi inte trixa med bilder på samma sätt. Namnet sprite har dock blivit kvar. Med det sagt så bör vi ändå se till att våra bilder har rätt storlek när den läses in i spelet, vilket är bra att tänka på när/om du kommer skapa egna sprites.
2.3.2 Arbete med speltutorial
Nu är det dags att skapa projektet SpaceShooter
och börja med bokens tutorial. När projektet är skapat så börjar du med att gå till kunskapsdokument - hjälp till boken som är stöd till boken. Här kommer saker som inte längre stämmer med hur boken gör det att fångas upp. Den första delen i kunskapsdokumentet, “6.5 Lägg till en sprite” visar hur du måste göra för att få det att fungera. I övrigt börjar du på kapitel 6.5.1 i boken och jobbar dig sedan igen kapitel 6 i boken.
Uppgift
När du är klar med kapitel 6 så har du säkerligen en ganska så rörig kod, gå igenom koden, snygga till, kommentera de saker du har gjort medan du kommer ihåg vad du har gjort.
Spara en kopia som innehåller allt som fungerar så här långt så kan du jobba vidare med en kopia i nästa kapitel. Skulle något bli väldigt fel i nästa del så kan du enkelt börja om från ett fungerande projekt istället för att behöva felsöka allt för länge.