In dit hoofdstuk maken we als voorbeeld een programma dat 4 ballonnen op het scherm plaatst. Met de spatiebalk kan je tussen de ballonnen switchen. Met de toetsen W, S, A en D kan je de actieve ballon van plaats veranderen. Met de pijltjestoetsen kan je de actieve ballon van grootte veranderen.
Je leerde in het vorige hoofdstuk al hoe je afbeeldingen kan tonen. Je leerde dat je, om in je Player
class gebruik te kunnen maken van objecten uit de Game class (zoals spriteBatch
en ContentManager
), je deze objecten moest doorgeven als functie argumenten.
In wat volgt gebruiken we een andere aanpak. We maken deze objecten static
in de game. Deze static objecten kan je ze vanuit elk object gebruiken en ze moeten dus niet meer als functie argumenten doorgegeven worden.
Voorbereiding: Maak een nieuw project aan met de naam Voorbeeld_Textures. Laad de afbeelding Balloon via de Pipeline tool naar de content. In dit project werk je onderstaande stappen uit.
Pas de definities in je Game1
class aan door hier static objecten van het type SpriteBatch, ContentManager en GraphicsDeviceManager toe te voegen. Zoals je ziet geven we deze objecten in onderstaand voorbeeld de namen sContent en sGraphics.
public static SpriteBatch sSpriteBatch;
public static ContentManager sContent;
public static GraphicsDeviceManager sGraphics;
Aangezien we nu met een static GraphicsDeviceManager object werken, moet de onderstaande lijn uit de constructor verwijderd worden. We kunnen immers gebruik maken van het static GraphicsDeviceManager object sGraphics, dus de constructor moet geen object van dit type meer maken.
graphics = new GraphicsDeviceManager(this);
Maak in je project een nieuwe folder Support
. Daarin voeg je een nieuwe class toe Texture
.
De Texture
class lijkt sterk op de player class in het vorige hoofdstuk. We laten dan ook opnieuw een afbeelding zien. Maar, naast de Texture2D variabele (voor de image) voegen we ook nog de nodige variabelen toe de positie en de grootte. De variabelen voor de positie en de grootte zijn van het type Vector2
. Een Vector2
variabele definieert een positie in een tweedimensionaal vlak en heeft een X en een Y coördinaat. Deze X en Y coördinaten zijn van het type float en kunnen apart aangesproken worden. Zo kunnen we voor de Vector2 met naam position spreken van position.X (bevat de waarde van de X coördinaat) en position.Y (bevat de waarde van de Y coördinaat).
Texture2D image;
Vector2 position;
Vector2 size;
De constructor moet via argumenten deze drie variabelen initialiseren. Hij moet dus de naam van de afbeelding, zijn positie en zijn grootte doorgeven. Merk in de code hieronder op dat we nu geen ContentManager
meer moeten doorgeven. We kunnen nu gewoon de contentManager van Game1
gebruiken omdat die static
is en dus beschikbaar is in ons hele project.
public Texture(String image, Vector2 position, Vector2 size)
{
this.image = Game1.sContent.Load<Texture2D>(image);
this.position = position;
this.size = size;
}
In de Update
functie geven we niet echt de positie en schaal door, maar de wijzigingen ten opzichte van de huidige positie en schaal. Met andere woorden: we geven door hoeveel de huidige positie naar boven, onder, links of rechts moet. Zo’n wijziging noemen we een delta. Daarover leer je later meer. Voor de size geven we dan weer de wijziging in grootte door, ook dit gebeurt met een delta.
public void Update(Vector2 deltaTranslate, Vector2 deltaScale)
{
position += deltaTranslate;
size += deltaScale;
}
In de Draw
functie gebruiken we deze keer een andere werkwijze dan bij de Draw functie uit het hoofdstuk Inleiding. In de Draw functie van de Inleiding, maakten we a.h.v. 2 Point-objecten een Rectangle
object waarbinnen we de figuur plaatsten.
Omdat we nu niet meer met Point
argumenten werken, maar met Vector2
variabelen levert dit volgend probleem: Een Rectangle object verwacht integers om te initialiseren en de Vector2
variabelen bevatten floats. We omzeilen dit probleem door eerst het Rectangle
object te maken en hierbij de X en Y coördinaten van de Vector2
variabelen even te behandelen als integers.
Deze Rectangle
geven we dan als argument aan de Draw
functie door en zal gebruikt worden op de image te positioneren.
Natuurlijk geven we naast de Rectangle
nog steeds de weer te geven image en de achtergrondkleur mee. Dit blijft hetzelfde als bij Draw
functie van de inleiding.
Verder maken we in de Draw
functie gebruik van het static object sSpriteBatch dat we in de Game1 class declareerden.
public void Draw()
{
//We maken eerst het Rectangle object a.h.v. de Vector2 variabelen position en size.
Rectangle destRect = new Rectangle((int)position.X, (int)position.Y, (int)size.X, (int)size.Y);
//Het Rectangle object wordt doorgegeven aan de Draw functie.
Game1.sSpriteBatch.Draw(image, destRect, Color.White);
}
De Texture
class is nu klaar voor gebruik. We gebruiken deze class in Game1
. Let op, zowel de class Texture
als de class Game1
hebben functies met dezelfde naam. Zorg dat je duidelijk weet welke functie wanneer gebruikt wordt. Dit staat vaak ook in de commentaar aangegeven.
Voer voor de implementatie van de Texture
class in de Game1
class de volgende stappen uit:
Voeg aan de lijst met variabelen een List
toe om textures te onthouden. We gaan zo dadelijk textures selecteren via de spatiebalk. Daarom moet je ook kunnen onthouden welke de geselecteerde texture is.
List<Support.Texture> Textures = new List<Support.Texture>();
int selected = 0; //Met selected verwijzen we naar het element van de list dat
//op een bepaald moment actief is. (zie verder in punt 4).
static
variabelen sGraphics en sContent te initialiseren:
public Game1()
{
sGraphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
sContent = Content;
}
In de functie LoadContent()
moet ook de initialisatie van spriteBatch wat aangepast worden. Hier voegen we 4 afbeeldingen aan de List
Textures toe. Merk op dat de constructor voor elk Texture
object de naam van een afbeelding en 2 Vector2
argumenten nodig heeft. We voegen 4 maal de afbeelding balloon toe, telkens op een andere positie en in 2 verschillende groottes.
sSpriteBatch = new SpriteBatch(GraphicsDevice);
Textures.Add(new Support.Texture("balloon", new Vector2(10, 10), new Vector2(30, 30)));
Textures.Add(new Support.Texture("balloon", new Vector2(200, 200), new Vector2(100, 100)));
Textures.Add(new Support.Texture("balloon", new Vector2(50, 10), new Vector2(30, 30)));
Textures.Add(new Support.Texture("balloon", new Vector2(50, 200), new Vector2(100, 100)));
Update
functie moet het meeste werk gebeuren.
In deze functie voorzien we de volgende stappen:
//Als de spatiebalk ingedrukt wordt, verleggen we de focus
//naar het volgende element uit de List Textures.
//Van zodra we het einde van de lijst bereikt hebben,
//leggen we de focus terug op het eerste element (index wordt terug 0).
if(Keyboard.GetState().IsKeyDown(Keys.Space)) {
selected++;
if (selected >= Textures.Count) selected = 0;
}
//Declaratie van hulpvariabelen waarin een eventuele aangepaste
//positie en schaal zal opgeslagen worden.
var position = new Vector2();
var scale = new Vector2();
if (Keyboard.GetState().IsKeyDown(Keys.W)) position.Y++;
if (Keyboard.GetState().IsKeyDown(Keys.S)) position.Y--;
if (Keyboard.GetState().IsKeyDown(Keys.A)) position.X--;
if (Keyboard.GetState().IsKeyDown(Keys.D)) position.X++;
if (Keyboard.GetState().IsKeyDown(Keys.Up)) scale.Y++;
if (Keyboard.GetState().IsKeyDown(Keys.Down)) scale.Y--;
if (Keyboard.GetState().IsKeyDown(Keys.Left)) scale.X--;
if (Keyboard.GetState().IsKeyDown(Keys.Right)) scale.X++;
//We maken gebruik van de functie Update (die we in de class
//Texture maakten) om position en scale die we hierboven
//een waarde gaven bij de position en scale van het actieve
//Texture object uit de lijst op te tellen. Op die manier kan
//de positie en/of de size van een Texture object gewijzigd worden.
Textures[selected].Update(position, scale);
Draw
functie aan. Hier moeten we de static sSpriteBatch gebruiken en de lijst met textures op het scherm tonen.
sSpriteBatch.Begin();
//D.m.v. ForEach wordt de Draw functie van de Texture class
//op elk Texture object uit de List toegepast.
Textures.ForEach(texture => texture.Draw());
sSpriteBatch.End();
Als je het programma start, zie je de 4 ballonnen verschijnen, elk op hun eigen positie. Met de spatiebalk kan je tussen de 4 ballonnen switchen. Met de toetsen W, S, A en D kan je de actieve ballon van plaats veranderen. Met de pijltjestoetsen kan je de actieve ballon van grootte veranderen.