Skip to content

Commit

Permalink
lua - coroutine system
Browse files Browse the repository at this point in the history
  • Loading branch information
nem0 committed Nov 12, 2024
1 parent f02c56f commit 31bdc37
Show file tree
Hide file tree
Showing 4 changed files with 153 additions and 21 deletions.
41 changes: 20 additions & 21 deletions data/maps/demo/button.lua
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
local co = require "scripts/coroutine"
local lumix_math = require "scripts/math"
local interactive = false

Expand Down Expand Up @@ -58,33 +59,31 @@ function onInputEvent(event : InputEvent)
if interactive and event.type == "button" and event.device.type == "keyboard" then
if event.key_id == string.byte("F") then
if event.down then
-- start by moving the hand to button
ik_target_input = player.animator:getInputIndex("left_hand_ik_target")
ik_alpha_input = player.animator:getInputIndex("left_hand_ik_alpha")
local ik_time = 0

ik_co = coroutine.create(function()
local td = 0
while ik_time < 1 do
player.animator:setVec3Input(ik_target_input, calcIKTarget())
if ik_time < 0.2 then
if ik_time + td >= 0.2 then
-- play the sound
playSound(sound)
-- press (move) the button
this.property_animator.enabled = false
this.property_animator.enabled = true
end
player.animator:setFloatInput(ik_alpha_input, easeOutBack(ik_time / 0.2))
else
player.animator:setFloatInput(ik_alpha_input, 1 - easeOutBack((ik_time - 0.2) / 0.8))
player.animator:setVec3Input(ik_target_input, calcIKTarget())
co.run(function()
co.parallel(
-- move hand to the button
function() co.lerpAnimatorFloat(player, ik_alpha_input, 0, 1, 0.3) end,
-- wait a bit and then press the button
function()
co.wait(0.2)
co.lerpVec3(this, "local_position", {0, 0, 0}, {0, 0, 0.1}, 0.1)
end
td = coroutine.yield(true)
ik_time = ik_time + td
end
)
-- play a sound and wait a bit
playSound(sound)
co.wait(0.1)
co.parallel(
-- move hand back
function() co.lerpAnimatorFloat(player, ik_alpha_input, 1, 0, 0.3) end,
-- release the button
function() co.lerpVec3(this, "local_position", {0, 0, 0.1}, {0, 0, 0}, 0.1) end
)
return false
end)

end
end
end
Expand Down
Binary file modified data/maps/demo/demo.unv
Binary file not shown.
114 changes: 114 additions & 0 deletions data/scripts/coroutine.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
-- TODO proper error handling
local cores = function(co, ...)
local res, err = coroutine.resume(co, ...)
if not res and err then
LumixAPI.logError(err)
end
return res and err ~= false
end

local function iff(condition, a, b)
if condition then
return a
else
return b
end
end

local function easeInOutCirc(x: number): number
return iff(x < 0.5
, (1 - math.sqrt(1 - math.pow(2 * x, 2))) / 2
, (math.sqrt(1 - math.pow(-2 * x + 2, 2)) + 1) / 2)
end

return {

lerp = function(obj, property, start_val, end_val, length)
local time = 0
while time < length do
local rel = time / length
obj[property] = start_val + (end_val - start_val) * rel
td = coroutine.yield()
time = time + td
end
return false
end,

lerpVec3 = function(obj, property, start_val, end_val, length)
local time = 0
while time < length do
local rel = time / length
obj[property] = {
start_val[1] + (end_val[1] - start_val[1]) * rel,
start_val[2] + (end_val[2] - start_val[2]) * rel,
start_val[3] + (end_val[3] - start_val[3]) * rel
}
td = coroutine.yield()
time = time + td
end
end,



lerpAnimatorFloat = function(obj, property, from, to, length)
local time = 0
while time < length do
local rel = time / length
local val = from + (to - from) * rel
val = easeInOutCirc(val)
obj.animator:setFloatInput(property, val)
td = coroutine.yield()
time += td
end
end,

-- takes a list of functions, converts them to couroutines and runs them "in parallel"
-- it runs as long as there are coroutines still not finished
parallel = function(...)
local to_tick = {}
for _, v in ipairs({...}) do
table.insert(to_tick, coroutine.create(function()
v()
return false
end))
end

while #to_tick > 0 do
local n = #to_tick
for i = n, 1, -1 do
if not cores(to_tick[i], td) then
table.remove(to_tick, i)
end
end
td = coroutine.yield()
end
end,

-- wait for specified time
wait = function(length)
local time = 0
while time < length do
td = coroutine.yield()
time = time + td
end
end,

-- conver the function to coroutine and run it
run = function(fn)
local co = coroutine.create(fn)
table.insert(_G["global"].running_coroutines, co)
end,

-- tick all running coroutines
tick = function(td)
local global = _G["global"]
local n = #global.running_coroutines
for i = n, 1, -1 do
local co = global.running_coroutines[i]
if not cores(co, td) then
table.remove(global.running_coroutines, i)
end
end
end

}
19 changes: 19 additions & 0 deletions data/scripts/global.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
local co = require "scripts/coroutine"

if _G["global"] ~= nil then
LumixAPI.logError("Only one component with global.lua should exist in the scene")
end

local global = {
running_coroutines = {}
}

_G["global"] = global

function onDestroy()
_G["global"] = nil
end

function update(td)
co.tick(td)
end

0 comments on commit 31bdc37

Please sign in to comment.