Textures

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.

Static objecten

  1. 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);
    

Texture Class

  1. Maak in je project een nieuwe folder Support. Daarin voeg je een nieuwe class toe Texture.

  2. 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;
    
  3. 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;
    }
    
  4. 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;
    }
    
  5. 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);
     }
    

Implementatie van de Texture class in de class Game1

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:

  1. 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).
    
  2. In de constructor moeten we enkele aanpassingen doen om de static variabelen sGraphics en sContent te initialiseren:
     public Game1()
         {
             sGraphics = new GraphicsDeviceManager(this);
             Content.RootDirectory = "Content";
             sContent = Content;
         }
    
  3. In de functie LoadContent() moet ook de initialisatie van spriteBatch wat aangepast worden. Hier voegen we 4 afbeeldingen aan de ListTextures 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)));
    
  4. In de Update functie moet het meeste werk gebeuren. In deze functie voorzien we de volgende stappen:
    • Eerst controleren of de spatiebalk ingedrukt werd. We wijzigen in dat geval het geselecteerde object.
    • Daarna moeten we de toetsen W, A, S en D controleren om eventueel de positie aan te passen. We doen dit door de correcte coördinaat van de position variabele te wijzigen.
    • Daarna controleren we de pijltjestoetsen om de schaal aan te passen. Dit doen we a.h.v. de variabele scale.
    • Als laatste worden de position en scale via de Update functie in het geselecteerde element van de list geplaatst.
     //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);
    
  5. Tot slot passen we de 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();
    

Test van het programma

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.

Oefeningen

  1. Laat de objecten sneller bewegen.
  2. Als de spatiebalk ingedrukt is, beweeg en schaal dan alle objecten tegelijk.
  3. Voeg een nieuwe afbeelding toe wanneer je op de T toets drukt. Gebruik random getallen om de positie en de schaal te bepalen. Tip: zoek op het internet op hoe je in C# een random nummer genereert.
  4. Wissel af tussen windowed mode en full-screen mode met de toets F12. Wat is het probleem?

Previous section:
Next section:
Navigatie