TL;DR
What is the best way of creating reusable collections for spawning procedurally generated levels that can be customized when you instantiate them? That is, using the same collection to generate different level types, as opposed to having one collection for each type of level.
Long version:
I’m struggling on with my procedural generation experiments in Defold and keep running into problems with they way I’d like to code, and the way Defold/lua is designed to work (I think).
I have a procedurally generated Galaxy map, with planets of different types. When the player lands on a planet I would like to generate a random world based on the type of planet. So a desert planet would have dry biomes, a jungle planet lots of forest and so on.
I use Collection Proxies for switching between the Galaxy map and the World map (planet surface). When the player goes to a planet, I Unload the galaxy collection and Load the Worldmap collection via proxies. This works fine, but I would like to be able to tell the Worldmap-GO which kind of world to generate. And I can’t figure out how achieve this.
I have tried sending messages to the worldmap instance after it’s been loaded, but that means I need to know it’s ID and I don’t know how to get that in runtime. If I print msg.Url() form Worldmap I can see that the id of the instance is “#worldmap1”, but I don’t know how to get that Id in runtime from my main controller. The 1 on the end is of course an incremental id, and I wouldn’t want to hardcode that.
Is there a (good) way to send messages or context data to the instances created by the Collection proxy?
Or is there a different way of solving this altogether?
I’ve seen some people suggesting using global Lua modules for shared state, but that seems so centralised. I’d rather have some way of distributing state to each GO so they can be more autonomous and easier to reuse.
What would be the “Defold-way” of doing this?
You can use Monarch that have that possibility to send data between screens which are also collection proxies. Or longer way: if I imagine it correctly, you have a main collection loaded at the beginning that could now have a subscription handling script - whenever a new world you are loading, send its msg.url() in init to the main script, which id is static, so you can then send any data to the loaded world
Ah, I see. So in the init of my collection I would send a message to main which in turn would give me my data? Seems a bit roundabout. But it’s logically rather close to what I was trying: send a message from main to the instantiated collection.
I like the sound of that! It’s a bit like a pub-sub relationship.
I’ll try it out Thanks!
Indeed if you want to set up a “conversation” between two instantiated collections only, just collect their urls in main collection and send to each other, like “changing handshakes”, so they know about themselves
So, you want to recreate No Man’s Sky if I am getting you right.
For that type of thing I would rather suggest using lua modules to store current scene, rather than making gos handle them. Instead, make them handle the functionality of creating the level.
Store the data, basically name or the id of the level you want to generate, and access them using GOs. The GOs will then make descisions using the data you stored, and then use it to create the various structures of the level.
{Meanwhile, spoiler request, is your game 2D or 3D, and if 2D then sidescroller or top down?(I am just to curious about this, as this reminds me of an old game I was working on In July)}
So, I make a Lua module with variables for global data and then call accessor functions on that? Or what is the best way of using a state module like that?
Would you keep the all the game state in modules?
Regarding the game, I wouldn’t say I’m aiming for a new No Man’s Sky So far I’m thinking a 2D top down exploration sand box game. Travel a random galaxy, land on planets, excavate ore, find artifacts, enter locations. All procedurally generated.
My vision of this includes some kind of randomized difficulty made up of several different difficulty factors that vary for different locations/planets/regions. So you get the risk-reward push your luck gameplay where you can pick a more difficult planet that gives greater rewards.
But really I’m mostly trying out Defold and procedural generation.
And this game is similar to an OLD game I was working on in 1992 But that time I was using 68k assembler. Good old times!
(Defold is rather easier to work with )
Here is an (ugly) result of my Defold struggles so far
-- mymodule.lua
local M = {}
local privatedata = "foo"
M.publicdata = "bar"
local function privatefunction()
print("I'm private")
end
function M.publicfunction()
print("I'm public")
end
return M
-- use it like this
local mymodule = require "mymodule"
print(mymodule.publicdata) -- "bar"
mymodule.publicfunction() -- "I'm public"
Once you’ve required it once the returned value (the M table) will get cached and every subsequent require call for the same module will return the same value (the M table). You can unload a module, but that is usually not done.
Yes, you’re manipulating the M table directly. It’s not a copy or anything like that. All loaded modules has their values stored in the package.loaded table and any subsequent require call returns the same value, which in the case of a table will be the same table, not a copy.