First commit
This commit is contained in:
@@ -0,0 +1,109 @@
|
||||
function state_game_gameover()
|
||||
local box
|
||||
local event_bus
|
||||
|
||||
local y = 90
|
||||
local buttons = {
|
||||
-- {
|
||||
-- hover = false,
|
||||
-- label = "Play Again",
|
||||
-- box = { x = 120 - prn_len("Play Again") / 2, y = y, width = prn_len("Play Again"), height = 10 },
|
||||
-- cb = function()
|
||||
-- trace("again")
|
||||
-- end
|
||||
-- },
|
||||
{
|
||||
hover = false,
|
||||
label = "Main Menu",
|
||||
box = { x = 120 - prn_len("Main Menu") / 2, y = y + 15, width = prn_len("Main Menu"), height = 10 },
|
||||
cb = function()
|
||||
reset()
|
||||
end
|
||||
}
|
||||
}
|
||||
|
||||
local function open_box()
|
||||
while box.w < 180 do
|
||||
box.w = box.w * 1.1
|
||||
waitframes(1)
|
||||
end
|
||||
if box.w > 180 then
|
||||
box.w = 180
|
||||
end
|
||||
while box.h < 20 do
|
||||
box.h = box.h + 1
|
||||
waitframes(1)
|
||||
end
|
||||
end
|
||||
|
||||
local function show_buttons()
|
||||
-- show a button "again", and another "main menu"
|
||||
-- right under the box
|
||||
for _, button in ipairs(buttons) do
|
||||
button.hover = false
|
||||
-- rect(button.box.x - 1, button.box.y - 1, button.box.width + 2, button.box.height + 2, 2)
|
||||
-- Hover button
|
||||
if mouse_in_rect(button.box) then
|
||||
button.hover = true
|
||||
|
||||
-- Click button
|
||||
if Input:mouse_released()
|
||||
then
|
||||
button.cb()
|
||||
end
|
||||
end
|
||||
prn_border(button.label,
|
||||
button.box.x, button.box.y,
|
||||
button.hover and 12 or 13,
|
||||
ALIGN.Left,
|
||||
0)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local function update(self)
|
||||
-- draw box
|
||||
rect(120 - box.w / 2, 67 - box.h / 2, box.w, box.h, 0)
|
||||
rectb(120 - box.w / 2, 67 - box.h / 2, box.w, box.h, 15)
|
||||
clip(120 - box.w / 2, 67 - box.h / 2, box.w, box.h)
|
||||
|
||||
-- print who won according to score
|
||||
local text
|
||||
local color
|
||||
local score_player = get_total_score(SCORES.player)
|
||||
local score_enemy = get_total_score(SCORES.enemy)
|
||||
if score_player > score_enemy then
|
||||
color = COLOR_PLAYER
|
||||
text = "YOU WON " .. score_player .. " - " .. score_enemy
|
||||
elseif score_player < score_enemy then
|
||||
color = COLOR_ENEMY
|
||||
text = "YOU LOST " .. score_player .. " - " .. score_enemy
|
||||
else
|
||||
color = 14
|
||||
text = "DRAW " .. score_player .. " - " .. score_enemy
|
||||
end
|
||||
prn_border(text, 120, 67 - 3, 12, ALIGN.Center, color)
|
||||
clip()
|
||||
|
||||
show_buttons()
|
||||
end
|
||||
|
||||
---comment
|
||||
---@param self any
|
||||
---@param die Die
|
||||
---@param _event_bus EventBus
|
||||
---@param turn "player"|"enemy"
|
||||
local function _enter(self, die, _event_bus, turn)
|
||||
assert(_event_bus, "event_bus is nil")
|
||||
assert(turn, "turn is nil")
|
||||
event_bus = _event_bus
|
||||
event_bus:emit(EVENT_REMOVE_DIE)
|
||||
|
||||
box = {
|
||||
h = 0, w = 1
|
||||
}
|
||||
addcoroutine(open_box)
|
||||
end
|
||||
|
||||
return { update = update, _enter = _enter }
|
||||
end
|
||||
@@ -0,0 +1,91 @@
|
||||
function state_game_loading()
|
||||
local covering
|
||||
local event_bus
|
||||
local turn
|
||||
local banner
|
||||
|
||||
local function show_transition()
|
||||
-- slightly scale up the transition dice
|
||||
for i, die in ipairs(covering) do
|
||||
die.scale = die.scale - 0.03 / i * 80
|
||||
die.angle = die.angle - i / 50
|
||||
if die.scale < 0 then
|
||||
die.scale = 0
|
||||
end
|
||||
swap_color(12, 15)
|
||||
swap_color(13, 15)
|
||||
swap_color(14, 15)
|
||||
swap_color(0, 15)
|
||||
die:draw(-1)
|
||||
end
|
||||
-- clean
|
||||
if table.count(covering, function(d) return d.scale == 0 end) == #covering then
|
||||
covering = {}
|
||||
end
|
||||
end
|
||||
|
||||
local function _enter(self, data)
|
||||
assert(data.covering, "needs data.covering")
|
||||
assert(data.event_bus, "needs data.event_bus")
|
||||
covering = data.covering
|
||||
event_bus = data.event_bus
|
||||
turn = data.turn
|
||||
banner = {
|
||||
h = 0,
|
||||
w = 1,
|
||||
}
|
||||
|
||||
addcoroutine(function()
|
||||
|
||||
while banner.w < 240 do
|
||||
banner.w = banner.w *1.1
|
||||
waitframes(1)
|
||||
end
|
||||
if banner.w > 240 then
|
||||
banner.w = 240
|
||||
end
|
||||
while banner.h < 20 do
|
||||
banner.h = banner.h + 1
|
||||
waitframes(1)
|
||||
end
|
||||
waitsecs(1.5)
|
||||
while banner.h > 0.5 do
|
||||
banner.h = banner.h - 1
|
||||
waitframes(1)
|
||||
end
|
||||
while banner.w > 1 do
|
||||
banner.w = banner.w * 0.9
|
||||
waitframes(1)
|
||||
end
|
||||
waitsecs(0.5)
|
||||
event_bus:emit(EVENT_RESET_DIE)
|
||||
event_bus:emit(EVENT_SET_STEP, "rolling")
|
||||
end)
|
||||
end
|
||||
|
||||
local function update(self)
|
||||
-- black banner in the middle
|
||||
rect(120 - banner.w / 2, 67 - banner.h / 2, banner.w, banner.h, 0)
|
||||
rectb(120 - banner.w / 2, 67 - banner.h / 2, banner.w, banner.h, 15)
|
||||
clip(120 - banner.w / 2, 67 - banner.h / 2, banner.w, banner.h)
|
||||
|
||||
-- show who's going first
|
||||
local text
|
||||
local color
|
||||
if turn == "player" then
|
||||
color = COLOR_PLAYER
|
||||
text = "You begin this round"
|
||||
else
|
||||
color = COLOR_ENEMY
|
||||
text = "Your opponent begins this round"
|
||||
end
|
||||
prn_border(text, 120, 67 - 4, 12, ALIGN.Center, color)
|
||||
clip()
|
||||
|
||||
if #covering > 0 then
|
||||
show_transition()
|
||||
end
|
||||
end
|
||||
|
||||
return { _enter = _enter, update = update }
|
||||
end
|
||||
@@ -0,0 +1,102 @@
|
||||
include "ai"
|
||||
|
||||
function state_game_placing()
|
||||
--- @type Die
|
||||
local die
|
||||
--- @type EventBus
|
||||
local event_bus
|
||||
--- @type 'player'|'enemy'
|
||||
local turn
|
||||
local placing = false
|
||||
|
||||
local waiting = 30
|
||||
|
||||
--- Click on a column to place the die
|
||||
local function place_die(col_id)
|
||||
if placing then return end
|
||||
|
||||
placing = true
|
||||
|
||||
local cell_id = 0
|
||||
for i = 1, 3 do
|
||||
if PLACED_DICE[turn][col_id][i] == 0 then
|
||||
cell_id = i
|
||||
break
|
||||
end
|
||||
end
|
||||
step = "waiting"
|
||||
addcoroutine(function()
|
||||
-- move the die to its cell
|
||||
local cell = get_cell_coords(turn, col_id, cell_id)
|
||||
die.box = nil
|
||||
die.angle = die.angle % 360
|
||||
-- get value closest to 0. e.g. 270 -> -90
|
||||
if die.angle > 180 then
|
||||
die.angle = die.angle - 360
|
||||
end
|
||||
local tween = Tween.new(0.5, die, { x = cell.x + 3, y = cell.y + 1, angle = 0 }, "outQuad")
|
||||
repeat
|
||||
coroutine.yield()
|
||||
until tween:update(dt)
|
||||
PLACED_DICE:set(turn, col_id, cell_id, die.value)
|
||||
|
||||
-- Animate the dice and update the scores
|
||||
event_bus:emit(EVENT_REMOVE_DIE)
|
||||
event_bus:emit(EVENT_SET_STEP, "scoring")
|
||||
end)
|
||||
end
|
||||
|
||||
---@param self any
|
||||
---@param _die Die
|
||||
---@param _event_bus EventBus
|
||||
---@param _turn 'player'|'enemy'
|
||||
local _enter = function(self, _die, _event_bus, _turn)
|
||||
assert(_die, "missing die")
|
||||
assert(_event_bus, "missing event_bus")
|
||||
assert(_turn, "missing turn")
|
||||
die = _die
|
||||
event_bus = _event_bus
|
||||
turn = _turn
|
||||
waiting = 30
|
||||
placing = false
|
||||
end
|
||||
|
||||
local update = function(self)
|
||||
waiting = waiting - 1
|
||||
if turn == "enemy" then
|
||||
if waiting <= 0 and not placing then
|
||||
local col = ai_pick_column(PLACED_DICE.enemy, PLACED_DICE.player, die.value)
|
||||
place_die(col)
|
||||
end
|
||||
else -- turn == "player"
|
||||
-- Highlight the hovered column
|
||||
local columns = {
|
||||
get_column_rect(turn, 1),
|
||||
get_column_rect(turn, 2),
|
||||
get_column_rect(turn, 3),
|
||||
}
|
||||
local col, col_id = table.find(columns, function(c)
|
||||
return mouse_in_rect(c)
|
||||
end)
|
||||
if col then
|
||||
if PLACED_DICE:has_free_slot(turn, col_id) then
|
||||
-- draw hovered column
|
||||
rect(col.x, col.y, col.width, col.height, 14)
|
||||
-- place the die if clicked
|
||||
if Input:mouse_released() then
|
||||
place_die(col_id)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Redraw the board because the hovered column is drawn on top of it
|
||||
-- and i'm too lazy to fix this properly.
|
||||
draw_board()
|
||||
end
|
||||
|
||||
return {
|
||||
_enter = _enter,
|
||||
update = update,
|
||||
}
|
||||
end
|
||||
@@ -0,0 +1,40 @@
|
||||
function state_game_rolling()
|
||||
--- @type Die
|
||||
local die
|
||||
--- @type EventBus
|
||||
local event_bus
|
||||
|
||||
local function roll_die()
|
||||
die.bouncing = true
|
||||
local rot = Tween.new(0.7, die, {
|
||||
angle = (die.angle + math.random(180,360))-- die.angle + (math.random()<.5 and 1 or -1)* math.random(270, 360)
|
||||
}, "outSine")
|
||||
local done = false
|
||||
repeat
|
||||
done = rot:update(dt)
|
||||
coroutine.yield()
|
||||
until done
|
||||
|
||||
die.bouncing = false
|
||||
event_bus:emit(EVENT_SET_STEP, "placing")
|
||||
end
|
||||
|
||||
---@param self any
|
||||
---@param _die Die
|
||||
---@param _event_bus EventBus
|
||||
local _enter = function(self, _die, _event_bus)
|
||||
assert(_die, "states.game.rolling needs a die")
|
||||
assert(_event_bus, "states.game.rolling needs an event_bus")
|
||||
die = _die
|
||||
event_bus = _event_bus
|
||||
addcoroutine(roll_die)
|
||||
end
|
||||
|
||||
local update = function(self)
|
||||
end
|
||||
|
||||
return {
|
||||
_enter = _enter,
|
||||
update = update
|
||||
}
|
||||
end
|
||||
@@ -0,0 +1,93 @@
|
||||
function state_game_scoring()
|
||||
local dice_to_destroy = {}
|
||||
--- @type EventBus
|
||||
local event_bus
|
||||
|
||||
local destroyed = 0
|
||||
|
||||
local function update_board_and_score(player, col, row)
|
||||
assert(player)
|
||||
assert(col)
|
||||
assert(row)
|
||||
|
||||
-- Create a Die and place it on the cell
|
||||
local cell = get_cell_coords(player, col, row)
|
||||
local die = Die:new({ value = PLACED_DICE:get(player, col, row), x = cell.x + 3, y = cell.y + 1 })
|
||||
|
||||
-- Set the score to 0
|
||||
PLACED_DICE:set(player, col, row, 0)
|
||||
|
||||
table.insert(dice_to_destroy, die)
|
||||
addcoroutine(function()
|
||||
waitframes(10)
|
||||
local tween = Tween.new(0.5, die, { scale = 0.1 }, "inOutQuad")
|
||||
repeat
|
||||
coroutine.yield()
|
||||
until tween:update(dt)
|
||||
table.remove_item(dice_to_destroy, die)
|
||||
end)
|
||||
end
|
||||
|
||||
---comment
|
||||
---@param self any
|
||||
---@param _die Die|nil
|
||||
---@param _event_bus EventBus
|
||||
---@param player 'player'|'enemy'
|
||||
local function _enter(self, _die, _event_bus, player)
|
||||
assert(_event_bus)
|
||||
assert(player == "player" or player == "enemy")
|
||||
|
||||
event_bus = _event_bus
|
||||
destroyed = 0
|
||||
local other_player = player == "player" and "enemy" or "player"
|
||||
|
||||
-- Check if the newly placed die must remove other dice
|
||||
local current_dice = PLACED_DICE[player]
|
||||
local other_dice = PLACED_DICE[other_player]
|
||||
|
||||
-- Check the dice for each column, and remove corresponding dice in the opposing column
|
||||
for col = 1, 3 do
|
||||
for row = 1, 3 do
|
||||
local value = current_dice[col][row]
|
||||
for row2 = 1, 3 do
|
||||
local value2 = other_dice[col][row2]
|
||||
if value > 0 and value2 > 0 and value2 == value then
|
||||
trace("destroy " .. other_player .. " " .. col .. " " .. row2 .. " = " .. value2)
|
||||
update_board_and_score(other_player, col, row2)
|
||||
destroyed = destroyed + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Update the scores and move on to next state
|
||||
addcoroutine(function()
|
||||
waitsecs((destroyed > 0) and 0.6 or 0.3)
|
||||
SCORES:update()
|
||||
|
||||
-- Check if it's game over
|
||||
if PLACED_DICE:is_game_over() then
|
||||
SCORES:update()
|
||||
event_bus:emit(EVENT_SET_STEP, "game_over")
|
||||
else
|
||||
event_bus:emit(EVENT_CHANGE_TURN)
|
||||
end
|
||||
|
||||
end)
|
||||
end
|
||||
|
||||
local function update(self)
|
||||
for _, die in ipairs(dice_to_destroy) do
|
||||
die:draw()
|
||||
end
|
||||
end
|
||||
|
||||
local function _leave(self)
|
||||
end
|
||||
|
||||
return {
|
||||
_enter = _enter,
|
||||
update = update,
|
||||
_leave = _leave
|
||||
}
|
||||
end
|
||||
@@ -0,0 +1,106 @@
|
||||
include "board"
|
||||
include "classes.die"
|
||||
include "states.game.loading"
|
||||
include "states.game.rolling"
|
||||
include "states.game.placing"
|
||||
include "states.game.scoring"
|
||||
include "states.game.gameover"
|
||||
include "utils.event_bus"
|
||||
|
||||
function state_game()
|
||||
local game = {}
|
||||
local event_bus = EventBus:new()
|
||||
|
||||
--- @type "player"|"enemy"
|
||||
local turn = "player"
|
||||
|
||||
--- @type "waiting"|"rolling"|"placing"
|
||||
local step = "rolling"
|
||||
|
||||
--- @type Die|nil
|
||||
local die
|
||||
|
||||
local function reset_die()
|
||||
die = Die:new({ box = get_dice_box(turn), bouncing = false })
|
||||
end
|
||||
|
||||
--
|
||||
-- #region State management
|
||||
--
|
||||
|
||||
--- Sub-states
|
||||
--- @type StateManager
|
||||
local state_manager = StateManager:new()
|
||||
local states = {
|
||||
loading = state_game_loading(),
|
||||
rolling = state_game_rolling(),
|
||||
placing = state_game_placing(),
|
||||
scoring = state_game_scoring(),
|
||||
game_over = state_game_gameover(),
|
||||
}
|
||||
|
||||
event_bus:on(EVENT_SET_STEP, function(new_step)
|
||||
trace("[Event] set_step: " .. step .. " -> " .. new_step)
|
||||
assert(states[new_step], "state " .. new_step .. " does not exist")
|
||||
state_manager:change_state(states[new_step], die, event_bus, turn)
|
||||
step = new_step
|
||||
end)
|
||||
|
||||
event_bus:on(EVENT_CHANGE_TURN, function()
|
||||
turn = turn == "player" and "enemy" or "player"
|
||||
reset_die()
|
||||
state_manager:change_state(states.rolling, die, event_bus)
|
||||
step = "rolling"
|
||||
end)
|
||||
|
||||
event_bus:on(EVENT_REMOVE_DIE, function()
|
||||
die = nil
|
||||
end)
|
||||
|
||||
event_bus:on(EVENT_RESET_DIE, function()
|
||||
reset_die()
|
||||
end)
|
||||
|
||||
--
|
||||
-- #endregion State management
|
||||
--
|
||||
|
||||
game._enter = function(self, data)
|
||||
assert(data.covering, "needs data.covering")
|
||||
trace("entering game state")
|
||||
|
||||
turn = math.random(1, 2) == 1 and "player" or "enemy"
|
||||
|
||||
state_manager:change_state(states.loading, {
|
||||
turn = turn,
|
||||
event_bus = event_bus,
|
||||
covering = data.covering
|
||||
})
|
||||
end
|
||||
|
||||
game.update = function()
|
||||
cls()
|
||||
if die then die:update() end
|
||||
draw_board()
|
||||
print_scores()
|
||||
print_names()
|
||||
draw_dice_boxes()
|
||||
|
||||
state_manager:update()
|
||||
|
||||
if die and die.value then
|
||||
die:draw()
|
||||
end
|
||||
|
||||
|
||||
-- prn_border("Turn: " .. turn, 1, 1, 2)
|
||||
-- prn_border("Step: " .. step, 1, 10, 2)
|
||||
reset_colors()
|
||||
end
|
||||
|
||||
|
||||
game._leave = function()
|
||||
end
|
||||
|
||||
return game
|
||||
end
|
||||
@@ -0,0 +1,130 @@
|
||||
function state_main_menu()
|
||||
local covering = {}
|
||||
local falling = {}
|
||||
local states
|
||||
|
||||
local buttons = {
|
||||
{
|
||||
hover = false,
|
||||
label = "Play",
|
||||
box = { x = 120 - prn_len("Play") / 2, y = 100, w = prn_len("Play"), h = 10 },
|
||||
cb = function()
|
||||
trace("play")
|
||||
for i = 0, 240, 16 do
|
||||
for j = 0, 135, 16 do
|
||||
table.insert(covering, Die:new({
|
||||
value = math.random(1, 6),
|
||||
angle = 360,
|
||||
x = i,
|
||||
y = j,
|
||||
scale = 0
|
||||
}))
|
||||
end
|
||||
end
|
||||
end
|
||||
}
|
||||
}
|
||||
|
||||
local function show_transition()
|
||||
-- slightly scale up the transition dice
|
||||
for i, die in ipairs(covering) do
|
||||
die.scale = die.scale + 0.03 / i * 80
|
||||
die.angle = die.angle * 0.90
|
||||
if die.scale > 1 then
|
||||
die.scale = 1
|
||||
end
|
||||
swap_color(12, 15)
|
||||
swap_color(0, 15)
|
||||
die:draw(-1)
|
||||
end
|
||||
if table.count(covering, function(d) return d.scale == 1 end) == #covering then
|
||||
state_manager:change_state(states.game, { covering = covering })
|
||||
end
|
||||
end
|
||||
|
||||
local function falling_dice()
|
||||
local remove = {}
|
||||
for i, die in ipairs(falling) do
|
||||
die.y = die.y + 1
|
||||
die.angle = die.angle + die.rot_speed
|
||||
if die.y > 160 then
|
||||
table.insert(remove, i)
|
||||
end
|
||||
end
|
||||
for _, i in ipairs(remove) do
|
||||
table.remove(falling, i)
|
||||
end
|
||||
end
|
||||
|
||||
local function draw_dice()
|
||||
for _, die in ipairs(falling) do
|
||||
swap_color(12, 15)
|
||||
swap_color(13, 15)
|
||||
swap_color(14, 15)
|
||||
die:draw()
|
||||
reset_colors(12)
|
||||
end
|
||||
end
|
||||
|
||||
local function _enter(self, data)
|
||||
assert(data.states, "needs a states table")
|
||||
states = data.states
|
||||
covering = {}
|
||||
end
|
||||
|
||||
local function update()
|
||||
-- random sign
|
||||
if math.random() < 0.05 then
|
||||
local sign = math.random() < 0.5 and -1 or 1
|
||||
-- Spawn a random die
|
||||
local die = Die:new({
|
||||
value = math.random(1, 6),
|
||||
x = math.random(240),
|
||||
y = -20,
|
||||
angle = math.random(10, 40),
|
||||
rot_speed = sign * math.random(6, 10) / 10,
|
||||
})
|
||||
table.insert(falling, die)
|
||||
end
|
||||
|
||||
falling_dice()
|
||||
|
||||
cls()
|
||||
draw_dice()
|
||||
|
||||
-- prn_border("KNUCKLEBONES", 118, 10, 1, ALIGN.Center, 0, 2, 0)
|
||||
-- prn_border("KNUCKLEBONES", 122, 10, 2, ALIGN.Center, 0, 2, 1)
|
||||
prn_border("KNUCKLEBONES", 120, 10, 12, ALIGN.Center, 0, 2)
|
||||
|
||||
local l = prn_len("A game of risk and reward")
|
||||
local x = 120 - l / 2
|
||||
local y = 50
|
||||
x = x + prn_border("A game of ", x, y, 13, ALIGN.Left, 0)
|
||||
x = x + prn_border_floaty("risk ", x, y + 5, 12, ALIGN.Left, 1, 1, 20)
|
||||
x = x + prn_border("and ", x, y, 13, ALIGN.Left, 0)
|
||||
x = x + prn_border_floaty("reward", x, y - 5, 12, ALIGN.Left, 8)
|
||||
print_border("Originally from \"The Cult of the Lamb\"", 104, 130, 14, 0, false, 1, true)
|
||||
local mx, my = mouse()
|
||||
|
||||
for i, button in ipairs(buttons) do
|
||||
-- Print button
|
||||
local x, y, w, h = button.box.x, button.box.y, button.box.w, button.box.h
|
||||
local hover = mx >= x and mx <= x + w and my >= y and my <= y + h
|
||||
button.hover = hover
|
||||
local color = hover and 12 or 13
|
||||
-- rect(x, y, w, h, color)
|
||||
prn_border(button.label, x, y, color, ALIGN.Left, 0)
|
||||
|
||||
-- Click button
|
||||
if hover and Input:mouse_pressed()
|
||||
then
|
||||
button.cb()
|
||||
end
|
||||
end
|
||||
|
||||
if #covering > 0 then
|
||||
show_transition()
|
||||
end
|
||||
end
|
||||
return { update = update, _enter = _enter }
|
||||
end
|
||||
@@ -0,0 +1,60 @@
|
||||
--- States stack
|
||||
--- @class StateManager
|
||||
StateManager = {
|
||||
states = {},
|
||||
---
|
||||
---@param self StateManager
|
||||
new = function(self, o)
|
||||
o = o or {}
|
||||
setmetatable(o, self)
|
||||
self.__index = self
|
||||
return o
|
||||
end,
|
||||
---
|
||||
---@param self StateManager
|
||||
---@return unknown
|
||||
_get_current_state = function(self)
|
||||
return self.states[#self.states]
|
||||
end,
|
||||
---
|
||||
---@param self StateManager
|
||||
---@param state any
|
||||
_set_current_state = function(self, state)
|
||||
if #self.states == 0 then
|
||||
self.states = { state }
|
||||
else
|
||||
local last = self.states[#self.states]
|
||||
if last._leave then last:_leave() end
|
||||
self.states[#self.states] = state
|
||||
end
|
||||
end,
|
||||
---
|
||||
---@param self StateManager
|
||||
---@param state any
|
||||
change_state = function(self, state, ...)
|
||||
local current = self:_get_current_state()
|
||||
if current and current._leave then current:_leave() end
|
||||
self:_set_current_state(state)
|
||||
if state._enter then state:_enter(...) end
|
||||
end,
|
||||
---
|
||||
---@param self StateManager
|
||||
push_state = function(self, state, data)
|
||||
table.insert(self.states, state)
|
||||
if state._enter then state:_enter(data) end
|
||||
end,
|
||||
---
|
||||
---@param self StateManager
|
||||
pop_state = function(self)
|
||||
local state = table.remove(self.states)
|
||||
if #self.states == 0 then trace("No state left", 2) end
|
||||
if state._leave then state:_leave() end
|
||||
end,
|
||||
---
|
||||
---@param self StateManager
|
||||
update = function(self)
|
||||
local current = self:_get_current_state()
|
||||
if not current then return end
|
||||
if current.update then current:update() end
|
||||
end,
|
||||
}
|
||||
Reference in New Issue
Block a user