local BaseRenda = {} BaseRenda.__index = BaseRenda function BaseRenda.new(index, path) local self = setmetatable({}, BaseRenda) self.name = "renda_" .. index self.path = path local screen_width = tex.get_screen_width() local screen_scale = tex.get_screen_scale() self.hori_move = anim.move(1500 * screen_scale, {total_distance = screen_width}) self.hori_move:start() return self end function BaseRenda:update(current_time_ms) self.hori_move:update(current_time_ms) end local Renda0 = setmetatable({}, {__index = BaseRenda}) Renda0.__index = Renda0 function Renda0.new(index, path) local self = setmetatable({}, Renda0) local base = BaseRenda.new(index, path) for k, v in pairs(base) do self[k] = v end local screen_scale = tex.get_screen_scale() local screen_height = tex.get_screen_height() self.vert_move = anim.move(1500 * screen_scale, {total_distance = screen_height + (80 * screen_scale)}) self.vert_move:start() local tex_info = tex.get_texture_info("renda", self.name) local num_frames = (tex_info and tex_info.frame_count) or 1 self.frame = math.random(0, num_frames - 1) self.x = math.random(0, math.floor(500 * screen_scale)) self.y = math.random(0, math.floor(20 * screen_scale)) self._id = tex.get_texture(self.path .. "/renda/" .. self.name) or 0 return self end function Renda0:update(current_time_ms) BaseRenda.update(self, current_time_ms) self.vert_move:update(current_time_ms) end function Renda0:draw() tex.draw_texture(self._id, { frame = self.frame, x = self.hori_move.attribute + self.x, y = -self.vert_move.attribute + self.y }) end local Renda1 = setmetatable({}, {__index = BaseRenda}) Renda1.__index = Renda1 function Renda1.new(index, path) local self = setmetatable({}, Renda1) local base = BaseRenda.new(index, path) for k, v in pairs(base) do self[k] = v end local screen_scale = tex.get_screen_scale() local screen_height = tex.get_screen_height() self.frame = math.random(0, 5) self.y = math.random(0, math.floor(200 * screen_scale)) self.rotate = anim.move(800 * screen_scale, {total_distance = math.floor(screen_height / 2), loop = true}) self.rotate:start() self.origin = {64, 64} self._id = tex.get_texture(self.path .. "/renda/" .. self.name) or 0 return self end function Renda1:update(current_time_ms) BaseRenda.update(self, current_time_ms) self.rotate:update(current_time_ms) end function Renda1:draw() tex.draw_texture(self._id, { frame = self.frame, x = self.hori_move.attribute + self.origin[1], y = self.y + self.origin[2], origin = self.origin, rotation = self.rotate.attribute }) end local Renda2 = setmetatable({}, {__index = BaseRenda}) Renda2.__index = Renda2 function Renda2.new(index, path) local self = setmetatable({}, Renda2) local base = BaseRenda.new(index, path) for k, v in pairs(base) do self[k] = v end local screen_scale = tex.get_screen_scale() local screen_height = tex.get_screen_height() self.vert_move = anim.move(1500, {total_distance = screen_height + (80 * screen_scale)}) self.vert_move:start() self.x = math.random(0, math.floor(500 * screen_scale)) self.y = math.random(0, math.floor(20 * screen_scale)) self._id = tex.get_texture(self.path .. "/renda/" .. self.name) or 0 return self end function Renda2:update(current_time_ms) BaseRenda.update(self, current_time_ms) self.vert_move:update(current_time_ms) end function Renda2:draw() tex.draw_texture(self._id, { x = self.hori_move.attribute + self.x, y = -self.vert_move.attribute + self.y }) end local RendaController = {} RendaController.__index = RendaController function RendaController.new(path, index) local self = setmetatable({}, RendaController) self.rendas = {} self.path = path or "background" self.index = (index ~= nil) and index or math.random(0, 2) tex.load_folder(self.path, "renda") return self end function RendaController:add_renda() local classes = {Renda0, Renda1, Renda2} local cls = classes[self.index + 1] table.insert(self.rendas, cls.new(self.index, self.path)) end function RendaController:update(current_time_ms) for i = #self.rendas, 1, -1 do self.rendas[i]:update(current_time_ms) if self.rendas[i].hori_move.is_finished then table.remove(self.rendas, i) end end end function RendaController:draw() for _, renda in ipairs(self.rendas) do renda:draw() end end function RendaController:destroy() tex.unload_folder(self.path, "renda") end -- LumenRenda: the Lumen collabs' drumroll (Miku, GUMI). Every hit sends two notes flying straight across from the right edge, -- each one of the five pictures at one of two speeds local RENDA_KINDS = { -- { frame, flight ms } { 0, 1333 }, { 0, 2000 }, { 1, 1667 }, { 1, 2000 }, { 2, 2333 }, { 2, 2000 }, { 3, 1667 }, { 3, 2000 }, { 4, 1333 }, { 4, 2000 }, } local RENDA_PER_HIT = 2 local RENDA_LIMIT = 25 local RENDA_DISTANCE = 2060 -- where a note starts (its top-left). The original takes these from the game rather -- than the animation data, so they are picked to start just off the right edge and -- fly over the stage below the lane local RENDA_X, RENDA_X_RANGE = 1280, 200 local RENDA_Y, RENDA_Y_RANGE = 384, 288 local LumenRenda = {} LumenRenda.__index = LumenRenda function LumenRenda.new(path) local self = setmetatable({}, LumenRenda) self.path = path tex.load_folder(path, "renda") self._id = tex.get_texture(self.path .. "/renda/renda_0") or 0 self.notes = {} return self end function LumenRenda:add_renda() local scale = tex.get_screen_scale() for _ = 1, RENDA_PER_HIT do if #self.notes >= RENDA_LIMIT then return end local kind = RENDA_KINDS[math.random(#RENDA_KINDS)] local move = anim.move(kind[2], { total_distance = -math.floor(RENDA_DISTANCE * scale) }) move:start() table.insert(self.notes, { frame = kind[1], x = math.floor((RENDA_X + math.random(0, RENDA_X_RANGE)) * scale), y = math.floor((RENDA_Y + math.random(0, RENDA_Y_RANGE)) * scale), move = move, }) end end function LumenRenda:update(current_time_ms) for i = #self.notes, 1, -1 do local note = self.notes[i] note.move:update(current_time_ms) if note.move.is_finished then table.remove(self.notes, i) end end end function LumenRenda:draw() for _, note in ipairs(self.notes) do tex.draw_texture(self._id, { frame = note.frame, x = note.x + note.move.attribute, y = note.y }) end end function LumenRenda:destroy() tex.unload_folder(self.path, "renda") end RendaController.Lumen = LumenRenda return RendaController