Looks great, wish you the best.
no enemies to fight with? interesting
Looks great, wish you the best.
Thanks for AABB again
There will be some enemies, but none implemented yet. Enemies will be less of a focus than in Void Scrappers.
I wonder how you implemented the world, is it a tile map?
Thank you for the wishlist!
Each block is a game object → sprite → tilesource. This is so that I can apply auto-tiling.
Here’s what a tilesource looks like:
Each animation in the tilesource corresponds to a bitmask. I used this excellent guide to figure out how to use bitmasking for auto-tiling.
Happy to share more if people have any questions about the project.
One thing I was grappling with for a while was garbage collection. I frequently spawn/despawn lots of blocks as the player moves around in the world. This eventually triggers the garbage collector, which results in a really noticeable stutter.
I used the discussion in this thread as a starting point for a solution. Thank you @cornedbeer - your thoughts were really useful and I would have struggled to realise that placing this script in the main collection would ensure it runs last.
The idea is that I run the garbage collector in tiny increments each frame, until I reach the time limit (e.g. 0.167 seconds for 60 fps). I have also implemented a flag which prevents the garbage collector from running on particularly intensive frames (e.g. if I despawn a chunk of blocks).
Simplified, it looks something like this:
if garbage.intensive_frame then --Don't run the garbage collector during a particulary intensive frame --This flag can be set by any script and will prevent garbage collection from running that frame collectgarbage("stop") garbage.intensive_frame = false else --Run garbage collection steps until finished or we run out of time this frame -- https://forum.defold.com/t/solved-optimizing-frame-stability-avoiding-garbage-collector-related-hitches/70930/3 frame_time_diff = socket.gettime() - frame_start_time garbage_finished = false while not garbage_finished and frame_time_diff < frame_time_target do garbage_finished = collectgarbage("step", 1) frame_time_diff = socket.gettime() - frame_start_time end end frame_start_time = socket.gettime()
A key component of making this work is setting a reasonable step size for the garbage collector. For me, this was 110:
Thanks! These are really lots of very useful information.
Maybe you can create a separate thread where you can discuss some of your solutions?
Thank you! I really don’t mind sharing a mix of general updates and technical stuff. If it becomes too cluttered though I’d be happy to start separate threads.
Maybe a small blog post? It’s very interesting and helpful!
Great tips! Personally, I love everything about code optimisation
Please tell us more details about why does spawning/despawning blocks stress GC? I assume it’s because a lot of tables are created and deleted, right? Are they created by collectionfactory?
Thanks! I am very proud about pulling off the garbage collection implementation (but of course it wasn’t my idea!). Otherwise I actually find code optimisation a bit stressful, but I keep making really intense games so I guess I have to learn some things
Just regular factories actually.
Each block has two tables associated with it - permanent data (such as what type it is, location, etc). It also has temporary data when it is spawned (game object reference, AABB id for collisions, etc). The table with temporary data is created/deleted when I perform culling.
I’m not entirely sure what exactly stresses out the garbace collector. What I found, surprisingly, is that deletion is much costlier than creation. I haven’t narrowed down whether that is go deletion or table splicing or something else.
When I have to spawn block “sectors” (sector is what I call a set of blocks that ~cover the player’s window), I batch them so that one sector is spawned each frame. When I have to remove sectors, I batch it so that one row of a sector is deleted each frame (so it takes about 20 frames to remove one sector). If I delete an entire sector in a frame, I get a stutter!
Glad my thread was helpful! Since then I’ve actually discovered one very unfortunate issue with Lua’s GC that you may or may not run into depending on the scope of the project/how much you rely on pre-processing and storing data and how you structure that data.
Luckily the work-around isn’t too bad, but it’s something that might drive you crazy if you start running into issues and don’t know why. I’ll make a post about it in my original thread for anyone who’s interested.
Good luck with the new project, the destructible terrain looks really satisfying already!
Thanks for the heads up! Very interesting, and you are correct in saying that would be very hard to debug. I think this project will manage to avoid hitting these large numbers, because I do end up doing a fair bit of table nesting + the mining shafts are finite in depth and width.
I love destruction and chain reactions so this vein of explosive ores was a great idea (courtesy of wife)!
Thank you! This helps us out a lot
Infested caves! Been working on enemies a bit. I think this feels super satisfying (and the wriggly eggs are disgusting).
We’ve got a fresh new trailer out! Would love to hear what you think. You can check it out here:
Looks great, wishlisted!
Thanks for the support everybody! I’m super excited about this game. I’ve taken a lot of what I’ve learned from Void Scrappers, and applied it to something that isn’t quite so close to the Vampire Survivors formula. Wasn’t sure I would be able to pull it off, but I am very pleased with the game feel we’ve achieved so far. It feels very powerful and intense, which is just what we wanted.
Working with Defold remains fantastic, and I recommend the engine to anyone that asks. Thanks to everybody on the forums/Discord, thanks to everyone making extensions, and thanks to the Defold team!
If I may shill a bit further… We are so close to 100 followers on Steam! Maybe someone could push us over the edge!