-
Notifications
You must be signed in to change notification settings - Fork 0
/
LoveCoroutine.lua
145 lines (127 loc) · 2.92 KB
/
LoveCoroutine.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
local LC = {}
LC.__index = LC
setmetatable(LC, {
__call = function(cls)
return cls:new()
end
})
function LC:new()
local t = {
times = {},
frames = {},
signals = {},
signaltasks = {},
signaltasks2 = {}
}
setmetatable(t, LC)
return t
end
function LC:run(f, ...)
local co = coroutine.create(f)
coroutine.resume(co, ...)
return co
end
function LC:update(dt)
local frs = self.frames
local tis = self.times
self.frames = {}
self.times = {}
self.signals = {}
for co, _ in pairs(frs) do
coroutine.resume(co, dt)
end
for co, remain in pairs(tis) do
remain = remain - dt
if remain <= 0 then
coroutine.resume(co, -remain)
else
self.times[co] = remain
end
end
end
function LC:stop(co)
if self.times[co] then
local remain = self.times[co]
self.times[co] = nil
return remain
elseif self.frames[co] then
self.frames[co] = nil
return true
else
local signal = self.signaltasks2[co]
self.signaltasks2[co] = nil
self.signaltasks[signal][co] = nil
return signal
end
end
local function addSignalTask(tasks, s, co)
local cos = tasks[s]
if not cos then
cos = {}
tasks[s] = cos
end
cos[co] = true
end
function LC:resume(co, argu)
if argu and coroutine.status(co) == "suspended" then
if type(argu) == "boolean" then
self.frames[co] = true
elseif type(argu) == "number" then
self.times[co] = argu
else
self.signaltasks2[co] = argu
addSignalTask(self.signaltasks, argu, co)
end
return true
end
end
function LC:clear()
self.times = {}
self.frames = {}
self.signals = {}
self.signaltasks = {}
self.signaltasks2 = {}
end
-- used in subtask
-- paused until next update
-- return time delta
function LC:waitNextFrame()
local co = coroutine.running()
self.frames[co] = true
return coroutine.yield()
end
-- used in sub task
-- paused a period of time t
-- return the deviation
function LC:waitTime(t)
local co = coroutine.running()
if t > 0 then
self.times[co] = t
return coroutine.yield()
end
return 0
end
function LC:sendSignal(s, ...)
self.signals[s] = {...}
while true do
local ss = self.signaltasks[s]
if not ss then
break
end
self.signaltasks[s] = nil
for co, _ in pairs(ss) do
self.signaltasks2[co] = nil
coroutine.resume(co, ...)
end
end
end
function LC:waitSignal(s)
if self.signals[s] then
return table.unpack(self.signals[s])
end
local co = coroutine.running()
self.signaltasks2[co] = s
addSignalTask(self.signaltasks, s, co)
return coroutine.yield()
end
return LC