Objecten en Methoden Arjan Egges & Paul Bergervoet Eigen methode toevoegen class Painter : Game { public void HandleInput() { … } Eigen bedachte methode! protected override void Update(GameTime gameTime) { HandleInput(); … } } De ‘HandleInput’ methode public void HandleInput() { prevMS = currMS; prevKS = currKS; currMS = Mouse.GetState(); currKS = Keyboard.GetState(); if (currKS.IsKeyDown(Keys.R) && prevKS.IsKeyUp(Keys.R)) cannonColor = Color.Red; else if (currKS.IsKeyDown(Keys.G) && prevKS.IsKeyUp(Keys.G)) cannonColor = Color.Green; else if (currKS.IsKeyDown(Keys.B) && prevKS.IsKeyUp(Keys.B)) cannonColor = Color.Blue; } Verschillende soorten methoden • Methoden met een resultaat object: currMS = Mouse.GetState(); • Methoden zonder een resultaat object: GraphicsDevice.Clear(Color.Olive); • Methoden met parameters: currKS.IsKeyDown(Keys.G) • Methoden zonder parameters: spriteBatch.Begin() Verschillende soorten methoden • Sommige methoden bewerken objecten spriteBatch.Begin() • Sommige methoden bewerken geen objecten (maar horen wel bij een klasse) – Deze methoden noemen we static Console.WriteLine("Hallo"); • In de methode header kun je zien wat voor soort methode het is! Methode headers public static void Main() { static methode (bewerkt geen object) … } public void HandleInput() methode zonder parameters { … methode zonder resultaatobject } protected override void Update(GameTime gameTime) { … methode met 1 parameter } Methoden met resultaat We stoppen er een float in... ...en we leveren een float op. public float CalculateSquare(float x) { Met return geven we aan return x*x; wat opgeleverd wordt. } • Vergelijkbaar met wiskundige functie – f(x) = x2; • In het gebruik: float f = CalculateSquare(10.0f); Methoden met resultaat • Na een return stopt de methode public int SomeMethod() { return 12; int tmp = 45; Wordt nooit uitgevoerd! } • Daar kunnen we gebruik van maken! public float SquareRoot(float f) { if (f < 0.0f) return 0.0f; // Hier weten we nu zeker dat altijd geldt dat f >= 0 } Methoden met resultaat • Return waarde kunnen we in een variabele bewaren: float f = CalculateSquare(10.0f); • Maar dat hoeft niet! if (CalculateSquare(10.0f) != 100.0f) Console.WriteLine("Your processor is broken"); Tekenen of opleveren? • Console.Writeline (x, ...) • spriteBatch.Draw(cannon, Vector2.Zero,...) • return x; resultaat komt meteen op het scherm resultaat wordt teruggegeven aan de aanroeper, die zelf kan beslissen wat hij ermee doet Declaraties vs. parameters • Lijken erg op elkaar public float SquareRoot(float f) { Gebruiken we als locale variabele if (f < 0.0f) return 0.0f; … } protected override void Update(GameTime gameTime) { Locale variabele int red; red = gameTime.TotalGameTime.Milliseconds; … } Methoden • Hoe meer parameters, des te flexibeler de methode public void Draw(Texture2D sprite, Vector2 position, Color col, float rotation, float scale, bool mirror, float transparency, Rectangle part, Vector2 origin, Rectangle destination, …) { … en des te lastiger aan te roepen... Flexibiliteit Veel parameters: • Nu lastig om te programmeren • In de toekomst misschien gemakkelijk uit te breiden Weinig parameters: • Nu gemakkelijk om te programmeren • In de toekomst misschien lastig te onderhouden Programma en geheugen opdrachten veranderen zijn gegroepeerd in methoden zijn gegroepeerd in bewerken zijn gegroepeerd in klasse variabelen objecten hebben als type klasse klasse Objecten en geheugen • Built-in types in het geheugen - Numerieke typen (int, double, ...) int i = 12; double pi = 3.14; - Tekst (strings) string s = "hallo, "; s += "Arjan"; i s 12 b 3.14 "hallo, "hallo, Arjan" " - Waarheidswaarden bool b = true; b = !b; pi false true Objecten en geheugen • Gevolg: public void keerTwee(int getal) i) { i *= 2;*= 2; getal } int i = 3; keerTwee(i); // wat is nu de waarde van i? Nog steeds 3, want de waarde wordt gekopieerd bij het doorgeven aan de keerTwee methode! Objecten en geheugen • Typen die gebaseerd zijn op een klasse werken anders verwijzing! Texture2D cannonBarrel width height data … … … … Waarom verwijzingen? • Bij een aanroep van een methode wordt niet het hele geheugen gekopieerd, alleen de verwijzing • Objecten kunnen worden doorgegeven tussen methoden Verwijzingen • Built-in types (int, double, float) – Values – Speciaal geval: string “non-mutable” • Object-typen gedefinieerd door klassen – References (verwijzingen) • Object-typen gedefinieerd door structs – Values (!) – Wordt gebruikt voor simpele datastructuren – Voorbeelden: Vector2, Point, Color… Creatie van objecten • Opbouw van object is gespecificeerd in de klasse Painter game class Painter : Game { GraphicsDeviceManager graphics; SpriteBatch spriteBatch; Texture2D background, cannonBarrel; Vector2 barrelPosition, barrelOrigin; float angle; // methoden... Overgeërfd uit de Game-klasse GraphicsDevice IsMouseVisible Content barrelPosition angle barrelOrigin graphics } spriteBatch background cannonBarrel game Painter geërfd van Game zelf gedeclareerd game GraphicsDeviceManager Painter SpriteBatch graphics spriteBatch background barrelPosition 72 405 angle 0 barrelOrigin 34 34 Texture2D cannonBarrel Texture2D De Cannon klasse • Groepeer alle member variabelen die bij het kannon horen in een klasse Cannon class Cannon { Texture2D cannonBarrel; Texture2D colorRed, colorGreen, colorBlue; Texture2D currentColor; Vector2 position; Vector2 barrelOrigin, colorOrigin; Color color; float angle; // methoden worden nog toegevoegd. } Declaratie Declaratie reserveert geheugenruimte • Voor een primitieve waarde int x; x = 5; zoals beschreven in struct Vector2 5 x • Voor een object-waarde Vector2 p; p = new Vector2(10,20); p X Y • Voor een object-verwijzing SpriteBatch s; s = new SpriteBatch(…); s 10 0 0 20 zoals beschreven in klasse SpriteBatch Constructie van nieuw object new-expressie doet twee dingen: cannon = new Cannon (…) ; • Geheugenruimte klaarzetten cannon position 72 405 Texture2D • Constructormethode aanroepen waarde is pijl naar het nieuwe object die je kunt opslaan color cannonBarrel … Cannon 0 0 255 Geen return type! Parameter(s) van de constructormethode public Cannon(ContentManager Content) { this.cannonBarrel = Content.Load<Texture2D>("spr_cannon_barrel"); this.colorRed = Content.Load<Texture2D>("spr_cannon_red"); this.colorGreen = Content.Load<Texture2D>("spr_cannon_green"); this.colorBlue = Content.Load<Texture2D>("spr_cannon_blue"); this.currentColor = colorBlue; color = Color.Blue; MemberbarrelOrigin = new Vector2(cannonBarrel.Height, cannonBarrel.Height) / 2; variabelen krijgen een colorOrigin = new Vector2(currentColor.Width, waarde. currentColor.Height) / 2; position = new Vector2(72, 405); } Constructie van een nieuw object class Painter : Game { ... Cannon cannon; ... Membervariabele protected override LoadContent() { spriteBatch = new SpriteBatch(GraphicsDevice); background = Content.Load<Texture2D>("spr_background"); cannon = new Cannon(Content); } Informatie doorgeven ... via parameters! } null • Als een variabele nog nergens naar wijst, dan zeggen we dat de variabele null is: Cannon cannon; • Dit kunnen we zelfs in condities gebruiken: if (cannon == null) cannon = new Cannon(Content); • Of korter: null mapt naar de booleanwaarde false if (!cannon) cannon = new Cannon(Content); Objecten • Object: groepje variabelen dat bij elkaar hoort r 255 g 255 b 0 w 100 h 20 aantal prijs ha l l o ! 3 199.95 Objecten "vraag niet hoe het kan... " • Om een object te gebruiken, hoef je niet te weten uit welke variabelen het object bestaat "maar profiteer ervan! " • Je hoeft alleen te weten - welke methoden er zijn - welke properties er zijn Game objecten ontwerpen • Wat doet een game object? – Invoer van de speler afhandelen – Zichzelf bijwerken (update) – Zichzelf tekenen (draw) • Bijbehorende methoden: – HandleInput – Update – Draw • Daarnaast: – Reset Methoden in Cannon public void Draw(GameTime gameTime, SpriteBatch spriteBatch) { spriteBatch.Draw(cannonBarrel, position, null, Color.White, angle, barrelOrigin, 1f, SpriteEffects.None, 0); spriteBatch.Draw(currentColor, position, null, Color.White, 0f, colorOrigin, 1f, SpriteEffects.None, 0); } public void Reset() { currentColor = colorBlue; color = Color.Blue; angle = 0.0f; } Property voor lezen positie Type van de property Naam van de property public Vector2 Position { get Property lezen { return position; } } • Zo gebruiken we de property: Vector2 cannonPos = cannon.Position; public Color Color Property lezen { get { return color; } Controleren of set het wel mag. Property schrijven { if (value != Color.Red && value != Color.Green && value != Color.Blue) return; color = value; value bevat de if (color == Color.Red) rechterkant van de currentColor = colorRed; toekenning else if (color == Color.Green) currentColor = colorGreen; else if (color == Color.Blue) currentColor = colorBlue; } } Properties • Sommige properties mag je alleen lezen – String.Length – Viewport.Width • Sommige properties mag je ook schrijven – Vector2.X – Content.RootDirectory – Cannon.Color Properties • Properties hoeven niet altijd direct met een waarde van een membervariabele te corresponderen, bijv.: public Vector2 Center { get { return new Vector2(sprite.Width, sprite.Height) / 2; } } Spelerinvoer afhandelen • Spelerinvoer afhandelen is nogal omslachtig momenteel: previousMS = currentMS; previousKS = currentKS; currentMS = Mouse.GetState(); currentKS = Keyboard.GetState(); Veel dubbele code, dus je maakt snel fouten! if (currentKS.IsKeyDown(Keys.R) && previousKS.IsKeyUp(Keys.R)) cannon.Color = Color.Red; else if (currentKS.IsKeyDown(Keys.G) && previousKS.IsKeyUp(Keys.G)) cannon.Color = Color.Green; else if (currentKS.IsKeyDown(Keys.B) && previousKS.IsKeyUp(Keys.B)) cannon.Color = Color.Blue; ... De InputHelper klasse class InputHelper { MouseState currMS, prevMS; KeyboardState currKS, prevKS; Deze informatie wordt bewaard in een InputHelper object // methoden en properties } De klasse InputHelper beschrijft hoe een object van het type InputHelper eruit ziet! class Painter : Game { GraphicsDeviceManager graphics; SpriteBatch spriteBatch; Declaratie InputHelper inputHelper; … static void Main() { Painter game = new Painter(); game.Run(); } public Painter() { Content.RootDirectory = "Content"; graphics = new GraphicsDeviceManager(this); inputHelper = new InputHelper(); Toekenning en maken } van een instantie … Handige methoden class InputHelper { MouseState currMS, prevMS; KeyboardState currKS, prevKS; InputHelper object public void Update() bijwerken in zijn eigen { Update methode prevMS = currMS; prevKS = currKS; currMS = Mouse.GetState(); currKS = Keyboard.GetState(); } … Handige methoden = deze methode mag in een andere klasse aangeroepen worden. public bool MouseLeftButtonPressed() { return currMS.LeftButton == ButtonState.Pressed && prevMS.LeftButton == ButtonState.Released; } public bool KeyPressed(Keys k) { return currKS.IsKeyDown(k) && prevKS.IsKeyUp(k); } InputHelper gebruiken protected override void Update(GameTime gameTime) { inputHelper.Update(); HandleInput(inputHelper); // hier nog de game wereld bijwerken } Cannon krijgt zijn eigen HandleInput public void HandleInput(InputHelper inputHelper) { if (inputHelper.KeyPressed(Keys.R)) Color = Color.Red; Veel korter en veel else if (inputHelper.KeyPressed(Keys.G)) overzichtelijker! Color = Color.Green; else if (inputHelper.KeyPressed(Keys.B)) Color = Color.Blue; double opposite = inputHelper.MousePosition.Y - position.Y; double adjacent = inputHelper.MousePosition.X - position.X; angle = (float)Math.Atan2(opposite, adjacent); } GameWorld klasse class GameWorld { Texture2D background; Cannon cannon; Game wereld bestaat uit alle game objecten public GameWorld(ContentManager Content) { background = Content.Load<Texture2D>("spr_background"); cannon = new Cannon(Content); } public void HandleInput(InputHelper inputHelper) { cannon.HandleInput(inputHelper); } ... ... public void Update(GameTime gameTime) { } public void Draw(GameTime gameTime, SpriteBatch spriteBatch) { spriteBatch.Begin(); spriteBatch.Draw(background, Vector2.Zero, Color.White); cannon.Draw(gameTime, spriteBatch); spriteBatch.End(); } public Cannon Cannon { get { return cannon; } } } class Painter : Game { GraphicsDeviceManager graphics; SpriteBatch spriteBatch; Static member variabele InputHelper inputHelper; static GameWorld gameWorld; … protected override void LoadContent() { spriteBatch = new SpriteBatch(GraphicsDevice); gameWorld = new GameWorld(Content); } Constructie van de game wereld … public static GameWorld GameWorld { Static property om get { return gameWorld; } erbij te kunnen } } protected override void Update(GameTime gameTime) { inputHelper.Update(); gameWorld.HandleInput(inputHelper); gameWorld.Update(gameTime); } protected override void Draw(GameTime gameTime) { GraphicsDevice.Clear(Color.White); gameWorld.Draw(gameTime, spriteBatch); } Overzicht programma-constructies geeft het type van variabelen Type Declaratie • Lokale variabele voor tijdelijk gebruik • Membervariabele permanent deel van het object • Parameter om waarden door te spelen aan methoden waarde-verzameling van een expressie • Primitief type – int – double – bool, enz. • Object-type – Color, Vector2 enz. – Game, SpriteBatch, enz.