Online Sequencer Make music online
  • Sequences
  • Members
  • Chat
  • Forum
  • Wiki

Existing user? Sign In Create account
Login at Online Sequencer Forums

Online Sequencer Forums › Off Topic › General Discussion
« Previous 1 … 3 4 5 6 7 … 60 Next »

LUA coding

Thread tools
LUA coding
Umbry Offline
Your Therapist.
25 Posts:
   
#1
09-17-2025, 10:35 AM
Here's some code I wrote for the framework of an ULTRAKILL-type boss

Code:
-- Boss AI Framework (Advanced)
local Boss = {}
Boss.__index = Boss

-- A Boss requires an initial state, a health pool, and a set of attack patterns.
function Boss.new(options)
    local boss = {
        name = options.name or "Cyber-Fiend",
        current_health = options.max_health or 1000,
        max_health = options.max_health or 1000,
        state = "Idle",
        attack_cooldown_timer = 0,
        current_phase = 1,
        active_target = options.player, -- The player instance.
        position = options.position,
        attack_patterns = {
            -- Phase 1 (100% - 51% health)
            {
                {name = "bullet_hell", cooldown = 5, duration = 3},
                {name = "laser_beam", cooldown = 10, duration = 2},
            },
            -- Phase 2 (50% - 1% health)
            {
                {name = "bullet_hell", cooldown = 4, duration = 2},
                {name = "laser_beam", cooldown = 8, duration = 2.5},
                {name = "charge_attack", cooldown = 6, duration = 1.5},
            },
            -- Death animation, or other final action
            {
                {name = "self_destruct", cooldown = 0, duration = 5},
            }
        }
    }
    setmetatable(boss, Boss)
    return boss
end

-- Main update loop. This should be called every frame by your game engine.
function Boss:update(dt)
    -- Check if the boss is dead
    if self.current_health <= 0 then
        self:die()
        return
    end

    -- Update boss phase based on health
    self:update_phase()

    -- State machine logic
    if self.state == "Idle" then
        self:idle_state(dt)
    elseif self.state == "Attacking" then
        self:attacking_state(dt)
    elseif self.state == "TakingDamage" then
        self:taking_damage_state(dt)
    end
end

-- A simple function to simulate taking damage.
function Boss:take_damage(amount)
    if self.state ~= "Dying" then
        self.current_health = self.current_health - amount
        print(self.name .. " took " .. amount .. " damage. Health: " .. self.current_health)
        -- Trigger a visual or audio effect for taking damage
        self.state = "TakingDamage"
        -- Add screen shake or hit-stop effects here
    end
end

-- Handle the boss's death.
function Boss:die()
    self.state = "Dying"
    -- Trigger explosion, fall animation, loot drop, etc.
    print(self.name .. " has been defeated!")
    -- Clean up enemy from the game world
end

-- Internal function to check and update the boss's current phase.
function Boss:update_phase()
    local health_percentage = self.current_health / self.max_health
    if health_percentage <= 0.5 and self.current_phase == 1 then
        self.current_phase = 2
        print("Boss enters Phase 2! Prepare for new attacks.")
        -- Trigger special phase change animations or effects.
    elseif health_percentage <= 0 and self.current_phase < 3 then
        self.current_phase = 3
    end
end

-- Defines the Idle state behavior.
function Boss:idle_state(dt)
    -- Wait for player to be in range
    local distance_to_player = self:distance_to(self.active_target.position)
    if distance_to_player < 500 then -- Chase range
        self.state = "Attacking"
        self.attack_cooldown_timer = 0
    end
end

-- Defines the Attacking state behavior.
function Boss:attacking_state(dt)
    self.attack_cooldown_timer = self.attack_cooldown_timer + dt

    local current_patterns = self.attack_patterns[self.current_phase]
    local attack_chosen = false

    -- Iterate through available attacks and trigger if cooldown is ready
    for _, attack in ipairs(current_patterns) do
        if self.attack_cooldown_timer >= attack.cooldown then
            self:execute_attack(attack)
            self.attack_cooldown_timer = 0 -- Reset cooldown for next attack
            attack_chosen = true
            break -- Only do one attack at a time
        end
    end

    -- If no attack was chosen, continue to move or wait
    if not attack_chosen then
        self:chase_player()
    end
end

-- Defines the TakingDamage state behavior.
function Boss:taking_damage_state(dt)
    -- Can add hit stun logic here
    self.state = "Attacking" -- Resume attacking after being hit
end

-- Placeholder for specific attack logic.
function Boss:execute_attack(attack)
    if attack.name == "bullet_hell" then
        print(self.name .. " initiates a bullet hell attack!")
        -- Call a function in your game engine to spawn many projectiles
    elseif attack.name == "laser_beam" then
        print(self.name .. " fires a devastating laser beam!")
        -- Call a function in your game engine for a large, single-line attack
    elseif attack.name == "charge_attack" then
        print(self.name .. " charges the player!")
        -- Move the boss rapidly toward the player's last known position
    elseif attack.name == "self_destruct" then
        print(self.name .. " self-destructs in a massive explosion!")
        -- Trigger a large explosion effect and kill the player if they are nearby
    end
end

-- Movement logic to chase the player.
function Boss:chase_player()
    local dir_x = self.active_target.position.x - self.position.x
    local dir_y = self.active_target.position.y - self.position.y
    -- Normalize direction vector and move the boss
    local distance = math.sqrt(dir_x*dir_x + dir_y*dir_y)
    if distance > 1 then
        self.position.x = self.position.x + dir_x / distance
        self.position.y = self.position.y + dir_y / distance
    end
end

-- Simple distance calculation.
function Boss:distance_to(target_pos)
    return math.sqrt( (self.position.x - target_pos.x)^2 + (self.position.y - target_pos.y)^2 )
end

return Boss


O
y g g

d

r

a

s

i

l



What miracle is this? This giant tree.
It stands ten thousand feet high
But doesn't touch the ground. Yet it stands.
Its roots must hold the sky.

0

Reply
Umbry Offline
Your Therapist.
25 Posts:
   
#2
09-17-2025, 10:36 AM
(09-17-2025, 10:35 AM)Umbry Wrote: Here's some code I wrote for the framework of an ULTRAKILL-type boss

Code:
-- Boss AI Framework (Advanced)
local Boss = {}
Boss.__index = Boss

-- A Boss requires an initial state, a health pool, and a set of attack patterns.
function Boss.new(options)
    local boss = {
        name = options.name or "Cyber-Fiend",
        current_health = options.max_health or 1000,
        max_health = options.max_health or 1000,
        state = "Idle",
        attack_cooldown_timer = 0,
        current_phase = 1,
        active_target = options.player, -- The player instance.
        position = options.position,
        attack_patterns = {
            -- Phase 1 (100% - 51% health)
            {
                {name = "bullet_hell", cooldown = 5, duration = 3},
                {name = "laser_beam", cooldown = 10, duration = 2},
            },
            -- Phase 2 (50% - 1% health)
            {
                {name = "bullet_hell", cooldown = 4, duration = 2},
                {name = "laser_beam", cooldown = 8, duration = 2.5},
                {name = "charge_attack", cooldown = 6, duration = 1.5},
            },
            -- Death animation, or other final action
            {
                {name = "self_destruct", cooldown = 0, duration = 5},
            }
        }
    }
    setmetatable(boss, Boss)
    return boss
end

-- Main update loop. This should be called every frame by your game engine.
function Boss:update(dt)
    -- Check if the boss is dead
    if self.current_health <= 0 then
        self:die()
        return
    end

    -- Update boss phase based on health
    self:update_phase()

    -- State machine logic
    if self.state == "Idle" then
        self:idle_state(dt)
    elseif self.state == "Attacking" then
        self:attacking_state(dt)
    elseif self.state == "TakingDamage" then
        self:taking_damage_state(dt)
    end
end

-- A simple function to simulate taking damage.
function Boss:take_damage(amount)
    if self.state ~= "Dying" then
        self.current_health = self.current_health - amount
        print(self.name .. " took " .. amount .. " damage. Health: " .. self.current_health)
        -- Trigger a visual or audio effect for taking damage
        self.state = "TakingDamage"
        -- Add screen shake or hit-stop effects here
    end
end

-- Handle the boss's death.
function Boss:die()
    self.state = "Dying"
    -- Trigger explosion, fall animation, loot drop, etc.
    print(self.name .. " has been defeated!")
    -- Clean up enemy from the game world
end

-- Internal function to check and update the boss's current phase.
function Boss:update_phase()
    local health_percentage = self.current_health / self.max_health
    if health_percentage <= 0.5 and self.current_phase == 1 then
        self.current_phase = 2
        print("Boss enters Phase 2! Prepare for new attacks.")
        -- Trigger special phase change animations or effects.
    elseif health_percentage <= 0 and self.current_phase < 3 then
        self.current_phase = 3
    end
end

-- Defines the Idle state behavior.
function Boss:idle_state(dt)
    -- Wait for player to be in range
    local distance_to_player = self:distance_to(self.active_target.position)
    if distance_to_player < 500 then -- Chase range
        self.state = "Attacking"
        self.attack_cooldown_timer = 0
    end
end

-- Defines the Attacking state behavior.
function Boss:attacking_state(dt)
    self.attack_cooldown_timer = self.attack_cooldown_timer + dt

    local current_patterns = self.attack_patterns[self.current_phase]
    local attack_chosen = false

    -- Iterate through available attacks and trigger if cooldown is ready
    for _, attack in ipairs(current_patterns) do
        if self.attack_cooldown_timer >= attack.cooldown then
            self:execute_attack(attack)
            self.attack_cooldown_timer = 0 -- Reset cooldown for next attack
            attack_chosen = true
            break -- Only do one attack at a time
        end
    end

    -- If no attack was chosen, continue to move or wait
    if not attack_chosen then
        self:chase_player()
    end
end

-- Defines the TakingDamage state behavior.
function Boss:taking_damage_state(dt)
    -- Can add hit stun logic here
    self.state = "Attacking" -- Resume attacking after being hit
end

-- Placeholder for specific attack logic.
function Boss:execute_attack(attack)
    if attack.name == "bullet_hell" then
        print(self.name .. " initiates a bullet hell attack!")
        -- Call a function in your game engine to spawn many projectiles
    elseif attack.name == "laser_beam" then
        print(self.name .. " fires a devastating laser beam!")
        -- Call a function in your game engine for a large, single-line attack
    elseif attack.name == "charge_attack" then
        print(self.name .. " charges the player!")
        -- Move the boss rapidly toward the player's last known position
    elseif attack.name == "self_destruct" then
        print(self.name .. " self-destructs in a massive explosion!")
        -- Trigger a large explosion effect and kill the player if they are nearby
    end
end

-- Movement logic to chase the player.
function Boss:chase_player()
    local dir_x = self.active_target.position.x - self.position.x
    local dir_y = self.active_target.position.y - self.position.y
    -- Normalize direction vector and move the boss
    local distance = math.sqrt(dir_x*dir_x + dir_y*dir_y)
    if distance > 1 then
        self.position.x = self.position.x + dir_x / distance
        self.position.y = self.position.y + dir_y / distance
    end
end

-- Simple distance calculation.
function Boss:distance_to(target_pos)
    return math.sqrt( (self.position.x - target_pos.x)^2 + (self.position.y - target_pos.y)^2 )
end

return Boss

Here is the Player framework

Code:
-- Player Framework
local Player = {}
Player.__index = Player
-- Constructor to create a new player instance.
function Player.new(options)
    local player = {
        name = options.name or "Player",
        current_health = options.max_health or 100,
        max_health = options.max_health or 100,
        position = options.position or {x = 0, y = 0},
        speed = options.speed or 300, -- Pixels per second
        is_alive = true,
        is_invincible = false,
        invincibility_timer = 0,
        invincibility_duration = 1, -- Seconds
        collider = {width = 32, height = 32}, -- For collision detection
    }
    setmetatable(player, Player)
    return player
end
-- Main update loop, called every frame.
function Player:update(dt)
    if not self.is_alive then
        return
    end
    -- Process player input for movement.
    self:handle_input(dt)
    -- Update invincibility timer if active.
    if self.is_invincible then
        self.invincibility_timer = self.invincibility_timer + dt
        if self.invincibility_timer >= self.invincibility_duration then
            self.is_invincible = false
            self.invincibility_timer = 0
            print("Invincibility worn off.")
        end
    end
end
-- Handles player input for movement. This function needs to be adapted
-- for your specific game engine's input system. This example uses
-- Love2D's keyboard functions.
function Player:handle_input(dt)
    local dx, dy = 0, 0
    -- These are examples, replace with your engine's input handlers.
    if love.keyboard.isDown("w") or love.keyboard.isDown("up") then
        dy = dy - 1
    end
    if love.keyboard.isDown("s") or love.keyboard.isDown("down") then
        dy = dy + 1
    end
    if love.keyboard.isDown("a") or love.keyboard.isDown("left") then
        dx = dx - 1
    end
    if love.keyboard.isDown("d") or love.keyboard.isDown("right") then
        dx = dx + 1
    end
    -- Normalize movement vector to prevent faster diagonal movement.
    local length = math.sqrt(dx^2 + dy^2)
    if length > 0 then
        self.position.x = self.position.x + (dx / length) * self.speed * dt
        self.position.y = self.position.y + (dy / length) * self.speed * dt
    end
end
-- Function to handle the player taking damage.
function Player:take_damage(amount)
    if self.is_invincible or not self.is_alive then
        return
    end
    self.current_health = self.current_health - amount
    print(self.name .. " took " .. amount .. " damage. Health: " .. self.current_health)
    -- Trigger invincibility to prevent instant re-damage.
    self.is_invincible = true
    self.invincibility_timer = 0
    if self.current_health  other_entity.position.x and
           self.position.y  other_entity.position.y
end
return Player


O
y g g

d

r

a

s

i

l



What miracle is this? This giant tree.
It stands ten thousand feet high
But doesn't touch the ground. Yet it stands.
Its roots must hold the sky.

0

Reply



Users browsing this thread:   1 Guest(s)


  •  Return to Top
  •  Contact Us
  •   Home
  •  Lite mode
© Rush Crafted with ❤ by iAndrew
Powered By MyBB, © 2002-2026 MyBB Group.
Linear Mode
Threaded Mode
View a Printable Version
Subscribe to this thread
Add Poll to this thread
Send thread to a friend