1
0
Fork 0
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:
Étienne Fildadut 2019-12-28 16:13:52 +01:00
parent f6fb8ad649
commit 15dfb18c65
3 changed files with 102 additions and 78 deletions

View file

@ -1,7 +1,7 @@
--- ubiquitousse.ecs --- ubiquitousse.ecs
-- Optional dependency: ubiquitousse.scene, to allow quick creation of ECS-based scenes. -- Optional dependency: ubiquitousse.scene, to allow quick creation of ECS-based scenes.
local loaded, newScene = pcall(require, (...):match("^(.-)ecs").."scene") local loaded, scene = pcall(require, (...):match("^(.-)ecs").."scene")
if not loaded then newScene = nil end if not loaded then scene = nil end
--- Entity Component System library, inspired by the excellent tiny-ecs. Main differences include: --- Entity Component System library, inspired by the excellent tiny-ecs. Main differences include:
-- * ability to nest systems; -- * ability to nest systems;
@ -268,70 +268,72 @@ let recCallOnAddToWorld = (world, systems)
end end
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. --- ECS module.
return { let ecs = {
world = world, --- Create and returns a world system based on a list of systems.
all = all, -- The systems will be instancied for this world.
any = any, -- @impl ubiquitousse
scene = scene 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

View file

@ -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 -- 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 -- 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). -- 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. --- Makes a new button detector from a identifier string.
-- The function may error if the identifier is incorrect. -- The function may error if the identifier is incorrect.
@ -509,7 +510,7 @@ input = {
-- @impl backend -- @impl backend
basicButtonDetector = function(str) end, 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 -- @tparam string, function button identifier
-- @impl ubiquitousse -- @impl ubiquitousse
buttonDetector = function(obj) buttonDetector = function(obj)
@ -517,6 +518,19 @@ input = {
return obj return obj
elseif type(obj) == "string" then elseif type(obj) == "string" then
return input.basicButtonDetector(obj) 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 end
error(("Not a valid button detector: %s"):format(obj)) error(("Not a valid button detector: %s"):format(obj))
end, end,

View file

@ -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 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 -- * all scene exit/suspend callbacks are called before scene enter/resume callbacks
local scene local scene
scene = setmetatable({ scene = {
--- The current scene table. --- The current scene table.
-- @impl ubiquitousse -- @impl ubiquitousse
current = nil, current = nil,
@ -34,6 +34,9 @@ scene = setmetatable({
--- Shortcut for scene.current.timer. --- Shortcut for scene.current.timer.
-- @impl ubiquitousse -- @impl ubiquitousse
timer = nil, timer = nil,
--- Shortcut for scene.current.signal.
-- @impl ubiquitousse
signal = nil,
--- The scene stack: list of scene, from the farest one to the nearest. --- The scene stack: list of scene, from the farest one to the nearest.
-- @impl ubiquitousse -- @impl ubiquitousse
@ -77,6 +80,7 @@ scene = setmetatable({
name = name or "unamed", -- The scene name. name = name or "unamed", -- The scene name.
timer = timer and timer.new(), -- Scene-specific TimerRegistry, if uqt.time is available. 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. 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). 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 local previous = scene.current
scene.current = type(scenePath) == "string" and scene.load(scene.prefix..scenePath) or scenePath scene.current = type(scenePath) == "string" and scene.load(scene.prefix..scenePath) or scenePath
scene.timer = scene.current.timer scene.timer = scene.current.timer
scene.signal = scene.current.signal
scene.current.name = scene.current.name or tostring(scenePath) 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.current:enter(...)
scene.stack[math.max(#scene.stack, 1)] = scene.current scene.stack[math.max(#scene.stack, 1)] = scene.current
end, end,
@ -118,6 +126,7 @@ scene = setmetatable({
local previous = scene.current local previous = scene.current
scene.current = type(scenePath) == "string" and scene.load(scene.prefix..scenePath) or scenePath scene.current = type(scenePath) == "string" and scene.load(scene.prefix..scenePath) or scenePath
scene.timer = scene.current.timer scene.timer = scene.current.timer
scene.signal = scene.current.signal
scene.current.name = scene.current.name or tostring(scenePath) scene.current.name = scene.current.name or tostring(scenePath)
if previous then previous:suspend() end if previous then previous:suspend() end
scene.current:enter(...) scene.current:enter(...)
@ -131,8 +140,12 @@ scene = setmetatable({
pop = function() pop = function()
local previous = scene.current local previous = scene.current
scene.current = scene.stack[#scene.stack-1] scene.current = scene.stack[#scene.stack-1]
scene.timer = scene.current.timer scene.timer = scene.current and scene.current.timer or nil
if previous then previous:exit() end 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 if scene.current then scene.current:resume() end
table.remove(scene.stack) table.remove(scene.stack)
end, end,
@ -164,12 +177,7 @@ scene = setmetatable({
draw = function(...) draw = function(...)
if scene.current then scene.current:draw(...) end if scene.current then scene.current:draw(...) end
end end
}, { }
--- scene(...) is a shortcut for scene.new(...)
__call = function(self, ...)
return scene.new(...)
end
})
-- Bind signals -- Bind signals
if signal then if signal then