Dynamically loading scenes and managing scene-specific assets

I have a problem similar to one described in another topic here, Incremental asset downloading.

As the original poster, I’m working on a game that’s going to include a lot of assets. Think of like a comic book where each scene is a page in the book. From each page you can go to a couple of other pages (scenes). So I thought that instead of loading all assets and scenes at once, I could load only assets required for this specific scene and then preload other scenes.

I started with something like this:

class Scene00 extends Phaser.Scene {
  constructor() {
    super('Scene00')
  }

  preload() {
    this.load.image('defaultTextBg', 'assets/UI/UI-defaultTextBg.png')
    this.load.image('defaultButton', 'assets/UI/UI-defaultButton.png')
    this.load.sceneFile('Scene01', 'js/scene01.js')
  }

Right off the bat I ran into a couple of problems with this. The cache is global, so if I go from scene Scene00 to Scene01 and then back to Scene00, preload will be called again and so:

  1. The task created by this.load.image('defaultTextBg', …) fails because defaultTextBg is already loaded. For assets shared by all scenes this can be solved by preloading them somewhere else, but what about scene-specific assets? Should I just add explicit checks for the given keys before I attempt to load them?
    • My teammate suggested that we should look into removing scene-specific assets after the scene is closed to avoid problems with memory. Does Phaser have anything to help with that or do we need to build something custom using CacheManager API?
  2. this.load.sceneFile('Scene01', …) raises an error because Scene01 is already loaded. Do I need to check if Scene01 is available before calling this.load.sceneFile or is there a better way to solve this problem?

Would appreciate any help with these problems or some general thoughts on structuring a Phaser game with requirements like that!

Hi!

Do you need to stop your scenes every time you switch them? Have you considered just putting them to sleep/waking up? This way you won’t call preload() and create() every transition.

2 Likes

Hi,
What is the size of all images in Mo ?
And how do you plan to serve the game? Html? Electron?..

That’s one way to solve it I suppose! Not sure what the overhead of having several dozen of scenes sleeping will be though, but we can definitely try it.

You mean in megabytes? We haven’t got around to converting PSD files to images yet, but I suppose we might end up with images taking 2.5–5MB, accounting for retina screens and there will be several dozen of them.

Edit: Oh yeah, I forgot, the game will be served in the browser for now.

Sleeping scene does not update nor render, so I wouldn’t worry too much :slight_smile:

imo, if the size of the game is excessive for a html game, i would serve it with electron or node webkit, so people download it once (better for the planet, and people hate long loading times) and you can preload all your assets in one preload scene, it will be fast from disk to disk. Where i have a doubt is how the browser cache the image, i think on disk but i can be wrong…

1 Like

:wave:

  1. IMO the best strategy is to always use unique asset keys. But if you don’t, then you must remove assets with ambiguous keys in the scene’s shutdown event.
  2. I think don’t you need load.sceneFile() and should avoid it.
2 Likes

Removing assets on shutdown could also help me with clearing up cache if bloating it becomes a problem, thanks.

As to unique asset keys: my initial thinking was that each scene would preload its own dependencies: the assets it uses and the scenes it transitions to. Hence why assets shared between the scenes have the same key. I thought I could just this.load.image the same key twice and Phaser would ignore it, but it doesn’t work like that.

I know that the usual approach is to have a loading screen where you preload all assets that are going to be used in the game, but I don’t think that’s going to cut it in our case.

What should I use instead to load scenes dynamically as needed? In theory I could use Webpack and dynamic imports, but based on my experiences from writing single page apps in React, I’d like to avoid using Webpack unless I absolutely have to. :no_mouth:

I’m afraid I don’t understand what this problem is. The asset cache is global, so every asset is shared between scenes. There is no need to load any asset twice. There is no need to load any asset twice by the same key. It’s already in the cache, with that key.

It’s very rare to need to download scene scripts on demand. Likely you just need to start or add scenes on demand.

1 Like

I was trying to explain what my mental model was and that it was wrong. :wink:

And that’s because even if I add a scene, the preloading won’t start until I start the scene, right? :thinking: I think I’m finally starting to get the hang of it, thanks!


BTW, my problem with calling this.load.image describe in my original post seems to be solved. I’m not sure what I’m doing differently, but now when I call this.load.image in preload and then stop and start the scene again, I’m not getting any errors. The example with changing scenes also works like that. Hell, I can even have two scenes preload the same asset with the same key and I’m not getting any errors.

Maybe I misunderstood the error message and it was related to calling this.load.sceneFile twice.

1 Like

That is it. :+1: