Notes: the cabinet's flight and big-note sparkle trail #70
No files matched your search
Binary file not shown.
@@ -146,5 +146,87 @@
|
||||
336
|
||||
]
|
||||
]
|
||||
},
|
||||
"firework": {
|
||||
"crop": [
|
||||
[
|
||||
0,
|
||||
0,
|
||||
256,
|
||||
256
|
||||
],
|
||||
[
|
||||
256,
|
||||
0,
|
||||
256,
|
||||
256
|
||||
],
|
||||
[
|
||||
512,
|
||||
0,
|
||||
256,
|
||||
256
|
||||
],
|
||||
[
|
||||
768,
|
||||
0,
|
||||
256,
|
||||
256
|
||||
],
|
||||
[
|
||||
0,
|
||||
256,
|
||||
256,
|
||||
256
|
||||
],
|
||||
[
|
||||
256,
|
||||
256,
|
||||
256,
|
||||
256
|
||||
],
|
||||
[
|
||||
512,
|
||||
256,
|
||||
256,
|
||||
256
|
||||
],
|
||||
[
|
||||
768,
|
||||
256,
|
||||
256,
|
||||
256
|
||||
],
|
||||
[
|
||||
0,
|
||||
512,
|
||||
256,
|
||||
256
|
||||
],
|
||||
[
|
||||
256,
|
||||
512,
|
||||
256,
|
||||
256
|
||||
],
|
||||
[
|
||||
512,
|
||||
512,
|
||||
256,
|
||||
256
|
||||
],
|
||||
[
|
||||
768,
|
||||
512,
|
||||
256,
|
||||
256
|
||||
],
|
||||
[
|
||||
0,
|
||||
768,
|
||||
256,
|
||||
256
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
-- This skin's note arc: the parent's script with the flight and the big-note sparks redone as
|
||||
-- the cabinet's (onp_jump):
|
||||
-- * the note flies from the judge circle to 魂 in 30 frames on the cabinet's path, here a
|
||||
-- cubic Bezier fitted to it (within 6 px), P1 arcing up and P2 down, each with its own fit;
|
||||
-- it then waits at 魂 until the engine's flight (31 frames) ends
|
||||
-- * a big note leaves 9 sparks (hit_effect/firework, the cabinet's 13-frame spark on black),
|
||||
-- the first at frame 5 and then every 3 frames, each centred where the note was about 2
|
||||
-- frames before, at full size, added onto the scene
|
||||
-- The balloon keeps the parent's flight and rainbow (the cabinet's balloon has its own path).
|
||||
-- Everything else is the parent's file, loaded from its own copy.
|
||||
|
||||
-- the parent skin's copy of a script: the second match on package.path (the first is this file)
|
||||
local function load_parent(name)
|
||||
local seen = false
|
||||
for tmpl in package.path:gmatch("[^;]+") do
|
||||
local chunk = loadfile((tmpl:gsub("%?", name)))
|
||||
if chunk then
|
||||
if seen then return chunk end
|
||||
seen = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
assert(load_parent("game/note_arc"), "game/note_arc: the parent skin has no note_arc script")()
|
||||
|
||||
local FRAME_MS = 16.67
|
||||
local FLIGHT_MS = 30 * FRAME_MS
|
||||
-- control points as offsets from the start (c1) and from the end (c2)
|
||||
local CONTROL = {
|
||||
[1] = { c1x = 196.8, c1y = -474.8, c2x = -300.4, c2y = -419.3 },
|
||||
[2] = { c1x = 178.5, c1y = 486.4, c2x = -314.9, c2y = 414.3 },
|
||||
}
|
||||
-- sparks: spawn frames, and where each sits on the 30-frame flight (frames)
|
||||
local SPARK_COUNT = 9
|
||||
local SPARK_SPAWN, SPARK_SPAWN_STEP = 5, 3
|
||||
local SPARK_AT, SPARK_AT_STEP = 2.58, 3.085
|
||||
|
||||
local parent_new = NoteArc.new
|
||||
function NoteArc.new(note_tex_type, big, is_balloon, player_num, start_x, start_y)
|
||||
local self = parent_new(note_tex_type, big, is_balloon, player_num, start_x, start_y)
|
||||
local c = CONTROL[self.p2 and 2 or 1]
|
||||
self.c1x, self.c1y = self.sx + c.c1x, self.sy + c.c1y
|
||||
self.c2x, self.c2y = self.ex + c.c2x, self.ey + c.c2y
|
||||
|
||||
-- a spark is centred on the note: both textures' own offsets and sizes
|
||||
local note = tex.get_texture_info("notes", tostring(note_tex_type))
|
||||
local spark = self.t_firework and tex.get_texture_info("hit_effect", "firework")
|
||||
if note and spark then
|
||||
self.spark_dx = note.x[1] - spark.x[1] + (note.x2[1] - spark.x2[1]) / 2
|
||||
self.spark_dy = note.y[1] - spark.y[1] + (note.y2[1] - spark.y2[1]) / 2
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
local parent_point = NoteArc.point
|
||||
local parent_draw = NoteArc.draw
|
||||
|
||||
-- the cabinet's flight, progress 0..1 over its 30 frames
|
||||
function NoteArc:point(progress)
|
||||
if self.is_balloon then return parent_point(self, progress) end
|
||||
local t = math.max(0, math.min(1, progress))
|
||||
local u = 1 - t
|
||||
local b0, b1, b2, b3 = u * u * u, 3 * u * u * t, 3 * u * t * t, t * t * t
|
||||
return b0 * self.sx + b1 * self.c1x + b2 * self.c2x + b3 * self.ex,
|
||||
b0 * self.sy + b1 * self.c1y + b2 * self.c2y + b3 * self.ey
|
||||
end
|
||||
|
||||
function NoteArc:draw_fireworks(y, elapsed_ms)
|
||||
if not self.spark_dx then return end
|
||||
for i = 0, SPARK_COUNT - 1 do
|
||||
local age_ms = elapsed_ms - (SPARK_SPAWN + SPARK_SPAWN_STEP * i) * FRAME_MS
|
||||
local frame = math.floor(age_ms / FRAME_MS)
|
||||
if age_ms >= 0 and frame < self.firework_frames then
|
||||
local fx, fy = self:point((SPARK_AT + SPARK_AT_STEP * i) * FRAME_MS / FLIGHT_MS)
|
||||
tex.draw_texture(self.t_firework, {
|
||||
frame = frame, center = true, blend = "additive",
|
||||
x = fx + self.spark_dx, y = y + fy + self.spark_dy,
|
||||
})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function NoteArc:draw(y, elapsed_ms, duration_ms)
|
||||
if self.is_balloon then return parent_draw(self, y, elapsed_ms, duration_ms) end
|
||||
if self.big and self.t_firework and self.firework_frames > 0 then
|
||||
self:draw_fireworks(y, elapsed_ms)
|
||||
end
|
||||
if elapsed_ms < duration_ms then
|
||||
local x_i, y_i = self:point(elapsed_ms / FLIGHT_MS)
|
||||
tex.draw_texture(self.t_note, { x = x_i, y = y + y_i })
|
||||
end
|
||||
end
|
||||
|
||||
return NoteArc
|
||||
Reference in new issue
Block a user