Last active
March 22, 2023 17:06
-
-
Save AGulev/484dea838528f86ff93ae530e333f76a to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Here is a simple manual about how to make a simple flappy bird-like game on Defold with code examples: | |
* A flappy bird-like game is a game where you have to control a bird that flies through gaps between pipes. The bird falls down because of gravity, but you can make it flap its wings and go up by tapping the screen or pressing a key. The game ends when the bird hits a pipe or the ground. The goal is to fly as far as possible and get a high score. | |
* To make a flappy bird-like game on Defold, you need to do these steps: | |
* Create a new project in Defold and name it “Flappy Bird”. | |
* Create a new collection file and name it “main.collection”. This will be the main scene of your game. | |
* Create a new game object file and name it “bird.go”. This will be the bird that the player controls. | |
* Add a sprite component to the bird game object and set the image to a bird image of your choice. You can use the built-in “hero.atlas” or import your own image. | |
* Add a script component to the bird game object and name it “bird.script”. This will be the code that controls the bird’s movement and collision. | |
* Add a collision object component to the bird game object and set the type to “Kinematic”. This will make the bird move according to the code and detect collisions with other objects. Set the shape to a box that fits the bird sprite and set the group to “bird” and the mask to “pipe”. | |
* Create a new game object file and name it “pipe.go”. This will be the pipe that the bird has to avoid. | |
* Add a sprite component to the pipe game object and set the image to a pipe image of your choice. You can use the built-in “pipe.atlas” or import your own image. | |
* Add a collision object component to the pipe game object and set the type to “Static”. This will make the pipe stay in place and collide with other objects. Set the shape to a box that fits the pipe sprite and set the group to “pipe” and the mask to “bird”. | |
* Create a new game object file and name it “spawner.go”. This will be the object that spawns the pipes at regular intervals. | |
* Add a script component to the spawner game object and name it “spawner.script”. This will be the code that creates and destroys the pipes and keeps track of the score. | |
* Add the bird, the spawner, and a camera game object to the main collection. Set the camera’s projection to “Orthographic” and adjust the size to fit the screen. Set the bird’s position to (0, 0, 0) and the spawner’s position to (200, 0, 0). | |
* Write the code for the bird.script. Here is an example: | |
`bird.script`: | |
``` | |
-- The gravity constant that pulls the bird down | |
local GRAVITY = -1000 | |
-- The flap impulse that pushes the bird up | |
local FLAP = 400 | |
-- The maximum speed that the bird can reach | |
local MAX_SPEED = 500 | |
-- The minimum and maximum angles that the bird can rotate | |
local MIN_ANGLE = -90 | |
local MAX_ANGLE = 45 | |
-- The angular speed that the bird rotates | |
local ANGULAR_SPEED = 5 | |
-- The initial velocity of the bird | |
local velocity = vmath.vector3(0, 0, 0) | |
-- The initial angle of the bird | |
local angle = 0 | |
-- The initial state of the bird | |
local state = "idle" | |
-- The input action that makes the bird flap | |
local FLAP_ACTION = hash("flap") | |
-- The message that indicates the bird has collided with something | |
local COLLISION_MESSAGE = hash("collision_response") | |
-- The message that indicates the game has started | |
local START_MESSAGE = hash("start") | |
-- The message that indicates the game has ended | |
local END_MESSAGE = hash("end") | |
-- The message that indicates the bird has passed a pipe | |
local PASS_MESSAGE = hash("pass") | |
-- The message that indicates the bird has scored a point | |
local SCORE_MESSAGE = hash("score") | |
-- The message that indicates the bird has died | |
local DIE_MESSAGE = hash("die") | |
-- The message that indicates the bird has reset | |
local RESET_MESSAGE = hash("reset") | |
-- The function that updates the bird's position and angle | |
local function update(dt) | |
-- Apply gravity to the velocity | |
velocity.y = velocity.y + GRAVITY * dt | |
-- Clamp the velocity to the maximum speed | |
velocity.y = math.min(velocity.y, MAX_SPEED) | |
-- Move the bird according to the velocity | |
local position = go.get_position() | |
position = position + velocity * dt | |
go.set_position(position) | |
-- Calculate the angle based on the velocity | |
angle = vmath.lerp(ANGULAR_SPEED * dt, angle, math.deg(math.atan2(velocity.y, MAX_SPEED))) | |
-- Clamp the angle to the minimum and maximum values | |
angle = math.max(MIN_ANGLE, math.min(MAX_ANGLE, angle)) | |
-- Rotate the bird according to the angle | |
go.set_rotation(vmath.quat_rotation_z(math.rad(angle))) | |
end | |
-- The function that makes the bird flap | |
local function flap() | |
-- Set the velocity to the flap impulse | |
velocity.y = FLAP | |
-- Play a flap sound | |
sound.play("#flap") | |
end | |
-- The function that handles the input action | |
local function on_input(action_id, action) | |
-- If the action is the flap action and the state is not "dead" | |
if action_id == FLAP_ACTION and state ~= "dead" then | |
-- If the state is "idle" | |
if state == "idle" then | |
-- Send a start message to the spawner | |
msg.post("spawner#spawner", START_MESSAGE) | |
-- Set the state to "flap" | |
state = "flap" | |
end | |
-- If the action is pressed | |
if action.pressed then | |
-- Call the flap function | |
flap() | |
end | |
end | |
end | |
-- The function that handles the collision message | |
local function on_collision(message_id, message, sender) | |
-- If the message is the collision message and the state is not "dead" | |
if message_id == COLLISION_MESSAGE and state ~= "dead" then | |
-- Send an end message to the spawner | |
msg.post("spawner#spawner", END_MESSAGE) | |
-- Set the state to "dead" | |
state = "dead" | |
-- Play a die sound | |
sound.play("#die") | |
-- Send a die message to the bird | |
msg.post(".", DIE_MESSAGE) | |
end | |
end | |
-- The function that handles the pass message | |
local function on_pass(message_id, message, sender) | |
-- If the message is the pass message and the state is not "dead" | |
if message_id == PASS_MESSAGE and state ~= "dead" then | |
-- Send a score message to the bird | |
msg.post(".", SCORE_MESSAGE) | |
-- Play a score sound | |
sound.play("#score") | |
end | |
end | |
-- The function that handles the reset message | |
local function on_reset(message_id, message, sender) | |
-- If the message is the reset message | |
if message_id == RESET_MESSAGE then | |
-- Reset the velocity, angle, and state of the bird | |
velocity = vmath.vector3(0, 0, 0) | |
angle = 0 | |
state = "idle" | |
-- Reset the position and rotation of the bird | |
go.set_position(vmath.vector3(0, 0, 0)) | |
go.set_rotation(vmath.quat_rotation_z(0)) | |
end | |
end | |
-- The function that is called every frame | |
function update(self, dt) | |
-- Call the update function | |
update(dt) | |
end | |
-- The function that is called when an input action is received | |
function on_input(self, action_id, action) | |
-- Call the on_input function | |
on_input(action_id, action) | |
end | |
-- The function that is called when a message is received | |
function on_message(self, message_id, message, sender) | |
-- Call the on_collision function | |
on_collision(message_id, message, sender) | |
-- Call the on_pass function | |
on_pass(message_id, message, sender) | |
-- Call the on_reset function | |
on_reset(message_id, message, sender) | |
end | |
``` | |
Here is the code for the `spawner.script`: | |
``` | |
-- The interval between each pipe spawn | |
local INTERVAL = 2 | |
-- The minimum and maximum gap size between the pipes | |
local MIN_GAP = 100 | |
local MAX_GAP = 200 | |
-- The minimum and maximum pipe height | |
local MIN_HEIGHT = 50 | |
local MAX_HEIGHT = 400 | |
-- The speed that the pipes move to the left | |
local SPEED = -200 | |
-- The initial state of the spawner | |
local state = "idle" | |
-- The timer that counts down to the next pipe spawn | |
local timer = 0 | |
-- The message that indicates the game has started | |
local START_MESSAGE = hash("start") | |
-- The message that indicates the game has ended | |
local END_MESSAGE = hash("end") | |
-- The message that indicates the bird has passed a pipe | |
local PASS_MESSAGE = hash("pass") | |
-- The message that indicates the bird has reset | |
local RESET_MESSAGE = hash("reset") | |
-- The function that spawns a pair of pipes | |
local function spawn() | |
-- Calculate a random gap size between the pipes | |
local gap = math.random(MIN_GAP, MAX_GAP) | |
-- Calculate a random pipe height | |
local height = math.random(MIN_HEIGHT, MAX_HEIGHT) | |
-- Create a top pipe game object | |
local top_pipe = factory.create("#pipe_factory") | |
-- Set the position and scale of the top pipe | |
go.set_position(vmath.vector3(200, height + gap / 2, 0), top_pipe) | |
go.set_scale(vmath.vector3(1, -1, 1), top_pipe) | |
-- Set the linear velocity of the top pipe | |
go.set("#collisionobject", "linear_velocity", vmath.vector3(SPEED, 0, 0), top_pipe) | |
-- Create a bottom pipe game object | |
local bottom_pipe = factory.create("#pipe_factory") | |
-- Set the position and scale of the bottom pipe | |
go.set_position(vmath.vector3(200, height - gap / 2, 0), bottom_pipe) | |
go.set_scale(vmath.vector3(1, 1, 1), bottom_pipe) | |
-- Set the linear velocity of the bottom pipe | |
go.set("#collisionobject", "linear_velocity", vmath.vector3(SPEED, 0, 0), bottom_pipe) | |
-- Create a sensor game object | |
local sensor = factory.create("#sensor_factory") | |
-- Set the position and size of the sensor | |
go.set_position(vmath.vector3(200, height, 0), sensor) | |
go.set("#collisionobject", "size", vmath.vector3(10, gap, 0), sensor) | |
-- Set the linear velocity of the sensor | |
go.set("#collisionobject", "linear_velocity", vmath.vector3(SPEED, 0, 0), sensor) | |
end | |
-- The function that updates the timer and spawns pipes | |
local function update(dt) | |
-- Decrease the timer by the delta time | |
timer = timer - dt | |
-- If the timer is less than or equal to zero | |
if timer <= 0 then | |
-- Call the spawn function | |
spawn() | |
-- Reset the timer to the interval | |
timer = INTERVAL | |
end | |
end | |
-- The function that handles the start message | |
local function on_start(message_id, message, sender) | |
-- If the message is the start message and the state is "idle" | |
if message_id == START_MESSAGE and state == "idle" then | |
-- Set the state to "spawn" | |
state = "spawn" | |
-- Reset the timer to the interval | |
timer = INTERVAL | |
end | |
end | |
-- The function that handles the end message | |
local function on_end(message_id, message, sender) | |
-- If the message is the end message and the state is "spawn" | |
if message_id == END_MESSAGE and state == "spawn" then | |
-- Set the state to "idle" | |
state = "idle" | |
-- Delete all the pipe and sensor game objects | |
go.delete("#pipe_factory") | |
go.delete("#sensor_factory") | |
end | |
end | |
-- The function that handles the reset message | |
local function on_reset(message_id, message, sender) | |
-- If the message is the reset message | |
if message_id == RESET_MESSAGE then | |
-- Set the state to "idle" | |
state = "idle" | |
-- Delete all the pipe and sensor game objects | |
go.delete("#pipe_factory") | |
go.delete("#sensor_factory") | |
end | |
end | |
-- The function that is called every frame | |
function update(self, dt) | |
-- If the state is "spawn" | |
if state == "spawn" then | |
-- Call the update function | |
update(dt) | |
end | |
end | |
-- The function that is called when a message is received | |
function on_message(self, message_id, message, sender) | |
-- Call the on_start function | |
on_start(message_id, message, sender) | |
-- Call the on_end function | |
on_end(message_id, message, sender) | |
-- Call the on_reset function | |
on_reset(message_id, message, sender) | |
end | |
``` |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment