-
Notifications
You must be signed in to change notification settings - Fork 1
/
game.lua
127 lines (104 loc) · 2.98 KB
/
game.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
--- dokidoki.game
--- =============
using 'pl'
using 'dokidoki'
game = pl.class(dokidoki.component)
game._name = 'game'
function game:_init(update_events, draw_events)
self.game = self
---- events ----
-- ordered
self.update_events = {}
self.draw_events = {}
-- by name
self.events = { handle_event = dokidoki.event() }
-- fill them in
for i = 1, #update_events do
local e = dokidoki.event()
self.events[update_events[i]] = e
self.update_events[i] = e
end
for i = 1, #draw_events do
local e = dokidoki.event()
self.events[draw_events[i]] = e
self.draw_events[i] = e
end
---- components ----
self.components = {}
self._components_to_start = {}
self._components_to_remove = {}
self.init_callback = false
-- self:super calls game:add_component, so we need to call this last
self:super(self)
self.parent = false
end
function game:start_main_loop(init)
self.init_callback = init
dokidoki.kernel.start_main_loop{
update = function (...) return self:_update(...) end,
draw = function (...) return self:_draw(...) end,
handle_event = function (...) return self:_handle_event(...) end
}
end
function game:add_component(child)
table.insert(self.components, child)
table.insert(self._components_to_start, child)
end
function game:remove_component(component_to_remove)
assert(not component_to_remove.dead, 'tried to remove dead component')
self._components_to_remove[component_to_remove] = true
end
local function not_dead(c) return not c.dead end
function game:_start_new_components()
while #self._components_to_start > 0 do
local components_to_start = self._components_to_start
self._components_to_start = {}
for i = 1, #components_to_start do
local component = components_to_start[i]
if not component.dead and component._start then
component:_start()
end
end
end
end
function game:_update()
if self.init_callback then
self.init_callback(self)
self.init_callback = false
end
for i = 1, #self.update_events do
self:_start_new_components()
self.update_events[i]()
end
if next(self._components_to_remove) ~= nil then
-- transitive closure forwards
for i = 1, #self.components do
local component = self.components[i]
if self._components_to_remove[component.parent] then
self._components_to_remove[component] = true
end
end
-- delete nodes reverse order (children first)
for i = #self.components, 1, -1 do
local component = self.components[i]
if self._components_to_remove[component] then
self._components_to_remove[component] = nil
component.removed()
component.dead = true
end
end
dokidoki.base.ifilter_in_place(not_dead, self.components)
if self.dead then
kernel.abort_main_loop()
end
end
end
function game:_draw()
for i = 1, #self.draw_events do
self.draw_events[i]()
end
end
function game:_handle_event(e)
self.events.handle_event(e)
end
return game