If you are new to Defold, this guide will help you getting your bearings right in the editor. It also explains the basic ideas and the most common building blocks in Defold: Game objects, Collections, Scripts and Sprites.
We’re going to start from an empty project and work step by step to a very small, playable application. At the end you will hopefully have a feel for how Defold works and you will be ready to tackle a more extensive tutorial or dive right into the manuals.
Start by creating a new project and opening it in the editor. If you double-click the file main/main.collection the file will open up:
The editor consists of the following main areas:
print()
and pprint()
debug messages from your scripts. If your app or game won’t start the console is the first thing to check. Behind the console are a set of tabs displaying error information as well as a curve editor that is used when building particle effects.The “Empty” project template actually isn’t completely empty. As you’ve already seen, it contains one game object with a simple image. Select Project ▸ Build and Launch to build the project and launch the game.
It’s perhaps not very exciting, but it’s a running Defold game application and we can easily modify it into something more interesting. So let’s do that.
First of all, let’s clean the file main.collection of the one game object it contains. Select “logo” in the Outline view, right-click and select Delete. That’s it. If you run the game again, the application window will be totally black.
The first thing we’re going to do is to create a new collection. A collection is a container of game objects that you have placed and put into position. Collections are most commonly used to build game levels but they are very useful whenever you need to reuse groups and/or hierarchies of game objects that belong together. It might be helpful to think about collections as a kind of prefab.
Click on the main folder in the Assets pane, then right-click and select New ▸ Collection File. You can also select File ▸ New ▸ Collection File from the main menu.
Name the new collection file car.collection and open it. We’re going to use this new, empty collection to build a small car out of a couple of game objects. A game object is a container of components (like sprites, sounds, logic scripts etc) that you use to build your game. Each game object is uniquely identified in the game by its id. Game objects can communicate with each other through message passing, but more on that later.
Also, it’s possible to create a game object in place in a collection, as we did here. That results in a one-of-a-kind object. You can copy that object but each copy is separate—changing one does not affect the others. This means that if you create 10 copies of a game object and realize that you want to change them all, you will need to edit all 10 instances of the object. Therefore, in place created game objects should be used for objects that you do not intend to make a lot of copies of.
However, a game object that is stored in a file works as a blueprint. When you place instances of a file stored game object in a collection each object is placed by reference—it is a clone based on the blueprint. If you decide you need to change the blueprint, every single placed game object based on that blueprint is instantly updated.
Select the root “Collection” node in the Outline view, right-click and select Add Game Object. A new game object with the id “go” will appear in the collection. Mark it and set its id to “car” in the Properties view. So far, “car” is very uninteresting. It is empty, has neither visual representation nor any logic. To add a visual representation, we need to add a sprite component.
Components are used to extend game objects with presence (graphics, sound) and functionality (spawn factories, collisions, scripted behaviors). A component can’t exist by itself but has to reside inside a game object. Components are usually defined in place in the same file as the game object. However, if you want to reuse a component you can store it in a separate file (like you can with game objects) and include it as a reference in any game object file. Some component types (Lua scripts, for instance) has to be placed in a separate component file and then included as reference in your objects.
Note that you do not manipulate components directly—you can move, rotate, scale and animate properties of game objects that in turn contain components.
Select the “car” game object, right-click and select Add Component, then select Sprite and click Ok. If you mark the sprite in the Outline view you will see that it needs a few properties set:
Images for our game:
Add these images to the atlas:
Continue by adding two more game objects in the collection. Call them “left_wheel” and “right_wheel” and put a sprite component in each, showing the tire image that we added to sprites.atlas. Then grab the wheel game objects and drop them onto “car” to make them children under “car”. Game objects that are children under other game objects will be attached to their parent when the parent moves. They can be moved individually as well, but all motion happens relative to the parent object. For the tires this is perfect since we want them to stick to the car and we can just rotate them slightly left and right as we steer the car. A collection can contain any number of game objects, side by side or arranged into complex parent-child trees, or a mix.
Move the tire game objects into place by selecting them and then choosing Scene ▸ Move Tool. Grab the arrow handlebars, or the center green square to move the object to a good spot. The final thing we need to do is to make sure that the tires are drawn below the car. We do that by setting the Z component of the position to -0.5. Every visual item in a game is drawn from the back to front, sorted on their Z value. An object with a Z-value of 0 will be drawn on top of an object with a Z-value of -0.5. Since the default Z-value of the car game object is 0, the new value on the tire objects will put them under the car image.
The last piece of the puzzle is a script to control the car. A script is a component that contains a program that defines game object behaviors. With scripts you can specify the rules of your game, how objects should respond to various interactions (with the player as well as other objects). All scripts are written in the Lua programming language. To be able to work with Defold, you or someone on your team needs to learn how to program in Lua.
Mark “main” in the Assets pane, right-click and select New ▸ Script File. Name the new file car.script, then add it to the “car” game object by marking “car” in the Outline view, right click and select Add Component File. Select car.script and click OK. Save the collection file.
Double click car.script and edit the script so it contains the following:
-- car.script
-- Constants
local turn_speed = 0.1 -- Slerp factor
local max_steer_angle_left = vmath.quat_rotation_z(math.pi / 6) -- 30 degrees
local max_steer_angle_right = vmath.quat_rotation_z(-math.pi / 6) -- -30 degrees
local wheels_vector = vmath.vector3(0, 72, 0) -- Vector from center of back and front wheel pairs
function init(self)
-- Send a message to the render script (see builtins/render/default.render_script) to set the clear color.
-- This changes the background color of the game. The vector4 contains color information
-- by channel from 0-1: Red = 0.2. Green = 0.2, Blue = 0.2 and Alpha = 1.0
msg.post("@render:", "clear_color", { color = vmath.vector4(0.2, 0.2, 0.2, 1.0) } )
-- Acquire input focus so we can react to input
msg.post(".", "acquire_input_focus")
-- Some variables
self.steer_angle = vmath.quat()
self.direction = vmath.quat()
-- Velocity and acceleration are car relative (not rotated)
self.velocity = vmath.vector3()
self.acceleration = vmath.vector3()
end
function update(self, dt)
-- Calculate new velocity based on current acceleration
self.velocity = self.velocity + self.acceleration * dt
-- Calculate the new positions of front and back wheels
local front_vel = vmath.rotate(self.steer_angle, self.velocity)
local new_front_pos = vmath.rotate(self.direction, wheels_vector + front_vel)
local new_back_pos = vmath.rotate(self.direction, self.velocity)
-- Calculate the car's new direction
local new_dir = vmath.normalize(new_front_pos - new_back_pos)
self.direction = vmath.quat_rotation_z(math.atan2(new_dir.y, new_dir.x) - math.pi / 2)
-- Update position based on current velocity and direction
local pos = go.get_position()
pos = pos + vmath.rotate(self.direction, self.velocity)
go.set_position(pos)
-- Set the game object's rotation to the direction
go.set_rotation(self.direction)
end
function on_message(self, message_id, message, sender)
if message_id == hash("left") then
-- Interpolate the steering angle.
self.steer_angle = vmath.slerp(turn_speed, self.steer_angle, max_steer_angle_left)
go.set_rotation(self.steer_angle, "left_wheel")
go.set_rotation(self.steer_angle, "right_wheel")
elseif message_id == hash("right") then
-- Interpolate the steering angle.
self.steer_angle = vmath.slerp(turn_speed, self.steer_angle, max_steer_angle_right)
go.set_rotation(self.steer_angle, "left_wheel")
go.set_rotation(self.steer_angle, "right_wheel")
elseif message_id == hash("set_acceleration") then
-- Set acceleration y component (car relative) to the message data field "acc".
self.acceleration.y = message.acc
end
end
function on_input(self, action_id, action)
if action_id == hash("left") then
msg.post("#", "left")
elseif action_id == hash("right") then
msg.post("#", "right")
elseif action_id == hash("accelerate") and action.value == 1 then
msg.post("#", "set_acceleration", { acc = 10 })
elseif action_id == hash("accelerate") and action.value == 0 then
msg.post("#", "set_acceleration", { acc = 0 })
elseif action_id == hash("brake") and action.value == 1 then
msg.post("#", "set_acceleration", { acc = -10 })
elseif action_id == hash("brake") and action.value == 0 then
msg.post("#", "set_acceleration", { acc = 0 })
end
end
Don’t forget to save your edits. The script contains 5 parts:
init()
init()
is run when the game object that the script component exists in is brought to life in the game. This function is usually used to set up internal variables, that we add to the game object “self” that is passed to the function. Any variable added to “self” will be kept through the lifetime of the game object. This script sends two messages during initialization. The first is to the rendering system, which sets the background color for the game. The second message is sent to the game object harboring the script (“.” is shorthand for that) asking the game object to start receiving input.update()
on_message()
vmath.slerp()
against the max values, if we are accelerating or decelerating both are handled by the message “set_acceleration” and a message value “acc” with the value of acceleration, positive or negative.on_input()
init()
we receive input actions. Input are mapped from actual key, mouse, touch or game pad input to input “actions”. We react to steering, accelerate and brake actions. When these actions arrive we send messages to the script component itself (“#” is shorthand for that) and through the logic in on_message()
the car reacts. Now, we could just as well have skipped on_message()
and put all logic straight into on_input()
but there are benefits to using messages like we do. By allowing the car object to react to messages we can move the input handling to a different place, or perhaps add an AI driver somewhere that could drive the car through messages.There is no input actions set up yet, so let’s fix that. Open the file /input/game.input_bindings and add key_trigger bindings for “accelerate”, “brake”, “left” and “right”. We set them to the arrow keys (KEY_LEFT, KEY_RIGHT, KEY_UP and KEY_DOWN):
Now the car is ready to roll. We have created it inside “car.collection” but it does not yet exist in the game. That is because the engine currently loads “main.collection” on startup. To fix that we simply have to add car.collection to main.collection. Open main.collection, mark the “Collection” root node in the Outline view, right-click and select Add Collection From File, select car.collection and click OK. Now the contents of the car.collection will be placed in main.collection as new instances. If you change the content of car.collection, each instance of the collection will be updated automatically when the game is built.
Now, select Project ▸ Build And Launch from the main menu and take your new car for a spin!
If you want you can try to add more instances of car.collection to main.collection. Each instance is a clone of what’s inside car.collection with the exact same behavior. Each one listens to input and reacts to the same messages.
That concludes this introductory tutorial. Now go ahead and dive into Defold. We have lots of manuals and tutorials prepared to guide you, and if you get stuck, you are very welcome to the forum.
Happy Defolding!
Did you spot an error or do you have a suggestion? Please let us know on GitHub!
GITHUB