RhythmGame/scripts/RadialMeshTools.gd

204 lines
11 KiB
GDScript3
Raw Normal View History

2021-11-27 23:22:42 +10:30
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)
)