|
@@ -26,197 +26,106 @@ Collections are tree structures that hold game objects and other collections. A
|
|
|
|
|
|
When the Defold engine starts, it loads a single _bootstrap collection_ as specified in the "game.project" settings file. The bootstrap collection is often named "main.collection" but you are free to use any name you like.
|
|
When the Defold engine starts, it loads a single _bootstrap collection_ as specified in the "game.project" settings file. The bootstrap collection is often named "main.collection" but you are free to use any name you like.
|
|
|
|
|
|
-A collection can contain game objects and other collection, nested arbitrarily deep. Here is an example file called "main.collection". It contains one game object (with the id "can") and one sub-collection (with the id "bean"). The sub-collection, in turn, contains two game objects: "bean" and "shield".
|
|
|
|
|
|
+A collection can contain game objects and other collections (by reference to the sub-collection's file), nested arbitrarily deep. Here is an example file called "main.collection". It contains one game object (with the id "can") and one sub-collection (with the id "bean"). The sub-collection, in turn, contains two game objects: "bean" and "shield".
|
|
|
|
|
|
{srcset="images/building_blocks/[email protected] 2x"}
|
|
{srcset="images/building_blocks/[email protected] 2x"}
|
|
|
|
|
|
-Notice that the sub-collection with id "bean" is stored in its own file, called "/main/bean.collection":
|
|
|
|
|
|
+Notice that the sub-collection with id "bean" is stored in its own file, called "/main/bean.collection" and is only referenced in "main.collection":
|
|
|
|
|
|
{srcset="images/building_blocks/[email protected] 2x"}
|
|
{srcset="images/building_blocks/[email protected] 2x"}
|
|
|
|
|
|
-You can see what file an object instance is based on in the outline view. The file "main.collection" contains three instances that are based on files:
|
|
|
|
-
|
|
|
|
-1. The "bean" sub-collection.
|
|
|
|
-2. The "bean" script component in the "bean" game object in the "bean" sub-collection.
|
|
|
|
-3. The "can" script component in the "can" game object.
|
|
|
|
-
|
|
|
|
-{srcset="images/building_blocks/[email protected] 2x"}
|
|
|
|
|
|
+You cannot address collections themselves since there are no runtime objects corresponding to the "main" and "bean" collections. However, you sometimes need to use the identity of a collection as part of the _path_ to a game object (See the [addressing manual](/manuals/addressing) for details):
|
|
|
|
|
|
-If you bootstap the engine from the above "main.collection", it will instanciate three game objects with the following identities:
|
|
|
|
|
|
+```lua
|
|
|
|
+-- file: can.script
|
|
|
|
+-- get position of the "bean" game object in the "bean" collection
|
|
|
|
+local pos = go.get_position("bean/bean")
|
|
|
|
+```
|
|
|
|
|
|
-- "/bean/bean"
|
|
|
|
-- "/bean/shield"
|
|
|
|
-- "/can"
|
|
|
|
|
|
+A collection is always added to another collection as a reference to a collection file:
|
|
|
|
|
|
-Note that there is _no runtime object_ corresponding to the sub-collection "bean" itself. Please refer to the [addressing manual](/manuals/addressing) for details on how to address objects in Defold.
|
|
|
|
|
|
+<kbd>Right-click</kbd> the collection in the *Outline* view and select <kbd>Add Collection File</kbd>.
|
|
|
|
|
|
## Game objects
|
|
## Game objects
|
|
|
|
|
|
-Game objects are simple objects that each have a separate lifespan during the execution of your game. Game objects are usually equipped with visual or audible representation (a sound or sprite component, for instance). They can also be equipped with behavior through script components. Game objects are thus a separate thing from sprites, models or sounds in that they are _containers_ for these different type of components. You create game objects and place them in collections in the editor, or spawn them dynamically at run-time with _factories_.
|
|
|
|
-
|
|
|
|
-There are two different ways you can create game objects in the editor:
|
|
|
|
-
|
|
|
|
-1. Create a game object file and then create an instance of that file in a collection.
|
|
|
|
-2. Create an _in-place_ instance of a game object in a collection.
|
|
|
|
-
|
|
|
|
-Let's look at the difference between these.
|
|
|
|
|
|
+Game objects are simple objects that each have a separate lifespan during the execution of your game. Game objects have a position, rotation and scale that each can be manipulated and animated at runtime.
|
|
|
|
|
|
-## Prototypes and instances
|
|
|
|
-
|
|
|
|
-When you create a game object _file_, you create a blueprint, or a prototype, for a game object. This prototype can then be _instanced_ into one or many game objects.
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-Creating a game object file does not add anything to your running game. The game object does not exist yet, only the formula to create it. To add an actual game object based on the blueprint just created, you add an instance of the game object to a collection in your project by right clicking the collection and selecting <kbd>Add Game Object File</kbd>.
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-Now you are able to start working on the game object. You might create a large number of instances of the object, each one being an exact clone of what's stored in the game object file.
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-The nice thing with this model is that if you change the game object file you are changing the prototype, so any instance that uses the file as its blueprint will immediately change.
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-## Childing game objects
|
|
|
|
|
|
+```lua
|
|
|
|
+-- animate X position of "can" game object
|
|
|
|
+go.animate("can", "position.x", go.PLAYBACK_LOOP_PINGPONG, 100, go.EASING_LINEAR, 1.0)
|
|
|
|
+```
|
|
|
|
|
|
-Let's now look at a case which might seem peculiar at first. Add an instance "my_gameobject" of the above prototype file to a collection, then create another game object called "heart" _in place_ (right click and select <kbd>Add Game Object</kbd>) with some component. Finally, make "heart" the child of "my_gameobject" by dragging it onto it. You now have a collection that looks like this:
|
|
|
|
|
|
+Game objects can be used empty (as position markers, for instance) but are usually used equipped with various components, like sprites, sounds, scripts, models, factories and more. Game objects are either created in the editor, placed in collection files, or dynamically spawned at run-time through _factory_ components.
|
|
|
|
|
|
-
|
|
|
|
|
|
+Game objects are either added in-place in a collection, or added to a collection as a reference to a game object file:
|
|
|
|
|
|
-You might assume that by dragging the "heart" object onto "my_gameobject" you would change the file "my_gameobject.go", but that is not what happens. The effect of the operation is that the game object _instance_ "my_gameobject" gets a child attached to it. The game object instance has two separate properties for its prototype and its children. When you add children to a game object instance you add the object to the object's *children* property -- you don't touch the prototype.
|
|
|
|
|
|
+<kbd>Right-click</kbd> the collection in the *Outline* view and select <kbd>Add Game Object</kbd> (add in-place) or <kbd>Add Game Object File</kbd> (add as file reference).
|
|
|
|
|
|
-If you open the collection in the text editor by right clicking and selecting <kbd>Open With ▸ Text Editor</kbd> you can inspect the game object data structure:
|
|
|
|
|
|
|
|
-```txt
|
|
|
|
-name: "default"
|
|
|
|
-instances {
|
|
|
|
- id: "my_gameobject"
|
|
|
|
- prototype: "/a_simple_test/my_gameobject.go"
|
|
|
|
- children: "heart"
|
|
|
|
- ...
|
|
|
|
-}
|
|
|
|
-scale_along_z: 0
|
|
|
|
-embedded_instances {
|
|
|
|
- id: "heart"
|
|
|
|
- data: "embedded_components {\n id: \"sprite\"\n type: \"sprite\"\n data: \"tile_set: \\\"/cards_example/cards_sprites.atlas\\\"\\ndefault_animation: \\\"heart\\\"\\nmaterial: \\\"/builtins/materials/sprite.material\\\"\\nblend_mode: BLEND_MODE_ALPHA\\n\"\n position {\n x: 0.0\n y: 0.0\n z: 0.0\n }\n rotation {\n x: 0.0\n y: 0.0\n z: 0.0\n w: 1.0\n }\n}\n"
|
|
|
|
- ...
|
|
|
|
-}
|
|
|
|
-```
|
|
|
|
|
|
+## Components
|
|
|
|
|
|
-You can see clearly that the game object instance has a property *prototype* that is set to the game object file. It has another property *children* that lists "heart" as its only child. The game object "heart" is different. Since it's an in_place game object not based on a prototype, it is listed under *embedded_instances* and all its data is stored right inside the collection file.
|
|
|
|
|
|
+Components are used to give specific expression and/or functionality to game objects. Components have to be contained inside game objects and are affected by the position, rotation and scale of the game object that contains the component:
|
|
|
|
|
|
-::: important
|
|
|
|
-Apart from making a clear distinction between game object prototypes and instances when working with them in the editor, you should also take the time to carefully study how game objects are identified with a _fixed_ id in run time and how and why the id is unaffected by childing. The [Message passing documentation](/manuals/message-passing) explains this in detail.
|
|
|
|
-:::
|
|
|
|
|
|
+{srcset="images/building_blocks/[email protected] 2x"}
|
|
|
|
|
|
-At this point you might ask yourself _"What if I create a game object file with a game object and a child, and then remove the child after having instanced the object in a collection?"_ The answer is simply that you can't. A game object file is a blueprint for a single game object. It only makes sense to add children to instances of game objects, either at build time in the editor by editing a collection---or at runtime via:
|
|
|
|
|
|
+Many components have type specific properties that can be manipulated and there are component type specific functions available for interacting with them in runtime:
|
|
|
|
|
|
```lua
|
|
```lua
|
|
-msg.post("my_object", "set_parent", { parent_id = go.get_id("my_parent") })
|
|
|
|
-```
|
|
|
|
-
|
|
|
|
-## Components
|
|
|
|
|
|
+-- disable the can "body" sprite
|
|
|
|
+msg.post("can#body", "disable")
|
|
|
|
|
|
-Components are used to give specific expression and/or functionality to game objects. They don't live a life of their own but have to be contained inside game objects. There are two different ways in which you can create new components in the editor:
|
|
|
|
|
|
+-- play "hoohoo" sound on "bean" in 1 second
|
|
|
|
+sound.play("bean#hoohoo", { delay = 1, gain = 0.5 } )
|
|
|
|
+```
|
|
|
|
|
|
-1. Create a component-type _file_, then create an instance of that component inside a game object.
|
|
|
|
-2. Create an _in-place_ instance of a component in a game object.
|
|
|
|
|
|
+Components are either added in-place in a game object, or added to a game object as a reference to a component file:
|
|
|
|
|
|
-In either of these cases you create components of a specific type. Opening that component in the editor fires up a component type specific editor that allows you to manipulate the component in ways that make sense for the type.
|
|
|
|
|
|
+<kbd>Right-click</kbd> the game object in the *Outline* view and select <kbd>Add Component</kbd> (add in-place) or <kbd>Add Component File</kbd> (add as file reference).
|
|
|
|
|
|
-In the previous section you saw how the editor stores embedded components in a game object though the *embedded_components* property. If we instead chose to instance the component from a file reference, the data looks like this:
|
|
|
|
|
|
+In most cases it makes most sense to create components in-place, but the following component types must be created in separate resource files before being added by reference to a game object:
|
|
|
|
|
|
-```lua
|
|
|
|
-embedded_instances {
|
|
|
|
- id: "heart2"
|
|
|
|
- data: "components {\n id: \"sprite\"\n component: \"/a_simple_test/my_heart.sprite\"\n position {\n x: 0.0\n y: 0.0\n z: 0.0\n }\n rotation {\n x: 0.0\n y: 0.0\n z: 0.0\n w: 1.0\n }\n}\n"
|
|
|
|
- ...
|
|
|
|
-}
|
|
|
|
-```
|
|
|
|
|
|
+* Script
|
|
|
|
+* GUI
|
|
|
|
+* Particle FX
|
|
|
|
+* Tile Map
|
|
|
|
|
|
-The component specific data are stored in the component file referenced via the *component* property.
|
|
|
|
|
|
+## Objects added in-place or by reference
|
|
|
|
|
|
-The most common component type is probably the _script component_, which you use to create behaviors. It is easy to forget that there is a clear boundary between the script component and the containing game object. For instance, the following style of message passing is common:
|
|
|
|
|
|
+When you create a collection, game object or component _file_, you create a blueprint, or a prototype. This only adds a file to the project file structure, nothing is added to your running game. To add an instance of a collection, game object or component based on a blueprint file, you add an instance of it in one of your collection files.
|
|
|
|
|
|
-```lua
|
|
|
|
-msg.post("my_object", "my_message", { my_data = 1 }})
|
|
|
|
-```
|
|
|
|
|
|
+You can see what file an object instance is based on in the outline view. The file "main.collection" contains three instances that are based on files:
|
|
|
|
|
|
-Here, we send a custom message to a game object "my_object". This usually works, but is not recommended. First, since sending messages to a game object _broadcasts_ the message to all containing components you create unnecessary overhead. Secondly, you might even break the behavior of a game object. Suppose, for instance, that the game object has several script components that all listen to the "my_message" message and they are not designed to run simultaneously. The recommended way of addressing messages is to instead be as specific as possible, and that requires that you keep the difference between game object and component in mind.
|
|
|
|
|
|
+1. The "bean" sub-collection.
|
|
|
|
+2. The "bean" script component in the "bean" game object in the "bean" sub-collection.
|
|
|
|
+3. The "can" script component in the "can" game object.
|
|
|
|
|
|
-```lua
|
|
|
|
-msg.post("my_object#script", "my_message", { my_data = 1 })
|
|
|
|
-```
|
|
|
|
|
|
+{srcset="images/building_blocks/[email protected] 2x"}
|
|
|
|
|
|
-## Custom component properties
|
|
|
|
|
|
+The benefit of creating blueprint files becomes apparent when you have multiple instances of a game object or collection and wishes to change all of them:
|
|
|
|
|
|
-Components have type specific properties that you set to alter the component in one way or another. It may be the width and height of a sprite component, or a flag dictating whether a sound component should loop its sound or not during playback. _Script components_, in contrast, allow you to specify custom properties for any purpose. In a script you define a script component simply by adding its definition to the script file:
|
|
|
|
|
|
+{srcset="images/building_blocks/[email protected] 2x"}
|
|
|
|
|
|
-```lua
|
|
|
|
--- self.health will be automatically set to 100 by default. You can change
|
|
|
|
--- the init value for any instance containing the script component in the editor.
|
|
|
|
-go.property("health", 100)
|
|
|
|
-
|
|
|
|
-function on_message(self, message_id, message, sender)
|
|
|
|
- -- Now we can access the property as "self.health"
|
|
|
|
- ...
|
|
|
|
-end
|
|
|
|
-```
|
|
|
|
|
|
+By changing the blueprint file, any instance that uses that file will immediately be updated.
|
|
|
|
|
|
-A detailed explanation of how script properties work and how they can be used is found in the [Script properties documentation](/manuals/script-properties). The script properties you define are a type of instance property associated your script component. Defold stores them on file as a generic component property. If the game object is instanced from a prototype, a separate *component_properties* property is added to the object instance containing any script properties (and in the future, possibly other component properties):
|
|
|
|
|
|
+{srcset="images/building_blocks/[email protected] 2x"}
|
|
|
|
|
|
-
|
|
|
|
|
|
+## Childing game objects
|
|
|
|
|
|
-```txt
|
|
|
|
-component_properties {
|
|
|
|
- id: "script"
|
|
|
|
- properties {
|
|
|
|
- id: "my_property"
|
|
|
|
- value: "4712.0"
|
|
|
|
- type: PROPERTY_TYPE_NUMBER
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-```
|
|
|
|
|
|
+In a collection file, you can build hierarchies of game objects so that one or more game objects are children to a single parent game object. By simply <kbd>dragging</kbd> one game object and <kbd>dropping</kbd> it onto another the dragged game object is childed under the target:
|
|
|
|
|
|
-Conversely, in an embedded game object, any component properties are explicitly expressed as a *properties* property in the collection file:
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-```txt
|
|
|
|
-data: "components {\n"
|
|
|
|
-" id: \"some_script\"\n"
|
|
|
|
-" component: \"/a_simple_test/my_thing.script\"\n"
|
|
|
|
-" position {\n"
|
|
|
|
-" x: 0.0\n"
|
|
|
|
-" y: 0.0\n"
|
|
|
|
-" z: 0.0\n"
|
|
|
|
-" }\n"
|
|
|
|
-" rotation {\n"
|
|
|
|
-" x: 0.0\n"
|
|
|
|
-" y: 0.0\n"
|
|
|
|
-" z: 0.0\n"
|
|
|
|
-" w: 1.0\n"
|
|
|
|
-" }\n"
|
|
|
|
-" properties {\n"
|
|
|
|
-" id: \"my_property\"\n"
|
|
|
|
-" value: \"4713.0\"\n"
|
|
|
|
-" type: PROPERTY_TYPE_NUMBER\n"
|
|
|
|
-" }\n"
|
|
|
|
-"}\n"
|
|
|
|
-```
|
|
|
|
|
|
+{srcset="images/building_blocks/[email protected] 2x"}
|
|
|
|
|
|
|
|
+Object parent-child hierarchies is a dynamic relation affecting how objects react to transformations. Any transformation (movement, rotation or scaling) applied to an object will in turn be applied to the object’s children, both in the editor and in runtime:
|
|
|
|
|
|
-## Child-parent hierarchies
|
|
|
|
|
|
+{srcset="images/building_blocks/[email protected] 2x"}
|
|
|
|
|
|
-When editing a collection file, you can build hierarchies of game objects so that one or more game objects are children to a parent game object. Object parent-child hierarchies is a dynamic relation affecting how objects react to transformations. Any transformation (movement, rotation or scaling) applied to an object will in turn be applied to the object’s children.
|
|
|
|
|
|
+Conversely, a child's translations are done in the local space of the parent. In the editor, you can choose to edit a child game object in the local space or world space by selecting <kbd>Edit ▸ World Space</kbd> (the default) or <kbd>Edit ▸ Local Space</kbd>.
|
|
|
|
|
|
-It is also possible to alter an object’s parent in run-time by sending `set_parent` messages.
|
|
|
|
|
|
+It is also possible to alter an object’s parent in run-time by sending a `set_parent` message to the object.
|
|
|
|
|
|
```lua
|
|
```lua
|
|
-local parent = go.get_id("some_object")
|
|
|
|
-msg.post(".", "set_parent", { parent_id = parent })
|
|
|
|
|
|
+local parent = go.get_id("bean")
|
|
|
|
+msg.post("child_bean", "set_parent", { parent_id = parent })
|
|
```
|
|
```
|
|
|
|
|
|
-A common misunderstanding is that a game object's place in the collection hierarchy is connected to this runtime parent-child hierarchy. But they are two very different things. Parent-child hierarchies dynamically alters the scene graph which allows objects to be visually attached to each other. The place a game object has in the collection hierarchy dictates its id. This id is static throughout the lifetime of the object and will *never change*.
|
|
|
|
|
|
+A common misunderstanding is that a game object's place in the collection hierarchy changes when it becomes part of a parent-child hierarchy. However, these are two very different things. Parent-child hierarchies dynamically alters the scene graph which allows objects to be visually attached to each other. The only thing that dictates a game object's address is its place in the collection hierarchy. The address is static throughout the lifetime of the object.
|