Wintermute – Preloding von Animationen und Bildern

Wenn eine WME-Scene viele Sprite-Entities enthält, jeweils mit Animationen über viele Frames, so kann das Wechseln zu dieser Szene leicht bis zu 10 Sekunden und darüber hinaus dauern. Um das zu verhindern, müsste man z.B. die einzelnen Grafiken und Animationen bereits beim Spielstart laden (preload), damit sie beim Szenenwechsel bereits  im Speicher liegen. Da die Engine keine richtige „Preload“-Funktion hat, müssen wir einem Trick anwenden.

Warum dauert das Laden so lang?

Die lange Ladezeit rührt daher, dass beim Wechsel der Szene alle Einzelbilder für Hintergründe, Sprites, Animationen, etc. in den Speicher geladen werden müssen. Haben wir es dann mit „großen“ PNG-Files zu tun, z.B. als Frames über die gesamte Auflösung von 1280×720 kommen leicht mehrere 100 MB zusammen.

Beispielrechnung: width * height * 4 bytes of memory
Angenommen wir haben 3 Sprites mit jeweils 32 Frames und in voller Auflösung von 1280×720.
Benötigter Speicher = ((1280 x 720 x 4 x 32 x 3)/1024)/1024 = 337 MB

Was kann ich dagegen tun?

Entferne den ungenutzten Platz im PNG-File, d.h. wenn das PNG 1280×720 Pixel groß ist, die Grafik aber nur 100 Pixel in der oberen Ecke einnimmt, entferne den ungenutzten Platz, mach das PNG 100×100 Pixel groß. Dein Speicher wird es Dir danken.

Und was war das jetzt mit dem Trick?

Ach ja, wenn das noch nicht ausreicht für performantes Laden der Scene, können wir folgenden Trick anwenden, um die Animationen beim Spielstart vorzuladen.

  1. Wir erstellen ein Sprite mit allen Einzelbildern, die geladen werden sollen (z.B. preloadContainer.sprite)
  2. Wir erstellen ein Entity-Objekt z.B. unter entities\preloadContainer.entity
  3. Wir hängen das Sprite an das Entity-Objekt
    ENTITY
    {
      NAME="preloadContainer"
      ACTIVE=TRUE
      X=200
      Y=200
      SCALABLE=TRUE
      INTERACTIVE=TRUE
      COLORABLE=TRUE
      SPRITE="entities\preloadContainer.sprite"
      TALK="entities\preloadContainer.sprite"
      SCRIPT="entities\preloadContainer.script"
      FONT = "fonts\defaultGrey10.font"
    }
    
  4. Wir laden das Entity-Objekt mit dem Sprite-Container in Startdatei des Spiels, im game.script.
    var entity;
    entity = Game.LoadEntity("entities\preloadContainer.entity");
    entity.Active = false;
    

Dadurch werden unmittelbar beim Spielstart die im Sprite enthaltenen Bilder in den Speicher geladen. Die Engine gibt während dem initialen Ausführen des game.script automatisch die Zeile „Loading“ auf dem Bildschirm aus.
Wenn man will, kann man den Preload-Prozess aber auch in eine komplett eigene Scene auslagern und dort einen Ladebildschirm oder eine Animation anzeigen.

Einen eigenen Ladebildschirm verwenden

Um einen eigenen Ladebildschirm zu verwenden, erstellen wir eine neue Scene. Diese verwenden wir als „Startup scene“.
Wir können uns nun einen entspr. Ladebildschirm malen, z.B. den Titel-Screen des Spieles mit einem Lade-Hinweis oder eine Art Fortschrittsbalken als Animation.
Für ersteres setzen wir das Bild einfach als Sprite einer Background-Entity im Scene-Editor.

Für den Fortschrittsbalken benötigen wir ein paar Einzelbilder als PNG. Während des Ladens von Bildern in den Speicher werden keine Frames einer Animationen geupdatet, d.h. für eine Fortschrittsbalkenanimation müssen wir etwas tricksen. Folgendes schreiben wir in das init_scene.script unserer Ladeszene.

// show progressbar via DisplayLoadingIcon
Game.DisplayLoadingIcon("scenes\startup\loading\img\progress00.png", 500, 450, true);
// hide the inventory
Game.InventoryVisible = false;
Sleep(500);
// show next state of progress bar
Game.DisplayLoadingIcon("scenes\startup\loading\img\progress01.png", 500, 450, true);

// load the preload entity - it takes a while
var entity;
entity = Game.LoadEntity("entities\preloadContainer.entity");
entity.Active = false;

// the other states
Game.DisplayLoadingIcon("scenes\startup\loading\img\progress02.png", 500, 450, true);
Sleep(500);
Game.DisplayLoadingIcon("scenes\startup\loading\img\progress03.png", 500, 450, true);
Sleep(500);
Game.DisplayLoadingIcon("scenes\startup\loading\img\progress04.png", 500, 450, true);
Sleep(500);

// and hide progress bar
Game.HideLoadingIcon();

// load the scene after preloading
Game.ChangeScene("scenes\startup\logo\logo.scene");

Mit Game.DisplayLoadingIcon können wir manuell ein Bild / Sprite anzeigen, wann immer wir etwas komplexes laden oder berechnen müssen. Hier zeigen wir zunächst einen leeren Balken (progress00.png) an, setzen den Füllstand auf 25% (progress01.png) und beginnen dann mit dem eigentlichen Laden der Entität und somit dem Laden der Bilder in den Speicher. Nach dem Laden mit LoadEntity() schließen wir die manuelle Füllanimation ab und blenden den Fortschrittsbalken mit HideLoadingIcon() wieder aus. Zum Schluss wechseln wir zur nächsten Szene.

Und so könnte der LadeScreen aussehen:

loadingScreenProgress

Ähnliche Beiträge

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert