576 lines
21 KiB
Lua
576 lines
21 KiB
Lua
local Timing = require("background/bg_objects/timing")
|
|
local chain_moves, frame_change, sum = Timing.chain_moves, Timing.frame_change, Timing.sum
|
|
|
|
-- BaseDancer: single dancer that starts off-screen and bounces in, then loops
|
|
local BaseDancer = {}
|
|
BaseDancer.__index = BaseDancer
|
|
|
|
function BaseDancer.new(name, index, bpm, path)
|
|
local self = setmetatable({}, BaseDancer)
|
|
self.name = name
|
|
self.index = index
|
|
self.bpm = bpm
|
|
self.path = path or "background"
|
|
self.is_started = false
|
|
|
|
local tex_info = tex.get_texture_info(self.name, tostring(self.index) .. "_loop")
|
|
local frame_count = (tex_info and tex_info.frame_count) or 1
|
|
self.keyframes = {}
|
|
for i = 0, frame_count - 1 do
|
|
table.insert(self.keyframes, i)
|
|
end
|
|
|
|
local duration = (60000 / bpm) / 2
|
|
local total_duration = duration * #self.keyframes
|
|
local textures = {}
|
|
for i, frame_idx in ipairs(self.keyframes) do
|
|
table.insert(textures, { duration * (i - 1), duration * i, frame_idx })
|
|
end
|
|
self.texture_change = anim.texture_change(total_duration, textures, { loop = true })
|
|
self.texture_change:start()
|
|
|
|
return self
|
|
end
|
|
|
|
function BaseDancer:start()
|
|
self.is_started = true
|
|
local screen_scale = tex.get_screen_scale()
|
|
local duration = 60000 / self.bpm
|
|
|
|
self.s_bounce_up = anim.move(duration / 2, {
|
|
start_position = math.floor(-200 * screen_scale),
|
|
total_distance = math.floor(350 * screen_scale),
|
|
ease_out = "quadratic",
|
|
delay = 500
|
|
})
|
|
self.s_bounce_down = anim.move(duration / 2, {
|
|
total_distance = math.floor(140 * screen_scale),
|
|
ease_in = "quadratic",
|
|
delay = duration / 2 + 500
|
|
})
|
|
|
|
local start_info = tex.get_texture_info(self.name, tostring(self.index) .. "_start")
|
|
local s_frame_count = (start_info and start_info.frame_count) or 1
|
|
local s_keyframes = {}
|
|
for i = 0, s_frame_count - 1 do
|
|
table.insert(s_keyframes, i)
|
|
end
|
|
local start_textures = {}
|
|
for i, frame_idx in ipairs(s_keyframes) do
|
|
table.insert(start_textures, { (duration / #s_keyframes) * (i - 1), (duration / #s_keyframes) * i, frame_idx })
|
|
end
|
|
self.s_texture_change = anim.texture_change(duration, start_textures, { delay = 500 })
|
|
self.s_texture_change:start()
|
|
self.s_bounce_up:start()
|
|
self.s_bounce_down:start()
|
|
end
|
|
|
|
function BaseDancer:update(current_time_ms, bpm)
|
|
self.texture_change:update(current_time_ms)
|
|
if self.is_started then
|
|
self.s_texture_change:update(current_time_ms)
|
|
self.s_bounce_up:update(current_time_ms)
|
|
self.s_bounce_down:update(current_time_ms)
|
|
end
|
|
if bpm and bpm ~= self.bpm then
|
|
self.bpm = bpm
|
|
local duration = (60000 / bpm) / 2
|
|
local total_duration = duration * #self.keyframes
|
|
local textures = {}
|
|
for i, frame_idx in ipairs(self.keyframes) do
|
|
table.insert(textures, { duration * (i - 1), duration * i, frame_idx })
|
|
end
|
|
self.texture_change = anim.texture_change(total_duration, textures, { loop = true })
|
|
self.texture_change:start()
|
|
end
|
|
end
|
|
|
|
function BaseDancer:draw(x)
|
|
if not self.is_started then return end
|
|
local y = -self.s_bounce_up.attribute + self.s_bounce_down.attribute
|
|
if not self.s_texture_change.is_finished then
|
|
tex.draw_texture(tex.get_texture(self.path .. "/" .. self.name .. "/" .. tostring(self.index) .. "_start"), {
|
|
frame = self.s_texture_change.attribute, x = x, y = y
|
|
})
|
|
else
|
|
tex.draw_texture(tex.get_texture(self.path .. "/" .. self.name .. "/" .. tostring(self.index) .. "_loop"), {
|
|
frame = self.texture_change.attribute, x = x
|
|
})
|
|
end
|
|
end
|
|
|
|
-- Dancer0_4: dancer 4 in group 0, has a bouncing object on top
|
|
local Dancer0_4 = setmetatable({}, { __index = BaseDancer })
|
|
Dancer0_4.__index = Dancer0_4
|
|
|
|
function Dancer0_4.new(name, index, bpm, path)
|
|
local self = setmetatable({}, Dancer0_4)
|
|
local base = BaseDancer.new(name, index, bpm, path)
|
|
for k, v in pairs(base) do self[k] = v end
|
|
|
|
self.keyframes = {}
|
|
for i = 0, 53 do
|
|
table.insert(self.keyframes, i)
|
|
end
|
|
|
|
local duration = (60000 / bpm) / 2
|
|
local total_duration = duration * #self.keyframes
|
|
local textures = {}
|
|
for i, frame_idx in ipairs(self.keyframes) do
|
|
table.insert(textures, { duration * (i - 1), duration * i, frame_idx })
|
|
end
|
|
self.texture_change = anim.texture_change(total_duration, textures, { loop = true })
|
|
self.texture_change:start()
|
|
|
|
self.bounce_up = anim.move(duration, {
|
|
total_distance = 20, ease_out = "quadratic", delay = duration * 2
|
|
})
|
|
self.bounce_down = anim.move(duration, {
|
|
total_distance = 20, ease_in = "quadratic", delay = duration * 3
|
|
})
|
|
self.bounce_up:start()
|
|
self.bounce_down:start()
|
|
self._id_4_start = tex.get_texture(self.path .. "/" .. self.name .. "/" .. "4_start") or 0
|
|
self._id_4_loop = tex.get_texture(self.path .. "/" .. self.name .. "/" .. "4_loop") or 0
|
|
return self
|
|
end
|
|
|
|
function Dancer0_4:update(current_time_ms, bpm)
|
|
BaseDancer.update(self, current_time_ms, bpm)
|
|
self.bounce_up:update(current_time_ms)
|
|
self.bounce_down:update(current_time_ms)
|
|
if self.bounce_down.is_finished then
|
|
self.bounce_up:restart()
|
|
self.bounce_down:restart()
|
|
end
|
|
end
|
|
|
|
function Dancer0_4:draw(x)
|
|
if not self.is_started then return end
|
|
local sy = -self.s_bounce_up.attribute + self.s_bounce_down.attribute
|
|
local screen_scale = tex.get_screen_scale()
|
|
if not self.s_texture_change.is_finished then
|
|
tex.draw_texture(self._id_4_start, {
|
|
frame = 7, x = x, y = (-50 * screen_scale) + sy
|
|
})
|
|
tex.draw_texture(self._id_4_start, {
|
|
frame = self.s_texture_change.attribute, x = x, y = sy
|
|
})
|
|
else
|
|
local attr = self.texture_change.attribute
|
|
local by = -self.bounce_up.attribute + self.bounce_down.attribute
|
|
if attr >= 0 and attr <= 3 then
|
|
tex.draw_texture(self._id_4_loop, { frame = 54, x = x, y = by })
|
|
elseif attr >= 5 and attr <= 8 then
|
|
tex.draw_texture(self._id_4_loop, { frame = 56, x = x, y = by })
|
|
elseif attr == 4 then
|
|
tex.draw_texture(self._id_4_loop, { frame = 55, x = x, y = by })
|
|
end
|
|
tex.draw_texture(self._id_4_loop, { frame = attr, x = x })
|
|
end
|
|
end
|
|
|
|
-- DancerPoof: dancer with a poof animation on spawn
|
|
local DancerPoof = setmetatable({}, { __index = BaseDancer })
|
|
DancerPoof.__index = DancerPoof
|
|
|
|
function DancerPoof.new(name, index, bpm, path)
|
|
local self = setmetatable({}, DancerPoof)
|
|
local base = BaseDancer.new(name, index, bpm, path)
|
|
for k, v in pairs(base) do self[k] = v end
|
|
|
|
local duration = 60000 / bpm
|
|
local poof_keyframes = {}
|
|
for i = 0, 6 do
|
|
table.insert(poof_keyframes, { (duration / 7) * i, (duration / 7) * (i + 1), i })
|
|
end
|
|
self.poof_texture_change = anim.texture_change(duration, poof_keyframes, { delay = 250 })
|
|
self.poof_texture_change:start()
|
|
self._id_poof = tex.get_texture(self.path .. "/" .. self.name .. "/" .. "poof") or 0
|
|
return self
|
|
end
|
|
|
|
function DancerPoof:update(current_time_ms, bpm)
|
|
BaseDancer.update(self, current_time_ms, bpm)
|
|
self.poof_texture_change:update(current_time_ms)
|
|
end
|
|
|
|
function DancerPoof:draw(x)
|
|
BaseDancer.draw(self, x)
|
|
if not self.poof_texture_change.is_finished then
|
|
tex.draw_texture(self._id_poof, { x = x, frame = self.poof_texture_change.attribute })
|
|
end
|
|
end
|
|
|
|
-- DancerPoof2: like DancerPoof but uses per-index poof texture
|
|
local DancerPoof2 = setmetatable({}, { __index = DancerPoof })
|
|
DancerPoof2.__index = DancerPoof2
|
|
|
|
function DancerPoof2.new(name, index, bpm, path)
|
|
local self = setmetatable({}, DancerPoof2)
|
|
local base = DancerPoof.new(name, index, bpm, path)
|
|
for k, v in pairs(base) do self[k] = v end
|
|
return self
|
|
end
|
|
|
|
function DancerPoof2:draw(x)
|
|
if not self.is_started then return end
|
|
local sy = -self.s_bounce_up.attribute + self.s_bounce_down.attribute
|
|
if not self.s_texture_change.is_finished then
|
|
tex.draw_texture(tex.get_texture(self.path .. "/" .. self.name .. "/" .. tostring(self.index) .. "_start"), {
|
|
frame = self.s_texture_change.attribute, x = x, y = sy
|
|
})
|
|
else
|
|
tex.draw_texture(tex.get_texture(self.path .. "/" .. self.name .. "/" .. tostring(self.index) .. "_loop"), {
|
|
frame = self.texture_change.attribute, x = x
|
|
})
|
|
end
|
|
if not self.poof_texture_change.is_finished then
|
|
tex.draw_texture(tex.get_texture(self.path .. "/" .. self.name .. "/" .. tostring(self.index) .. "_poof"), {
|
|
x = x, frame = self.poof_texture_change.attribute
|
|
})
|
|
end
|
|
end
|
|
|
|
-- BaseDancerGroup: manages a pool of dancers spread across the screen
|
|
local BaseDancerGroup = {}
|
|
BaseDancerGroup.__index = BaseDancerGroup
|
|
|
|
local function get_variant_count(dancer_name)
|
|
local keys = tex.get_texture_keys(dancer_name)
|
|
if not keys then return 1 end
|
|
local variants = {}
|
|
for _, key in ipairs(keys) do
|
|
local num = tonumber(key:match("^(%d+)"))
|
|
if num then variants[num] = true end
|
|
end
|
|
local count = 0
|
|
for _ in pairs(variants) do count = count + 1 end
|
|
return math.max(1, count)
|
|
end
|
|
|
|
function BaseDancerGroup.new(index, bpm, max_dancers, path, dancer_class)
|
|
local self = setmetatable({}, BaseDancerGroup)
|
|
dancer_class = dancer_class or BaseDancer
|
|
self.name = "dancer_" .. index
|
|
self.active_count = 0
|
|
self.path = path or "background"
|
|
tex.load_folder(self.path, "dancer/" .. self.name)
|
|
-- center(2), left(1), right(3), far-left(0), far-right(4) — 0-indexed
|
|
self.spawn_positions = { 2, 1, 3, 0, 4 }
|
|
self.active_dancers = {}
|
|
self.max_dancers = max_dancers
|
|
|
|
local variant_count = get_variant_count(self.name)
|
|
self.dancers = {}
|
|
for i = 1, max_dancers do
|
|
local variant_idx = (i - 1) % variant_count
|
|
local dancer = dancer_class.new(self.name, variant_idx, bpm, self.path)
|
|
dancer.group = self
|
|
table.insert(self.dancers, dancer)
|
|
end
|
|
|
|
-- Shuffle dancers
|
|
for i = #self.dancers, 2, -1 do
|
|
local j = math.random(1, i)
|
|
self.dancers[i], self.dancers[j] = self.dancers[j], self.dancers[i]
|
|
end
|
|
|
|
self.needs_initial_dancer = true
|
|
return self
|
|
end
|
|
|
|
function BaseDancerGroup:add_dancer()
|
|
if self.active_count < #self.dancers and self.active_count < #self.spawn_positions then
|
|
self.active_count = self.active_count + 1
|
|
local position = self.spawn_positions[self.active_count] + 1 -- convert to 1-indexed
|
|
local dancer = self.dancers[self.active_count]
|
|
self.active_dancers[position] = dancer
|
|
dancer:start()
|
|
end
|
|
end
|
|
|
|
function BaseDancerGroup:remove_dancer()
|
|
if self.active_count > 1 then
|
|
local position = self.spawn_positions[self.active_count] + 1
|
|
self.active_dancers[position] = nil
|
|
self.active_count = self.active_count - 1
|
|
end
|
|
end
|
|
|
|
function BaseDancerGroup:update(current_time_ms, bpm)
|
|
if self.needs_initial_dancer then
|
|
self.needs_initial_dancer = false
|
|
self:add_dancer()
|
|
end
|
|
for _, dancer in ipairs(self.dancers) do
|
|
dancer:update(current_time_ms, bpm)
|
|
end
|
|
end
|
|
|
|
function BaseDancerGroup:draw()
|
|
local screen_width = tex.get_screen_width()
|
|
local num_dancers = self.max_dancers
|
|
|
|
local first_dancer = nil
|
|
for i = 1, num_dancers do
|
|
local d = self.active_dancers[i]
|
|
if d then
|
|
first_dancer = d; break
|
|
end
|
|
end
|
|
if not first_dancer then return end
|
|
|
|
local info = tex.get_texture_info(self.name, tostring(first_dancer.index) .. "_loop")
|
|
local dancer_width = info and info.width or 0
|
|
|
|
local available_space = screen_width - (num_dancers * dancer_width)
|
|
local spacing = available_space / (num_dancers + 1)
|
|
|
|
for i = 1, num_dancers do
|
|
local dancer = self.active_dancers[i]
|
|
if dancer then
|
|
local x_pos = math.floor(spacing + (i - 1) * (dancer_width + spacing))
|
|
dancer:draw(x_pos)
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Draws dancers on fixed slot centres (Lumen positions) instead of even spacing
|
|
function BaseDancerGroup:draw_slots(centers, order)
|
|
local screen_scale = tex.get_screen_scale()
|
|
for _, i in ipairs(order) do
|
|
local dancer = self.active_dancers[i]
|
|
if dancer then
|
|
local info = tex.get_texture_info(self.name, tostring(dancer.index) .. "_loop")
|
|
dancer:draw(math.floor(centers[i] * screen_scale - info.width / 2))
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Beats since the first dancer started dancing: the routine's shared clock, so dancers that
|
|
-- join later dance in step with the rest. Re-anchored when the bpm changes so it doesn't jump.
|
|
function BaseDancerGroup:dance_clock(now, beat)
|
|
local c = self.clock
|
|
if not c then
|
|
c = { t0 = now, beat = beat }
|
|
self.clock = c
|
|
elseif c.beat ~= beat then
|
|
c.t0, c.beat = now - (now - c.t0) / c.beat * beat, beat
|
|
end
|
|
return (now - c.t0) / beat
|
|
end
|
|
|
|
-- Like remove_dancer, but the dancer stays in its slot to play its exit
|
|
function BaseDancerGroup:leave_dancer()
|
|
if self.active_count > 1 then
|
|
self.active_dancers[self.spawn_positions[self.active_count] + 1]:leave()
|
|
self.active_count = self.active_count - 1
|
|
end
|
|
end
|
|
|
|
function BaseDancerGroup:destroy()
|
|
tex.unload_folder(self.path, "dancer/" .. self.name)
|
|
end
|
|
|
|
-- DancerGroup0: index 0 uses BaseDancers 0-3 + Dancer0_4 at position 4
|
|
local DancerGroup0 = setmetatable({}, { __index = BaseDancerGroup })
|
|
DancerGroup0.__index = DancerGroup0
|
|
|
|
function DancerGroup0.new(index, bpm, max_dancers, path)
|
|
local self = setmetatable({}, DancerGroup0)
|
|
self.name = "dancer_" .. index
|
|
self.active_count = 0
|
|
self.path = path or "background"
|
|
tex.load_folder(self.path, "dancer/" .. self.name)
|
|
self.spawn_positions = { 2, 1, 3, 0, 4 }
|
|
self.active_dancers = {}
|
|
self.max_dancers = max_dancers
|
|
self.dancers = {
|
|
BaseDancer.new(self.name, 0, bpm, self.path),
|
|
BaseDancer.new(self.name, 1, bpm, self.path),
|
|
BaseDancer.new(self.name, 2, bpm, self.path),
|
|
BaseDancer.new(self.name, 3, bpm, self.path),
|
|
Dancer0_4.new(self.name, 4, bpm, self.path)
|
|
}
|
|
for i = #self.dancers, 2, -1 do
|
|
local j = math.random(1, i)
|
|
self.dancers[i], self.dancers[j] = self.dancers[j], self.dancers[i]
|
|
end
|
|
self.needs_initial_dancer = true
|
|
return self
|
|
end
|
|
|
|
-- DancerGroupPoof1: uses DancerPoof
|
|
local DancerGroupPoof1 = setmetatable({}, { __index = BaseDancerGroup })
|
|
DancerGroupPoof1.__index = DancerGroupPoof1
|
|
|
|
function DancerGroupPoof1.new(index, bpm, max_dancers, path)
|
|
return BaseDancerGroup.new(index, bpm, max_dancers, path, DancerPoof)
|
|
end
|
|
|
|
-- DancerGroupPoof2: uses DancerPoof2
|
|
local DancerGroupPoof2 = setmetatable({}, { __index = BaseDancerGroup })
|
|
DancerGroupPoof2.__index = DancerGroupPoof2
|
|
|
|
function DancerGroupPoof2.new(index, bpm, max_dancers, path)
|
|
return BaseDancerGroup.new(index, bpm, max_dancers, path, DancerPoof2)
|
|
end
|
|
|
|
-- LumenDancer: a dancer ported from Lumen data, driven by a spec of beat timings:
|
|
-- start_offset, in_moves, squash, in_frames: entry from below (chain_moves / frame_change)
|
|
-- dance: looping frame_change steps, kept in step across the group (see dance_clock);
|
|
-- out_moves, out_squash, out_frame: exit (optional);
|
|
-- out_frames: frame_change steps for the exit instead of the single out_frame
|
|
-- Dancer.lumen(specs) makes a class for BaseDancerGroup; specs[index] or specs.default.
|
|
local LumenDancer = {}
|
|
LumenDancer.__index = LumenDancer
|
|
|
|
function LumenDancer.new(cls, name, index, bpm, path)
|
|
local self = setmetatable({}, cls)
|
|
self.name = name
|
|
self.index = index
|
|
self.spec = cls.specs[index] or cls.specs.default
|
|
self._id = tex.get_texture(path .. "/" .. name .. "/" .. index .. "_loop") or 0
|
|
self.state = nil -- nil (hidden), "in", "dance", "out"
|
|
self.moves = {}
|
|
self.squash = {}
|
|
self.bpm = bpm
|
|
self.beat = 60000 / bpm
|
|
return self
|
|
end
|
|
|
|
-- The routine's steps from `pos` beats in to the end of the cycle
|
|
local function rest_of(steps, pos)
|
|
local out, t = {}, 0
|
|
for _, step in ipairs(steps) do
|
|
local finish = t + step[2]
|
|
if finish > pos then table.insert(out, { step[1], finish - math.max(t, pos) }) end
|
|
t = finish
|
|
end
|
|
return out
|
|
end
|
|
|
|
function LumenDancer:set_bpm(bpm, current_time_ms)
|
|
self.bpm = bpm
|
|
self.beat = 60000 / bpm
|
|
if self.state == "dance" then self:start_dance(current_time_ms) end
|
|
end
|
|
|
|
-- Starts the routine at the point the rest of the group is at: plays the rest of the current
|
|
-- cycle, then loops it from the top
|
|
function LumenDancer:start_dance(current_time_ms)
|
|
local steps, period = self.spec.dance, 0
|
|
for _, step in ipairs(steps) do period = period + step[2] end
|
|
local pos = self.group and self.group:dance_clock(current_time_ms, self.beat) % period or 0
|
|
local lead = rest_of(steps, pos)
|
|
self.dance_lead = #lead > 0 and pos > 0 and frame_change(lead, self.beat) or nil
|
|
self.dance = frame_change(steps, self.beat, { loop = true })
|
|
if self.dance_lead then self.dance_lead:start() else self.dance:start() end
|
|
end
|
|
|
|
function LumenDancer:start()
|
|
local scale = tex.get_screen_scale()
|
|
self.state = "in"
|
|
self.offset = math.floor(self.spec.start_offset * scale)
|
|
self.moves = chain_moves(self.spec.in_moves, self.beat, scale)
|
|
self.squash = chain_moves(self.spec.squash, self.beat, scale)
|
|
self.in_frames = frame_change(self.spec.in_frames, self.beat)
|
|
self.in_frames:start()
|
|
end
|
|
|
|
function LumenDancer:leave()
|
|
if not self.spec.out_moves then
|
|
self.state = nil
|
|
return
|
|
end
|
|
local scale = tex.get_screen_scale()
|
|
self.offset = self.offset + sum(self.moves) -- leaves from wherever it is
|
|
self.state = "out"
|
|
self.moves = chain_moves(self.spec.out_moves, self.beat, scale)
|
|
self.squash = chain_moves(self.spec.out_squash or {}, self.beat, scale)
|
|
if self.spec.out_frames then
|
|
self.out_frames = frame_change(self.spec.out_frames, self.beat)
|
|
self.out_frames:start()
|
|
end
|
|
end
|
|
|
|
function LumenDancer:update(current_time_ms, bpm)
|
|
if bpm and bpm ~= self.bpm then self:set_bpm(bpm, current_time_ms) end
|
|
if not self.state then return end
|
|
for _, m in ipairs(self.moves) do m:update(current_time_ms) end
|
|
for _, m in ipairs(self.squash) do m:update(current_time_ms) end
|
|
if self.state == "in" then
|
|
self.in_frames:update(current_time_ms)
|
|
if self.in_frames.is_finished then
|
|
self.state = "dance"
|
|
self:start_dance(current_time_ms)
|
|
end
|
|
elseif self.state == "out" and self.moves[#self.moves].is_finished then
|
|
self.state = nil
|
|
end
|
|
if self.state == "dance" then
|
|
if self.dance_lead then
|
|
self.dance_lead:update(current_time_ms)
|
|
if self.dance_lead.is_finished then
|
|
self.dance_lead = nil
|
|
self.dance:start()
|
|
end
|
|
end
|
|
self.dance:update(current_time_ms)
|
|
end
|
|
if self.state == "out" and self.out_frames then self.out_frames:update(current_time_ms) end
|
|
end
|
|
|
|
function LumenDancer:draw(x)
|
|
if not self.state then return end
|
|
local frame
|
|
if self.state == "in" then
|
|
frame = self.in_frames.attribute
|
|
elseif self.state == "out" then
|
|
frame = self.out_frames and self.out_frames.attribute or self.spec.out_frame
|
|
else
|
|
frame = (self.dance_lead or self.dance).attribute
|
|
end
|
|
-- squash keeps the feet planted: shrink the height and push the top down
|
|
local squash = sum(self.squash)
|
|
tex.draw_texture(self._id, {
|
|
frame = frame,
|
|
x = x,
|
|
y = self.offset + sum(self.moves) + squash,
|
|
y2 = -squash,
|
|
})
|
|
end
|
|
|
|
local function lumen(specs)
|
|
local cls = setmetatable({ specs = specs }, { __index = LumenDancer })
|
|
cls.__index = cls
|
|
cls.new = function(...) return LumenDancer.new(cls, ...) end
|
|
return cls
|
|
end
|
|
|
|
-- Factory: maps dancer index 0-20 to the appropriate group class
|
|
local Dancer = {}
|
|
Dancer.Base = BaseDancer
|
|
Dancer.BaseDancerGroup = BaseDancerGroup
|
|
Dancer.lumen = lumen
|
|
|
|
function Dancer.create(index, bpm, path, max_dancers)
|
|
max_dancers = max_dancers or 5
|
|
local map = {
|
|
DancerGroup0, DancerGroup0, DancerGroup0,
|
|
BaseDancerGroup, BaseDancerGroup, BaseDancerGroup,
|
|
BaseDancerGroup,
|
|
DancerGroupPoof1, DancerGroupPoof1,
|
|
BaseDancerGroup, BaseDancerGroup, BaseDancerGroup,
|
|
DancerGroupPoof2, DancerGroupPoof2,
|
|
BaseDancerGroup, BaseDancerGroup,
|
|
DancerGroupPoof2,
|
|
BaseDancerGroup, BaseDancerGroup, BaseDancerGroup, BaseDancerGroup
|
|
}
|
|
local cls = map[index + 1]
|
|
return cls.new(index, bpm, max_dancers, path)
|
|
end
|
|
|
|
return Dancer
|