From 3e9f16dfbdab813e92c35ca629be2ffe3d5e1818 Mon Sep 17 00:00:00 2001 From: fnicon Date: Sun, 22 Mar 2026 23:42:13 +0900 Subject: [PATCH] Add countdown --- .../src/new/shared/components/animation.lua | 61 +++++++++++++++++++ .../new/world/race/components/checkpoint.lua | 0 .../new/world/race/components/countdown.lua | 32 ++++++++++ .../src/new/world/race/components/phase.lua | 27 ++++++++ game/love_src/src/new/world/race/init.lua | 33 ++++++++++ game/love_src/src/system/animation.lua | 50 +++++++++++++++ 6 files changed, 203 insertions(+) create mode 100644 game/love_src/src/new/shared/components/animation.lua create mode 100644 game/love_src/src/new/world/race/components/checkpoint.lua create mode 100644 game/love_src/src/new/world/race/components/countdown.lua create mode 100644 game/love_src/src/new/world/race/components/phase.lua create mode 100644 game/love_src/src/system/animation.lua diff --git a/game/love_src/src/new/shared/components/animation.lua b/game/love_src/src/new/shared/components/animation.lua new file mode 100644 index 0000000..7fde508 --- /dev/null +++ b/game/love_src/src/new/shared/components/animation.lua @@ -0,0 +1,61 @@ +local vm = require"lib.vornmath" +local uib = require"love_src.src.system.ui_behavior" +local uir = require"love_src.src.system.ui_render" + +local sfx = require"love_src.wrapper.lappy.new.source".obj + +local anim_math = require("love_src.src.system.animation") + +local main_wrapper = require "love_src.wrapper.lappy.world" +---@class wrappers.Concord.world : lappy.world +local world = main_wrapper:extend() + +local reap = require("lib.reap") +local BASE = reap.base_path(...) + +function world:new() + world.super.new(self, BASE, "animation") +end + +local function default_trigger() +end + +function world:load(e, data) + self.data = {} + + self.data.run_time = data.run_time or 0 + self.data.anim_direction = data.anim_direction or 1 + self.data.fps = data.fps or 12 + self.data.frames = data.frames or {} + self.data.current_frame = data.current_frame or 1 + self.data.triggers = data.triggers or {} + self.data.next_trigger = data.next_trigger or 1 + + self.data.triggers_fn = data.triggers_fn or {} +end + +function world:update(dt) + self.data.run_time = anim_math.update_time( + self.data.run_time, dt, self.data.anim_direction + ) + local new_index = anim_math.update_fps_time( + self.data.run_time, self.data.fps + ) + self.data.current_frame = anim_math.get_loop( + new_index, + #self.data.frames + ) + + if (anim_math.is_trigger( + self.data.triggers, + self.data.next_trigger, + self.data.current_frame + )) then + self.data.triggers_fn[self.data.current_frame]() + self.data.next_trigger = anim_math.get_loop( + self.data.next_trigger + 1, #self.data.triggers + ) + end +end + +return world diff --git a/game/love_src/src/new/world/race/components/checkpoint.lua b/game/love_src/src/new/world/race/components/checkpoint.lua new file mode 100644 index 0000000..e69de29 diff --git a/game/love_src/src/new/world/race/components/countdown.lua b/game/love_src/src/new/world/race/components/countdown.lua new file mode 100644 index 0000000..ce1e3ad --- /dev/null +++ b/game/love_src/src/new/world/race/components/countdown.lua @@ -0,0 +1,32 @@ +local vm = require"lib.vornmath" +local uib = require"love_src.src.system.ui_behavior" +local uir = require"love_src.src.system.ui_render" + +local main_wrapper = require "love_src.wrapper.lappy.world" +---@class wrappers.Concord.world : lappy.world +local world = main_wrapper:extend() + +local reap = require("lib.reap") +local BASE = reap.base_path(...) + +function world:new() + world.super.new(self, BASE, "phase") +end + +function world:load(entity, data) + self.data = data + self.e = entity +end + +function world:update(dt) + self.data.label = self.e.components.animation.data.frames[self.e.components.animation.data.current_frame] +end + +function world:ui_draw() + uir.draw_text(self.data.label, + self.data.pos[1], self.data.pos[2], + self.data.label_color + ) +end + +return world diff --git a/game/love_src/src/new/world/race/components/phase.lua b/game/love_src/src/new/world/race/components/phase.lua new file mode 100644 index 0000000..b1cfcbb --- /dev/null +++ b/game/love_src/src/new/world/race/components/phase.lua @@ -0,0 +1,27 @@ +local vm = require"lib.vornmath" +local uib = require"love_src.src.system.ui_behavior" +local uir = require"love_src.src.system.ui_render" + +local main_wrapper = require "love_src.wrapper.lappy.world" +---@class wrappers.Concord.world : lappy.world +local world = main_wrapper:extend() + +local reap = require("lib.reap") +local BASE = reap.base_path(...) + +function world:new() + world.super.new(self, BASE, "phase") +end + +function world:load(entity, data) + self.data = data +end + +function world:ui_draw() + uir.draw_text(self.data.label, + self.data.pos[1], self.data.pos[2], + self.data.label_color + ) +end + +return world diff --git a/game/love_src/src/new/world/race/init.lua b/game/love_src/src/new/world/race/init.lua index fc463fa..06a5e9e 100644 --- a/game/love_src/src/new/world/race/init.lua +++ b/game/love_src/src/new/world/race/init.lua @@ -14,6 +14,8 @@ local default = { } } +local lw, lh = love.graphics.getDimensions() + local entities_default = { { components = { @@ -62,6 +64,37 @@ local entities_default = { drag = vm.vec2(0.1, 0.0) } } + }, + { + type = "countdown", + name = "321go", + components = { + countdown = require("love_src.src.new.world.race.components.countdown"), + animation = require("love_src.src.new.shared.components.animation"), + }, + data = { + countdown = { + label = "", + pos = vm.vec2(lw/2, lh/2), + label_color = {1, 0, 1} + }, + animation = { + frames = { + "3", + "2", + "1", + "go", + "" + }, + fps = 1, + triggers = {4}, + triggers_fn = { + [4] = function () + print("GO") + end + } + } + } } } diff --git a/game/love_src/src/system/animation.lua b/game/love_src/src/system/animation.lua new file mode 100644 index 0000000..f6739a4 --- /dev/null +++ b/game/love_src/src/system/animation.lua @@ -0,0 +1,50 @@ +local floor = math.floor + +--- system time +---@param time number +---@param delta number +---@param indicator number 1 | -1 forward/backward +---@return number +local function update_time(time, delta, indicator) + return time + (delta * indicator) +end + +--- loop index from min to max +---@param index number +---@param _max number +---@param _min number? +---@return number +local function get_loop(index, _max, _min) + _min = _min or 0 + local md = _min + index % (_max - _min) + if (md == _min) then + return _max + else + return _min + index % (_max - _min) + end +end + +---comment +---@param time number +---@param fps number +---@return integer +local function update_fps_time(time, fps) + -- floor time to 1. check x fps per second + return floor(time / (1 / fps)) +end + +---check if it's time to trigger something +---@param trigger_frames any[] +---@param trigger_id number | string +---@param frame_id number id to compare +---@return boolean +local function is_trigger(trigger_frames, trigger_id, frame_id) + return (trigger_frames[trigger_id] == frame_id) +end + +return { + update_time = update_time, + update_fps_time = update_fps_time, + get_loop = get_loop, + is_trigger = is_trigger +}