More refactoring
This commit is contained in:
parent
ab848312e2
commit
d45a4ae0fa
|
@ -68,6 +68,27 @@ static func directory_list(directory: String, hidden: bool, sort:=true) -> Dicti
|
||||||
return output
|
return output
|
||||||
|
|
||||||
|
|
||||||
|
static func find_by_extensions(array, extensions=null) -> Dictionary:
|
||||||
|
# Both args can be Array or PoolStringArray
|
||||||
|
# If extensions omitted, do all extensions
|
||||||
|
var output = {}
|
||||||
|
if extensions:
|
||||||
|
for ext in extensions:
|
||||||
|
output[ext] = []
|
||||||
|
for filename in array:
|
||||||
|
for ext in extensions:
|
||||||
|
if filename.ends_with(ext):
|
||||||
|
output[ext].append(filename)
|
||||||
|
else:
|
||||||
|
for filename in array:
|
||||||
|
var ext = filename.rsplit('.', false, 1)[1]
|
||||||
|
if ext in output:
|
||||||
|
output[ext].append(filename)
|
||||||
|
else:
|
||||||
|
output[ext] = [filename]
|
||||||
|
return output
|
||||||
|
|
||||||
|
|
||||||
static func init_directory(directory: String):
|
static func init_directory(directory: String):
|
||||||
var dir = Directory.new()
|
var dir = Directory.new()
|
||||||
var err = dir.make_dir_recursive(directory)
|
var err = dir.make_dir_recursive(directory)
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
extends Control
|
extends Control
|
||||||
|
var RadialMeshTools := preload('res://scripts/RadialMeshTools.gd')
|
||||||
|
|
||||||
var screen_height := 1080
|
var screen_height := 1080
|
||||||
|
|
||||||
|
@ -18,11 +19,6 @@ onready var notelines = $'Viewport/Center/notelines'
|
||||||
onready var meshinstance = $'Viewport/Center/meshinstance'
|
onready var meshinstance = $'Viewport/Center/meshinstance'
|
||||||
onready var lbl_combo = $lbl_combo
|
onready var lbl_combo = $lbl_combo
|
||||||
|
|
||||||
const SQRT2 := sqrt(2)
|
|
||||||
const DEG45 := deg2rad(45.0)
|
|
||||||
const DEG90 := deg2rad(90.0)
|
|
||||||
const DEG135 := deg2rad(135.0)
|
|
||||||
|
|
||||||
var time_zero_msec: int = 0
|
var time_zero_msec: int = 0
|
||||||
var time: float = 0.0
|
var time: float = 0.0
|
||||||
var t: float = 0.0 # Game time
|
var t: float = 0.0 # Game time
|
||||||
|
@ -42,37 +38,7 @@ var slide_trail_mesh_instances := {}
|
||||||
|
|
||||||
var noteline_array_image := Image.new()
|
var noteline_array_image := Image.new()
|
||||||
|
|
||||||
# Text UVs
|
#----------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
var text_UV_arrays := []
|
|
||||||
func make_text_UV(row: int, column: int) -> PoolVector2Array:
|
|
||||||
return PoolVector2Array([Vector2(column/4.0, row/8.0), Vector2((column+1)/4.0, row/8.0), Vector2(column/4.0, (row+1)/8.0), Vector2((column+1)/4.0, (row+1)/8.0)])
|
|
||||||
func make_text_UVs():
|
|
||||||
for row in 8:
|
|
||||||
for column in 4:
|
|
||||||
text_UV_arrays.append(make_text_UV(row, column))
|
|
||||||
enum TextStyle {STRAIGHT=0, ARC=1, ARC_EARLY=2, ARC_LATE=3}
|
|
||||||
enum TextWord {NICE=0, OK=4, NG=8, PERFECT=12, GREAT=16, GOOD=20, ALMOST=24, MISS=28}
|
|
||||||
const TextJudgement := {
|
|
||||||
0: TextWord.PERFECT + TextStyle.ARC,
|
|
||||||
1: TextWord.GREAT + TextStyle.ARC_LATE,
|
|
||||||
-1: TextWord.GREAT + TextStyle.ARC_EARLY,
|
|
||||||
2: TextWord.GOOD + TextStyle.ARC_LATE,
|
|
||||||
-2: TextWord.GOOD + TextStyle.ARC_EARLY,
|
|
||||||
3: TextWord.ALMOST + TextStyle.ARC_LATE,
|
|
||||||
-3: TextWord.ALMOST + TextStyle.ARC_EARLY,
|
|
||||||
'MISS': TextWord.MISS + TextStyle.ARC
|
|
||||||
}
|
|
||||||
const TextJudgementStraight := {
|
|
||||||
0: TextWord.PERFECT + TextStyle.STRAIGHT,
|
|
||||||
1: TextWord.GREAT + TextStyle.STRAIGHT,
|
|
||||||
-1: TextWord.GREAT + TextStyle.STRAIGHT,
|
|
||||||
2: TextWord.GOOD + TextStyle.STRAIGHT,
|
|
||||||
-2: TextWord.GOOD + TextStyle.STRAIGHT,
|
|
||||||
3: TextWord.ALMOST + TextStyle.STRAIGHT,
|
|
||||||
-3: TextWord.ALMOST + TextStyle.STRAIGHT,
|
|
||||||
'MISS': TextWord.MISS + TextStyle.STRAIGHT
|
|
||||||
}
|
|
||||||
|
|
||||||
var current_combo := 0
|
var current_combo := 0
|
||||||
func increment_combo():
|
func increment_combo():
|
||||||
current_combo += 1
|
current_combo += 1
|
||||||
|
@ -87,132 +53,16 @@ func initialise_scores():
|
||||||
scores = {}
|
scores = {}
|
||||||
for type in [Note.NOTE_TAP, Note.NOTE_HOLD, Note.NOTE_STAR]:
|
for type in [Note.NOTE_TAP, Note.NOTE_HOLD, Note.NOTE_STAR]:
|
||||||
scores[type] = {}
|
scores[type] = {}
|
||||||
for key in TextJudgement:
|
for key in RadialMeshTools.TextJudgement:
|
||||||
scores[type][key] = 0
|
scores[type][key] = 0
|
||||||
# Release types
|
# Release types
|
||||||
for type in [Note.NOTE_HOLD, Note.NOTE_SLIDE]:
|
for type in [Note.NOTE_HOLD, Note.NOTE_SLIDE]:
|
||||||
scores[Note.RELEASE_SCORE_TYPES[type]] = {}
|
scores[Note.RELEASE_SCORE_TYPES[type]] = {}
|
||||||
for key in TextJudgement:
|
for key in RadialMeshTools.TextJudgement:
|
||||||
scores[Note.RELEASE_SCORE_TYPES[type]][key] = 0
|
scores[Note.RELEASE_SCORE_TYPES[type]][key] = 0
|
||||||
scores['max_combo'] = 0
|
scores['max_combo'] = 0
|
||||||
current_combo = 0
|
current_combo = 0
|
||||||
|
|
||||||
func make_text_mesh(mesh: ArrayMesh, text_id: int, pos: Vector2, angle: float, alpha:=1.0, scale:=1.0):
|
|
||||||
var r := GameTheme.judge_text_size2 * scale
|
|
||||||
var vertex_array := PoolVector2Array([
|
|
||||||
pos+polar2cartesian(r, angle+GameTheme.JUDGE_TEXT_ANG2), # TODO: fix this UV/vertex order mess
|
|
||||||
pos+polar2cartesian(r, angle+GameTheme.JUDGE_TEXT_ANG1),
|
|
||||||
pos+polar2cartesian(r, angle+GameTheme.JUDGE_TEXT_ANG4),
|
|
||||||
pos+polar2cartesian(r, angle+GameTheme.JUDGE_TEXT_ANG3)
|
|
||||||
])
|
|
||||||
var arrays = []
|
|
||||||
arrays.resize(Mesh.ARRAY_MAX)
|
|
||||||
arrays[Mesh.ARRAY_VERTEX] = vertex_array
|
|
||||||
arrays[Mesh.ARRAY_TEX_UV] = text_UV_arrays[text_id]
|
|
||||||
arrays[Mesh.ARRAY_COLOR] = GameTheme.color_array_text(alpha)
|
|
||||||
mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLE_STRIP, arrays)
|
|
||||||
|
|
||||||
func make_judgement_text(mesh: ArrayMesh, text_id: int, col: int, progress:=0.0):
|
|
||||||
make_text_mesh(mesh, text_id,
|
|
||||||
GameTheme.RADIAL_UNIT_VECTORS[col] * GameTheme.receptor_ring_radius * lerp(0.85, 0.85*0.75, progress),
|
|
||||||
GameTheme.RADIAL_COL_ANGLES[col]-PI/2.0, lerp(1.0, 0.0, progress), lerp(1.0, 0.75, progress)
|
|
||||||
)
|
|
||||||
|
|
||||||
# ----------------------------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
# Helper functions to generate meshes from vertex arrays
|
|
||||||
func make_tap_mesh(mesh: ArrayMesh, note_center: Vector2, scale:=1.0, color_array:=GameTheme.COLOR_ARRAY_TAP):
|
|
||||||
var dim = GameTheme.sprite_size2 * scale
|
|
||||||
var vertex_array = PoolVector2Array([note_center + Vector2(-dim, -dim), note_center + Vector2(dim, -dim), note_center + Vector2(-dim, dim), note_center + Vector2(dim, dim)])
|
|
||||||
var arrays = []
|
|
||||||
arrays.resize(Mesh.ARRAY_MAX)
|
|
||||||
arrays[Mesh.ARRAY_VERTEX] = vertex_array
|
|
||||||
arrays[Mesh.ARRAY_TEX_UV] = GameTheme.UV_ARRAY_TAP
|
|
||||||
arrays[Mesh.ARRAY_COLOR] = color_array
|
|
||||||
mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLE_STRIP, arrays)
|
|
||||||
|
|
||||||
func make_hold_mesh(mesh: ArrayMesh, note_center: Vector2, note_center_rel: Vector2, scale:=1.0, angle:=0.0, color_array = GameTheme.COLOR_ARRAY_HOLD):
|
|
||||||
var dim = GameTheme.sprite_size2 * scale
|
|
||||||
var dim2 = dim * SQRT2
|
|
||||||
var a1 = angle - DEG45
|
|
||||||
var a2 = angle + DEG45
|
|
||||||
var a3 = angle - DEG90
|
|
||||||
var a4 = angle + DEG90
|
|
||||||
var a5 = angle - DEG135
|
|
||||||
var a6 = angle + DEG135
|
|
||||||
var vertex_array = PoolVector2Array([
|
|
||||||
note_center + polar2cartesian(dim2, a1), note_center + polar2cartesian(dim2, a2),
|
|
||||||
note_center + polar2cartesian(dim, a3), note_center + polar2cartesian(dim, a4),
|
|
||||||
note_center_rel + polar2cartesian(dim, a3), note_center_rel + polar2cartesian(dim, a4),
|
|
||||||
note_center_rel + polar2cartesian(dim2, a5), note_center_rel + polar2cartesian(dim2, a6)
|
|
||||||
])
|
|
||||||
var arrays = []
|
|
||||||
arrays.resize(Mesh.ARRAY_MAX)
|
|
||||||
arrays[Mesh.ARRAY_VERTEX] = vertex_array
|
|
||||||
arrays[Mesh.ARRAY_TEX_UV] = GameTheme.UV_ARRAY_HOLD
|
|
||||||
arrays[Mesh.ARRAY_COLOR] = color_array
|
|
||||||
mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLE_STRIP, arrays)
|
|
||||||
|
|
||||||
func make_star_mesh(mesh: ArrayMesh, note_center: Vector2, scale:=1.0, angle:=0.0, color_array:=GameTheme.COLOR_ARRAY_STAR):
|
|
||||||
var dim = GameTheme.sprite_size2 * scale * SQRT2
|
|
||||||
var a1 = angle - DEG45
|
|
||||||
var a2 = angle + DEG45
|
|
||||||
var a3 = angle - DEG135
|
|
||||||
var a4 = angle + DEG135
|
|
||||||
var vertex_array = PoolVector2Array([
|
|
||||||
note_center + polar2cartesian(dim, a1), note_center + polar2cartesian(dim, a2),
|
|
||||||
note_center + polar2cartesian(dim, a3), note_center + polar2cartesian(dim, a4)
|
|
||||||
])
|
|
||||||
var arrays = []
|
|
||||||
arrays.resize(Mesh.ARRAY_MAX)
|
|
||||||
arrays[Mesh.ARRAY_VERTEX] = vertex_array
|
|
||||||
arrays[Mesh.ARRAY_TEX_UV] = GameTheme.UV_ARRAY_STAR
|
|
||||||
arrays[Mesh.ARRAY_COLOR] = color_array
|
|
||||||
mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLE_STRIP, arrays)
|
|
||||||
|
|
||||||
#func make_arrow_mesh(mesh: ArrayMesh, vertex_array, color_array = GameTheme.COLOR_ARRAY_TAP):
|
|
||||||
# var arrays = []
|
|
||||||
# arrays.resize(Mesh.ARRAY_MAX)
|
|
||||||
# arrays[Mesh.ARRAY_VERTEX] = vertex_array
|
|
||||||
# arrays[Mesh.ARRAY_TEX_UV] = UV_ARRAY_ARROW
|
|
||||||
# arrays[Mesh.ARRAY_COLOR] = color_array
|
|
||||||
# mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLE_STRIP, arrays)
|
|
||||||
|
|
||||||
|
|
||||||
const slide_arrows_per_unit_length := 10
|
|
||||||
func make_slide_trail_mesh(note) -> ArrayMesh:
|
|
||||||
# Generates a mesh centered around origin. Make sure the MeshInstance2D that draws this is centered on the screen.
|
|
||||||
var mesh = ArrayMesh.new()
|
|
||||||
var arrays = []
|
|
||||||
arrays.resize(Mesh.ARRAY_MAX)
|
|
||||||
var vertices := PoolVector2Array()
|
|
||||||
var uvs := PoolVector2Array()
|
|
||||||
var colors := PoolColorArray()
|
|
||||||
var size := GameTheme.sprite_size2 * sqrt(2)
|
|
||||||
var color := GameTheme.COLOR_DOUBLE_SLIDE if note.double_hit else GameTheme.COLOR_SLIDE
|
|
||||||
|
|
||||||
match note.get_points():
|
|
||||||
[var positions, var angles]:
|
|
||||||
var trail_length : int = len(positions)
|
|
||||||
vertices.resize(3*trail_length)
|
|
||||||
uvs.resize(3*trail_length)
|
|
||||||
colors.resize(3*trail_length)
|
|
||||||
for i in trail_length:
|
|
||||||
var idx = (trail_length-i-1)*3 # We want the earliest ones to be drawn last so that loops/sharp bends will have the first pass on top
|
|
||||||
var u = GameTheme.UV_ARRAY_SLIDE_ARROW if i%3 else GameTheme.UV_ARRAY_SLIDE_ARROW2
|
|
||||||
for j in 3:
|
|
||||||
uvs[idx+j] = u[j]
|
|
||||||
colors[idx+j] = Color(color.r, color.g, color.b, (1.0+float(i))/float(trail_length))
|
|
||||||
var angle : float = angles[i]
|
|
||||||
var offset : Vector2 = positions[i] * GameTheme.receptor_ring_radius
|
|
||||||
vertices[idx] = offset
|
|
||||||
vertices[idx+1] = offset + polar2cartesian(size, angle+PI*0.75)
|
|
||||||
vertices[idx+2] = offset + polar2cartesian(size, angle-PI*0.75)
|
|
||||||
|
|
||||||
arrays[Mesh.ARRAY_VERTEX] = vertices
|
|
||||||
arrays[Mesh.ARRAY_TEX_UV] = uvs
|
|
||||||
arrays[Mesh.ARRAY_COLOR] = colors
|
|
||||||
mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, arrays)
|
|
||||||
return mesh
|
|
||||||
|
|
||||||
#----------------------------------------------------------------------------------------------------------------------------------------------
|
#----------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
func make_judgement_column(judgement, column: int):
|
func make_judgement_column(judgement, column: int):
|
||||||
|
@ -345,11 +195,11 @@ func _draw():
|
||||||
match note.type:
|
match note.type:
|
||||||
Note.NOTE_TAP:
|
Note.NOTE_TAP:
|
||||||
color = GameTheme.color_array_tap(clamp((note.time_death-t)/Note.DEATH_DELAY, 0.0, 1.0), note.double_hit)
|
color = GameTheme.color_array_tap(clamp((note.time_death-t)/Note.DEATH_DELAY, 0.0, 1.0), note.double_hit)
|
||||||
make_tap_mesh(mesh, note_center, scale, color)
|
RadialMeshTools.make_tap_mesh(mesh, note_center, scale, color)
|
||||||
Note.NOTE_STAR:
|
Note.NOTE_STAR:
|
||||||
color = GameTheme.color_array_star(clamp((note.time_death-t)/Note.DEATH_DELAY, 0.0, 1.0), note.double_hit)
|
color = GameTheme.color_array_star(clamp((note.time_death-t)/Note.DEATH_DELAY, 0.0, 1.0), note.double_hit)
|
||||||
var angle = fmod(t/note.duration, 1.0)*TAU
|
var angle = fmod(t/note.duration, 1.0)*TAU
|
||||||
make_star_mesh(mesh, note_center, scale, angle, color)
|
RadialMeshTools.make_star_mesh(mesh, note_center, scale, angle, color)
|
||||||
Note.NOTE_HOLD:
|
Note.NOTE_HOLD:
|
||||||
if note.is_held:
|
if note.is_held:
|
||||||
position = (t+GameTheme.note_forecast_beats-note.time_release)/GameTheme.note_forecast_beats
|
position = (t+GameTheme.note_forecast_beats-note.time_release)/GameTheme.note_forecast_beats
|
||||||
|
@ -376,7 +226,7 @@ func _draw():
|
||||||
if position_rel < GameTheme.INNER_NOTE_CIRCLE_RATIO:
|
if position_rel < GameTheme.INNER_NOTE_CIRCLE_RATIO:
|
||||||
position_rel = GameTheme.INNER_NOTE_CIRCLE_RATIO
|
position_rel = GameTheme.INNER_NOTE_CIRCLE_RATIO
|
||||||
var note_center_rel = (GameTheme.RADIAL_UNIT_VECTORS[note.column] * position_rel * GameTheme.receptor_ring_radius)
|
var note_center_rel = (GameTheme.RADIAL_UNIT_VECTORS[note.column] * position_rel * GameTheme.receptor_ring_radius)
|
||||||
make_hold_mesh(mesh, note_center, note_center_rel, scale, GameTheme.RADIAL_COL_ANGLES[note.column], color)
|
RadialMeshTools.make_hold_mesh(mesh, note_center, note_center_rel, scale, GameTheme.RADIAL_COL_ANGLES[note.column], color)
|
||||||
Note.NOTE_SLIDE:
|
Note.NOTE_SLIDE:
|
||||||
var trail_alpha := 1.0
|
var trail_alpha := 1.0
|
||||||
if position < GameTheme.INNER_NOTE_CIRCLE_RATIO:
|
if position < GameTheme.INNER_NOTE_CIRCLE_RATIO:
|
||||||
|
@ -387,7 +237,7 @@ func _draw():
|
||||||
var trail_progress : float = clamp((t - note.time_hit - GameTheme.SLIDE_DELAY)/(note.duration - GameTheme.SLIDE_DELAY), 0.0, 1.0)
|
var trail_progress : float = clamp((t - note.time_hit - GameTheme.SLIDE_DELAY)/(note.duration - GameTheme.SLIDE_DELAY), 0.0, 1.0)
|
||||||
var star_pos : Vector2 = note.get_position(trail_progress) * GameTheme.receptor_ring_radius
|
var star_pos : Vector2 = note.get_position(trail_progress) * GameTheme.receptor_ring_radius
|
||||||
var star_angle : float = note.get_angle(trail_progress)
|
var star_angle : float = note.get_angle(trail_progress)
|
||||||
make_star_mesh(mesh, star_pos, 1.33, star_angle)
|
RadialMeshTools.make_star_mesh(mesh, star_pos, 1.33, star_angle)
|
||||||
if note.progress != INF:
|
if note.progress != INF:
|
||||||
slide_trail_mesh_instances[note.slide_id].material.set_shader_param('trail_progress', note.progress)
|
slide_trail_mesh_instances[note.slide_id].material.set_shader_param('trail_progress', note.progress)
|
||||||
if t > note.time_release:
|
if t > note.time_release:
|
||||||
|
@ -403,7 +253,7 @@ func _draw():
|
||||||
|
|
||||||
var textmesh := ArrayMesh.new()
|
var textmesh := ArrayMesh.new()
|
||||||
for text in active_judgement_texts:
|
for text in active_judgement_texts:
|
||||||
make_judgement_text(textmesh, TextJudgement[text.judgement], text.col, (t-text.time)/GameTheme.judge_text_duration)
|
RadialMeshTools.make_judgement_text(textmesh, RadialMeshTools.TextJudgement[text.judgement], text.col, (t-text.time)/GameTheme.judge_text_duration)
|
||||||
JudgeText.set_mesh(textmesh)
|
JudgeText.set_mesh(textmesh)
|
||||||
|
|
||||||
|
|
||||||
|
@ -436,7 +286,6 @@ func _input(event):
|
||||||
func _init():
|
func _init():
|
||||||
Input.set_mouse_mode(Input.MOUSE_MODE_HIDDEN)
|
Input.set_mouse_mode(Input.MOUSE_MODE_HIDDEN)
|
||||||
GameTheme.init_radial_values()
|
GameTheme.init_radial_values()
|
||||||
make_text_UVs()
|
|
||||||
initialise_scores()
|
initialise_scores()
|
||||||
|
|
||||||
func set_time(seconds: float):
|
func set_time(seconds: float):
|
||||||
|
@ -507,7 +356,7 @@ func load_track(song_key: String, difficulty_key: String):
|
||||||
Note.process_note_list(all_notes, false)
|
Note.process_note_list(all_notes, false)
|
||||||
for note in all_notes:
|
for note in all_notes:
|
||||||
if note.type == Note.NOTE_SLIDE:
|
if note.type == Note.NOTE_SLIDE:
|
||||||
slide_trail_meshes[note.slide_id] = make_slide_trail_mesh(note)
|
slide_trail_meshes[note.slide_id] = RadialMeshTools.make_slide_trail_mesh(note)
|
||||||
|
|
||||||
initialise_scores() # Remove old score
|
initialise_scores() # Remove old score
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,203 @@
|
||||||
|
extends Node
|
||||||
|
|
||||||
|
const SQRT2 := sqrt(2)
|
||||||
|
const DEG45 := deg2rad(45.0)
|
||||||
|
const DEG90 := deg2rad(90.0)
|
||||||
|
const DEG135 := deg2rad(135.0)
|
||||||
|
|
||||||
|
# ----------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
# Helper functions to generate meshes from vertex arrays
|
||||||
|
static func make_tap_mesh(mesh: ArrayMesh, note_center: Vector2, scale:=1.0, color_array:=GameTheme.COLOR_ARRAY_TAP):
|
||||||
|
var dim = GameTheme.sprite_size2 * scale
|
||||||
|
var vertex_array = PoolVector2Array([note_center + Vector2(-dim, -dim), note_center + Vector2(dim, -dim), note_center + Vector2(-dim, dim), note_center + Vector2(dim, dim)])
|
||||||
|
var arrays = []
|
||||||
|
arrays.resize(Mesh.ARRAY_MAX)
|
||||||
|
arrays[Mesh.ARRAY_VERTEX] = vertex_array
|
||||||
|
arrays[Mesh.ARRAY_TEX_UV] = GameTheme.UV_ARRAY_TAP
|
||||||
|
arrays[Mesh.ARRAY_COLOR] = color_array
|
||||||
|
mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLE_STRIP, arrays)
|
||||||
|
|
||||||
|
static func make_hold_mesh(mesh: ArrayMesh, note_center: Vector2, note_center_rel: Vector2, scale:=1.0, angle:=0.0, color_array = GameTheme.COLOR_ARRAY_HOLD):
|
||||||
|
var dim = GameTheme.sprite_size2 * scale
|
||||||
|
var dim2 = dim * SQRT2
|
||||||
|
var a1 = angle - DEG45
|
||||||
|
var a2 = angle + DEG45
|
||||||
|
var a3 = angle - DEG90
|
||||||
|
var a4 = angle + DEG90
|
||||||
|
var a5 = angle - DEG135
|
||||||
|
var a6 = angle + DEG135
|
||||||
|
var vertex_array = PoolVector2Array([
|
||||||
|
note_center + polar2cartesian(dim2, a1), note_center + polar2cartesian(dim2, a2),
|
||||||
|
note_center + polar2cartesian(dim, a3), note_center + polar2cartesian(dim, a4),
|
||||||
|
note_center_rel + polar2cartesian(dim, a3), note_center_rel + polar2cartesian(dim, a4),
|
||||||
|
note_center_rel + polar2cartesian(dim2, a5), note_center_rel + polar2cartesian(dim2, a6)
|
||||||
|
])
|
||||||
|
var arrays = []
|
||||||
|
arrays.resize(Mesh.ARRAY_MAX)
|
||||||
|
arrays[Mesh.ARRAY_VERTEX] = vertex_array
|
||||||
|
arrays[Mesh.ARRAY_TEX_UV] = GameTheme.UV_ARRAY_HOLD
|
||||||
|
arrays[Mesh.ARRAY_COLOR] = color_array
|
||||||
|
mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLE_STRIP, arrays)
|
||||||
|
|
||||||
|
static func make_star_mesh(mesh: ArrayMesh, note_center: Vector2, scale:=1.0, angle:=0.0, color_array:=GameTheme.COLOR_ARRAY_STAR):
|
||||||
|
var dim = GameTheme.sprite_size2 * scale * SQRT2
|
||||||
|
var a1 = angle - DEG45
|
||||||
|
var a2 = angle + DEG45
|
||||||
|
var a3 = angle - DEG135
|
||||||
|
var a4 = angle + DEG135
|
||||||
|
var vertex_array = PoolVector2Array([
|
||||||
|
note_center + polar2cartesian(dim, a1), note_center + polar2cartesian(dim, a2),
|
||||||
|
note_center + polar2cartesian(dim, a3), note_center + polar2cartesian(dim, a4)
|
||||||
|
])
|
||||||
|
var arrays = []
|
||||||
|
arrays.resize(Mesh.ARRAY_MAX)
|
||||||
|
arrays[Mesh.ARRAY_VERTEX] = vertex_array
|
||||||
|
arrays[Mesh.ARRAY_TEX_UV] = GameTheme.UV_ARRAY_STAR
|
||||||
|
arrays[Mesh.ARRAY_COLOR] = color_array
|
||||||
|
mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLE_STRIP, arrays)
|
||||||
|
|
||||||
|
#func make_arrow_mesh(mesh: ArrayMesh, vertex_array, color_array = GameTheme.COLOR_ARRAY_TAP):
|
||||||
|
# var arrays = []
|
||||||
|
# arrays.resize(Mesh.ARRAY_MAX)
|
||||||
|
# arrays[Mesh.ARRAY_VERTEX] = vertex_array
|
||||||
|
# arrays[Mesh.ARRAY_TEX_UV] = UV_ARRAY_ARROW
|
||||||
|
# arrays[Mesh.ARRAY_COLOR] = color_array
|
||||||
|
# mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLE_STRIP, arrays)
|
||||||
|
|
||||||
|
|
||||||
|
const slide_arrows_per_unit_length := 10
|
||||||
|
static func make_slide_trail_mesh(note) -> ArrayMesh:
|
||||||
|
# Generates a mesh centered around origin. Make sure the MeshInstance2D that draws this is centered on the screen.
|
||||||
|
var mesh = ArrayMesh.new()
|
||||||
|
var arrays = []
|
||||||
|
arrays.resize(Mesh.ARRAY_MAX)
|
||||||
|
var vertices := PoolVector2Array()
|
||||||
|
var uvs := PoolVector2Array()
|
||||||
|
var colors := PoolColorArray()
|
||||||
|
var size := GameTheme.sprite_size2 * sqrt(2)
|
||||||
|
var color := GameTheme.COLOR_DOUBLE_SLIDE if note.double_hit else GameTheme.COLOR_SLIDE
|
||||||
|
|
||||||
|
match note.get_points():
|
||||||
|
[var positions, var angles]:
|
||||||
|
var trail_length : int = len(positions)
|
||||||
|
vertices.resize(3*trail_length)
|
||||||
|
uvs.resize(3*trail_length)
|
||||||
|
colors.resize(3*trail_length)
|
||||||
|
for i in trail_length:
|
||||||
|
var idx = (trail_length-i-1)*3 # We want the earliest ones to be drawn last so that loops/sharp bends will have the first pass on top
|
||||||
|
var u = GameTheme.UV_ARRAY_SLIDE_ARROW if i%3 else GameTheme.UV_ARRAY_SLIDE_ARROW2
|
||||||
|
for j in 3:
|
||||||
|
uvs[idx+j] = u[j]
|
||||||
|
colors[idx+j] = Color(color.r, color.g, color.b, (1.0+float(i))/float(trail_length))
|
||||||
|
var angle : float = angles[i]
|
||||||
|
var offset : Vector2 = positions[i] * GameTheme.receptor_ring_radius
|
||||||
|
vertices[idx] = offset
|
||||||
|
vertices[idx+1] = offset + polar2cartesian(size, angle+PI*0.75)
|
||||||
|
vertices[idx+2] = offset + polar2cartesian(size, angle-PI*0.75)
|
||||||
|
|
||||||
|
arrays[Mesh.ARRAY_VERTEX] = vertices
|
||||||
|
arrays[Mesh.ARRAY_TEX_UV] = uvs
|
||||||
|
arrays[Mesh.ARRAY_COLOR] = colors
|
||||||
|
mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, arrays)
|
||||||
|
return mesh
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
# Text UVs
|
||||||
|
|
||||||
|
# Old dynamic code:
|
||||||
|
#var text_UV_arrays := []
|
||||||
|
#func make_text_UV(row: int, column: int) -> PoolVector2Array:
|
||||||
|
# return PoolVector2Array([Vector2(column/4.0, row/8.0), Vector2((column+1)/4.0, row/8.0), Vector2(column/4.0, (row+1)/8.0), Vector2((column+1)/4.0, (row+1)/8.0)])
|
||||||
|
#func make_text_UVs():
|
||||||
|
# for row in 8:
|
||||||
|
# for column in 4:
|
||||||
|
# text_UV_arrays.append(make_text_UV(row, column))
|
||||||
|
|
||||||
|
# This is replaced by a quick hacky python codegen:
|
||||||
|
#>>> def make_text_UV(row, column):
|
||||||
|
#... return f'PoolVector2Array([Vector2({column}/4.0, {row}/8.0), Vector2({column+1}/4.0, {row}/8.0), Vector2({column}/4.0, {row+1}/8.0), Vector2({column+1}/4.0, {row+1}/8.0)])'
|
||||||
|
#>>> for row in range(8):
|
||||||
|
#... for col in range(4):
|
||||||
|
#... print(make_text_UV(row, col) + ',')
|
||||||
|
|
||||||
|
const text_UV_arrays := [
|
||||||
|
PoolVector2Array([Vector2(0/4.0, 0/8.0), Vector2(1/4.0, 0/8.0), Vector2(0/4.0, 1/8.0), Vector2(1/4.0, 1/8.0)]),
|
||||||
|
PoolVector2Array([Vector2(1/4.0, 0/8.0), Vector2(2/4.0, 0/8.0), Vector2(1/4.0, 1/8.0), Vector2(2/4.0, 1/8.0)]),
|
||||||
|
PoolVector2Array([Vector2(2/4.0, 0/8.0), Vector2(3/4.0, 0/8.0), Vector2(2/4.0, 1/8.0), Vector2(3/4.0, 1/8.0)]),
|
||||||
|
PoolVector2Array([Vector2(3/4.0, 0/8.0), Vector2(4/4.0, 0/8.0), Vector2(3/4.0, 1/8.0), Vector2(4/4.0, 1/8.0)]),
|
||||||
|
PoolVector2Array([Vector2(0/4.0, 1/8.0), Vector2(1/4.0, 1/8.0), Vector2(0/4.0, 2/8.0), Vector2(1/4.0, 2/8.0)]),
|
||||||
|
PoolVector2Array([Vector2(1/4.0, 1/8.0), Vector2(2/4.0, 1/8.0), Vector2(1/4.0, 2/8.0), Vector2(2/4.0, 2/8.0)]),
|
||||||
|
PoolVector2Array([Vector2(2/4.0, 1/8.0), Vector2(3/4.0, 1/8.0), Vector2(2/4.0, 2/8.0), Vector2(3/4.0, 2/8.0)]),
|
||||||
|
PoolVector2Array([Vector2(3/4.0, 1/8.0), Vector2(4/4.0, 1/8.0), Vector2(3/4.0, 2/8.0), Vector2(4/4.0, 2/8.0)]),
|
||||||
|
PoolVector2Array([Vector2(0/4.0, 2/8.0), Vector2(1/4.0, 2/8.0), Vector2(0/4.0, 3/8.0), Vector2(1/4.0, 3/8.0)]),
|
||||||
|
PoolVector2Array([Vector2(1/4.0, 2/8.0), Vector2(2/4.0, 2/8.0), Vector2(1/4.0, 3/8.0), Vector2(2/4.0, 3/8.0)]),
|
||||||
|
PoolVector2Array([Vector2(2/4.0, 2/8.0), Vector2(3/4.0, 2/8.0), Vector2(2/4.0, 3/8.0), Vector2(3/4.0, 3/8.0)]),
|
||||||
|
PoolVector2Array([Vector2(3/4.0, 2/8.0), Vector2(4/4.0, 2/8.0), Vector2(3/4.0, 3/8.0), Vector2(4/4.0, 3/8.0)]),
|
||||||
|
PoolVector2Array([Vector2(0/4.0, 3/8.0), Vector2(1/4.0, 3/8.0), Vector2(0/4.0, 4/8.0), Vector2(1/4.0, 4/8.0)]),
|
||||||
|
PoolVector2Array([Vector2(1/4.0, 3/8.0), Vector2(2/4.0, 3/8.0), Vector2(1/4.0, 4/8.0), Vector2(2/4.0, 4/8.0)]),
|
||||||
|
PoolVector2Array([Vector2(2/4.0, 3/8.0), Vector2(3/4.0, 3/8.0), Vector2(2/4.0, 4/8.0), Vector2(3/4.0, 4/8.0)]),
|
||||||
|
PoolVector2Array([Vector2(3/4.0, 3/8.0), Vector2(4/4.0, 3/8.0), Vector2(3/4.0, 4/8.0), Vector2(4/4.0, 4/8.0)]),
|
||||||
|
PoolVector2Array([Vector2(0/4.0, 4/8.0), Vector2(1/4.0, 4/8.0), Vector2(0/4.0, 5/8.0), Vector2(1/4.0, 5/8.0)]),
|
||||||
|
PoolVector2Array([Vector2(1/4.0, 4/8.0), Vector2(2/4.0, 4/8.0), Vector2(1/4.0, 5/8.0), Vector2(2/4.0, 5/8.0)]),
|
||||||
|
PoolVector2Array([Vector2(2/4.0, 4/8.0), Vector2(3/4.0, 4/8.0), Vector2(2/4.0, 5/8.0), Vector2(3/4.0, 5/8.0)]),
|
||||||
|
PoolVector2Array([Vector2(3/4.0, 4/8.0), Vector2(4/4.0, 4/8.0), Vector2(3/4.0, 5/8.0), Vector2(4/4.0, 5/8.0)]),
|
||||||
|
PoolVector2Array([Vector2(0/4.0, 5/8.0), Vector2(1/4.0, 5/8.0), Vector2(0/4.0, 6/8.0), Vector2(1/4.0, 6/8.0)]),
|
||||||
|
PoolVector2Array([Vector2(1/4.0, 5/8.0), Vector2(2/4.0, 5/8.0), Vector2(1/4.0, 6/8.0), Vector2(2/4.0, 6/8.0)]),
|
||||||
|
PoolVector2Array([Vector2(2/4.0, 5/8.0), Vector2(3/4.0, 5/8.0), Vector2(2/4.0, 6/8.0), Vector2(3/4.0, 6/8.0)]),
|
||||||
|
PoolVector2Array([Vector2(3/4.0, 5/8.0), Vector2(4/4.0, 5/8.0), Vector2(3/4.0, 6/8.0), Vector2(4/4.0, 6/8.0)]),
|
||||||
|
PoolVector2Array([Vector2(0/4.0, 6/8.0), Vector2(1/4.0, 6/8.0), Vector2(0/4.0, 7/8.0), Vector2(1/4.0, 7/8.0)]),
|
||||||
|
PoolVector2Array([Vector2(1/4.0, 6/8.0), Vector2(2/4.0, 6/8.0), Vector2(1/4.0, 7/8.0), Vector2(2/4.0, 7/8.0)]),
|
||||||
|
PoolVector2Array([Vector2(2/4.0, 6/8.0), Vector2(3/4.0, 6/8.0), Vector2(2/4.0, 7/8.0), Vector2(3/4.0, 7/8.0)]),
|
||||||
|
PoolVector2Array([Vector2(3/4.0, 6/8.0), Vector2(4/4.0, 6/8.0), Vector2(3/4.0, 7/8.0), Vector2(4/4.0, 7/8.0)]),
|
||||||
|
PoolVector2Array([Vector2(0/4.0, 7/8.0), Vector2(1/4.0, 7/8.0), Vector2(0/4.0, 8/8.0), Vector2(1/4.0, 8/8.0)]),
|
||||||
|
PoolVector2Array([Vector2(1/4.0, 7/8.0), Vector2(2/4.0, 7/8.0), Vector2(1/4.0, 8/8.0), Vector2(2/4.0, 8/8.0)]),
|
||||||
|
PoolVector2Array([Vector2(2/4.0, 7/8.0), Vector2(3/4.0, 7/8.0), Vector2(2/4.0, 8/8.0), Vector2(3/4.0, 8/8.0)]),
|
||||||
|
PoolVector2Array([Vector2(3/4.0, 7/8.0), Vector2(4/4.0, 7/8.0), Vector2(3/4.0, 8/8.0), Vector2(4/4.0, 8/8.0)])
|
||||||
|
]
|
||||||
|
|
||||||
|
enum TextStyle {STRAIGHT=0, ARC=1, ARC_EARLY=2, ARC_LATE=3}
|
||||||
|
enum TextWord {NICE=0, OK=4, NG=8, PERFECT=12, GREAT=16, GOOD=20, ALMOST=24, MISS=28}
|
||||||
|
const TextJudgement := {
|
||||||
|
0: TextWord.PERFECT + TextStyle.ARC,
|
||||||
|
1: TextWord.GREAT + TextStyle.ARC_LATE,
|
||||||
|
-1: TextWord.GREAT + TextStyle.ARC_EARLY,
|
||||||
|
2: TextWord.GOOD + TextStyle.ARC_LATE,
|
||||||
|
-2: TextWord.GOOD + TextStyle.ARC_EARLY,
|
||||||
|
3: TextWord.ALMOST + TextStyle.ARC_LATE,
|
||||||
|
-3: TextWord.ALMOST + TextStyle.ARC_EARLY,
|
||||||
|
'MISS': TextWord.MISS + TextStyle.ARC
|
||||||
|
}
|
||||||
|
const TextJudgementStraight := {
|
||||||
|
0: TextWord.PERFECT + TextStyle.STRAIGHT,
|
||||||
|
1: TextWord.GREAT + TextStyle.STRAIGHT,
|
||||||
|
-1: TextWord.GREAT + TextStyle.STRAIGHT,
|
||||||
|
2: TextWord.GOOD + TextStyle.STRAIGHT,
|
||||||
|
-2: TextWord.GOOD + TextStyle.STRAIGHT,
|
||||||
|
3: TextWord.ALMOST + TextStyle.STRAIGHT,
|
||||||
|
-3: TextWord.ALMOST + TextStyle.STRAIGHT,
|
||||||
|
'MISS': TextWord.MISS + TextStyle.STRAIGHT
|
||||||
|
}
|
||||||
|
|
||||||
|
static func make_text_mesh(mesh: ArrayMesh, text_id: int, pos: Vector2, angle: float, alpha:=1.0, scale:=1.0):
|
||||||
|
var r := GameTheme.judge_text_size2 * scale
|
||||||
|
var vertex_array := PoolVector2Array([
|
||||||
|
pos+polar2cartesian(r, angle+GameTheme.JUDGE_TEXT_ANG2), # TODO: fix this UV/vertex order mess
|
||||||
|
pos+polar2cartesian(r, angle+GameTheme.JUDGE_TEXT_ANG1),
|
||||||
|
pos+polar2cartesian(r, angle+GameTheme.JUDGE_TEXT_ANG4),
|
||||||
|
pos+polar2cartesian(r, angle+GameTheme.JUDGE_TEXT_ANG3)
|
||||||
|
])
|
||||||
|
var arrays = []
|
||||||
|
arrays.resize(Mesh.ARRAY_MAX)
|
||||||
|
arrays[Mesh.ARRAY_VERTEX] = vertex_array
|
||||||
|
arrays[Mesh.ARRAY_TEX_UV] = text_UV_arrays[text_id]
|
||||||
|
arrays[Mesh.ARRAY_COLOR] = GameTheme.color_array_text(alpha)
|
||||||
|
mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLE_STRIP, arrays)
|
||||||
|
|
||||||
|
static func make_judgement_text(mesh: ArrayMesh, text_id: int, col: int, progress:=0.0):
|
||||||
|
make_text_mesh(mesh, text_id,
|
||||||
|
GameTheme.RADIAL_UNIT_VECTORS[col] * GameTheme.receptor_ring_radius * lerp(0.85, 0.85*0.75, progress),
|
||||||
|
GameTheme.RADIAL_COL_ANGLES[col]-PI/2.0, lerp(1.0, 0.0, progress), lerp(1.0, 0.75, progress)
|
||||||
|
)
|
||||||
|
|
|
@ -51,27 +51,6 @@ func load_image(name: String) -> ImageTexture: # Searches through all of the pa
|
||||||
var filename: return FileHelpers.load_image(filename)
|
var filename: return FileHelpers.load_image(filename)
|
||||||
|
|
||||||
|
|
||||||
func find_by_extensions(array, extensions=null) -> Dictionary:
|
|
||||||
# Both args can be Array or PoolStringArray
|
|
||||||
# If extensions omitted, do all extensions
|
|
||||||
var output = {}
|
|
||||||
if extensions:
|
|
||||||
for ext in extensions:
|
|
||||||
output[ext] = []
|
|
||||||
for filename in array:
|
|
||||||
for ext in extensions:
|
|
||||||
if filename.ends_with(ext):
|
|
||||||
output[ext].append(filename)
|
|
||||||
else:
|
|
||||||
for filename in array:
|
|
||||||
var ext = filename.rsplit('.', false, 1)[1]
|
|
||||||
if ext in output:
|
|
||||||
output[ext].append(filename)
|
|
||||||
else:
|
|
||||||
output[ext] = [filename]
|
|
||||||
return output
|
|
||||||
|
|
||||||
|
|
||||||
func scan_library() -> Dictionary:
|
func scan_library() -> Dictionary:
|
||||||
print('Scanning library')
|
print('Scanning library')
|
||||||
var song_defs = {}
|
var song_defs = {}
|
||||||
|
@ -131,7 +110,7 @@ func scan_library() -> Dictionary:
|
||||||
genres[song_defs[song_key]['genre']] = [song_key]
|
genres[song_defs[song_key]['genre']] = [song_key]
|
||||||
|
|
||||||
else:
|
else:
|
||||||
var files_by_ext = find_by_extensions(FileHelpers.directory_list(full_folder, false).files)
|
var files_by_ext = FileHelpers.find_by_extensions(FileHelpers.directory_list(full_folder, false).files)
|
||||||
if 'sm' in files_by_ext:
|
if 'sm' in files_by_ext:
|
||||||
var sm_filename = files_by_ext['sm'][0]
|
var sm_filename = files_by_ext['sm'][0]
|
||||||
print(sm_filename)
|
print(sm_filename)
|
||||||
|
|
|
@ -2,6 +2,7 @@ extends Node
|
||||||
|
|
||||||
const difficulty_translations = {'01': 'Z', '02': 'B', '03': 'A', '04': 'E', '05': 'M', '06': 'R', '10': '宴'} # A bit redundant now but might be useful later for other hacks
|
const difficulty_translations = {'01': 'Z', '02': 'B', '03': 'A', '04': 'E', '05': 'M', '06': 'R', '10': '宴'} # A bit redundant now but might be useful later for other hacks
|
||||||
|
|
||||||
|
|
||||||
class MultilangStr:
|
class MultilangStr:
|
||||||
# Automatically propogate higher langs to lower ones if lower ones are missing.
|
# Automatically propogate higher langs to lower ones if lower ones are missing.
|
||||||
# e.g. if we don't have a proper english title, return the transliterated one instead
|
# e.g. if we don't have a proper english title, return the transliterated one instead
|
||||||
|
@ -28,6 +29,7 @@ class MultilangStr:
|
||||||
func _to_string() -> String:
|
func _to_string() -> String:
|
||||||
return self[GameTheme.display_language]
|
return self[GameTheme.display_language]
|
||||||
|
|
||||||
|
|
||||||
class Song:
|
class Song:
|
||||||
var title: MultilangStr
|
var title: MultilangStr
|
||||||
var subtitle: MultilangStr
|
var subtitle: MultilangStr
|
||||||
|
@ -98,6 +100,7 @@ var genre_songs = [] # Dictionaries of key: Song
|
||||||
var tile_tex_cache = {} # We'll need some way of managing this later since holding all the tiles in memory might be expensive
|
var tile_tex_cache = {} # We'll need some way of managing this later since holding all the tiles in memory might be expensive
|
||||||
var charts_cache = {}
|
var charts_cache = {}
|
||||||
|
|
||||||
|
|
||||||
func add_song(key: String, data: Dictionary):
|
func add_song(key: String, data: Dictionary):
|
||||||
if not data.has('index'):
|
if not data.has('index'):
|
||||||
data['index'] = key
|
data['index'] = key
|
||||||
|
@ -109,6 +112,7 @@ func add_song(key: String, data: Dictionary):
|
||||||
genre_songs.append({})
|
genre_songs.append({})
|
||||||
genre_songs[genre_ids[song.genre]][key] = song
|
genre_songs[genre_ids[song.genre]][key] = song
|
||||||
|
|
||||||
|
|
||||||
func get_song_tile_texture(song_key):
|
func get_song_tile_texture(song_key):
|
||||||
if song_key in tile_tex_cache:
|
if song_key in tile_tex_cache:
|
||||||
return tile_tex_cache[song_key]
|
return tile_tex_cache[song_key]
|
||||||
|
@ -118,6 +122,7 @@ func get_song_tile_texture(song_key):
|
||||||
else:
|
else:
|
||||||
print_debug('Invalid song_key: ', song_key)
|
print_debug('Invalid song_key: ', song_key)
|
||||||
|
|
||||||
|
|
||||||
func get_song_charts(song_key):
|
func get_song_charts(song_key):
|
||||||
if song_key in charts_cache:
|
if song_key in charts_cache:
|
||||||
return charts_cache[song_key]
|
return charts_cache[song_key]
|
||||||
|
@ -143,5 +148,6 @@ func get_song_charts(song_key):
|
||||||
else:
|
else:
|
||||||
print_debug('Invalid song_key: ', song_key)
|
print_debug('Invalid song_key: ', song_key)
|
||||||
|
|
||||||
|
|
||||||
func initialize():
|
func initialize():
|
||||||
pass
|
pass
|
||||||
|
|
|
@ -13,6 +13,7 @@ const RELEASE_SCORE_TYPES := {
|
||||||
NOTE_ROLL: -NOTE_ROLL
|
NOTE_ROLL: -NOTE_ROLL
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class NoteBase extends Resource:
|
class NoteBase extends Resource:
|
||||||
var time_hit: float setget set_time_hit
|
var time_hit: float setget set_time_hit
|
||||||
var time_death: float
|
var time_death: float
|
||||||
|
@ -26,26 +27,31 @@ class NoteBase extends Resource:
|
||||||
time_hit = value
|
time_hit = value
|
||||||
time_death = time_hit + DEATH_DELAY
|
time_death = time_hit + DEATH_DELAY
|
||||||
|
|
||||||
|
|
||||||
class NoteHittableBase extends NoteBase:
|
class NoteHittableBase extends NoteBase:
|
||||||
const hittable := true
|
const hittable := true
|
||||||
|
|
||||||
|
|
||||||
class NoteTapBase extends NoteHittableBase:
|
class NoteTapBase extends NoteHittableBase:
|
||||||
func _init(time_hit: float, column: int, is_break:=false):
|
func _init(time_hit: float, column: int, is_break:=false):
|
||||||
self.time_hit = time_hit
|
self.time_hit = time_hit
|
||||||
self.column = column
|
self.column = column
|
||||||
self.is_break = is_break
|
self.is_break = is_break
|
||||||
|
|
||||||
|
|
||||||
class NoteTap extends NoteTapBase:
|
class NoteTap extends NoteTapBase:
|
||||||
var type := NOTE_TAP
|
var type := NOTE_TAP
|
||||||
func _init(time_hit: float, column: int, is_break:=false).(time_hit, column, is_break):
|
func _init(time_hit: float, column: int, is_break:=false).(time_hit, column, is_break):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class NoteStar extends NoteTapBase: # Fancy charts have naked slides which necessitates separation of Star and Slide :(
|
class NoteStar extends NoteTapBase: # Fancy charts have naked slides which necessitates separation of Star and Slide :(
|
||||||
var type := NOTE_STAR
|
var type := NOTE_STAR
|
||||||
var duration := 1.0 # This is required for the spin speed
|
var duration := 1.0 # This is required for the spin speed
|
||||||
func _init(time_hit: float, column: int, is_break:=false).(time_hit, column, is_break):
|
func _init(time_hit: float, column: int, is_break:=false).(time_hit, column, is_break):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class NoteHoldBase extends NoteHittableBase:
|
class NoteHoldBase extends NoteHittableBase:
|
||||||
var time_release: float setget set_time_release
|
var time_release: float setget set_time_release
|
||||||
var time_released := INF
|
var time_released := INF
|
||||||
|
@ -72,16 +78,19 @@ class NoteHoldBase extends NoteHittableBase:
|
||||||
time_release = time_hit + duration
|
time_release = time_hit + duration
|
||||||
time_death = time_release + DEATH_DELAY
|
time_death = time_release + DEATH_DELAY
|
||||||
|
|
||||||
|
|
||||||
class NoteHold extends NoteHoldBase:
|
class NoteHold extends NoteHoldBase:
|
||||||
var type := NOTE_HOLD
|
var type := NOTE_HOLD
|
||||||
func _init(time_hit: float, column: int, duration: float).(time_hit, column, duration):
|
func _init(time_hit: float, column: int, duration: float).(time_hit, column, duration):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class NoteRoll extends NoteHoldBase:
|
class NoteRoll extends NoteHoldBase:
|
||||||
var type := NOTE_ROLL
|
var type := NOTE_ROLL
|
||||||
func _init(time_hit: float, column: int, duration: float).(time_hit, column, duration):
|
func _init(time_hit: float, column: int, duration: float).(time_hit, column, duration):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class NoteSlide extends NoteBase: # Fancy charts have naked slides which necessitates separation of Star and Slide :(
|
class NoteSlide extends NoteBase: # Fancy charts have naked slides which necessitates separation of Star and Slide :(
|
||||||
const hittable := false
|
const hittable := false
|
||||||
var type := NOTE_SLIDE
|
var type := NOTE_SLIDE
|
||||||
|
@ -204,6 +213,7 @@ class NoteSlide extends NoteBase: # Fancy charts have naked slides which necess
|
||||||
return values.curve2d.get_baked_length()
|
return values.curve2d.get_baked_length()
|
||||||
return 0.0
|
return 0.0
|
||||||
|
|
||||||
|
|
||||||
static func copy_note(note: NoteBase):
|
static func copy_note(note: NoteBase):
|
||||||
# Honestly disappointed I couldn't find a better, more OOP solution for this.
|
# Honestly disappointed I couldn't find a better, more OOP solution for this.
|
||||||
var newnote: NoteBase
|
var newnote: NoteBase
|
||||||
|
@ -223,16 +233,20 @@ static func copy_note(note: NoteBase):
|
||||||
newnote.double_hit = note.double_hit
|
newnote.double_hit = note.double_hit
|
||||||
return newnote
|
return newnote
|
||||||
|
|
||||||
|
|
||||||
static func make_slide(time_hit: float, duration: float, column: int, column_release: int, slide_type:=SlideType.CHORD) -> NoteSlide:
|
static func make_slide(time_hit: float, duration: float, column: int, column_release: int, slide_type:=SlideType.CHORD) -> NoteSlide:
|
||||||
return NoteSlide.new(time_hit, column, duration, column_release, slide_type)
|
return NoteSlide.new(time_hit, column, duration, column_release, slide_type)
|
||||||
|
|
||||||
|
|
||||||
static func make_touch(time_hit: float, location: Vector2) -> Dictionary:
|
static func make_touch(time_hit: float, location: Vector2) -> Dictionary:
|
||||||
return {type=NOTE_TOUCH, time_hit=time_hit, time_death=time_hit+DEATH_DELAY, location=location, double_hit=false}
|
return {type=NOTE_TOUCH, time_hit=time_hit, time_death=time_hit+DEATH_DELAY, location=location, double_hit=false}
|
||||||
|
|
||||||
|
|
||||||
static func make_touch_hold(time_hit: float, duration: float, location: Vector2) -> Dictionary:
|
static func make_touch_hold(time_hit: float, duration: float, location: Vector2) -> Dictionary:
|
||||||
var time_release := time_hit + duration
|
var time_release := time_hit + duration
|
||||||
return {type=NOTE_TOUCH_HOLD, time_hit=time_hit, time_release=time_release, time_death=time_release+DEATH_DELAY, location=location, double_hit=false}
|
return {type=NOTE_TOUCH_HOLD, time_hit=time_hit, time_release=time_release, time_death=time_release+DEATH_DELAY, location=location, double_hit=false}
|
||||||
|
|
||||||
|
|
||||||
static func process_note_list(note_array: Array, check_doubles:=true):
|
static func process_note_list(note_array: Array, check_doubles:=true):
|
||||||
# Preprocess double hits, assign Slide IDs
|
# Preprocess double hits, assign Slide IDs
|
||||||
# If this were performance-critical, we'd single iterate it
|
# If this were performance-critical, we'd single iterate it
|
||||||
|
@ -260,11 +274,13 @@ static func process_note_list(note_array: Array, check_doubles:=true):
|
||||||
note_array[i].slide_id = slide_id
|
note_array[i].slide_id = slide_id
|
||||||
slide_id += 1
|
slide_id += 1
|
||||||
|
|
||||||
|
|
||||||
# These should probably get their own singleton later
|
# These should probably get their own singleton later
|
||||||
const ORBIT_INNER_RADIUS = sin(deg2rad(22.5)) # ~0.38
|
const ORBIT_INNER_RADIUS = sin(deg2rad(22.5)) # ~0.38
|
||||||
const ORBIT_KAPPA = (sqrt(2)-1) * 4.0 / 3.0 # This is the length of control points along a tangent to approximate a circle (multiply by desired radius)
|
const ORBIT_KAPPA = (sqrt(2)-1) * 4.0 / 3.0 # This is the length of control points along a tangent to approximate a circle (multiply by desired radius)
|
||||||
|
|
||||||
func curve2d_make_orbit(curve2d, rad_in, rad_out, ccw, rad_max_arc:=PI*0.25, kappa:=ORBIT_KAPPA, inner_radius:=ORBIT_INNER_RADIUS):
|
|
||||||
|
static func curve2d_make_orbit(curve2d, rad_in, rad_out, ccw, rad_max_arc:=PI*0.25, kappa:=ORBIT_KAPPA, inner_radius:=ORBIT_INNER_RADIUS):
|
||||||
var d_sign = -1 if ccw else 1
|
var d_sign = -1 if ccw else 1
|
||||||
var rad_2 = rad_in+PI*3/8*d_sign
|
var rad_2 = rad_in+PI*3/8*d_sign
|
||||||
var rad_2t = rad_2+PI*0.5*d_sign
|
var rad_2t = rad_2+PI*0.5*d_sign
|
||||||
|
@ -285,7 +301,8 @@ func curve2d_make_orbit(curve2d, rad_in, rad_out, ccw, rad_max_arc:=PI*0.25, kap
|
||||||
curve2d.add_point(polar2cartesian(inner_radius, rad_3), polar2cartesian(k, rad_3t))
|
curve2d.add_point(polar2cartesian(inner_radius, rad_3), polar2cartesian(k, rad_3t))
|
||||||
# curve2d.add_point(polar2cartesian(1.0, rad_out))
|
# curve2d.add_point(polar2cartesian(1.0, rad_out))
|
||||||
|
|
||||||
func curve2d_make_sideorbit(curve2d: Curve2D, rad_in: float, rad_out: float, ccw: bool, rad_max_arc:=PI*0.25, kappa:=ORBIT_KAPPA, inner_radius:=ORBIT_INNER_RADIUS):
|
|
||||||
|
static func curve2d_make_sideorbit(curve2d: Curve2D, rad_in: float, rad_out: float, ccw: bool, rad_max_arc:=PI*0.25, kappa:=ORBIT_KAPPA, inner_radius:=ORBIT_INNER_RADIUS):
|
||||||
var d_sign := -1 if ccw else 1
|
var d_sign := -1 if ccw else 1
|
||||||
var sideorbit_center := polar2cartesian(inner_radius, rad_in-PI*0.5*d_sign)
|
var sideorbit_center := polar2cartesian(inner_radius, rad_in-PI*0.5*d_sign)
|
||||||
var rad_orbit_in := rad_in + PI*0.5*d_sign
|
var rad_orbit_in := rad_in + PI*0.5*d_sign
|
||||||
|
|
Loading…
Reference in New Issue