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

input: improve value source

This commit is contained in:
Étienne Fildadut 2022-09-20 13:55:51 +09:00
parent 8b994608a2
commit 336f4f01a5
14 changed files with 129 additions and 55 deletions

View file

@ -113,7 +113,7 @@
</div> <!-- id="main" --> </div> <!-- id="main" -->
<div id="about"> <div id="about">
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i> <i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i>
<i style="float:right;">Last updated 2022-09-20 01:08:14 </i> <i style="float:right;">Last updated 2022-09-20 13:52:55 </i>
</div> <!-- id="about" --> </div> <!-- id="about" -->
</div> <!-- id="container" --> </div> <!-- id="container" -->
</body> </body>

View file

@ -337,7 +337,7 @@
</div> <!-- id="main" --> </div> <!-- id="main" -->
<div id="about"> <div id="about">
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i> <i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i>
<i style="float:right;">Last updated 2022-09-20 01:08:14 </i> <i style="float:right;">Last updated 2022-09-20 13:52:55 </i>
</div> <!-- id="about" --> </div> <!-- id="about" -->
</div> <!-- id="container" --> </div> <!-- id="container" -->
</body> </body>

View file

@ -1729,7 +1729,7 @@ its sibling systems (i.e. completely stop the propagation of the event).</li>
</div> <!-- id="main" --> </div> <!-- id="main" -->
<div id="about"> <div id="about">
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i> <i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i>
<i style="float:right;">Last updated 2022-09-20 01:08:14 </i> <i style="float:right;">Last updated 2022-09-20 13:52:55 </i>
</div> <!-- id="about" --> </div> <!-- id="about" -->
</div> <!-- id="container" --> </div> <!-- id="container" -->
</body> </body>

View file

@ -278,11 +278,11 @@ end
</tr> </tr>
<tr> <tr>
<td class="name" nowrap><a href="#mouse.x">mouse.x</a></td> <td class="name" nowrap><a href="#mouse.x">mouse.x</a></td>
<td class="summary">Mouse input: X position of the mouse cursor.</td> <td class="summary">Mouse input: X position of the mouse cursor in the game window.</td>
</tr> </tr>
<tr> <tr>
<td class="name" nowrap><a href="#mouse.y">mouse.y</a></td> <td class="name" nowrap><a href="#mouse.y">mouse.y</a></td>
<td class="summary">Mouse input: Y position of the mouse cursor.</td> <td class="summary">Mouse input: Y position of the mouse cursor in the game window.</td>
</tr> </tr>
<tr> <tr>
<td class="name" nowrap><a href="#mouse.dx">mouse.dx</a></td> <td class="name" nowrap><a href="#mouse.dx">mouse.dx</a></td>
@ -316,6 +316,10 @@ end
<td class="name" nowrap><a href="#child.X">child.X</a></td> <td class="name" nowrap><a href="#child.X">child.X</a></td>
<td class="summary">Children inputs: current value of a child input of the current input.</td> <td class="summary">Children inputs: current value of a child input of the current input.</td>
</tr> </tr>
<tr>
<td class="name" nowrap><a href="#value">value</a></td>
<td class="summary">Current input: current value of the current input.</td>
</tr>
</table> </table>
<br/> <br/>
@ -418,7 +422,14 @@ player.fire.event:bind(<span class="string">"pressed"</span>, <span class="keywo
</span> <span class="string">"key.right - key.left, key.down - key.up"</span>, </span> <span class="string">"key.right - key.left, key.down - key.up"</span>,
dimension = <span class="number">2</span> dimension = <span class="number">2</span>
} }
special = { mouse = {
<span class="comment">-- Example input that returns the position of the mouse cursor, that can be controlled both using an actual mouse or
</span> <span class="comment">-- through a joystick.
</span> dimension = <span class="number">2</span>,
<span class="string">"mouse.x, mouse.y"</span>,
{ <span class="string">"value[1] + axis.leftx * speed * dt, value[2] + axis.lefty * speed * dt"</span>, speed = <span class="number">300</span> } <span class="comment">-- contains dt, so updated only once per frame. Thus speed here is the speed in pixel/second, as expected.
</span> }
mouse = {
<span class="comment">-- A special case: if the <a href="../modules/input.html#dt">dt</a> source is present in an expression, it will make every other input source passive by default in the expression. <span class="comment">-- A special case: if the <a href="../modules/input.html#dt">dt</a> source is present in an expression, it will make every other input source passive by default in the expression.
</span> <span class="comment">-- This is the case since <a href="../modules/input.html#dt">dt</a> will trigger an update every frame, and is therefore mostly relevant for input that is used once per frame only </span> <span class="comment">-- This is the case since <a href="../modules/input.html#dt">dt</a> will trigger an update every frame, and is therefore mostly relevant for input that is used once per frame only
</span> <span class="comment">-- (while other input sources might cause the input to update several times per frame). </span> <span class="comment">-- (while other input sources might cause the input to update several times per frame).
@ -798,7 +809,7 @@ player.fire.event:bind(<span class="string">"pressed"</span>, <span class="keywo
This table does not contain any userdata and should be easily serializable (e.g. to save custom input binding config). This table does not contain any userdata and should be easily serializable (e.g. to save custom input binding config).
This doesn&rsquo;t include input state, grab state, the event registry and the selected joystick since they may change often during runtime.</p> This doesn&rsquo;t include input state, grab state, the event registry and the selected joystick since they may change often during runtime.</p>
<p> Can be changed anytime, but you may need to call <a href="../modules/input.html#Input:reload">reload</a> to apply changes.</p> <p> Can be changed anytime, but you will need to call <a href="../modules/input.html#Input:reload">reload</a> to apply changes.</p>
<p> See <a href="#Input_expressions">expressions</a> for an explanation on how to write input expressions. <p> See <a href="#Input_expressions">expressions</a> for an explanation on how to write input expressions.
@ -1294,7 +1305,8 @@ player.fire.event:bind(<span class="string">"pressed"</span>, <span class="keywo
<h2 class="section-header has-description"><a name="Input_sources"></a>Input sources </h2> <h2 class="section-header has-description"><a name="Input_sources"></a>Input sources </h2>
<div class="section-description"> <div class="section-description">
Input sources are the initial source of input data. They are identified by a Lua identifier name. Input sources are the initial source of input data; each input source can return a single number value.
They are identified by a Lua identifier name.
See <a href="#Input_expressions">expressions</a> on how to use them in expressions.</p> See <a href="#Input_expressions">expressions</a> on how to use them in expressions.</p>
<p> Input sources are provided for common input methods (keyboard, mouse, gamepad) by default; see below for a list of built-in input sources.</p> <p> Input sources are provided for common input methods (keyboard, mouse, gamepad) by default; see below for a list of built-in input sources.</p>
@ -1385,7 +1397,7 @@ player.fire.event:bind(<span class="string">"pressed"</span>, <span class="keywo
<strong>mouse.x</strong> <strong>mouse.x</strong>
</dt> </dt>
<dd> <dd>
Mouse input: X position of the mouse cursor. Mouse input: X position of the mouse cursor in the game window.
</ul> </ul>
</ul> </ul>
@ -1403,7 +1415,7 @@ player.fire.event:bind(<span class="string">"pressed"</span>, <span class="keywo
<strong>mouse.y</strong> <strong>mouse.y</strong>
</dt> </dt>
<dd> <dd>
Mouse input: Y position of the mouse cursor. Mouse input: Y position of the mouse cursor in the game window.
</ul> </ul>
</ul> </ul>
@ -1567,7 +1579,7 @@ player.fire.event:bind(<span class="string">"pressed"</span>, <span class="keywo
</dt> </dt>
<dd> <dd>
Children inputs: current value of a child input of the current input. Children inputs: current value of a child input of the current input.
For child input of dimension 1. For child inputs of dimension 1.
Replace X with the name of the child input.</p> Replace X with the name of the child input.</p>
<p> If the child input is of dimension at least 2, instead use <code>child.X[N]</code>, which gives the <p> If the child input is of dimension at least 2, instead use <code>child.X[N]</code>, which gives the
@ -1584,6 +1596,38 @@ player.fire.event:bind(<span class="string">"pressed"</span>, <span class="keywo
</dd>
<dt>
<a name = "value"></a>
<strong>value</strong>
</dt>
<dd>
Current input: current value of the current input.
For inputs of dimension 1.</p>
<p> If the input is of dimension at least 2, instead use <code>value[N]</code>, which gives the
current value of the Nth dimension of the current input.
Replace N with the index of the dimension you want.</p>
<p> Note that is input is passive by default.
Think twice before marking it active as this may create a feedback loop (the input being updated will trigger it to be updated again, and so on).
</ul>
</ul>
</ul>
</ul>
<ul>
<li><span class="parameter">value</span>
</li>
</ul>
</dd> </dd>
</dl> </dl>
@ -1592,7 +1636,7 @@ player.fire.event:bind(<span class="string">"pressed"</span>, <span class="keywo
</div> <!-- id="main" --> </div> <!-- id="main" -->
<div id="about"> <div id="about">
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i> <i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i>
<i style="float:right;">Last updated 2022-09-20 01:08:14 </i> <i style="float:right;">Last updated 2022-09-20 13:52:55 </i>
</div> <!-- id="about" --> </div> <!-- id="about" -->
</div> <!-- id="container" --> </div> <!-- id="container" -->
</body> </body>

View file

@ -2066,7 +2066,7 @@ end
Level background. </p> Level background. </p>
<p> If there is a background image, <code>background.image</code> contains a table <code>{image=image, x=number, y=number, sx=number, sy=number}</code> <p> If there is a background image, <code>background.image</code> contains a table <code>{image=image, x=number, y=number, sx=number, sy=number}</code>
where <a href="../modules/ldtk.html#Tileset.image">image</a> is the LÖVE image (or image filepath if LÖVE not available) <a href="../modules/ldtk.html#Entity.x">x</a> and <a href="../modules/ldtk.html#IntTile.y">y</a> are the top-left position, where <a href="../modules/ldtk.html#Tileset.image">image</a> is the LÖVE image (or image filepath if LÖVE not available) <a href="../modules/ldtk.html#Tile.x">x</a> and <a href="../modules/ldtk.html#Layer.y">y</a> are the top-left position,
and <a href="../modules/ldtk.html#Entity.sx">sx</a> and <a href="../modules/ldtk.html#Entity.sy">sy</a> the horizontal and vertical scale factors. and <a href="../modules/ldtk.html#Entity.sx">sx</a> and <a href="../modules/ldtk.html#Entity.sy">sy</a> the horizontal and vertical scale factors.
</ul> </ul>
@ -2142,7 +2142,7 @@ end
<li>Enum are converted into a Lua string giving the currently selected enum value.</li> <li>Enum are converted into a Lua string giving the currently selected enum value.</li>
<li>Filepath are converted into a Lua string giving the file path.</li> <li>Filepath are converted into a Lua string giving the file path.</li>
<li>Arrays are converted into a Lua table with the elements in it as a list.</li> <li>Arrays are converted into a Lua table with the elements in it as a list.</li>
<li>Points are converted into a Lua table with the fields <a href="../modules/ldtk.html#Entity.x">x</a> and <a href="../modules/ldtk.html#IntTile.y">y</a>, in pixels: <code>{ x=number, y=number }</code>.</li> <li>Points are converted into a Lua table with the fields <a href="../modules/ldtk.html#Tile.x">x</a> and <a href="../modules/ldtk.html#Layer.y">y</a>, in pixels: <code>{ x=number, y=number }</code>.</li>
<li>Colors are converted into a Lua table with the red, green and blue components in [0-1] as a list: <code>{r,g,b}</code>.</li> <li>Colors are converted into a Lua table with the red, green and blue components in [0-1] as a list: <code>{r,g,b}</code>.</li>
<li>Tiles are converted into a Lua table { tileset = associated tileset object, quad = associated quad } where <a href="../modules/ldtk.html#Tile.quad">quad</a> is a LÖVE Quad if LÖVE is available, otherwise a table <code>{ x, y, width, height }</code>.</li> <li>Tiles are converted into a Lua table { tileset = associated tileset object, quad = associated quad } where <a href="../modules/ldtk.html#Tile.quad">quad</a> is a LÖVE Quad if LÖVE is available, otherwise a table <code>{ x, y, width, height }</code>.</li>
<li>EntityRef are converted into a Lua table { level = level, layerIid = layer IID, entityIid = entity IID, entity = see explanation }. If the entity being refernced belongs to another level and this level is not loaded, <code>entity</code> will be nil; otherwise (same level or the other level is also loaded), it will contain the entity.</li> <li>EntityRef are converted into a Lua table { level = level, layerIid = layer IID, entityIid = entity IID, entity = see explanation }. If the entity being refernced belongs to another level and this level is not loaded, <code>entity</code> will be nil; otherwise (same level or the other level is also loaded), it will contain the entity.</li>
@ -2170,7 +2170,7 @@ end
</div> <!-- id="main" --> </div> <!-- id="main" -->
<div id="about"> <div id="about">
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i> <i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i>
<i style="float:right;">Last updated 2022-09-20 01:08:14 </i> <i style="float:right;">Last updated 2022-09-20 13:52:55 </i>
</div> <!-- id="about" --> </div> <!-- id="about" -->
</div> <!-- id="container" --> </div> <!-- id="container" -->
</body> </body>

View file

@ -703,7 +703,7 @@
</div> <!-- id="main" --> </div> <!-- id="main" -->
<div id="about"> <div id="about">
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i> <i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i>
<i style="float:right;">Last updated 2022-09-20 01:08:14 </i> <i style="float:right;">Last updated 2022-09-20 13:52:55 </i>
</div> <!-- id="about" --> </div> <!-- id="about" -->
</div> <!-- id="container" --> </div> <!-- id="container" -->
</body> </body>

View file

@ -788,7 +788,7 @@ signal.event:bind(&quot;keypressed&quot;, function(key, scancode) print(&quot;pr
</div> <!-- id="main" --> </div> <!-- id="main" -->
<div id="about"> <div id="about">
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i> <i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i>
<i style="float:right;">Last updated 2022-09-20 01:08:14 </i> <i style="float:right;">Last updated 2022-09-20 13:52:55 </i>
</div> <!-- id="about" --> </div> <!-- id="about" -->
</div> <!-- id="container" --> </div> <!-- id="container" -->
</body> </body>

View file

@ -1154,7 +1154,7 @@
</div> <!-- id="main" --> </div> <!-- id="main" -->
<div id="about"> <div id="about">
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i> <i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i>
<i style="float:right;">Last updated 2022-09-20 01:08:14 </i> <i style="float:right;">Last updated 2022-09-20 13:52:55 </i>
</div> <!-- id="about" --> </div> <!-- id="about" -->
</div> <!-- id="container" --> </div> <!-- id="container" -->
</body> </body>

View file

@ -394,7 +394,7 @@ the repository to save you a few seconds.</p>
</div> <!-- id="main" --> </div> <!-- id="main" -->
<div id="about"> <div id="about">
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i> <i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i>
<i style="float:right;">Last updated 2022-09-20 01:08:14 </i> <i style="float:right;">Last updated 2022-09-20 13:52:55 </i>
</div> <!-- id="about" --> </div> <!-- id="about" -->
</div> <!-- id="container" --> </div> <!-- id="container" -->
</body> </body>

View file

@ -785,7 +785,7 @@
</div> <!-- id="main" --> </div> <!-- id="main" -->
<div id="about"> <div id="about">
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i> <i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i>
<i style="float:right;">Last updated 2022-09-20 01:08:14 </i> <i style="float:right;">Last updated 2022-09-20 13:52:55 </i>
</div> <!-- id="about" --> </div> <!-- id="about" -->
</div> <!-- id="container" --> </div> <!-- id="container" -->
</body> </body>

View file

@ -65,7 +65,7 @@
</div> <!-- id="main" --> </div> <!-- id="main" -->
<div id="about"> <div id="about">
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i> <i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i>
<i style="float:right;">Last updated 2022-09-20 01:08:14 </i> <i style="float:right;">Last updated 2022-09-20 13:52:55 </i>
</div> <!-- id="about" --> </div> <!-- id="about" -->
</div> <!-- id="container" --> </div> <!-- id="container" -->
</body> </body>

View file

@ -87,7 +87,7 @@
</div> <!-- id="main" --> </div> <!-- id="main" -->
<div id="about"> <div id="about">
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i> <i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i>
<i style="float:right;">Last updated 2022-09-20 01:08:14 </i> <i style="float:right;">Last updated 2022-09-20 13:52:55 </i>
</div> <!-- id="about" --> </div> <!-- id="about" -->
</div> <!-- id="container" --> </div> <!-- id="container" -->
</body> </body>

View file

@ -33,7 +33,7 @@ local function joystickAxisFilter(input, new, joystick)
if input._joystick and joystick:getID() ~= input._joystick:getID() then if input._joystick and joystick:getID() ~= input._joystick:getID() then
return nil -- ignore if not from the selected joystick return nil -- ignore if not from the selected joystick
end end
local deadzone = input:_deadzone() local deadzone = input._deadzone
if math.abs(new) < deadzone then if math.abs(new) < deadzone then
return 0 -- apply deadzone on axis value return 0 -- apply deadzone on axis value
else else

View file

@ -60,12 +60,15 @@ local signal = require((...):gsub("input%.input$", "signal"))
local event = require((...):gsub("input$", "event")) local event = require((...):gsub("input$", "event"))
local abs, sqrt, floor, ceil, min, max = math.abs, math.sqrt, math.floor, math.ceil, math.min, math.max local abs, sqrt, floor, ceil, min, max = math.abs, math.sqrt, math.floor, math.ceil, math.min, math.max
local unpack = table.unpack or unpack
-- TODO: friendly name for sources -- TODO: friendly name for sources
-- TODO: way to handle text input -- TODO: way to handle text input
-- don't want to change how everything is number based here (it's clean), but would be ok to eg give an additionnal metdatat (text string) along with the "text key pressed" input -- don't want to change how everything is number based here (it's clean), but would be ok to eg give an additionnal metdatat (text string) along with the "text key pressed" input
-- TODO: might be interesting to allow for some outputs, like rumble for a player's joystick?
-- Table to contain temporary calculations (mainly to compute input deltas without needing to allocate a new table). -- Table to contain temporary calculations (mainly to compute input deltas without needing to allocate a new table).
-- Note that this table is never cleared; don't fill it with large data and don't assume its length. -- Note that this table is never cleared; don't fill it with large data and don't assume its length.
local tmp = {} local tmp = {}
@ -164,7 +167,14 @@ end
-- "key.right - key.left, key.down - key.up", -- "key.right - key.left, key.down - key.up",
-- dimension = 2 -- dimension = 2
-- } -- }
-- special = { -- mouse = {
-- -- Example input that returns the position of the mouse cursor, that can be controlled both using an actual mouse or
-- -- through a joystick.
-- dimension = 2,
-- "mouse.x, mouse.y",
-- { "value[1] + axis.leftx * speed * dt, value[2] + axis.lefty * speed * dt", speed = 300 } -- contains dt, so updated only once per frame. Thus speed here is the speed in pixel/second, as expected.
-- }
-- mouse = {
-- -- A special case: if the `dt` source is present in an expression, it will make every other input source passive by default in the expression. -- -- A special case: if the `dt` source is present in an expression, it will make every other input source passive by default in the expression.
-- -- This is the case since `dt` will trigger an update every frame, and is therefore mostly relevant for input that is used once per frame only -- -- This is the case since `dt` will trigger an update every frame, and is therefore mostly relevant for input that is used once per frame only
-- -- (while other input sources might cause the input to update several times per frame). -- -- (while other input sources might cause the input to update several times per frame).
@ -283,7 +293,7 @@ input_mt = {
-- This table does not contain any userdata and should be easily serializable (e.g. to save custom input binding config). -- This table does not contain any userdata and should be easily serializable (e.g. to save custom input binding config).
-- This doesn't include input state, grab state, the event registry and the selected joystick since they may change often during runtime. -- This doesn't include input state, grab state, the event registry and the selected joystick since they may change often during runtime.
-- --
-- Can be changed anytime, but you may need to call `reload` to apply changes. -- Can be changed anytime, but you will need to call `reload` to apply changes.
-- --
-- See [expressions](#Input_expressions) for an explanation on how to write input expressions. -- See [expressions](#Input_expressions) for an explanation on how to write input expressions.
-- @usage -- @usage
@ -353,6 +363,8 @@ input_mt = {
_boundSourceEvents = {}, -- Map of sources events that are binded (and thus will send events to _afterFilterEvent). _boundSourceEvents = {}, -- Map of sources events that are binded (and thus will send events to _afterFilterEvent).
_joystick = nil, -- Currently selected joystick for this player. Also shared with children inputs. _joystick = nil, -- Currently selected joystick for this player. Also shared with children inputs.
_dimension = 1, -- Dimension of the input. _dimension = 1, -- Dimension of the input.
_deadzone = 0.05, -- Deadzone of the input.
_threshold = 0.05, -- Threshold of the input.
--- Update the input and its children. --- Update the input and its children.
-- Should be called every frame, typically _after_ you've done all your input handling -- Should be called every frame, typically _after_ you've done all your input handling
@ -377,8 +389,11 @@ input_mt = {
--- Reload the input `config`, and do the same for its children. --- Reload the input `config`, and do the same for its children.
-- This will reenable the input if it was disabled using `disable`. -- This will reenable the input if it was disabled using `disable`.
reload = function(self) reload = function(self)
-- resize dimensions -- get main options
self._dimension = self.config.dimension or 1 self._dimension = self.config.dimension or 1
self._deadzone = self.config.deadzone or 0.05
self._threshold = self.config.threshold or 0.05
-- resize dimensions
if #self._value > self._dimension then if #self._value > self._dimension then
for i=self._dimension+1, #self._value do for i=self._dimension+1, #self._value do
self._value[i] = nil self._value[i] = nil
@ -434,7 +449,6 @@ input_mt = {
for k, v in pairs(args) do env[k] = v end for k, v in pairs(args) do env[k] = v end
setmetatable(env, { setmetatable(env, {
__index = function(t, key) __index = function(t, key)
if key == "value" then return self:value() end
return self._sourceCache[key] or expressionEnv[key] return self._sourceCache[key] or expressionEnv[key]
end end
}) })
@ -472,7 +486,7 @@ input_mt = {
return setmetatable({ _ = i or #sources }, srcmt) return setmetatable({ _ = i or #sources }, srcmt)
end end
} }
local scanEnv = setmetatable({ value = 0 }, { __index = srcmt.__index }) -- value is not a source local scanEnv = setmetatable({}, { __index = srcmt.__index }) -- value is not a source
for k, v in pairs(args) do scanEnv[k] = v end -- add args for k, v in pairs(args) do scanEnv[k] = v end -- add args
for k in pairs(expressionEnv) do scanEnv[k] = zero end -- add functions for k in pairs(expressionEnv) do scanEnv[k] = zero end -- add functions
for _, mod in ipairs(sourceModifiers) do -- add modifiers functions for _, mod in ipairs(sourceModifiers) do -- add modifiers functions
@ -521,21 +535,33 @@ input_mt = {
local cname, index = sname:match("^child%.(.*)%[(%d+)%]$") local cname, index = sname:match("^child%.(.*)%[(%d+)%]$")
if not cname then cname = sname:match("^child%.(.*)$") end if not cname then cname = sname:match("^child%.(.*)$") end
local child = self.children[cname] local child = self.children[cname]
assert(child, ("input expression refer to %s but this input has no child named %s"):format(sname, cname)) assert(child, ("input expression refer to %q but this input has no child named %s"):format(sname, cname))
if child._dimension > 1 then if child._dimension > 1 then
assert(index, ("input expression refer to %s but this child only has more than one dimension"):format(sname)) assert(index, ("input expression refer to %q without specifing a dimension but this child has more than one dimension"):format(sname))
self._event:bind(self.children[cname].event, "moved", function(...) -- child event -> self._afterFilterEvent link
local new = select(tonumber(index), ...)
s.parentCache[s.lastKey] = new
self._afterFilterEvent:emit(sname, new)
end)
else else
assert(not index, ("input expression refer to %s but this child only has a single dimension"):format(sname)) assert(not index, ("input expression refer to %q but this child only has a single dimension"):format(sname))
self._event:bind(self.children[cname].event, "moved", function(new) -- child event -> self._afterFilterEvent link
s.parentCache[s.lastKey] = new
self._afterFilterEvent:emit(sname, new)
end)
end end
local i = index and tonumber(index) or 1
self._event:bind(self.children[cname].event, "moved", function(...) -- child event -> self._afterFilterEvent link
local new = select(i, ...)
s.parentCache[s.lastKey] = new
self._afterFilterEvent:emit(sname, new)
end)
elseif sname:match("^value") then
local index = sname:match("^value%[(%d+)%]$")
if not index then assert(sname == "value", ("%q is not a valid source; value should be either \"value\" or \"value[number]\""):format(sname)) end
s.passive = true
if self._dimension > 1 then
assert(index, ("input expression refer to %q without specifing a dimension but this input has more than one dimension"):format(sname))
else
assert(not index, ("input expression refer to %q but this input only has a single dimension"):format(sname))
end
local i = index and tonumber(index) or 1
self._event:bind(self.event, "moved", function(...) -- self event -> self._afterFilterEvent link
local new = select(i, ...)
s.parentCache[s.lastKey] = new
self._afterFilterEvent:emit(sname, new)
end)
else else
self._event:bind(event, sname, function(new, filter, ...) -- event source -> self._afterFilterEvent link self._event:bind(event, sname, function(new, filter, ...) -- event source -> self._afterFilterEvent link
if filter then if filter then
@ -584,7 +610,7 @@ input_mt = {
new = filterfn(self, new, ...) new = filterfn(self, new, ...)
if new == nil then return end if new == nil then return end
end end
if abs(new) >= self:_threshold() then if abs(new) >= self._threshold then
event:unbind("_active", onevent) event:unbind("_active", onevent)
fn(source) fn(source)
end end
@ -701,7 +727,7 @@ input_mt = {
if self.grabbed then if self.grabbed then
self.grabbed:_update(new) -- pass onto grabber self.grabbed:_update(new) -- pass onto grabber
else else
local threshold = self:_threshold() local threshold = self._threshold
-- update values -- update values
new = new or self._value new = new or self._value
local old = self._value local old = self._value
@ -736,20 +762,13 @@ input_mt = {
end end
end end
end end
end, end
-- Returns the deadzone of the input.
_deadzone = function(self)
return self.config.deadzone or 0.05
end,
-- Returns the threshold of the input.
_threshold = function(self)
return self.config.threshold or 0.05
end,
} }
input_mt.__index = input_mt input_mt.__index = input_mt
--- Input sources. --- Input sources.
-- Input sources are the initial source of input data. They are identified by a Lua identifier name. -- Input sources are the initial source of input data; each input source can return a single number value.
-- They are identified by a Lua identifier name.
-- See [expressions](#Input_expressions) on how to use them in expressions. -- See [expressions](#Input_expressions) on how to use them in expressions.
-- --
-- Input sources are provided for common input methods (keyboard, mouse, gamepad) by default; see below for a list of built-in input sources. -- Input sources are provided for common input methods (keyboard, mouse, gamepad) by default; see below for a list of built-in input sources.
@ -776,10 +795,10 @@ input_mt.__index = input_mt
-- N is either 1 for the primary mouse button, 2 for secondary or 3 for middle button. -- N is either 1 for the primary mouse button, 2 for secondary or 3 for middle button.
-- @field mouse.N -- @field mouse.N
--- Mouse input: X position of the mouse cursor. --- Mouse input: X position of the mouse cursor in the game window.
-- @field mouse.x -- @field mouse.x
--- Mouse input: Y position of the mouse cursor. --- Mouse input: Y position of the mouse cursor in the game window.
-- @field mouse.y -- @field mouse.y
--- Mouse input: latest X movement of the mouse cursor. --- Mouse input: latest X movement of the mouse cursor.
@ -817,7 +836,7 @@ input_mt.__index = input_mt
-- @field dt -- @field dt
--- Children inputs: current value of a child input of the current input. --- Children inputs: current value of a child input of the current input.
-- For child input of dimension 1. -- For child inputs of dimension 1.
-- Replace X with the name of the child input. -- Replace X with the name of the child input.
-- --
-- If the child input is of dimension at least 2, instead use `child.X[N]`, which gives the -- If the child input is of dimension at least 2, instead use `child.X[N]`, which gives the
@ -825,4 +844,15 @@ input_mt.__index = input_mt
-- Replace X with the name of the child input, and N with the index of the dimension you want. -- Replace X with the name of the child input, and N with the index of the dimension you want.
-- @field child.X -- @field child.X
--- Current input: current value of the current input.
-- For inputs of dimension 1.
--
-- If the input is of dimension at least 2, instead use `value[N]`, which gives the
-- current value of the Nth dimension of the current input.
-- Replace N with the index of the dimension you want.
--
-- Note that is input is passive by default.
-- Think twice before marking it active as this may create a feedback loop (the input being updated will trigger it to be updated again, and so on).
-- @field value
return make_input return make_input