Best practices for managing lots of assets

My game is taking many seconds to load at the beginning; I'm definitely loading like, everything at startup. Images, objects, etc. I've never really had to manage this sort of thing before, so I'm just curious about how y'all handle startup and just loading / unloading whatever is necessary for the current scene! Any advice, however general, is appreciated.

1 Like

My general approach involves an asset manager that performs lazy loading and handles providing already lazy loaded assets. When an asset is requested directly it is loaded immediately but all other assets are loaded whenever there is some extra time remaining in the current frame. I try to defer requesting an asset until the last possible moment so it has a better chance of being preloaded when it won't potentially block the update loop.

So basically you would have a preload method for each of your types that takes a list of all assets of that type. At the end of every frame you run a lazy loading method to load assets if there's available time left in that frame. Finally you use a get method for each type at the last possible moment that will either return the already lazy loaded asset or load it directly (and cache it for future calls).

Here's an (untested) example Lua implementation of that idea: AssetManagement.zip (6.3 KB) (updated 2021-01-05)

9 Likes

One additional thing I might do is add the following to the very end of Assets.lazyLoad():

if count==0 then 
	Assets.lazyLoad = function() end
end

effectively turning it into a no-op once there's nothing left to lazy load.

1 Like

My tip is to use image tables! Loading, say, one image table with 10 frames is much faster than loading 10 separate images. This, in hindsight, makes a lot of sense but it was not obvious to me when I got started on Playdate. :sweat_smile:

3 Likes

Oh yes, definitely start with using imagetables :playdate_wink:

1 Like

Thanks, @shaun! This is really helpful, and beyond what it does, I immediately see several code tricks I haven't been using. I'll try this out!

And yeah, I've been using imagetables for related images and animation sequences, @mistermo. I haven't been sure of the best way to create atlases of dissimilar images, since every cell in an imagetable has to be the same size. If I could combine, say 20 or 50 images of very different sizes into a single imagetable and... I guess draw them all centered, that would probably be better than using separate files? I'd have to update a lot of my draw calls since I've been using the default upper left origin, but that's not much work if it would save resources.

Is there an upper limit on how big you'd want any given imagetable to be on Playdate?

1 Like

I can't think of any limits you're likely to run into regarding the image table format itself. The image count and the image width and height are stored as 16-bit unsigned ints, so you could go up to 65,535 for any of those, in theory.

I have an open feature request to allow for creating image tables from multiple image files by using a filename convention like

image-table-1.png
image-table-2.png
image-table-3.png
...

That'll make it easier to create tables out of differently-sized images. I'll bump up the priority on that.

5 Likes

Oh, wow! That would be tremendous. We spent some time this weekend working out how to prepare and organize tables of related images of different sizes, but being able to create them at build time would be a massive help!

Could I offer a request that's similar?

Let the developer name folders with names having -table to make an imagetable of variable-sized images containing all images found within the folder, and let that imagetable be keyed by name (the names of the images in the folder) instead of integer.

So a folder structure containing hero-table/down.png and hero-table/right.png would create an imagetable named hero with images keyed as down and right.

(And while I'm at it: it would also be amazing if for grid-based tables I could get images based on their (x, y) cell coordinate pair, and not just index. I often work by building up a table cell-by-cell, and once a table has gotten sufficiently tall I sometimes want to make it wider to balance things out, but doing so would mess up all the indexes past the first row. But (x, y) coordinates of existing cells would remain constant.)

3 Likes

Yeah, named references within imagetables would help a lot for building atlases of non-sequential images.

Have you looked into spritesheet management software?

Adding table:getBitmap(x,y) will be a snap because the table does store how many cells across the image was. Great idea! And so obvious in retrospect I'm a bit embarrassed I hadn't thought of it. :slight_smile:

Adding named images to tables is.. not as easy. But I definitely see the value of it. I'll file it and try and think of the best way to implement that.

3 Likes

I've used other software to manage spritesheets before, but haven't dug into how to integrate any of them into the Playdate.

You're right, Nick. There would be sone leg work of getting things working together. I've not needed irregular sprite sheets... yet.

1 Like

The simplest idea I've had is just to set the cells to the largest included sprite, and then anchor everything in the upper left and draw from there. It shouldn't hurt anything to draw some extra transparent space. The only problem is keeping it organized and remembering which file is which since they have to be called by frame number rather than filename. But I can think of a few ways to manage that!

Here's a potentially terrible idea: a build script that generates imagetables from folders of related but arbitrarily sized images and provides a simple LUA API to load and access those images by name. Check the included README.md for usage: Autotable-20200514b.zip (17.2 KB)
(Apparently building proof-of-concepts nobody asked for is my thing :sweat_smile:)

10 Likes

This is great, @shaun! I'm gonna look into it this week. Your AssetManager library saved my butt a couple days ago; our game started crashing on boot because it look too long to load images, and it only took me 30 minutes to convert enough stuff to deferred loading with your code to get the game booting much faster! I really appreciate you taking the initiative to draft out these tools; it's a huge help for me as someone still comparatively-new to programming in this environment. Thank you!

2 Likes

@shaun Well, I've tried out the Autotable library, and our initial tests look great!

I had a scene that was lagging badly as I paged through a gridview, a book with a background image, and up to 9 different "stamps" on each page. I put all the images for the scene in an autotable together. 64 images, totaling 262 KB. The library produces a single 186 KB image, appears to reduce loading time, and eliminates all the FPS lag in the scene! Basically, it works great.

I'm going to stress-test it by creating scene-based autotables for the other ~250 images we have in the project so far (in a new git branch, don't worry). I'll report back once I make that change. But @dave, y'all might want to look into adding something like this to the standard library (assuming there's a compile step that doesn't require this external makefile arrangement). "Put related images in a folder and call them as an imagetable" is a huge quality of life improvement!

Thanks again, Shaun!

2 Likes

Just chiming in to say that this thread is super helpful!

1 Like

Glad to hear this is working out! Since it's actually proving useful I added caching so it will only regenerate imagetables when images are added, modified, or removed from its autotable directory, or when a previously generated imagetable is deleted, instead of on every build.

Autotable-20200525.zip (16.7 KB)

To update you should just need to replace your old make/autotable.php with the updated one.

2 Likes