Hello. I new to Defold. Earlier I use Cocos2d-x, Unity and libGDX to create games. Each engine had its own shortcomings, and I decided to try something new.
The question is how to add objects from the library to the scene dynamically. In the engines that I described above everything was simple, but in Defold I don’t clearly understand how it works.
For example, let there be a 2D racing game with 20 types of race tracks (each has its own objects (GameObject of: background, springboards, walls, etc.)) and 256 kinds of cars. When loading the level, I need to create only one skin of the race track and 8 cars.
Can I download only what I need without creating factories for each game object (cause I don’t know what objects I need to create before level data load, and if scene load all (by static creation via factory), it kills device RAM)?
You can load factories dynamically, there is a checkbox on the factory component named “Load Dynamically”. Is that what you need?
No. In cases of dynamic factory creation, I have to create 256 factory + factories manually, which looks like a workaround.
Maybe I’ll be able to figure out what I mean by the example of other engines.
On Unity, it would look like this:
//Creation start
//Create level data
int levelNumber = 5; //Index of level
string levelDirPrefix = “level/level” + levelNumber.ToString());
GameObject background = Instantiate(Resources.Load(levelDirPrefix + “background”, typeof(GameObject))) as GameObject;
GameObject wall = Instantiate(Resources.Load(levelDirPrefix + “wall”, typeof(GameObject))) as GameObject;
GameObject road = Instantiate(Resources.Load(levelDirPrefix + “road”, typeof(GameObject))) as GameObject;
…
//Create cars
int[] carrIds = new int[] { 97, 92, 81, 60 };//Car ids
List cars = new List();
GameObject car = null;
string carPrefix = "cars/car"
for (int i = 0; i < carrIds.Length; ++i) {
_ car = Instantiate(Resources.Load(carPrefix + carrIds[i].toString(), typeof(GameObject))) as GameObject;_
_ cars.Add();_
}
//Creation finish
In Cocos2d-x or libGDX actions will be the same (Differences will be in the fact that you need to add a texture atlas in the cache, and create a new elements of classes cause GameObject isn’t exist in engines).
Ok, what about this:
I would have a single car.go
with a car.script
, a sprite and a collision object. I would use a factory to create instances of car.go
. The car.script
would have a script property car_id
defined using go.property()
. This script property would be used to set the correct sprite and perhaps also look up stuff like acceleration, top speed etcs from a lookup table. I would have the car graphics in car.atlas
and the sprite would use this atlas.
-- create cars
local cars_ids = { 97, 92, 81, 60 }
local cars = {}
for _,car_id in ipairs(cars_ids) do
local car = factory.create("#carfactory", nil, nil, { car_id = car_id })
table.insert(cars, car)
end
-- car.script
go.property("car_id", 0)
function init(self)
-- change to the correct image for the car sprite
msg.post("#sprite", "play_animation", { id = "car" .. self.car_id })
-- use self.car_id to look up acceleration etc
end
When it comes to the level you have several options: one would be to create each level in a collection and use tilemaps to create the level geometry. You’d load the correct level using a collection proxy. Another option would be to create the level geometry using sprites and collision objects with custom shapes. You’d still need to put the levels in collections though.
Ok. As I understand, for level I need to create one level proxy and manualy add it to the stage. But is it any way don’t craet it manualy, and staticly bind to stage? For example if I know that I have 20 skins, create only one collection proxy and chanege the collection ref by “levelSkin/level1”, “levelSkin/level2”, … “levelSkin/level20” via script.
About cars. Every car use spine animation, and rider that use spine too (thay are diferent skeletons from diferent atlases). If I create game object with all referenced animations, is it means that all of them is loaded (Forr example I use car with id 18, but another 256 referenced in GameObject, is thay load?), or Defold load and unload them automaticly?
If you have 20 different levels you have two options:
- Have a single tilemap in a collection, load tilemap data from json and use tilemap.set_tile() to create the map at runtime based on level data
- Create each level as a collection containing the stuff you need to present the level. Load the one you want using collection proxies
If you use the second option then you need to create one collection per level, and yes, you need to do that manually in the editor, but I really don’t see the problem with this? Having all of your game data and objects in collections and game objects is the way Defold is designed to work. This allows us to at build time know exactly what to include in the project and what to exclude as dead/unused resources.
What do you mean when you say “skin”? Is this just visuals or is also things such as level geometry, collision objects and so on?
Oh, ok, I thought they were sprites. Well if each of the 256 cars are different spine models then you need 256 different game objects I’m afraid. Or is there some clever solution to this that I don’t see @sven?
Can you express the 256 different cars as different skins in the spine scene? If so you could use one GO with the spine model and switch skin depending on car type in runtime. If they truly are 256 different spine scenes you would need one GO per car.
In case of “skin” I mean that level have some standart parts: background, wall, road, paralax layer and etc.(Some of them are sprites, some spine objects, but all level skins have same parts). For example first level “snow pack”, second “city pack”, third “space station” and etc. When I load level data (Json with information about level), I need to select what skin to use (for example if in level data skin value is “1” I need to load collection “1” (“snowPack”)), and generate level by it parts.
About car. In start of the race I need to create car with character that use one of car, and one of character. I need to create 8 cars with character, but every user have different cars with different characters and I can’t create it staticly.
I only wont to know mechanis how to load only 8 of them without loading all.
I think you need a collection factory with “Load Dynamically” option:
Yes, but it means add staticly 256 factorys to stage, and 8 factorys for characters (cause I have I different characters). Or I somthing don’t understend. Factory can be added only in editor and I can’t change prototype by script. If this statement is true, I need to create factory for every car, character and level(256 cars + 8 characters + N levels = 264 + N factories ) in level collection set to all of them “Load dynamicly”. Is all atlases, jsons and other data load in this case to RAM? Or objects load only when I using single factory first time?
One game object with one spine model for the car and another for the player. Change skin on the car and player respectively.
Do you really have to have all the data about the level as json data that you parse and use to build the level? There’s a lot of advantages to having each level as a separate collection. You’re able to immediately look at the level and see the layout and all of the graphics. You’re able to move stuff around and see how it looks. Having it in a json file makes the whole process a lot more clunky.
If you really want to have it in json then sure, one collection for the level containing game objects for background, wall, road etc. For everything that is a sprite you use play_animation to change it’s visuals. For everything that is a spine model you change it’s skin.
But in this case I need to use one atlas for all skins, and load a lot of unused information for every level( for example I don’t need “city pack” sprites when use “snow pack” but it will be loaded to RAM).
You’re back to having one level per collection and loading the one you need OR one level collection and factories with the load dynamically checkbox ticked so that only the one needed is loaded in memory.