JAdventure - Kurs zur Softwareentwicklung
Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Back to homepage

2.3. Laden von Ressourcen

Bereitstellung von Ressourcen

Bilder

Wir brauchen ein paar Bilder für unser Spiel, die wir als Ressourcen in unser Projekt unter src/main/resources einfügen:

  • Eine Grafik für einen Level-Hintergrund
  • Mehrere Grafiken für Spielobjekte.

Ich nutze dazu einfach die Grafiken, die ich bereits habe:

  • Das Testlevel wurde mir von DALL-E generiert
  • DALL-E hat mir einen Drachen generiert, bei dem ich den Hintergrund nur noch transparent machen muss (Ich habe das nur grob auf die Schnelle gemacht und die Qualität ist dementsprechend schlecht in dieser ersten Version.)
  • Ich habe ein paar farbige Kreise (rot, grün und gelb), die ich einfach nutze. Das ist nicht schön, aber wir haben damit erst einmal ein paar Grafiken, die wir nutzen können.

Damit erhalten wir in unseren Projekt die folgenden Dateien:

  • src/main/resources/images/items/green.png
  • src/main/resources/images/items/red.png
  • src/main/resources/images/items/yellow.png
  • src/main/resources/images/level/testlevel.png
  • src/main/resources/images/npc/dragon.png

Level

Nun brauchen wir ein erstes TestLevel, welches wir als JSON bereitstellen können. Bei den Unit-Tests haben wir bereits gesehen, wie so ein Level als JSON serialisiert aussehen kann. Mit Zeilenumbrüchen und Einrückungen wird daraus ein relativ gut lesbarer Text:

{
  "name": "TestLevel",
  "width": 1024,
  "height": 1024,
  "graphicResource": "level/testlevel",
  "objects":[
    {
      "name": "Dragon",
      "size": { "width": 10, "height": 10, "type": "org.jadv.model.size.RectangleSize"},
      "position": {"x": 512,"y": 512},
      "type": "org.jadv.model.objects.GameObject",
      "graphicResource": "npc/dragon"
    },
    {
      "name": "redCircle",
      "size": {"width": 10, "height": 10, "type": "org.jadv.model.size.RectangleSize"},
      "position": {"x": 50, "y": 50 },
      "type": "org.jadv.model.objects.GameObject",
      "graphicResource": "items/red"
    }
  ],
  "type": "org.jadv.model.level.Level"
}

Damit erhalten wir in unserem Projekt die folgende Datei:

  • src/main/resources/level/testlevel.json

Laden der Bilder

Unser Programm soll Bilder laden können. Dazu schreiben wir einen Service, der den Namen einer Bild-Ressource entgegennimmt, die Ressource lädt und als Bild zurückgibt.

package org.jadv.services;

import javax.imageio.ImageIO;
import java.awt.*;
import java.io.IOException;
import java.io.InputStream;

/**
 * Service to provide images.
 */
public class ImageService {

    /**
     * Path where we find image resources.
     */
    public static final String IMAGE_RESOURCE_PATH = "/images/";

    /**
     * File type of image resources.
     */
    public static final String IMAGE_RESOURCE_TYPE = ".png";

    /**
     * Gets an image for a resource name.
     * @param resourceName Name of the resource.
     * @return Image of the resource of null if it could not be loaded.
     */
    public Image getImage(String resourceName) {
        String resourcePath = IMAGE_RESOURCE_PATH + resourceName + IMAGE_RESOURCE_TYPE;
        try (InputStream inputStream = getClass().getResourceAsStream(resourcePath)) {
            if (inputStream == null) {
                return null;
            }
            return ImageIO.read(inputStream);
        } catch (IOException exception) {
            System.out.println("Unable to load resource: " + resourcePath + " (" + exception.getMessage() + ")");
            exception.printStackTrace();
        }
        return null;
    }
}

Diesen Service müssen wir natürlich auch testen:

package org.jadv.services;

import org.junit.jupiter.api.Test;

import java.awt.*;

import static org.junit.jupiter.api.Assertions.*;

/**
 * Tests the ImageService
 */
class ImageServiceTest {

    /**
     * Tests loading of a test level image with a known size.
     */
    @Test
    public void testLoadingLevel() {
        ImageService imageService = new ImageService();

        Image image =  imageService.getImage("level/testlevel");

        assertAll(
                () -> assertNotNull(image),
                () -> assertEquals(1024, image.getWidth(null)),
                () -> assertEquals(1024, image.getHeight(null))
        );
    }

    /**
     * Tests that null is given back when the resource cannot be loaded.
     */
    @Test
    public void testFailedLoading() {
        ImageService imageService = new ImageService();

        Image image =  imageService.getImage("non/existing");

        assertNull(image);
    }
}

Laden der Level

So wie wir einen Service geschrieben haben zum Laden von Image-Ressourcen, benötigen wir auch einen Service zum Laden von Level-Ressourcen. Somit schreiben wir eine Klasse, die uns ein Level aus einer Ressource laden kann:

package org.jadv.services;

import com.google.gson.Gson;
import org.jadv.model.SavedObject;
import org.jadv.model.level.Level;

import javax.imageio.ImageIO;
import java.awt.*;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

/**
* Service to load a Level of a resource.
 */
 public class LevelService {

    /**
     * type of level resources.
     */
    private static final String LEVEL_RESOURCE_TYPE = ".json";

    /**
     * Resource path of level files.
     */
    private static final String LEVEL_RESOURCE_PATH = "/level/";

    /**
     * Loads a Level of a given resource name.
     *
     * @param resourceName Name of the resource.
     * @return The level if resource was found, else null.
     */
    public Level loadLevel(String resourceName) {
        String resourcePath = LEVEL_RESOURCE_PATH + resourceName + LEVEL_RESOURCE_TYPE;
        try (InputStream inputStream = getClass().getResourceAsStream(resourcePath)) {
            if (inputStream == null) {
                return null;
            }

            Gson gson = new Gson();
            return (Level) gson.fromJson(new InputStreamReader(inputStream), SavedObject.class);
        } catch (IOException exception) {
            System.out.println("Unable to load level resource: " + resourcePath + " (" + exception.getMessage() + ")");
            exception.printStackTrace();
        }
        return null;
    }
}

Und diesen testen wir dann auch:

package org.jadv.services;

import org.jadv.model.level.Level;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.*;

class LevelServiceTest {
    /**
     * Tests loading of a test level resource.
     */
    @Test
    public void testLoadingLevel() {
        LevelService levelService = new LevelService();

        Level level =  levelService.loadLevel("testlevel");

        assertAll(
                () -> assertNotNull(level),
                () -> assertEquals(1024, level.getWidth()),
                () -> assertEquals(1024, level.getHeight()),
                () -> assertEquals("TestLevel", level.getName())
        );
    }

    /**
     * Tests that null is given back when the resource cannot be loaded.
     */
    @Test
    public void testFailedLoading() {
        LevelService levelService = new LevelService();

        Level level = levelService.loadLevel("non/existing");

        assertNull(level);
    }
}