Before we start spawning our first astéroids, let's make a few adjustments to our ship.
Open the script file and add a property called rotateSpeed , as the name suggests, this variable represents the rotation speed of our ship.
Then, replace the relevant values with self.rotateSpeed as shown below.
Finally, create a folder named ship inside the main folder, and move everything related to the ship into it. And that’s it for this first part!
Feel free to run the game and adjust the rotateSpeed to your liking.
Now let’s move on to creating the asteroids.
First, we need to figure out what we’ll need.
For our game, we want two types of asteroids: a large one and a small one.
So, we’ll need sprites and game objects for each of them.
We also know that we want to instantiate them during the game, which means we’ll need a game object that contains a Factory component this will serve as our spawner.
Let’s start setting everything up!
You’ll notice I’ll keep things concise here, since if you’ve made it to this section, these are tasks we’ve already done together.
Open the main.atlas file and import the images "asteroid_large.png" and "asteroid_small.png".
Create a folder named "asteroid".
Inside this folder, create three game objects:
asteroid_l (for the large asteroid)
asteroid_s (for the small asteroid)
asteroid_factory (for spawning asteroids)
Also, create two scripts:
asteroid.script
asteroid_factory.script
For each asteroid game object (asteroid_l and asteroid_s),
add the corresponding sprite (asteroid_large.png or asteroid_small.png)
and attach the asteroid.script to it.
Before we handle the creation of our asteroids using the factory, let’s first code their individual behavior.
Open the asteroid.script and add the following code:
[1] – The type property will let us know whether it’s a large (asteroid_l) or small (asteroid_s) asteroid.
Use the value 0 for a large asteroid and 1 for a small one.
[5] – The rotation_speed variable defines how fast the asteroid rotates.
[7–11] – In the init function, we initialize three variables:
a speed, a direction, and a rotation value.
Let’s code the rotation of our asteroids.
Add an update function and write the following code:
[14] – First, the value of self.rotation is incremented.
[18] – I choose to clamp the rotation using the modulo operator.
This isn’t strictly necessary (I didn’t do it for the ship), but it keeps the value clean and ensures it always stays between 0 and 360 degrees.
[21–24] – Next, we convert the rotation from degrees to radians,
then create a quaternion representing rotation around the Z axis,
and finally apply it to our asteroid.
Before running our game, configure each type of asteroid as shown below.
Next, place a few asteroids in your game.
And there you have it, run your game and admire your work!
Alright, I admit it, it’s not very exciting yet...
It’s time to make them move.
Here’s a brief explanation of the behavior we want:
When an asteroid is instantiated, it will choose a random direction and move in that direction. If it goes off-screen, it will reappear on the opposite side.
Let’s start by coding the movement in the chosen direction.
Create a random_direction function just before our init function.
I’ll let you read through the code below and then copy it into your script.
[9] – The method math.random(a, b) lets us get a random value between 0 and 360 degrees.
[12] – We initialize a direction vector.
[15] – The random value is converted to radians using math.rad().
[18–22] – Using cosine and sine, we calculate the direction vector, which is then assigned to self.direction.
Now let’s call the random_direction function inside our init function.
As soon as an asteroid is created, it will choose a random direction.
Let’s go back to the update function to handle the movement of our asteroid.
[52] – We calculate the velocity by multiplying the speed by the direction.
[55–61] – Then, we apply this velocity to update the position of our asteroid.
Now, also add two variables for the screen height and width.
Then, we’ll reuse our wrapPosition function, we already use this in our ship script.
We could create a separate script file to hold this function and call it to avoid redundancy, but for now, we’ll modify it to suit the behavior of our meteors.
The function to wrap our game object.
Of course, before returning the game object's position, we wrap it!
Let’s run the game and admire our asteroids!
Well... the wrap effect works, but we’ll improve it later.
Great, we now have moving asteroids!
Before moving forward, let’s handle collision detection with the laser shots.
For this, we need to add a collision component!
I’ll let you read the short guide below.
A Collision Object is a special component that allows a game object to interact physically with other objects in the game world. In Defold, this system is built on top of the Box2D physics engine, which simulates realistic 2D physics.
Each collision object defines:
Its type (how it behaves in the physics world)
Its shape (the area that detects collisions)
Its group and mask (what it is and what it can collide with)
The physics engine runs automatically in the background and checks for overlaps between shapes on every frame. When a collision happens, Defold sends messages (like collision_response or trigger_response) to your scripts so you can react in code.
When you add a Collision Object component, you must choose a type:
STATIC: Does not move, used for the environment (e.g. ground, walls)
KINEMATIC: Moved manually via code (e.g. player)
DYNAMIC: Moved by physics simulation (e.g. falling crate)
TRIGGER: Detects overlaps, but has no physical response (e.g. power-up)
Add a shape (box, sphere, or capsule) to define the collision area of the object.
Group: What the object is (e.g. "player")
Mask: What it should detect (e.g. "ground", "enemy")
Example: A player with group "player" and mask "ground" will detect the ground but not other players.
Use the on_message function in your script:
function on_message(self, message_id, message, sender)
if message_id == hash("collision_response") then
print("Collision with:", message.other_id)
end
end
For TRIGGER objects, use "trigger_response" instead.
Open the asteroid game object and add a Collision Object component.
Then, right-click on the collision component, select Add Shape, and choose Sphere.
This shape will be used to detect collisions.
I recommend renaming the collision shape to "sphere_shape".
It’s always good practice to give your shapes meaningful names.
Then, adjust the shape so that it fully covers the asteroid.
Now, click on the scaling icon to resize the collision shape so it fits the visual of our asteroid.
Great, we have the shape set up!
But if you read the small guide, you know there are still a few more steps.
Click on the Collision Object component, then in the Type section, select Trigger.
Next, in the Group section, name it "asteroid".
We’re not going for realistic physics here, which is why we chose the Trigger type, it simply lets us know when something enters a collision, so we can react accordingly.
The Group section just means that this collision component belongs to the asteroid group.
I recommend repeating these steps for both game objects: asteroid_s and asteroid_l.
Now, to handle collisions between our lasers and the asteroids, we’ll repeat the same process but this time for the laser game object.
Add a Collision Object component, then add a shape that fits the laser’s visual. Mettre son type sur trigger et sur dans mask mettre asteroid
Our components are set up.
Now open the laser.script and add the on_message function.
What is on_message?
The on_message function is used to receive and handle messages sent to a game object.
In collisions, Defold automatically sends messages like "collision_response" or "trigger_response" to this function.
Example:
function on_message(self, message_id, message, sender)
if message_id == hash("collision_response") then
print("Collision with:", message.other_id)
end
end
message_id: the type of message (e.g. "collision_response")
message: contains details (like the other object ID and group)
sender: the ID of the object that sent the message
You now know what the on_message function is, and you also know that Defold automatically sends a message when two elements collide.
It’s thanks to this system that we’ll remove our lasers and make our asteroids disappear when they collide.
Add the following code inside the on_message function:
[29–32] – If the message_id received is "trigger_response", then we delete our game object using the go.delete() function.
Run your game, and you’ll see the lasers disappear as soon as they collide with a asteroid.
Close the game, and add the function pprint(message) inside your code.
The pprint function allows you to print the contents of tables in a readable format.
Run your game and shoot at one of the asteroids.
Then, check the console, you’ll see several variables printed.
Among these, the variable that will interest us is other_id.
The following code will let us filter whether the group our laser collided with is an asteroid, and if so, delete it.
And there you have it the lasers and asteroids disappear as soon as they come into contact!
Nice job! 🎉
You can download all parts of the project using the following link:
In the next part, we’ll make a few adjustments to our wrapping function before we implement the spawning system.
So come join me in the next Part!