Skip to content

Shooting Meteors

Now it's time to shoot some meteors.
In this section we will create bullets and implement the logic required to destroy meteors and earn points.


Creating the Bullet Behaviour

First, create the bullet behaviour in behaviours/bullet.lua:

local health = require("states.health")

return {
    init = function(state)
        state.speed = state.speed or 400 -- Bullet speed (default: 400)
        state.force_y = -state.speed -- Apply upward force
    end,

    tick = function(state)
        -- Destroy bullet when it leaves the screen
        if state.y < -16 then
            sucata.scene.destroy(state)
        end

        -- Get all meteors in the scene
        local meteors = sucata.scene.get_entities_by_tag("meteor")

        for _, id in ipairs(meteors) do
            local meteor = sucata.scene.find_by_id(id)

            if meteor and sucata.math.overlapping({
                x = state.x - 8,
                y = state.y - 8,
                width = 16,
                height = 16
            }, {
                x = meteor.x - 16,
                y = meteor.y - 16,
                width = 32,
                height = 32
            }) then
                -- Damage the meteor
                health.remove(meteor)

                if meteor.health <= 0 then
                    sucata.events.emit("meteor_destroyed", meteor)
                    sucata.scene.destroy(meteor)
                end

                -- Destroy the bullet
                sucata.scene.destroy(state)
                break
            end
        end
    end
}

Register the behaviour in behaviours/init.lua:

return {
    ...
    Bullet = require("behaviours.bullet"),
}

Creating the Bullet Entity

Now create the bullet entity in entities/bullet.lua:

local function bullet(x, y)
    return {
        state = {
            x = x,
            y = y
        },

        behaviours = {
            Behaviours.Bullet,      -- Bullet logic
            Behaviours.ApplyForces, -- Apply movement forces
            Behaviours.DrawSprite   -- Render the bullet
        }
    }
end

return bullet

Creating the Shooter Behaviour

Now we will allow the player to shoot bullets.

Create the file behaviours/shooter.lua:

local bullet = require("entities.bullet")

return {
    tick = function(state)
        if sucata.input.is_pressed("space", "enter") then
            sucata.scene.spawn(bullet(state.x, state.y - 16))
        end
    end
}

Register the behaviour in behaviours/init.lua:

return {
    ...
    Shooter = require("behaviours.shooter"),
}

Adding the Shooter to the Player

Now add the shooter behaviour to the player entity in entities/player.lua:

local function player(x, y)
    return {
        state = {
            x = x,
            y = y
        },

        behaviours = {
            Behaviours.Player,   -- Player movement
            Behaviours.Shooter,  -- Shooting logic
            Behaviours.DrawSprite -- Render player
        }
    }
end

return player

Note Behaviours are executed in order. The player logic runs first, followed by shooting logic, and finally rendering.


Now when you run the game, it should look like this: