UDPATE FOR ANYONE STILL FOLLOWING THIS THREAD
Since this post, Defold has been updated so now you can dynamically create atlases. You no longer need to do anything like what was said above.
local texture_name = "my_texture"
--create image resource from raw image data
local image_resource = imageloader.load{data = image_data}
--create the texture
--no need to add ".loaded", this is just for me to differenciate between runtime-loaded textures and normal texures
local texture_path = resource.create_texture(texture_name..".loaded.texturec", image_resource.header, image_resource.buffer)
...
Now we will tell it where the animations are by splitting the image. I already have an external json file that I converted to a lua table that dictates the x, y, width, and height of the different pieces of the “spritesheet”.
Note: You don’t need to use any json, this code is pulled out of a project that requires me to use javascript. You can easily make a lua table inside your code that has the same information.
BUT if you’re making something that will be importing images dynamically, you will most likely need to create an external json file to go with the texture image and convert it to a table through json.decode()
.
(dont judge me i worked on this in like 2021 ok)
"allocs": {
{
"id": "frame0",
"x": 0,
"y": 0,
"width": 128,
"height": 128
}, {
"id": "frame1",
"x": 129,
"y": 0,
"width": 128,
"height": 128
}, {
"id": "frame2",
"x": 271,
"y": 14,
"width": 100,
"height": 100
}, {
"id": "frame3",
"x": 385,
"y": 0,
"width": 128,
"height": 128
}
}
Even though many of these dimensions are 128x128, they don’t have to be! They don’t need to be square nor a factor of 2. I’m just using an example from when I needed to have it like that.
Now, you need to show where the geometries are. You’re basically just telling the code where in the image this single clip is and how big it is. Since we are giving the variables through a table, we can just iterate it:
--dont mind the weird indentations, I pulled the code out of a project
local geos = {}
for j, w in ipairs(allocs) do
table.insert(geos, {
vertices = {
0, 0,
0, w.height,
w.width, w.height,
w.width, 0
},
uvs = {
w.x, w.y,
w.x, w.y + w.height,
w.x + w.width, w.y + w.height,
w.x + w.width, w.y
},
indices = {0, 1, 2, 0, 2, 3} -- i have no idea what this does or means lol
})
end
Now you add in the animations! According to the API reference for the function we’ll be using, the frame range is non-inclusive of the last number, frame_end
, so frame_end
- frame_start
must equal the amount of frames in the animation.
local anim = {}
--animation of all four frames
table.insert(anim, {
id = "all",
width = 128,
height = 128,
frame_start = 1,
frame_end = 5,
fps = 12
})
--animation of a single frame (the first one)
frame = allocs[1]
table.insert(anim, {
id = frame.id,
width = frame.width,
height = frame.height,
frame_start = 1,
frame_end = 2
})
And if you wanted to add every single one independently, you could always iterate it.
Now we can actually create the atlas.
--again, ".loaded" isn't needed here
local atlas_path = resource.create_atlas(texture_name..".loaded.texturesetc", {
texture = texture_path,
animations = anims,
geometries = geos
})
Yay! Now a sprite can take this atlas and play an animation.
go.set("#sprite", "image", atlas_path)
sprite.play_flipbook("#sprite", "all")
When you’re done and want to delete the texture and atlas, make sure to either delete the objects that were using the atlas or change to a different one before deleting.
resource.release(texture_path)
resource.release(atlas_path)
This code had been pulled out and modified from one of my projects (geometry code isn’t mine either, I got it off some other forum post), so there could be mistakes. This is at least the gist of what needs to be done.