[TUT] Game development 04 - SpriteSheets en Sprites

This site uses cookies. By continuing to browse this site, you are agreeing to our Cookie Policy.

  • Dit is een vervolg op: [TUT] Game development 03 - Screen Class

    Hallo ICTScripters,

    In deze tutorial wordt een begin gemaakt aan het serieuze werk namelijk: SpriteSheets en Sprites. Maar voor we hier mee beginnen is het eerst belangrijk om te weten wat een Sprite en SpriteSheet is.

    Zoals je waarschijnlijk wel al weet, een game bestaat uit verschillende objecten. In onze game gaan we gebruik maken van 2D afbeeldingen waarbij elk object een Sprite wordt genoemd. Meestal bestaat een Sprite uit de volgende waardes: colordepth * width * height. Net als op het web willen wij er voor zorgen dat de laadtijd van deze Sprites zo klein mogelijk wordt. Om dit te bereiken gaan we deze losse Sprites naast en onder elkaar plaatsen als 1 afbeelding om zo de laadtijd van losse objecten (meerder afbeeldingen) te beperken naar 1 afbeelding. Zo'n afbeelding met losse Sprites wordt een SpriteSheet genoemd.

    Natuurlijk zal ik het maken van Sprites jullie besparen en kun je in de bijlage een SpriteSheet downloaden die wij gaan gebruiken voor onze game. Plaats de spritesheet.png in de volgende map: res/textures. De res map kun je aanmaken door met je rechter muis op het project te klikken en te selecteren: New => Source Folder. De submap kan gemaakt worden d.m.v de: New => Folder optie. Controleer vervolgens via de project properties of de res map tussen de source packages staat. Dit doe je door met je rechter muis op het project te klikken en te selecteren: Properties => Java Build Path => Libraries. Wanneer de res map er tussen staat is alles goed gegaan, wanneer dit niet het geval is moet je deze toevoegen via de Add Class Folder optie.

    Het voorbereidende werk is nu gedaan, we gaan nu beginnen met het maken van de SpriteSheet Class. Maak daarom in de gfx package een nieuwe class aan met de naam SpriteSheet:

    Java Source Code

    1. package com.michaelbeers.elysium.gfx;
    2. import java.awt.image.BufferedImage;
    3. import java.io.IOException;
    4. import javax.imageio.ImageIO;
    5. public class SpriteSheet {
    6. // Dit is een variabel voor de breedte en hoogte van de SpriteSheet.
    7. // Deze mag/moet statisch zijn omdat deze niet meer wijzigd
    8. public final int SIZE;
    9. // Hier wordt het pad van de SpriteSheet source opgeslagen.
    10. private String path;
    11. // Hier worden alle losse pixels opgeslagen van de SpriteSheet.
    12. // Dit is nodig om straks de Sprite te kunnen berekenen.
    13. public int[] pixels;
    14. public SpriteSheet(String path, int size) {
    15. this.path = path;
    16. this.SIZE = size;
    17. this.pixels = new int[SIZE * SIZE];
    18. // De spritesheet laden.
    19. load();
    20. }
    21. private void load() {
    22. try {
    23. // Hiermee laad je de sprite d.m.v. een resource loader.
    24. BufferedImage image = ImageIO.read(SpriteSheet.class.getResource(path));
    25. // Hier word de afbeelding van de resource loader opgeslagen als losse pixels.
    26. int w = image.getWidth();
    27. int h = image.getHeight();
    28. pixels = image.getRGB(0, 0, w, h, null, 0, w);
    29. } catch (IOException e) {
    30. e.printStackTrace();
    31. }
    32. }
    33. }
    Display All


    Nu kunnen wij een SpriteSheet inladen vanuit de resource map. Nu hebben we alleen nog een Class nodig om alles te slicen naar Sprite objecten maak daarom nog een Class Sprite aan:

    Source Code

    1. package com.michaelbeers.elysium.gfx;
    2. public class Sprite {
    3. public final int SIZE;
    4. private int x, y;
    5. public int[] pixels;
    6. private SpriteSheet sheet;
    7. public Sprite(int size, int x, int y, SpriteSheet sheet) {
    8. this.SIZE = size;
    9. this.pixels = new int[SIZE * SIZE];
    10. this.x = x * size;
    11. this.y = y * size;
    12. this.sheet = sheet;
    13. load();
    14. }
    15. private void load() {
    16. // Dit stukje code is eigenlijk het belangrijkste.
    17. // Hierin wordt doormiddel van een loop voor de X en Y as een berekening gemaakt
    18. // om zo de juiste aantal pixels uit te snijden. Hier wordt eigenlijk het zelfde trucje
    19. // toegepast als het tekenen van de pixels in render van de Screen Class
    20. for (int y = 0; y < SIZE; y++) {
    21. for (int x = 0; x < SIZE; x++) {
    22. pixels[x + y * SIZE] = sheet.pixels[(x + this.x) + (y + this.y) * sheet.SIZE];
    23. }
    24. }
    25. }
    26. }
    Display All


    Nu rest ons alleen nog de taak om deze SpriteSheet met in ons geval een grass Sprite in te laden en te gebruiken in onze client. Vul daarom de SpriteSheet klasse aan met een statische variabel voor de SpriteSheet die wij in de Resource map hebben staan.

    Source Code

    1. // Het path moet altijd beginnen met een / dit staat voor een root map.
    2. // In ons geval is dit de res map, de 256 staat voor de grootte van de spritesheet in pixels
    3. // dit is in ons geval 256x256 pixels
    4. public static SpriteSheet testSheet = new SpriteSheet("/textures/spritesheet.png", 256);


    Vervolgens kunnen wij nu de SpriteSheet gebruiken om Sprites te genereren. Vul daarom de Sprite klasse aan met een statische variabel voor de grass Sprite.

    Source Code

    1. // Het eerste parameter staat voor de grootte van de sprite in ons geval 16x16
    2. // De tweede en derde parameter staat voor de kolom en rij in de Spritesheet
    3. // Het vierde parameter staat voor de SpriteSheet waaruit de Sprite moet worden gesliced.
    4. public static Sprite grass = new Sprite(16, 0, 0, SpriteSheet.testSheet);


    We gaan tot slot nu de render() methoden aanpassen in de Screen klasse om te kijken of alles is gelukt, dit is allemaal voorbeeld code omdat wij nog levels moeten gaan genereren.

    Source Code

    1. public void render(int xOffset, int yOffset) {
    2. for (int y = 0; y < height; y++) {
    3. int ypixels = y + yOffset;
    4. if (ypixels < 0 || ypixels >= height) {
    5. continue;
    6. }
    7. for (int x = 0; x < width; x++) {
    8. int xpixels = x + xOffset;
    9. if (xpixels < 0 || xpixels >= width) {
    10. continue;
    11. }
    12. pixels[xpixels + ypixels * width] = Sprite.grass.pixels[(x & 15) + (y & 15) * Sprite.grass.SIZE];
    13. }
    14. }
    15. }
    Display All


    Om nu errors te voorkomen moeten we in de Game klasse render() veranderen naar render(0,0). Hiermee is dan ook het einde gekomen van deze tutorial, iets meer theorie omdat het zaak is dat je dit begrijpt voor we verder kunnen met de game. In de volgende tutorial gaan we de Keyboard events aanpakken en ervoor zorgen dat de "map" die we nu hebben gemaakt kan bewegen. In deze tutorial zal ik dan ook weer de Github repository updaten.

    Met vriendelijke groet,

    Michael Beers
    Images
    • spritesheet.png

      1.7 kB, 256×256, viewed 218 times
    Dit was mijn spreekbeurt, zijn er nog vragen?

    1,027 times read

Comments 3