1
0
Fork 0
mirror of https://github.com/Reuh/ubiquitousse.git synced 2025-10-27 17:19:31 +00:00

uqt.signal

This commit is contained in:
Étienne Fildadut 2019-12-27 18:54:30 +01:00
parent 82bc7268e6
commit f6fb8ad649
11 changed files with 331 additions and 80 deletions

View file

@ -2,18 +2,30 @@ local uqt = require((...):match("^(.-ubiquitousse)%."))
local ctr = require("ctr") local ctr = require("ctr")
local gfx = require("ctr.gfx") local gfx = require("ctr.gfx")
local function checkCompat(stuffName, expectedVersion, actualVersion) local madeForCtr = "v1.0"
if actualVersion ~= expectedVersion then local madeForUqt = "0.0.1"
local txt = ("Ubiquitousse ctrµLua backend was made for %s %s but %s is used!\nThings may not work as expected.")
:format(stuffName, expectedVersion, actualVersion) -- Check versions
print(txt) local txt = ""
for _=0,300 do
gfx.start(gfx.TOP) if ctr.version ~= madeForCtr then
gfx.wrappedText(0, 0, txt, gfx.TOP_WIDTH) txt = txt .. ("Ubiquitousse ctrµLua backend was made for ctrµLua %s but %s is used!\n")
gfx.stop() :format(madeForCtr, uqt.version)
gfx.render() end
end
if uqt.version ~= madeForUqt then
txt = txt .. ("Ubiquitousse ctrµLua backend was made for Ubiquitousse %s but %s is used!\n")
:format(madeForUqt, uqt.version)
end
-- Show warnings
if txt ~= "" then
txt = txt .. "Things may not work as expected.\n"
print(txt)
for _=0,300 do
gfx.start(gfx.TOP)
gfx.wrappedText(0, 0, txt, gfx.TOP_WIDTH)
gfx.stop()
gfx.render()
end end
end end
checkCompat("ctrµLua", "v1.0", ctr.version) -- not really a version, just get the latest build
checkCompat("Ubiquitousse", "0.0.1", uqt.version)

View file

@ -1,11 +1,30 @@
local uqt = require((...):match("^(.-ubiquitousse)%.")) local uqt = require((...):match("^(.-ubiquitousse)%."))
local function checkCompat(stuffName, expectedVersion, actualVersion) local madeForLove = { 11, "x", "x" }
if actualVersion ~= expectedVersion then local madeForUqt = "0.0.1"
local txt = ("Ubiquitousse Löve backend was made for %s %s but %s is used!\nThings may not work as expected.")
:format(stuffName, expectedVersion, actualVersion) -- Check versions
print(txt) local txt = ""
local actualLove = { love.getVersion() }
for i, v in ipairs(madeForLove) do
if v ~= "x" then
if actualLove[i] ~= v then
txt = txt .. ("Ubiquitousse Löve backend was made for LÖVE %s.%s.%s but %s.%s.%s is used!\n")
:format(madeForLove[1], madeForLove[2], madeForLove[3], actualLove[1], actualLove[2], actualLove[3])
break
end
end end
end end
checkCompat("Löve", "11.3.0", ("%s.%s.%s"):format(love.getVersion()))
checkCompat("Ubiquitousse", "0.0.1", uqt.version) if uqt.version ~= madeForUqt then
txt = txt .. ("Ubiquitousse Löve backend was made for Ubiquitousse %s but %s is used!\n")
:format(madeForUqt, uqt.version)
end
-- Show warnings
if txt ~= "" then
txt = txt .. "Things may not work as expected.\n"
print(txt)
love.window.showMessageBox("Compatibility warning", txt, "warning")
end

View file

@ -64,33 +64,19 @@ local ubiquitousse
ubiquitousse = { ubiquitousse = {
--- Ubiquitousse version. --- Ubiquitousse version.
-- @impl ubiquitousse -- @impl ubiquitousse
version = "0.0.1", version = "0.0.1"
--- Should be called each time the game loop is ran; will update every loaded Ubiquitousse module that needs it.
-- @tparam number dt time since last call, in miliseconds
-- @impl mixed
update = function(dt)
if ubiquitousse.timer then ubiquitousse.timer.update(dt) end
if ubiquitousse.scene then ubiquitousse.scene.update(dt) end
if ubiquitousse.input then ubiquitousse.input.update(dt) end
end,
--- Should be called each time the game expect a new frame to be drawn; will draw every loaded Ubiquitousse module that needs it
-- The screen is expected to be cleared since last frame.
-- @impl mixed
draw = function()
if ubiquitousse.scene then ubiquitousse.scene.draw() end
end
} }
-- We're going to require modules requiring Ubiquitousse, so to avoid stack overflows we already register the ubiquitousse package -- We're going to require modules requiring Ubiquitousse, so to avoid stack overflows we already register the ubiquitousse package
package.loaded[p] = ubiquitousse package.loaded[p] = ubiquitousse
-- Require external submodules -- Require external submodules
for _, m in ipairs{"asset", "ecs", "input", "scene", "timer", "util"} do for _, m in ipairs{"signal", "asset", "ecs", "input", "scene", "timer", "util"} do
local s, t = pcall(require, p.."."..m) local s, t = pcall(require, p.."."..m)
if s then if s then
ubiquitousse[m] = t ubiquitousse[m] = t
elseif not t:match("^module [^n]+ not found") then
error(t)
end end
end end

View file

@ -1,5 +1,8 @@
local input = require((...):match("^(.-%.)backend").."input") local input = require((...):match("^(.-%.)backend").."input")
local loaded, signal = pcall(require, (...):match("^(.-)input").."signal")
if not loaded then signal = nil end
local gfx = require("ctr.gfx") local gfx = require("ctr.gfx")
local hid = require("ctr.hid") local hid = require("ctr.hid")
@ -266,4 +269,9 @@ input.default.pointer:bind(
input.default.confirm:bind("key.a") input.default.confirm:bind("key.a")
input.default.cancel:bind("key.b") input.default.cancel:bind("key.b")
--- Register signals
if signal then
signal.event:replace("update", oUpdate, input.update)
end
return input return input

View file

@ -1,5 +1,8 @@
local input = require((...):match("^(.-%.)backend").."input") local input = require((...):match("^(.-%.)backend").."input")
local loaded, signal = pcall(require, (...):match("^(.-)input").."signal")
if not loaded then signal = nil end
-- Config -- -- Config --
-- Use ScanCodes (layout independant input) instead of KeyConstants (layout dependant) for keyboard input -- Use ScanCodes (layout independant input) instead of KeyConstants (layout dependant) for keyboard input
@ -13,24 +16,23 @@ local displayKeyConstant = true
love.mouse.setVisible(false) love.mouse.setVisible(false)
-- Button detection -- Button detection
-- FIXME love callbacks do something cleaner
local buttonsInUse = {} local buttonsInUse = {}
local axesInUse = {} local axesInUse = {}
function love.keypressed(key, scancode, isrepeat) function input.keypressed(key, scancode, isrepeat)
if useScancodes then key = scancode end if useScancodes then key = scancode end
buttonsInUse["keyboard."..key] = true buttonsInUse["keyboard."..key] = true
end end
function love.keyreleased(key, scancode) function input.keyreleased(key, scancode)
if useScancodes then key = scancode end if useScancodes then key = scancode end
buttonsInUse["keyboard."..key] = nil buttonsInUse["keyboard."..key] = nil
end end
function love.mousepressed(x, y, button, istouch) function input.mousepressed(x, y, button, istouch)
buttonsInUse["mouse."..button] = true buttonsInUse["mouse."..button] = true
end end
function love.mousereleased(x, y, button, istouch) function input.mousereleased(x, y, button, istouch)
buttonsInUse["mouse."..button] = nil buttonsInUse["mouse."..button] = nil
end end
function love.wheelmoved(x, y) function input.wheelmoved(x, y)
if y > 0 then if y > 0 then
buttonsInUse["mouse.wheel.up"] = true buttonsInUse["mouse.wheel.up"] = true
elseif y < 0 then elseif y < 0 then
@ -42,17 +44,17 @@ function love.wheelmoved(x, y)
buttonsInUse["mouse.wheel.left"] = true buttonsInUse["mouse.wheel.left"] = true
end end
end end
function love.mousemoved(x, y, dx, dy) function input.mousemoved(x, y, dx, dy)
if dx ~= 0 then axesInUse["mouse.move.x"] = dx/love.graphics.getWidth() end if dx ~= 0 then axesInUse["mouse.move.x"] = dx/love.graphics.getWidth() end
if dy ~= 0 then axesInUse["mouse.move.y"] = dy/love.graphics.getHeight() end if dy ~= 0 then axesInUse["mouse.move.y"] = dy/love.graphics.getHeight() end
end end
function love.gamepadpressed(joystick, button) function input.gamepadpressed(joystick, button)
buttonsInUse["gamepad.button."..joystick:getID().."."..button] = true buttonsInUse["gamepad.button."..joystick:getID().."."..button] = true
end end
function love.gamepadreleased(joystick, button) function input.gamepadreleased(joystick, button)
buttonsInUse["gamepad.button."..joystick:getID().."."..button] = nil buttonsInUse["gamepad.button."..joystick:getID().."."..button] = nil
end end
function love.gamepadaxis(joystick, axis, value) function input.gamepadaxis(joystick, axis, value)
if value ~= 0 then if value ~= 0 then
axesInUse["gamepad.axis."..joystick:getID().."."..axis] = value axesInUse["gamepad.axis."..joystick:getID().."."..axis] = value
else else
@ -61,11 +63,7 @@ function love.gamepadaxis(joystick, axis, value)
end end
-- Windows size -- Windows size
input.drawWidth, input.drawHeight = love.graphics.getWidth(), love.graphics.getHeight() input.getDrawWidth, input.getDrawHeight = love.graphics.getWidth, love.graphics.getHeight
function love.resize(width, height)
input.drawWidth = width
input.drawHeight = height
end
-- Update -- Update
local oUpdate = input.update local oUpdate = input.update
@ -190,7 +188,7 @@ input.basicAxisDetector = function(id)
end end
end end
input.buttonsInUse = function(threshold) input.buttonUsed = function(threshold)
local r = {} local r = {}
threshold = threshold or 0.5 threshold = threshold or 0.5
for b in pairs(buttonsInUse) do for b in pairs(buttonsInUse) do
@ -201,10 +199,10 @@ input.buttonsInUse = function(threshold)
table.insert(r, b.."%"..(v < 0 and -threshold or threshold)) table.insert(r, b.."%"..(v < 0 and -threshold or threshold))
end end
end end
return r return unpack(r)
end end
input.axesInUse = function(threshold) input.axisUsed = function(threshold)
local r = {} local r = {}
threshold = threshold or 0.5 threshold = threshold or 0.5
for b,v in pairs(axesInUse) do for b,v in pairs(axesInUse) do
@ -212,7 +210,7 @@ input.axesInUse = function(threshold)
table.insert(r, b.."%"..threshold) table.insert(r, b.."%"..threshold)
end end
end end
return r return unpack(r)
end end
input.buttonName = function(...) input.buttonName = function(...)
@ -316,4 +314,18 @@ input.default.cancel:bind(
"gamepad.button.1.b" "gamepad.button.1.b"
) )
--- Register signals
if signal then
signal.event:bind("keypressed", input.keypressed)
signal.event:bind("keyreleased", input.keyreleased)
signal.event:bind("mousepressed", input.mousepressed)
signal.event:bind("mousereleased", input.mousereleased)
signal.event:bind("wheelmoved", input.wheelmoved)
signal.event:bind("mousemoved", input.mousemoved)
signal.event:bind("gamepadpressed", input.gamepadpressed)
signal.event:bind("gamepadreleased", input.gamepadreleased)
signal.event:bind("gamepadaxis", input.gamepadaxis)
signal.event:replace("update", oUpdate, input.update)
end
return input return input

View file

@ -1,5 +1,8 @@
--- ubiquitousse.input --- ubiquitousse.input
-- Depends on a backend. -- Depends on a backend.
-- Optional dependencies: ubiquitousse.signal (to bind to update signal in signal.event)
local loaded, signal = pcall(require, (...):match("^(.-)input").."signal")
if not loaded then signal = nil end
-- TODO: some key selection helper? Will be backend-implemented, to account for all the possible input methods. -- TODO: some key selection helper? Will be backend-implemented, to account for all the possible input methods.
-- TODO: some way to list all possible input / outputs, or make the *inUse make some separation between inputs indiscutitably in use and those who are incertain. -- TODO: some way to list all possible input / outputs, or make the *inUse make some separation between inputs indiscutitably in use and those who are incertain.
@ -40,8 +43,8 @@ local button_mt = {
-- @treturn ButtonInput this ButtonInput object -- @treturn ButtonInput this ButtonInput object
unbind = function(self, ...) unbind = function(self, ...)
for _, d in ipairs({...}) do for _, d in ipairs({...}) do
for i, detector in ipairs(self.detectors) do for i=#self.detectors, 1, -1 do
if detector == d then if self.detectors[i] == d then
table.remove(self.detectors, i) table.remove(self.detectors, i)
break break
end end
@ -270,7 +273,9 @@ local axis_mt = {
self.val, self.raw, self.max = val, raw, max self.val, self.raw, self.max = val, raw, max
updated[self] = true updated[self] = true
end end
end end,
--- LÖVE note: other callbacks that are defined in backend/love.lua and need to be called in the associated LÖVE callbacks.
} }
axis_mt.__index = axis_mt axis_mt.__index = axis_mt
@ -382,9 +387,9 @@ local pointer_mt = {
x = function(self) x = function(self)
if self.grabbing == self then if self.grabbing == self then
self:update() self:update()
return self.valX + (self.offsetX or self.width or input.drawWidth/2) return self.valX + (self.offsetX or self.width or input.getDrawWidth()/2)
else else
return self.offsetX or self.width or input.drawWidth/2 return self.offsetX or self.width or input.getDrawWidth()/2
end end
end, end,
--- Returns the current Y value of the pointer. --- Returns the current Y value of the pointer.
@ -392,9 +397,9 @@ local pointer_mt = {
y = function(self) y = function(self)
if self.grabbing == self then if self.grabbing == self then
self:update() self:update()
return self.valY + (self.offsetY or self.height or input.drawHeight/2) return self.valY + (self.offsetY or self.height or input.getDrawHeight()/2)
else else
return self.offsetY or self.height or input.drawHeight/2 return self.offsetY or self.height or input.getDrawHeight()/2
end end
end, end,
@ -418,9 +423,9 @@ local pointer_mt = {
local magnitude = sqrt(x*x + y*y) local magnitude = sqrt(x*x + y*y)
cx, cy = cx / magnitude * width, cy / magnitude * height cx, cy = cx / magnitude * width, cy / magnitude * height
end end
return cx + (self.offsetX or width or input.drawWidth/2), cy + (self.offsetY or height or input.drawHeight/2) return cx + (self.offsetX or width or input.getDrawWidth()/2), cy + (self.offsetY or height or input.getDrawHeight()/2)
else else
return self.offsetX or width or input.drawWidth/2, self.offsetY or height or input.drawHeight/2 return self.offsetX or width or input.getDrawWidth()/2, self.offsetY or height or input.getDrawHeight()/2
end end
end, end,
@ -445,7 +450,7 @@ local pointer_mt = {
if not updated[self] then if not updated[self] then
local x, y = self.valX, self.valY local x, y = self.valX, self.valY
local xSpeed, ySpeed = self.xSpeed, self.ySpeed local xSpeed, ySpeed = self.xSpeed, self.ySpeed
local width, height = self.width or input.drawWidth/2, self.height or input.drawHeight/2 local width, height = self.width or input.getDrawWidth()/2, self.height or input.getDrawHeight()/2
local newX, newY = x, y local newX, newY = x, y
local maxMovX, maxMovY = 0, 0 -- the maxium axis movement in a direction (used to determine which axes have the priority) (absolute value) local maxMovX, maxMovY = 0, 0 -- the maxium axis movement in a direction (used to determine which axes have the priority) (absolute value)
for _, pointer in ipairs(self.detectors) do for _, pointer in ipairs(self.detectors) do
@ -642,16 +647,16 @@ input = {
--- Returns a list of the buttons currently in use, identified by their string button identifier. --- Returns a list of the buttons currently in use, identified by their string button identifier.
-- This may also returns "axis threshold" buttons if an axis passes the threshold. -- This may also returns "axis threshold" buttons if an axis passes the threshold.
-- @treturn table<string> buttons identifiers list -- @tparam[opt=0.5] number threshold the threshold to detect axes as button
-- @treturn[opt=0.5] number threshold the threshold to detect axes as button -- @treturn string,... buttons identifiers list
-- @impl backend -- @impl backend
buttonsInUse = function(threshold) end, buttonUsed = function(threshold) end,
--- Returns a list of the axes currently in use, identified by their string axis identifier --- Returns a list of the axes currently in use, identified by their string axis identifier
-- @treturn table<string> axes identifiers list -- @tparam[opt=0.5] number threshold the threshold to detect axes
-- @treturn[opt=0.5] number threshold the threshold to detect axes -- @treturn string,... axes identifiers list
-- @impl backend -- @impl backend
axesInUse = function(threshold) end, axisUsed = function(threshold) end,
--- Returns a nice name for the button identifier. --- Returns a nice name for the button identifier.
-- Can be locale-depedant and stuff, it's only for display. -- Can be locale-depedant and stuff, it's only for display.
@ -686,14 +691,14 @@ input = {
cancel = nil -- Button: used to cancel something. Example binds: Escape, B button. cancel = nil -- Button: used to cancel something. Example binds: Escape, B button.
}, },
--- Draw area dimensions. --- Get draw area dimensions.
-- Used for pointers. -- Used for pointers.
-- @impl backend -- @impl backend
drawWidth = 1, getDrawWidth = function() return 1 end,
drawHeight = 1, getDrawHeight = function() return 1 end,
--- Update all the Inputs. --- Update all the Inputs.
-- Should be called at every game update; called by ubiquitousse.update. -- Should be called at every game update. If ubiquitousse.signal is available, will be bound to the "update" signal in signal.event.
-- The backend can hook into this function to to its input-related updates. -- The backend can hook into this function to to its input-related updates.
-- @tparam numder dt the delta-time -- @tparam numder dt the delta-time
-- @impl ubiquitousse -- @impl ubiquitousse
@ -701,6 +706,11 @@ input = {
dt = newDt dt = newDt
updated = {} updated = {}
end end
--- If you use LÖVE, note that in order to provide every feature (especially key detection), several callbacks functions will
-- need to be called on LÖVE events. See backend/love.lua.
-- If ubiquitousse.signal is available, these callbacks will be bound to signals in signal.event (with the same name as the LÖVE
-- callbacks, minux the "love.").
} }
-- Create default inputs -- Create default inputs
@ -708,4 +718,9 @@ input.default.pointer = input.pointer()
input.default.confirm = input.button() input.default.confirm = input.button()
input.default.cancel = input.button() input.default.cancel = input.button()
-- Bind signals
if signal then
signal.event:bind("update", input.update)
end
return input return input

View file

@ -1,5 +1,8 @@
--- ubiquitousse.scene --- ubiquitousse.scene
-- Optional dependencies: ubiquitousse.timer (to provide each scene a timer registry) -- Optional dependencies: ubiquitousse.timer (to provide each scene a timer registry)
-- Optional dependencies: ubiquitousse.signal (to bind to update and draw signal in signal.event)
local loaded, signal = pcall(require, (...):match("^(.-)scene").."signal")
if not loaded then signal = nil end
local loaded, timer = pcall(require, (...):match("^(.-)scene").."timer") local loaded, timer = pcall(require, (...):match("^(.-)scene").."timer")
if not loaded then timer = nil end if not loaded then timer = nil end
@ -134,8 +137,16 @@ scene = setmetatable({
table.remove(scene.stack) table.remove(scene.stack)
end, end,
--- Pop all scenes.
-- @impl ubiquitousse
popAll = function()
while scene.current do
scene.pop()
end
end,
--- Update the current scene. --- Update the current scene.
-- Should be called at every game update; called by ubiquitousse.update. -- Should be called at every game update. If ubiquitousse.signal is available, will be bound to the "update" signal in signal.event.
-- @tparam number dt the delta-time (milisecond) -- @tparam number dt the delta-time (milisecond)
-- @param ... arguments to pass to the scene's update function after dt -- @param ... arguments to pass to the scene's update function after dt
-- @impl ubiquitousse -- @impl ubiquitousse
@ -147,7 +158,7 @@ scene = setmetatable({
end, end,
--- Draw the current scene. --- Draw the current scene.
-- Should be called every time the game is draw; called by ubiquitousse.draw. -- Should be called every time the game is draw. If ubiquitousse.signal is available, will be bound to the "draw" signal in signal.event.
-- @param ... arguments to pass to the scene's draw function -- @param ... arguments to pass to the scene's draw function
-- @impl ubiquitousse -- @impl ubiquitousse
draw = function(...) draw = function(...)
@ -160,4 +171,10 @@ scene = setmetatable({
end end
}) })
-- Bind signals
if signal then
signal.event:bind("update", scene.update)
signal.event:bind("draw", scene.draw)
end
return scene return scene

43
signal/backend/love.lua Normal file
View file

@ -0,0 +1,43 @@
local signal = require((...):match("^(.-%.)backend").."signal")
function signal.registerEvents()
local callbacks = { -- everything except run, errorhandler, threaderror
"displayrotated", "draw", "load", "lowmemory", "quit", "update",
"directorydropped", "filedropped", "focus", "mousefocus", "resize", "visible",
"keypressed", "keyreleased", "textedited", "textinput",
"mousemoved", "mousepressed", "mousereleased", "wheelmoved",
"gamepadaxis", "gamepadpressed", "gamepadreleased",
"joystickadded", "joystickaxis", "joystickhat", "joystickpressed", "joystickreleased", "joystickremoved",
"touchmoved", "touchpressed", "touchreleased"
}
local event = signal.event
for _, callback in ipairs(callbacks) do
if callback == "update" then
if love[callback] then
local old = love[callback]
love[callback] = function(dt)
old(dt)
event:emit(callback, dt*1000)
end
else
love[callback] = function(dt)
event:emit(callback, dt*1000)
end
end
else
if love[callback] then
local old = love[callback]
love[callback] = function(...)
old(...)
event:emit(callback, ...)
end
else
love[callback] = function(...)
event:emit(callback, ...)
end
end
end
end
end
return signal

14
signal/init.lua Normal file
View file

@ -0,0 +1,14 @@
local signal
local p = ...
if love then
signal = require(p..".backend.love")
elseif package.loaded["ctr"] then
error("NYI")
elseif package.loaded["libretro"] then
error("NYI")
else
error("no backend for ubiquitousse.signal")
end
return signal

116
signal/signal.can Normal file
View file

@ -0,0 +1,116 @@
--- ubiquitousse.signal
let registry_mt = {
--- Map of signals to list of listeners.
-- @impl ubiquitousse
signals = {},
--- Bind one or several functions to a signal name.
-- @impl ubiquitousse
bind = :(name, fn, ...)
if not @signals[name] then
@signals[name] = {}
end
table.insert(@signals[name], fn)
if ... then
return @bind(name, ...)
end
end,
--- Unbind one or several functions to a signal name.
-- @impl ubiquitousse
unbind = :(name, fn, ...)
if not @signals[name] then
return
end
for i=#@signals[name], 1, -1 do
if @signals[name] == fn then
table.remove(@signals[name], i)
end
end
if ... then
return @unbind(name, ...)
end
end,
--- Remove every bound function to a signal name.
-- @impl ubiquitousse
unbindAll = :(name)
@signals[name] = nil
end,
--- Replace a bound function with another function.
-- @impl ubiquitousse
replace = :(name, sourceFn, destFn)
if not @signals[name] then
@signals[name] = {}
end
for i, fn in ipairs(@signals[name]) do
if fn == sourceFn then
@signals[name][i] = destFn
break
end
end
end,
--- Remove every bound function to every signal.
-- @impl ubiquitousse
clear = :()
@signals = {}
end,
--- Emit a signal, i.e. call every function bound to it, with the given arguments.
-- @impl ubiquitousse
emit = :(name, ...)
if @signals[name] then
for _, fn in ipairs(@signals[name]) do
fn(...)
end
end
end
}
registry_mt.__index = registry_mt
let signal = {
--- Creates and return a new SignalRegistry.
-- A SignalRegistry is a separate ubiquitousse.signal instance: its signals will be independant from other registries.
-- @impl ubiquitousse
new = ()
return setmetatable({ signals = {} }, registry_mt)
end,
--- Global SignalRegistry.
-- @impl ubiquitousse
signals = {},
bind = (...)
return registry_mt.bind(signal, ...)
end,
unbind = (...)
return registry_mt.unbind(signal, ...)
end,
clear = (...)
return registry_mt.clear(signal, ...)
end,
emit = (...)
return registry_mt.emit(signal, ...)
end,
--- SignalRegistry which will be used to bind signals that need to be called on game engine event.
-- For example, every ubiquitousse module with a "update" function will bind it to the "update" signal in the registry;
-- you can then call this signal on each game update to update every ubiquitousse module easily.
-- Provided signals:
-- * update, should be called on every game update
-- * draw, should be called on every game draw
-- * for LÖVE, there are callbacks for every LÖVE callback function that need to be called on their corresponding LÖVE callback
-- @impl mixed
event = nil,
--- Call this function to hook signal.event signals to the current backend.
-- For LÖVE, this means overriding every existing LÖVE callback. If a callback is already defined, the new one will call the old function along with the signal:emit.
-- @impl backend
registerEvents = () end
}
signal.event = signal.new()
return signal

View file

@ -1,5 +1,9 @@
--- ubiquitousse.timer --- ubiquitousse.timer
-- Depends on a backend. -- Depends on a backend.
-- Optional dependencies: ubiquitousse.signal (to bind to update signal in signal.event)
local loaded, signal = pcall(require, (...):match("^(.-)timer").."signal")
if not loaded then signal = nil end
local ease = require((...):match("^.-timer")..".easing") local ease = require((...):match("^.-timer")..".easing")
local timer local timer
@ -332,7 +336,7 @@ timer = {
-- @impl ubiquitousse -- @impl ubiquitousse
delayed = {}, delayed = {},
lastTime = 0, lastTime = 0,
update = function(...) update = function(...) -- If ubiquitousse.signal is available, will be bound to the "update" signal in signal.event.
return registry_mt.update(timer, ...) return registry_mt.update(timer, ...)
end, end,
run = function(...) run = function(...)
@ -346,4 +350,9 @@ timer = {
end end
} }
-- Bind signals
if signal then
signal.event:bind("update", timer.update)
end
return timer return timer