mirror of
https://github.com/Reuh/ubiquitousse.git
synced 2025-10-27 09:09:30 +00:00
Added uqt.input for ctrulua and other stuff
This commit is contained in:
parent
42738cc7c9
commit
c0db856b82
7 changed files with 430 additions and 81 deletions
|
|
@ -3,7 +3,7 @@
|
|||
--- Audio functions.
|
||||
return {
|
||||
--- Loads an audio file and returns the corresponding audio object.
|
||||
-- TODO: audio object doc
|
||||
-- TODO: audio object doc & API
|
||||
-- @impl backend
|
||||
load = function(filepath) end
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ local version = "0.0.1"
|
|||
local uqt = require((...):match("^(.-ubiquitousse)%."))
|
||||
local ctr = require("ctr")
|
||||
local gfx = require("ctr.gfx")
|
||||
local hid = require("ctr.hid")
|
||||
|
||||
-- Version compatibility warning
|
||||
do
|
||||
|
|
@ -31,12 +32,17 @@ do
|
|||
end
|
||||
|
||||
-- Redefine all functions in tbl which also are in toAdd, so when used they call the old function (in tbl) and then the new (in toAdd).
|
||||
-- Functions with names prefixed by a exclamation mark will overwrite the old function.
|
||||
local function add(tbl, toAdd)
|
||||
for k,v in pairs(toAdd) do
|
||||
local old = tbl[k]
|
||||
tbl[k] = function(...)
|
||||
old(...)
|
||||
return v(...)
|
||||
if k:sub(1,1) == "!" then
|
||||
tbl[k] = v
|
||||
else
|
||||
tbl[k] = function(...)
|
||||
old(...)
|
||||
return v(...)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -57,4 +63,263 @@ add(uqt.time, {
|
|||
})
|
||||
end
|
||||
|
||||
-- uqt.input: TODO
|
||||
-- uqt.input
|
||||
if uqt.input then
|
||||
local keys = {}
|
||||
local touchX, touchY, dTouchX, dTouchY
|
||||
add(uqt.input, {
|
||||
update = function()
|
||||
hid.read()
|
||||
|
||||
keys = hid.keys()
|
||||
|
||||
local nTouchX, nTouchY = hid.touch()
|
||||
dTouchX, dTouchY = nTouchX - touchX, nTouchY - touchY
|
||||
touchX, touchY = nTouchX, nTouchY
|
||||
end,
|
||||
|
||||
buttonDetector = function(...)
|
||||
local ret = {}
|
||||
for _,id in ipairs({...}) do
|
||||
-- Keys
|
||||
if id:match("^key%.") then
|
||||
local key = id:match("^key%.(.+)$")
|
||||
table.insert(ret, function()
|
||||
return keys.held[key]
|
||||
end)
|
||||
else
|
||||
error("Unknown button identifier: "..id)
|
||||
end
|
||||
end
|
||||
return unpack(ret)
|
||||
end,
|
||||
|
||||
axisDetector = function(...)
|
||||
local ret = {}
|
||||
for _,id in ipairs({...}) do
|
||||
-- Binary axis
|
||||
if id:match(".+%,.+") then
|
||||
local d1, d2 = uqt.input.buttonDetector(id:match("^(.+)%,(.+)$"))
|
||||
table.insert(ret, function()
|
||||
local b1, b2 = d1(), d2()
|
||||
if b1 and b2 then return 0
|
||||
elseif b1 then return -1
|
||||
elseif b2 then return 1
|
||||
else return 0 end
|
||||
end)
|
||||
-- Touch movement
|
||||
elseif id:match("^touch%.move%.") then
|
||||
local axis, threshold = id:match("^touch%.move%.(.+)%%(.+)$")
|
||||
if not axis then axis = id:match("^touch%.move%.(.+)$") end -- no threshold (=0)
|
||||
threshold = tonumber(threshold) or 0
|
||||
table.insert(ret, function()
|
||||
local val, raw, max
|
||||
if axis == "x" then
|
||||
raw, max = dTouchX, gfx.BOTTOM_WIDTH
|
||||
elseif axis == "y" then
|
||||
raw, max = dTouchY, gfx.BOTTOM_HEIGHT
|
||||
end
|
||||
val = raw / max
|
||||
return math.abs(val) > math.abs(threshold) and val or 0, raw, max
|
||||
end)
|
||||
-- Touch position
|
||||
elseif id:match("^touch%.position%.") then
|
||||
local axis, threshold = id:match("^touch%.position%.(.+)%%(.+)$")
|
||||
if not axis then axis = id:match("^touch%.position%.(.+)$") end -- no threshold (=0)
|
||||
threshold = tonumber(threshold) or 0
|
||||
table.insert(ret, function()
|
||||
local val, raw, max
|
||||
if axis == "x" then
|
||||
max = gfx.BOTTOM_WIDTH / 2 -- /2 because x=0,y=0 is the center of the screen (an axis value is in [-1,1])
|
||||
raw = touchX - max
|
||||
elseif axis == "y" then
|
||||
max = gfx.BOTTOM_HEIGHT / 2
|
||||
raw = touchY - max
|
||||
end
|
||||
val = raw / max
|
||||
return math.abs(val) > math.abs(threshold) and val or 0, raw, max
|
||||
end)
|
||||
-- Circle pad axis
|
||||
elseif id:match("^circle%.") then
|
||||
local axis, threshold = id:match("^circle%.(.+)%%(.+)$")
|
||||
if not axis then axis = id:match("^circle%.(.+)$") end -- no threshold (=0)
|
||||
threshold = tonumber(threshold) or 0
|
||||
table.insert(ret, function()
|
||||
local x, y = hid.circle()
|
||||
local val, raw, max = 0, 0, 156
|
||||
if axis == "x" then raw = x
|
||||
elseif axis == "y" then raw = y end
|
||||
val = raw / max
|
||||
return math.abs(val) > math.abs(threshold) and val or 0, raw, max
|
||||
end)
|
||||
-- C-Stick axis
|
||||
elseif id:match("^cstick%.") then
|
||||
local axis, threshold = id:match("^cstick%.(.+)%%(.+)$")
|
||||
if not axis then axis = id:match("^cstick%.(.+)$") end -- no threshold (=0)
|
||||
threshold = tonumber(threshold) or 0
|
||||
table.insert(ret, function()
|
||||
local x, y = hid.cstick()
|
||||
local val, raw, max = 0, 0, 146
|
||||
if axis == "x" then raw = x
|
||||
elseif axis == "y" then raw = y end
|
||||
val = raw / max
|
||||
return math.abs(val) > math.abs(threshold) and val or 0, raw, max
|
||||
end)
|
||||
-- Accelerometer axis
|
||||
elseif id:match("^accel%.") then
|
||||
local axis, threshold = id:match("^accel%.(.+)%%(.+)$")
|
||||
if not axis then axis = id:match("^accel%.(.+)$") end -- no threshold (=0)
|
||||
threshold = tonumber(threshold) or 0
|
||||
table.insert(ret, function()
|
||||
local x, y, z = hid.accel()
|
||||
local val, raw, max = 0, 0, 32768 -- no idea actually, but it's a s16
|
||||
if axis == "x" then raw = x
|
||||
elseif axis == "y" then raw = y
|
||||
elseif axis == "z" then raw = z end
|
||||
val = raw / max
|
||||
return math.abs(val) > math.abs(threshold) and val or 0, raw, max
|
||||
end)
|
||||
-- Gyroscope axis
|
||||
elseif id:match("^gyro%.") then
|
||||
local axis, threshold = id:match("^gyro%.(.+)%%(.+)$")
|
||||
if not axis then axis = id:match("^gyro%.(.+)$") end -- no threshold (=0)
|
||||
threshold = tonumber(threshold) or 0
|
||||
table.insert(ret, function()
|
||||
local roll, pitch, yaw = hid.gyro()
|
||||
local val, raw, max = 0, 0, 32768 -- no idea actually, but it's a s16
|
||||
if axis == "roll" then raw = roll
|
||||
elseif axis == "pitch" then raw = pitch
|
||||
elseif axis == "yaw" then raw = yaw end
|
||||
val = raw / max
|
||||
return math.abs(val) > math.abs(threshold) and val or 0, raw, max
|
||||
end)
|
||||
else
|
||||
error("Unknown axis identifier: "..id)
|
||||
end
|
||||
end
|
||||
return unpack(ret)
|
||||
end,
|
||||
|
||||
buttonsInUse = function(threshold)
|
||||
local r = {}
|
||||
for key, held in pairs(keys.held) do
|
||||
if held then table.insert(r, "key."..key) end
|
||||
end
|
||||
return r
|
||||
end,
|
||||
|
||||
axesInUse = function(threshold)
|
||||
local r = {}
|
||||
threshold = threshold or 0.5
|
||||
|
||||
if math.abs(touchX) / gfx.BOTTOM_WIDTH > threshold then table.insert(r, "touch.position.x%"..threshold) end
|
||||
if math.abs(touchY) / gfx.BOTTOM_HEIGHT > threshold then table.insert(r, "touch.position.y%"..threshold) end
|
||||
|
||||
if math.abs(dTouchX) / gfx.BOTTOM_WIDTH > threshold then table.insert(r, "touch.move.x%"..threshold) end
|
||||
if math.abs(dTouchY) / gfx.BOTTOM_HEIGHT > threshold then table.insert(r, "touch.move.y%"..threshold) end
|
||||
|
||||
local circleX, circleY = hid.circle()
|
||||
if math.abs(circleX) / 156 > threshold then table.insert(r, "circle.x%"..threshold) end
|
||||
if math.abs(circleY) / 156 > threshold then table.insert(r, "circle.y%"..threshold) end
|
||||
|
||||
if ctr.apt.isNew3DS() then
|
||||
local cstickX, cstickY = hid.cstick()
|
||||
if math.abs(cstickY) / 146 > threshold then table.insert(r, "cstick.y%"..threshold) end
|
||||
if math.abs(cstickX) / 146 > threshold then table.insert(r, "cstick.x%"..threshold) end
|
||||
end
|
||||
|
||||
local accelX, accelY, accelZ = hid.accel()
|
||||
if math.abs(accelX) / 32768 > threshold then table.insert(r, "accel.x%"..threshold) end
|
||||
if math.abs(accelY) / 32768 > threshold then table.insert(r, "accel.y%"..threshold) end
|
||||
if math.abs(accelZ) / 32768 > threshold then table.insert(r, "accel.z%"..threshold) end
|
||||
|
||||
-- no gyro, because it is always in use
|
||||
|
||||
return r
|
||||
end,
|
||||
|
||||
buttonName = function(...)
|
||||
local ret = {}
|
||||
for _,id in ipairs({...}) do
|
||||
-- Key
|
||||
if id:match("^key%.") then
|
||||
local key = id:match("^key%.(.+)$")
|
||||
table.insert(ret, key:sub(1,1):upper()..key:sub(2).." key")
|
||||
else
|
||||
table.insert(ret, id)
|
||||
end
|
||||
end
|
||||
return unpack(ret)
|
||||
end,
|
||||
|
||||
axisName = function(...)
|
||||
local ret = {}
|
||||
for _,id in ipairs({...}) do
|
||||
-- Binary axis
|
||||
if id:match(".+%,.+") then
|
||||
local b1, b2 = uqt.input.buttonName(id:match("^(.+)%,(.+)$"))
|
||||
table.insert(ret, b1.." / "..b2)
|
||||
-- Touch movement
|
||||
elseif id:match("^touch%.move%.") then
|
||||
local axis, threshold = id:match("^touch%.move%.(.+)%%(.+)$")
|
||||
if not axis then axis = id:match("^touch%.move%.(.+)$") end -- no threshold (=0)
|
||||
threshold = tonumber(threshold) or 0
|
||||
table.insert(ret, ("Touch %s movement (threshold %s%%)"):format(axis, math.abs(threshold*100)))
|
||||
-- Touch position
|
||||
elseif id:match("^touch%.position%.") then
|
||||
local axis, threshold = id:match("^touch%.position%.(.+)%%(.+)$")
|
||||
if not axis then axis = id:match("^touch%.position%.(.+)$") end -- no threshold (=0)
|
||||
threshold = tonumber(threshold) or 0
|
||||
table.insert(ret, ("Touch %s position (threshold %s%%)"):format(axis, math.abs(threshold*100)))
|
||||
-- Circle pad axis
|
||||
elseif id:match("^circle%.") then
|
||||
local axis, threshold = id:match("^circle%.(.+)%%(.+)$")
|
||||
if not axis then axis = id:match("^circle%.(.+)$") end -- no threshold (=0)
|
||||
threshold = tonumber(threshold) or 0
|
||||
if axis == "x" then
|
||||
table.insert(ret, ("Circle pad horizontal axis (deadzone %s%%)"):format(math.abs(threshold*100)))
|
||||
elseif axis == "y" then
|
||||
table.insert(ret, ("Circle pad vertical axis (deadzone %s%%)"):format(math.abs(threshold*100)))
|
||||
else
|
||||
table.insert(ret, ("Circle pad %s axis (deadzone %s%%)"):format(axis, math.abs(threshold*100)))
|
||||
end
|
||||
-- C-Stick axis
|
||||
elseif id:match("^cstick%.") then
|
||||
local axis, threshold = id:match("^cstick%.(.+)%%(.+)$")
|
||||
if not axis then axis = id:match("^cstick%.(.+)$") end -- no threshold (=0)
|
||||
threshold = tonumber(threshold) or 0
|
||||
if axis == "x" then
|
||||
table.insert(ret, ("C-Stick horizontal axis (deadzone %s%%)"):format(math.abs(threshold*100)))
|
||||
elseif axis == "y" then
|
||||
table.insert(ret, ("C-Stick vertical axis (deadzone %s%%)"):format(math.abs(threshold*100)))
|
||||
else
|
||||
table.insert(ret, ("C-Stick %s axis (deadzone %s%%)"):format(axis, math.abs(threshold*100)))
|
||||
end
|
||||
-- Accelerometer axis
|
||||
elseif id:match("^accel%.") then
|
||||
local axis, threshold = id:match("^accel%.(.+)%%(.+)$")
|
||||
if not axis then axis = id:match("^accel%.(.+)$") end -- no threshold (=0)
|
||||
threshold = tonumber(threshold) or 0
|
||||
table.insert(ret, ("Accelerometer %s axis (deadzone %s%%)"):format(axis, math.abs(threshold*100)))
|
||||
-- Gyroscope axis
|
||||
elseif id:match("^gyro%.") then
|
||||
local axis, threshold = id:match("^gyro%.(.+)%%(.+)$")
|
||||
if not axis then axis = id:match("^gyro%.(.+)$") end -- no threshold (=0)
|
||||
threshold = tonumber(threshold) or 0
|
||||
table.insert(ret, ("Gyroscope %s axis (deadzone %s%%)"):format(axis, math.abs(threshold*100)))
|
||||
else
|
||||
table.insert(ret, id)
|
||||
end
|
||||
end
|
||||
return unpack(ret)
|
||||
end
|
||||
})
|
||||
|
||||
-- Defaults
|
||||
uqt.input.default.pointer:bind(
|
||||
{ "absolute", "key.left,key.right", "key.up,key.down" },
|
||||
{ "absolute", "circle.x", "circle.y" }
|
||||
)
|
||||
uqt.input.default.confirm:bind("key.a")
|
||||
uqt.input.default.cancel:bind("key.b")
|
||||
end
|
||||
|
|
|
|||
|
|
@ -30,12 +30,17 @@ do
|
|||
end
|
||||
|
||||
-- Redefine all functions in tbl which also are in toAdd, so when used they call the old function (in tbl) and then the new (in toAdd).
|
||||
-- Functions with names prefixed by a exclamation mark will overwrite the old function.
|
||||
local function add(tbl, toAdd)
|
||||
for k,v in pairs(toAdd) do
|
||||
local old = tbl[k]
|
||||
tbl[k] = function(...)
|
||||
old(...)
|
||||
return v(...)
|
||||
if k:sub(1,1) == "!" then
|
||||
tbl[k] = v
|
||||
else
|
||||
tbl[k] = function(...)
|
||||
old(...)
|
||||
return v(...)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -48,9 +53,6 @@ if uqt.event then
|
|||
local updateDefault = uqt.event.update
|
||||
uqt.event.update = function() end
|
||||
function love.update(dt)
|
||||
-- Value update
|
||||
uqt.draw.fps = love.timer.getFPS()
|
||||
|
||||
-- Stuff defined in ubiquitousse.lua
|
||||
updateDefault(dt*1000)
|
||||
|
||||
|
|
@ -93,6 +95,9 @@ add(uqt.draw, {
|
|||
resizable = p.resizable
|
||||
})
|
||||
end,
|
||||
fps = function()
|
||||
return love.timer.getFPS()
|
||||
end,
|
||||
color = function(r, g, b, a)
|
||||
love.graphics.setColor(r, g, b, a)
|
||||
end,
|
||||
|
|
@ -100,16 +105,34 @@ add(uqt.draw, {
|
|||
love.graphics.setFont(defaultFont)
|
||||
love.graphics.print(text, x, y)
|
||||
end,
|
||||
line = function(x1, y1, x2, y2)
|
||||
love.graphics.line(x1, y1, x2, y2)
|
||||
lineWidth = function(width)
|
||||
love.graphics.setLineWidth(width)
|
||||
end,
|
||||
rectangle = function(x, y, width, height)
|
||||
line = function(x1, y1, x2, y2, ...)
|
||||
love.graphics.line(x1, y1, x2, y2, ...)
|
||||
end,
|
||||
polygon = function(...)
|
||||
love.graphics.polygon("fill", ...)
|
||||
end,
|
||||
linedPolygon = function(...)
|
||||
love.graphics.polygon("line", ...)
|
||||
end,
|
||||
["!rectangle"] = function(x, y, width, height)
|
||||
love.graphics.rectangle("fill", x, y, width, height)
|
||||
end,
|
||||
["!linedRectangle"] = function(x, y, width, height)
|
||||
love.graphics.rectangle("line", x, y, width, height)
|
||||
end,
|
||||
circle = function(x, y, radius)
|
||||
love.graphics.circle("fill", x, y, radius)
|
||||
end,
|
||||
linedCircle = function(x, y, radius)
|
||||
love.graphics.circle("line", x, y, radius)
|
||||
end,
|
||||
scissor = function(x, y, width, height)
|
||||
love.graphics.setScissor(x, y, width, height)
|
||||
end,
|
||||
-- TODO: doc
|
||||
-- TODO: cf draw.lua
|
||||
image = function(filename)
|
||||
local img = love.graphics.newImage(filename)
|
||||
return {
|
||||
|
|
@ -144,7 +167,7 @@ end
|
|||
-- uqt.audio
|
||||
if uqt.audio then
|
||||
add(uqt.audio, {
|
||||
-- TODO: doc
|
||||
-- TODO: cf audio.lua
|
||||
load = function(filepath)
|
||||
local audio = love.audio.newSource(filepath)
|
||||
return {
|
||||
|
|
@ -199,18 +222,6 @@ function love.mousemoved(x, y, dx, dy)
|
|||
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
|
||||
end
|
||||
-- love.wheelmoved doesn't trigger when the wheel stop moving, so we need to clear up our stuff after love.update (so in love.draw)
|
||||
add(love, {
|
||||
draw = function()
|
||||
buttonsInUse["mouse.wheel.up"] = nil
|
||||
buttonsInUse["mouse.wheel.down"] = nil
|
||||
buttonsInUse["mouse.wheel.right"] = nil
|
||||
buttonsInUse["mouse.wheel.left"] = nil
|
||||
-- Same for mouse axis
|
||||
axesInUse["mouse.move.x"] = nil
|
||||
axesInUse["mouse.move.y"] = nil
|
||||
end
|
||||
})
|
||||
function love.gamepadpressed(joystick, button)
|
||||
buttonsInUse["gamepad.button."..joystick:getID().."."..button] = true
|
||||
end
|
||||
|
|
@ -228,6 +239,17 @@ end
|
|||
love.mouse.setVisible(false)
|
||||
|
||||
add(uqt.input, {
|
||||
-- love.wheelmoved doesn't trigger when the wheel stop moving, so we need to clear up our stuff at each update
|
||||
update = function()
|
||||
buttonsInUse["mouse.wheel.up"] = nil
|
||||
buttonsInUse["mouse.wheel.down"] = nil
|
||||
buttonsInUse["mouse.wheel.right"] = nil
|
||||
buttonsInUse["mouse.wheel.left"] = nil
|
||||
-- Same for mouse axis
|
||||
axesInUse["mouse.move.x"] = nil
|
||||
axesInUse["mouse.move.y"] = nil
|
||||
end,
|
||||
|
||||
buttonDetector = function(...)
|
||||
local ret = {}
|
||||
for _,id in ipairs({...}) do
|
||||
|
|
@ -356,7 +378,7 @@ add(uqt.input, {
|
|||
|
||||
buttonsInUse = function(threshold)
|
||||
local r = {}
|
||||
local threshold = threshold or 0.5
|
||||
threshold = threshold or 0.5
|
||||
for b in pairs(buttonsInUse) do
|
||||
table.insert(r, b)
|
||||
end
|
||||
|
|
@ -370,7 +392,7 @@ add(uqt.input, {
|
|||
|
||||
axesInUse = function(threshold)
|
||||
local r = {}
|
||||
local threshold = threshold or 0.5
|
||||
threshold = threshold or 0.5
|
||||
for b,v in pairs(axesInUse) do
|
||||
if math.abs(v) > threshold then
|
||||
table.insert(r, b.."%"..threshold)
|
||||
|
|
@ -416,7 +438,7 @@ add(uqt.input, {
|
|||
table.insert(ret, ("Gamepad %s axis %s (deadzone %s%%)"):format(gid, axis, math.abs(threshold*100)))
|
||||
end
|
||||
else
|
||||
table.insert(r, id)
|
||||
table.insert(ret, id)
|
||||
end
|
||||
end
|
||||
return unpack(ret)
|
||||
|
|
@ -429,13 +451,13 @@ add(uqt.input, {
|
|||
if id:match(".+%,.+") then
|
||||
local b1, b2 = uqt.input.buttonName(id:match("^(.+)%,(.+)$"))
|
||||
table.insert(ret, b1.." / "..b2)
|
||||
-- Mouse move
|
||||
-- Mouse movement
|
||||
elseif id:match("^mouse%.move%.") then
|
||||
local axis, threshold = id:match("^mouse%.move%.(.+)%%(.+)$")
|
||||
if not axis then axis = id:match("^mouse%.move%.(.+)$") end -- no threshold (=0)
|
||||
threshold = tonumber(threshold) or 0
|
||||
table.insert(ret, ("Mouse %s movement (threshold %s%%)"):format(axis, math.abs(threshold*100)))
|
||||
-- Mouse move
|
||||
-- Mouse position
|
||||
elseif id:match("^mouse%.position%.") then
|
||||
local axis, threshold = id:match("^mouse%.position%.(.+)%%(.+)$")
|
||||
if not axis then axis = id:match("^mouse%.position%.(.+)$") end -- no threshold (=0)
|
||||
|
|
@ -458,7 +480,7 @@ add(uqt.input, {
|
|||
table.insert(ret, ("Gamepad %s axis %s (deadzone %s%%)"):format(gid, axis, math.abs(threshold*100)))
|
||||
end
|
||||
else
|
||||
table.insert(r, id)
|
||||
table.insert(ret, id)
|
||||
end
|
||||
end
|
||||
return unpack(ret)
|
||||
|
|
|
|||
59
draw.lua
59
draw.lua
|
|
@ -11,6 +11,8 @@ local uqt = require((...):match("^(.-ubiquitousse)%."))
|
|||
--
|
||||
-- x and y values can be float, so make sure to perform math.floor if your engine only support
|
||||
-- integer coordinates.
|
||||
--
|
||||
-- Mostly plagiarized from the Löve API, with some parts from ctrµLua.
|
||||
local draw
|
||||
draw = {
|
||||
--- Initial game view paramters (some defaults).
|
||||
|
|
@ -46,9 +48,10 @@ draw = {
|
|||
draw.height = params.height
|
||||
end,
|
||||
|
||||
--- Frames per second (the backend should update this value).
|
||||
--- Return the number of frames per second.
|
||||
-- @treturn number the current FPS
|
||||
-- @impl backend
|
||||
fps = 60,
|
||||
fps = function() end,
|
||||
|
||||
--- Sets the drawing color
|
||||
-- @tparam number r the red component (0-255)
|
||||
|
|
@ -65,21 +68,63 @@ draw = {
|
|||
-- @impl backend
|
||||
text = function(x, y, text) end,
|
||||
|
||||
--- Sets the width.
|
||||
-- @tparam number width the line width
|
||||
-- @impl backend
|
||||
lineWidth = function(width) end,
|
||||
|
||||
--- Draws a line.
|
||||
-- @tparam number x1 line start x coordinate
|
||||
-- @tparam number y1 line start y coordinate
|
||||
-- @tparam number x2 line end x coordinate
|
||||
-- @tparam number y2 line end y coordinate
|
||||
-- @tparam number ... other vertices to continue drawing a polyline
|
||||
-- @impl backend
|
||||
line = function(x1, y1, x2, y2) end,
|
||||
line = function(x1, y1, x2, y2, ...) end,
|
||||
|
||||
--- Draws a filled rectangle
|
||||
--- Draws a filled polygon.
|
||||
-- @tparam number x1,y1,x2,y2... the vertices of the polygon
|
||||
-- @impl backend
|
||||
polygon = function(...) end,
|
||||
|
||||
--- Draws a polygon outline.
|
||||
-- @tparam number x1,y1,x2,y2... the vertices of the polygon
|
||||
-- @impl backend
|
||||
linedPolygon = function(...) end,
|
||||
|
||||
--- Draws a filled rectangle.
|
||||
-- @tparam number x rectangle top-left x coordinate
|
||||
-- @tparam number y rectangle top-left x coordinate
|
||||
-- @tparam number width rectangle width
|
||||
-- @tparam number height rectangle height
|
||||
-- @impl ubiquitousse
|
||||
rectangle = function(x, y, width, height)
|
||||
draw.polygon(x, y, x + width, y, x + width, y + height, x, y + height)
|
||||
end,
|
||||
|
||||
--- Draws a rectangle outline.
|
||||
-- @tparam number x rectangle top-left x coordinate
|
||||
-- @tparam number y rectangle top-left x coordinate
|
||||
-- @tparam number width rectangle width
|
||||
-- @tparam number height rectangle height
|
||||
-- @impl ubiquitousse
|
||||
linedRectangle = function(x, y, width, height)
|
||||
draw.linedPolygon(x, y, x + width, y, x + width, y + height, x, y + height)
|
||||
end,
|
||||
|
||||
--- Draws a filled circle.
|
||||
-- @tparam number x center x coordinate
|
||||
-- @tparam number y center x coordinate
|
||||
-- @tparam number radius circle radius
|
||||
-- @impl backend
|
||||
rectangle = function(x, y, width, height) end,
|
||||
circle = function(x, y, radius) end,
|
||||
|
||||
--- Draws a circle outline.
|
||||
-- @tparam number x center x coordinate
|
||||
-- @tparam number y center x coordinate
|
||||
-- @tparam number radius circle radius
|
||||
-- @impl backend
|
||||
linedCircle = function(x, y, radius) end,
|
||||
|
||||
--- Enables the scissor test.
|
||||
-- When enabled, every pixel drawn outside of the scissor rectangle is discarded.
|
||||
|
|
@ -102,9 +147,9 @@ draw = {
|
|||
-- TODO: doc & api
|
||||
push = function() end,
|
||||
pop = function() end,
|
||||
polygon = function(...) end,
|
||||
circle = function(x, y, radius) end,
|
||||
translate = function(x, y) end,
|
||||
rotate = function(angle) end,
|
||||
scale = function(sx, sy) end,
|
||||
font = function(filename) end,
|
||||
image = function(filename) end,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,8 @@ local scene = require((...):match("^(.-ubiquitousse)%.")..".scene")
|
|||
|
||||
--- The events: callback functions that will be called when something interesting occurs.
|
||||
-- Theses are expected to be redefined in the game.
|
||||
-- For backend writers: if they already contain code, then this code has to be called on each call.
|
||||
-- For backend writers: if they already contain code, then this code has to be called on each call, even
|
||||
-- if the user manually redefines them.
|
||||
-- @usage -- in the game's code
|
||||
-- ubiquitousse.event.draw = function()
|
||||
-- ubiquitousse.draw.text(5, 5, "Hello world")
|
||||
|
|
|
|||
29
init.lua
29
init.lua
|
|
@ -11,19 +11,30 @@
|
|||
--
|
||||
-- For backend writers:
|
||||
-- If a function defined here already contains some code, this means this code is mandatory and you must put/call
|
||||
-- it in your implementation.
|
||||
-- it in your implementation (except if the backend provides a more efficient implementation).
|
||||
-- Also, a backend file shouldn't redefine the ubiquitousse table itself but only redefine the backend-dependant fields.
|
||||
-- The API doesn't make the difference between numbers and integers, so convert to integers when needed.
|
||||
-- Lua 5.3: The API doesn't make the difference between numbers and integers, so convert to integers when needed.
|
||||
--
|
||||
-- For game writer:
|
||||
-- Ubiquitousse works with Lua 5.1 to 5.3, including LuaJit, but doesn't provide any version checking or compatibility layer
|
||||
-- between the different versions, so it's up to you to handle that in your game (or ignore the problem and sticks to your
|
||||
-- main's backend Lua version).
|
||||
--
|
||||
-- Ubiquitousse's goal is to run everywhere with the least porting effort possible.
|
||||
-- To achieve this, the engine needs to stay simple, and only provide features that are almost sure to be
|
||||
-- available everywhere, so writing a backend should be straighforward.
|
||||
-- However, Ubiquitousse still make some small assumptions about the engine:
|
||||
-- * The engine has some kind of main loop, or at least a function called very often (may or may not be the
|
||||
-- same as the redraw screen callback).
|
||||
-- * 32bit color depth.
|
||||
--
|
||||
-- Regarding data formats, Ubiquitousse reference implemtations expect and recommend:
|
||||
-- However, a full Ubiquitousse backend still have a few requirement about the destination platform:
|
||||
-- * The backend needs to have access to some kind of main loop, or at least a function called very often (may or may not be the
|
||||
-- same as the redraw screen callback).
|
||||
-- * A 2D matrix graphic output with 32bit RGB color depth.
|
||||
-- * Inputs which match ubiquitousse.input.default (a pointing/4 direction input, a confirm button, and a cancel button).
|
||||
-- * Some way of measuring time with millisecond-precision.
|
||||
-- * Some kind of filesystem.
|
||||
-- * An available audio output would be preferable.
|
||||
-- * Lua 5.1, 5.2, 5.3 or LuaJit.
|
||||
--
|
||||
-- Regarding data formats, Ubiquitousse implementations expect and recommend:
|
||||
-- * For images, PNG support is expected.
|
||||
-- * For audio files, OGG Vorbis support is expected.
|
||||
-- * For fonts, TTF support is expected.
|
||||
|
|
@ -47,6 +58,10 @@
|
|||
-- * ubiquitousse: fully-working version in Ubiquitousse, may or may not be redefined in backend
|
||||
-- The implementation level is indicated using the "@impl level" annotation.
|
||||
--
|
||||
-- Regarding the documentation: Ubiquitousse used LDoc/LuaDoc styled-comments, but since LDoc hates me and my code, the
|
||||
-- generated result is complete garbage, so please read the documentation directly in the comments here.
|
||||
-- Stuff you're interested in starts with triple - (e.g., "--- This functions saves the world").
|
||||
--
|
||||
-- @usage local ubiquitousse = require("ubiquitousse")
|
||||
|
||||
local p = ... -- require path
|
||||
|
|
|
|||
65
scene.lua
65
scene.lua
|
|
@ -12,9 +12,6 @@ local function getPath(modname)
|
|||
return filepath
|
||||
end
|
||||
|
||||
-- FIXME: http://hump.readthedocs.io/en/latest/gamestate.html
|
||||
-- FIXME: call order
|
||||
|
||||
--- Scene management.
|
||||
-- You can use use scenes to seperate the different states of your game: for example, a menu scene and a game scene.
|
||||
-- This module is fully implemented in Ubiquitousse and is mostly a "recommended way" of organising an Ubiquitousse-based game.
|
||||
|
|
@ -22,19 +19,17 @@ end
|
|||
-- make them scene-independent, for example by creating a scene-specific TimerRegistry (TimedFunctions that are keept accross
|
||||
-- states are generally a bad idea). Theses scene-specific states should be created and available in the table returned by
|
||||
-- ubiquitousse.scene.new.
|
||||
-- Currently, the implementation always execute a scene's file before setting it as current, but this may change in the future or
|
||||
-- for some implementations (e.g., on a computer where memory isn't a problem, the scene may be put in a cache). The result of this
|
||||
-- is that you can load assets, libraries, etc. outside of the enter callback, so they can be cached and not reloaded each time
|
||||
-- Currently, the implementation always execute a scene's file before switching to it or adding it to the stack, but this may change in
|
||||
-- the future or for some implementations (e.g., on a computer where memory isn't a problem, the scene may be put in a cache). The result
|
||||
-- of this is that you can load assets, libraries, etc. outside of the enter callback, so they can be cached and not reloaded each time
|
||||
-- the scene is entered, but all the other scene initialization should be done in the enter callback, since it won't be executed on
|
||||
-- each enter otherwise.
|
||||
-- The expected code-organisation is:
|
||||
-- * each scene is in a file, identified by its module name (same identifier used by Lua's require)
|
||||
-- * each scene file create a new scene table using ubiquitousse.scene.new and returns it at the end of the file
|
||||
-- Order of callbacks:
|
||||
-- * all scene exit callbacks are called before changing the stack or the current scene (ie, ubiquitousse.scene.current and the
|
||||
-- last stack element is the scene in which the exit or suspend function was called)
|
||||
-- * all scene enter callbacks are called before changing the stack or the current scene (ie, ubiquitousse.scene.current and the
|
||||
-- last stack element is the previous scene which was just exited, and not the new scene)
|
||||
-- * 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 = {
|
||||
--- The current scene table.
|
||||
|
|
@ -53,31 +48,35 @@ scene = {
|
|||
-- @impl ubiquitousse
|
||||
new = function()
|
||||
return {
|
||||
name = "loading scene", -- The scene name.
|
||||
|
||||
time = time.new(), -- Scene-specific TimerRegistry.
|
||||
|
||||
enter = function(...) end, -- Called when entering a scene.
|
||||
exit = function() end, -- Called when exiting a scene, and not expecting to come back (scene may be unloaded).
|
||||
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).
|
||||
|
||||
suspend = function() end, -- Called when suspending a scene, and expecting to come back (scene won't be unloaded).
|
||||
resume = function() end, -- Called when resuming a suspended scene (after calling suspend).
|
||||
suspend = function(self) end, -- Called when suspending a scene, and expecting to come back (scene won't be unloaded).
|
||||
resume = function(self) end, -- Called when resuming a suspended scene (after calling suspend).
|
||||
|
||||
update = function(dt, ...) end, -- Called on each ubiquitousse.event.update on the current scene.
|
||||
draw = function(...) end -- Called on each ubiquitousse.event.draw on the current scene.
|
||||
update = function(self, dt, ...) end, -- Called on each ubiquitousse.event.update on the current scene.
|
||||
draw = function(self, ...) end -- Called on each ubiquitousse.event.draw on the current scene.
|
||||
}
|
||||
end,
|
||||
|
||||
--- Switch to a new scene.
|
||||
-- The current scene exit function will be called, the new scene will be loaded,
|
||||
-- the current scene will then be replaced by the new one, and then the enter callback is called.
|
||||
-- The new scene will be loaded and the current scene will be replaced by the new one,
|
||||
-- then the previous scene exit function will be called, then the enter callback is called on the new scence.
|
||||
-- Then the stack is changed to replace the old scene with the new one.
|
||||
-- @tparam string scenePath the new scene module name
|
||||
-- @param ... arguments to pass to the scene's enter function
|
||||
-- @impl ubiquitousse
|
||||
switch = function(scenePath, ...)
|
||||
if scene.current then scene.current.exit() end
|
||||
local previous = scene.current
|
||||
scene.current = dofile(getPath(scene.prefix..scenePath))
|
||||
local i = #scene.stack
|
||||
scene.stack[math.max(i, 1)] = scene.current
|
||||
scene.current.enter(...)
|
||||
scene.current.name = scenePath
|
||||
if previous then previous:exit() end
|
||||
scene.current:enter(...)
|
||||
scene.stack[math.max(#scene.stack, 1)] = scene.current
|
||||
end,
|
||||
|
||||
--- Push a new scene to the scene stack.
|
||||
|
|
@ -88,21 +87,23 @@ scene = {
|
|||
-- @param ... arguments to pass to the scene's enter function
|
||||
-- @impl ubiquitousse
|
||||
push = function(scenePath, ...)
|
||||
if scene.current then scene.current.suspend() end
|
||||
local previous = scene.current
|
||||
scene.current = dofile(getPath(scene.prefix..scenePath))
|
||||
scene.current.name = scenePath
|
||||
if previous then previous:suspend() end
|
||||
scene.current:enter(...)
|
||||
table.insert(scene.stack, scene.current)
|
||||
scene.current.enter(...)
|
||||
end,
|
||||
|
||||
--- Pop the current scene from the scene stack.
|
||||
-- The current scene exit function will be called, then the previous scene resume function will be called.
|
||||
-- Then the current scene will be removed from the stack, and the previous scene will be set as the current scene.
|
||||
-- The previous scene will be set as the current scene, then the current scene exit function will be called,
|
||||
-- then the previous scene resume function will be called, and then the current scene will be removed from the stack.
|
||||
-- @impl ubiquitousse
|
||||
pop = function()
|
||||
if scene.current then scene.current.exit() end
|
||||
local previous = scene.stack[#scene.stack-1]
|
||||
scene.current = previous
|
||||
if previous then previous.resume() end
|
||||
local previous = scene.current
|
||||
scene.current = scene.stack[#scene.stack-1]
|
||||
if previous then previous:exit() end
|
||||
if scene.current then scene.current:resume() end
|
||||
table.remove(scene.stack)
|
||||
end,
|
||||
|
||||
|
|
@ -114,7 +115,7 @@ scene = {
|
|||
update = function(dt, ...)
|
||||
if scene.current then
|
||||
scene.current.time.update(dt)
|
||||
scene.current.update(dt, ...)
|
||||
scene.current:update(dt, ...)
|
||||
end
|
||||
end,
|
||||
|
||||
|
|
@ -123,7 +124,7 @@ scene = {
|
|||
-- @param ... arguments to pass to the scene's draw function
|
||||
-- @impl ubiquitousse
|
||||
draw = function(...)
|
||||
if scene.current then scene.current.draw(...) end
|
||||
if scene.current then scene.current:draw(...) end
|
||||
end
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue