Is this ok to use collection instead of game objects?

I’m doing prototype and have some compound shapes (several sprites combines in different orders with different scales)
And instead of doing this in photoshop I do this in defold editor. this is why for these kind of entities i use collection. (and think later i’ll add some simple tween animations to different parts of my object).

So the question is this a big performance difference with standard game object. which created as separated entities in the editor. As a workaround i can create these objects in spine which will reuse sprites in different places. but honestly i prefer to do that right in editor.

thx.

1 Like

Hi Nicloay,

Yes it’s okay, I asked the same question a while ago and they said the best way to make pre fab objects is making collections, not game objects. I found it a little strange that that was the case, because I understood that collections are for levels, menus, etc. and GO are for things in the collection.

I really wish you could directly change an image’s variables (position, rotation, scale, etc). Then I could do it all with Game Objects.

1 Like

One reason it is superior is that you can only parent GOs to each other (for transforms) when they are inside of a collection.

2 Likes

Remember that collections do not exist at runtime. When the game is running there is only the game objects that exist in the collections. And game objects in themselves are cheap. For complex things such as enemies or the player character and many other things it makes total sense to use collections. I use them all the time.

4 Likes

I just found that it’s not obvious to work with collection data. when you spawn collection instance it returns you set of all game objects. In case if i want to assign new parents to the object i need to know which one is a root object in that collection and it’s sims an issue.

Hi, is this still current information? I’m in the same situation right now – I’m using collections as a prefab for enemies. I asked ChatGPT about it, and it said: “Creating collections from a collection factory is more expensive than creating a game object from a traditional factory. Usually a developer uses a GO (game object) as a prefab.” I will have 30–50 enemies on the screen at one time.

2 Likes

Yeah I think Chatgpt is confused by collection proxies versus collection factories (but we are too..I guess).
As I understand it,
Collection proxies are expensive as it spawn a full physic world with its own lifecycle.
But Collection used as complex objects only exists at build time as a hierarchy of game object, and once spawned it is just like create all the gameobjects at once.

So I even guess that it will be more performant to spawn a collection with many gameobjects inside, than spawning each objects one by one from lua and parenting them. Because collection factory are optimised at build time in the C++ side, but looping to create game object is a lua+C++ operation. I am not sure about this, just an educated guess I am doing.

I think the thing that is missing is to allow put objects into objects when the root is a gameobject file. So we could use Gameobjects as prefabs even for a complex objects with many parts, and use collections only for screens/levels stuff. It would make our mind clearer

5 Likes

Correct!

Correct!

I think the difference will be hardly noticeable!

4 Likes

Yes :wink:

Then that shouldn’t be a bottleneck in terms on spawning them. It would maybe count for thousands or maybe even hundreds of thousands of enemies, I think, you would need to measure it. What would matter most probably is the frame time with all of them on screen - so what materials are used, what rendering pipeline, if those are 3D models then also how many polygons, etc. It all really depends. But when it comes to spawning it should be neglectible.

This is a too generic statement to be answered if it’s true or not, so a generic answer to such generic question would be “no, it’s not true”.

Maybe if what’s @Mathias wrote:

would really affect the creation and that might be true (also depends on what you’re spawning mainly and in what amounts) and as @britzl said above it would be most probably hardly noticeable.

A single collectionfactory.create() usually does more work than a single factory.create() if the collection contains multiple game objects, because it creates multiple instances and reconstructs their hierarchy. The alternative - manually calling factory.create() several times from Lua and then parenting everything yourself shouldn’t really be vastly different, but the only honest answer is to measure in the target case.

Collections differ from game objects in Defold, because collections are only files, there is no “collection” in runtime - collection is only a file/data telling game engine to spawn X game objects with this hierarchy, when this collection is loaded. Therefore there is a difference when loading collection and spawning collection. Spawning - via collectionfactory - is just spawning X game objects with a given hierarchy into currently existing game worlds where the factory is.

Loading through a collection proxy creates or loads a separate runtime collection - a new world with new physics world and a new namespace for addressing. Loading resources for a collection factory is something else: it only prepares the prototype resources used later by collectionfactory.create(). And loading can be done asynchronously. This is therefore used for loading levels, menus or very heavy collections, etc.


Why there are collections then in Defold, when in other game engines, like e.g. Unity you can just nest in prefabs?

TL:DR; It’s all because of the architecture of the game engine. In Runtime only Prototype instances exists and they contain Components, but does not contain other instances - instead a graph of hierarchy is a separate entity that is tracking parent-child relationships and helps e.g. in transforms calculations.

So the .go is a file - a prototype. It can be “included” in another file - called .collection, so that’s why we can add game objects on the left side of the Editor, in the Assets pane as files and add them to collections on the right side of the Editor, in the collection’s Outline - embed them inside a collection file.

The Game Object instance is a runtime equivalent to what is stated in the .go file or embedded inside a .collection file that is instantiated inside the game’s world.

A .collection file is not instantiated at runtime as a first-class “collection object” that you can manipulate like a GameObject. When spawned through collectionfactory, it is used as a data template describing which game object instances to create and how to parent them. However, Defold does have an internal runtime Collection structure representing a game world / collection context, especially for bootstrap collections and collection proxies.

Could then the .go file reference other .go files as .collection does?

Yes, it’s conceptually possible, Defold could move toward allowing game objects to nest other game objects in a way that would reduce the distinction between .go and .collection. The team has discussed merging these concepts, but this would be a breaking change, requiring a refactor of the engine code, of the ideas that are there since the very beginning, and therefore not something you should rely on today. Having a collection as a special idea is very well aligned with the data-driven approach in the engine architecture and it corresponds to how the relations in runtime are structured .

The Components in Defold are contained inside a Prototype instance (Prototype “has-a” Component):

Runtime Instances point to a Prototype, and component instance data is allocated separately through Component Worlds.

But Defold does not contain other Instances inside, instead it only has other instances indexes, e.g. a parent and children. Defold is focused on making structures as flat as possible. Defold doesn’t have a complex object oriented structure for a tree of the scene or the world, instead has arrays and instances only have indices to those arrays.

This flat, index-based representation is one of the architectural choices that helps Defold keep runtime data compact and predictable.

So the architecture is vastly different and that is what drives Defold performance.

@JCash or @britzl can perhaps correct me, if there’s something wrong here, that’s only my current understanding of the engine :slight_smile:

7 Likes

:raised_hand: ABSOLUTE EXPLANATION :raised_back_of_hand:
thank you :grinning_face:

1 Like

Yeah, too long and too deep for the answer, but I wanted it to be written somewhere, also for future reference on related questions :sweat_smile:

In case of simple games, simply don’t care. If it starts to lag - then you measure and then optimize based on this. But I get that we always want to write a most optimal code upfront already :sweat_smile:

1 Like

This explanation is a mind-opener for me, thank you! I think this should be in the manual, maybe it seems a bit too deep explanation, but this makes everything clear in my head now. Maybe add a “Want to know more?” section in the manual page for this kind of stuff?
It will help everybody to step in, instead of search through forum and finding random posts so helpful.

Regarding the “permit gameobjects hierarchy inside a gameobject file” feature, now I understand why it is like that, but for me the big drawback is when you must refactor a simple gameobject into a complex gameobject.
Like “ohh now I need to have a specific sub gameobject to move only a part of my hero sprite (like just the head)”… so you have all your code with factory etc. referencing your gameobject file, but then you must break all of it to create a collection instead and change factories to collectonfactories in calling scenes and change factory.create api to collectionfactory.create API…
just to make some parts of your character to move independently… etc.
Especially as you cannot move sprites position (or any components positions by the way) at runtime…which feels odd too.

I think that when you need all these changes for a change that should be encapsulated in one game object, it means there is something flawed, conceptualy.

In my mind, we should have collection usable only as collection proxy, and make gameobjects capable of handling hiearchies.
This would streamline development and make things clear by striping the dual role of collections. But I understand this totally breaks the engine :sweat_smile:

3 Likes