mirror of
https://github.com/Reuh/ubiquitousse.git
synced 2025-10-27 17:19:31 +00:00
Button combinations, create signal registry per scene
This commit is contained in:
parent
f6fb8ad649
commit
15dfb18c65
3 changed files with 102 additions and 78 deletions
136
ecs/ecs.can
136
ecs/ecs.can
|
|
@ -1,7 +1,7 @@
|
|||
--- ubiquitousse.ecs
|
||||
-- Optional dependency: ubiquitousse.scene, to allow quick creation of ECS-based scenes.
|
||||
local loaded, newScene = pcall(require, (...):match("^(.-)ecs").."scene")
|
||||
if not loaded then newScene = nil end
|
||||
local loaded, scene = pcall(require, (...):match("^(.-)ecs").."scene")
|
||||
if not loaded then scene = nil end
|
||||
|
||||
--- Entity Component System library, inspired by the excellent tiny-ecs. Main differences include:
|
||||
-- * ability to nest systems;
|
||||
|
|
@ -268,70 +268,72 @@ let recCallOnAddToWorld = (world, systems)
|
|||
end
|
||||
end
|
||||
|
||||
--- Create and returns a world system based on a list of systems.
|
||||
-- The systems will be instancied for this world.
|
||||
let world = (...)
|
||||
let world = setmetatable({
|
||||
filter = (e) return true end,
|
||||
s = {}
|
||||
}, { __index = system_mt })
|
||||
world.world = world
|
||||
world.systems = recInstanciateSystems(world, {...})
|
||||
recCallOnAddToWorld(world, world.systems)
|
||||
return world
|
||||
end
|
||||
|
||||
--- Returns a filter that returns true if, for every argument, a field with the same name exists in the entity.
|
||||
let all = (...)
|
||||
let l = {...}
|
||||
return function(s, e)
|
||||
for _, k in ipairs(l) do
|
||||
if e[k] == nil then
|
||||
return false
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
--- Returns a filter that returns true if one of the arguments if the name of a field in the entity.
|
||||
let any = (...)
|
||||
let l = {...}
|
||||
return function(s, e)
|
||||
for _, k in ipairs(l) do
|
||||
if e[k] ~= nil then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
let scene = (name, systems={}, entities={})
|
||||
let s = newScene(name)
|
||||
let w
|
||||
|
||||
function s:enter()
|
||||
w = world(unpack(systems))
|
||||
w:add(unpack(entities))
|
||||
end
|
||||
function s:exit()
|
||||
w:destroy()
|
||||
end
|
||||
function s:update(dt)
|
||||
w:update(dt)
|
||||
end
|
||||
function s:draw()
|
||||
w:draw()
|
||||
end
|
||||
|
||||
return s
|
||||
end
|
||||
|
||||
--- ECS module.
|
||||
return {
|
||||
world = world,
|
||||
all = all,
|
||||
any = any,
|
||||
scene = scene
|
||||
let ecs = {
|
||||
--- Create and returns a world system based on a list of systems.
|
||||
-- The systems will be instancied for this world.
|
||||
-- @impl ubiquitousse
|
||||
world = (...)
|
||||
let world = setmetatable({
|
||||
filter = (e) return true end,
|
||||
s = {}
|
||||
}, { __index = system_mt })
|
||||
world.world = world
|
||||
world.systems = recInstanciateSystems(world, {...})
|
||||
recCallOnAddToWorld(world, world.systems)
|
||||
return world
|
||||
end,
|
||||
|
||||
--- Returns a filter that returns true if, for every argument, a field with the same name exists in the entity.
|
||||
-- @impl ubiquitousse
|
||||
all = (...)
|
||||
let l = {...}
|
||||
return function(s, e)
|
||||
for _, k in ipairs(l) do
|
||||
if e[k] == nil then
|
||||
return false
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
end,
|
||||
|
||||
--- Returns a filter that returns true if one of the arguments if the name of a field in the entity.
|
||||
-- @impl ubiquitousse
|
||||
any = (...)
|
||||
let l = {...}
|
||||
return function(s, e)
|
||||
for _, k in ipairs(l) do
|
||||
if e[k] ~= nil then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
end,
|
||||
|
||||
--- If uqt.scene is available, returns a new scene that will consist of a ECS world with the specified systems and entities.
|
||||
-- @impl ubiquitousse
|
||||
scene = (name, systems={}, entities={})
|
||||
let s = scene.new(name)
|
||||
let w
|
||||
|
||||
function s:enter()
|
||||
w = ecs.world(unpack(systems))
|
||||
w:add(unpack(entities))
|
||||
end
|
||||
function s:exit()
|
||||
w:destroy()
|
||||
end
|
||||
function s:update(dt)
|
||||
w:update(dt)
|
||||
end
|
||||
function s:draw()
|
||||
w:draw()
|
||||
end
|
||||
|
||||
return s
|
||||
end
|
||||
}
|
||||
|
||||
return ecs
|
||||
|
|
|
|||
|
|
@ -501,6 +501,7 @@ input = {
|
|||
-- identifier, preceded by a % : for example "gamepad.axis.1.leftx%-0.5" should return true when the left-stick of the first gamepad is moved to the right
|
||||
-- by more of 50%. The negative threshold value means that the button will be pressed only when the axis has a negative value (in the example, it won't be
|
||||
-- pressed when the axis is moved to the right).
|
||||
-- Buttons can also be defined by a list of buttons (string or functions), in which case the button will be considered down if all the buttons are down.
|
||||
|
||||
--- Makes a new button detector from a identifier string.
|
||||
-- The function may error if the identifier is incorrect.
|
||||
|
|
@ -509,7 +510,7 @@ input = {
|
|||
-- @impl backend
|
||||
basicButtonDetector = function(str) end,
|
||||
|
||||
--- Make a new button detector from a detector function of string.
|
||||
--- Make a new button detector from a detector function, string, or list of buttons.
|
||||
-- @tparam string, function button identifier
|
||||
-- @impl ubiquitousse
|
||||
buttonDetector = function(obj)
|
||||
|
|
@ -517,6 +518,19 @@ input = {
|
|||
return obj
|
||||
elseif type(obj) == "string" then
|
||||
return input.basicButtonDetector(obj)
|
||||
elseif type(obj) == "table" then
|
||||
local l = {}
|
||||
for _, b in ipairs(obj) do
|
||||
table.insert(l, input.buttonDetector(b))
|
||||
end
|
||||
return function()
|
||||
for _, b in ipairs(l) do
|
||||
if not b() then
|
||||
return false
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
end
|
||||
error(("Not a valid button detector: %s"):format(obj))
|
||||
end,
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ if not loaded then timer = nil end
|
|||
-- * all scene change callbacks are called after setting scene.current to the new scene but before changing scene.stack
|
||||
-- * all scene exit/suspend callbacks are called before scene enter/resume callbacks
|
||||
local scene
|
||||
scene = setmetatable({
|
||||
scene = {
|
||||
--- The current scene table.
|
||||
-- @impl ubiquitousse
|
||||
current = nil,
|
||||
|
|
@ -34,6 +34,9 @@ scene = setmetatable({
|
|||
--- Shortcut for scene.current.timer.
|
||||
-- @impl ubiquitousse
|
||||
timer = nil,
|
||||
--- Shortcut for scene.current.signal.
|
||||
-- @impl ubiquitousse
|
||||
signal = nil,
|
||||
|
||||
--- The scene stack: list of scene, from the farest one to the nearest.
|
||||
-- @impl ubiquitousse
|
||||
|
|
@ -77,6 +80,7 @@ scene = setmetatable({
|
|||
name = name or "unamed", -- The scene name.
|
||||
|
||||
timer = timer and timer.new(), -- Scene-specific TimerRegistry, if uqt.time is available.
|
||||
signal = signal and signal.new(), -- Scene-specific SignalRegistry, if uqt.signal is available.
|
||||
|
||||
enter = function(self, ...) end, -- Called when entering a scene.
|
||||
exit = function(self) end, -- Called when exiting a scene, and not expecting to come back (scene may be unloaded).
|
||||
|
|
@ -101,8 +105,12 @@ scene = setmetatable({
|
|||
local previous = scene.current
|
||||
scene.current = type(scenePath) == "string" and scene.load(scene.prefix..scenePath) or scenePath
|
||||
scene.timer = scene.current.timer
|
||||
scene.signal = scene.current.signal
|
||||
scene.current.name = scene.current.name or tostring(scenePath)
|
||||
if previous then previous:exit() end
|
||||
if previous then
|
||||
previous:exit()
|
||||
if timer then previous.timer:clear() end
|
||||
end
|
||||
scene.current:enter(...)
|
||||
scene.stack[math.max(#scene.stack, 1)] = scene.current
|
||||
end,
|
||||
|
|
@ -118,6 +126,7 @@ scene = setmetatable({
|
|||
local previous = scene.current
|
||||
scene.current = type(scenePath) == "string" and scene.load(scene.prefix..scenePath) or scenePath
|
||||
scene.timer = scene.current.timer
|
||||
scene.signal = scene.current.signal
|
||||
scene.current.name = scene.current.name or tostring(scenePath)
|
||||
if previous then previous:suspend() end
|
||||
scene.current:enter(...)
|
||||
|
|
@ -131,8 +140,12 @@ scene = setmetatable({
|
|||
pop = function()
|
||||
local previous = scene.current
|
||||
scene.current = scene.stack[#scene.stack-1]
|
||||
scene.timer = scene.current.timer
|
||||
if previous then previous:exit() end
|
||||
scene.timer = scene.current and scene.current.timer or nil
|
||||
scene.signal = scene.current and scene.current.signal or nil
|
||||
if previous then
|
||||
previous:exit()
|
||||
if timer then previous.timer:clear() end
|
||||
end
|
||||
if scene.current then scene.current:resume() end
|
||||
table.remove(scene.stack)
|
||||
end,
|
||||
|
|
@ -164,12 +177,7 @@ scene = setmetatable({
|
|||
draw = function(...)
|
||||
if scene.current then scene.current:draw(...) end
|
||||
end
|
||||
}, {
|
||||
--- scene(...) is a shortcut for scene.new(...)
|
||||
__call = function(self, ...)
|
||||
return scene.new(...)
|
||||
end
|
||||
})
|
||||
}
|
||||
|
||||
-- Bind signals
|
||||
if signal then
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue