From 8e5f51cce9aa358efcdcb1b4dfa428b53f649f84 Mon Sep 17 00:00:00 2001 From: Luke Hubmayer-Werner Date: Wed, 13 Nov 2019 00:48:06 +1030 Subject: [PATCH] Refactor, first attempt at slides. Slides currently have no texture and need deletion --- Bezel.gd | 8 +- FileLoader.gd | 57 +++++- lbl_main.gd => InputHandler.gd | 47 +++-- Note.gd | 1 + NoteHandler.gd | 340 +++++++++++++++++++-------------- Receptors.gd | 4 +- Rules.gd | 8 + main.gd | 12 +- main.tscn | 37 ++-- project.godot | 3 + shaders/notemesh.shader | 4 + shaders/slidetrail.shader | 14 ++ shaders/slidetrail.tres | 8 + theme.gd | 33 ++++ video.gd | 13 ++ 15 files changed, 392 insertions(+), 197 deletions(-) rename lbl_main.gd => InputHandler.gd (54%) create mode 100644 Rules.gd create mode 100644 shaders/slidetrail.shader create mode 100644 shaders/slidetrail.tres create mode 100644 theme.gd create mode 100644 video.gd diff --git a/Bezel.gd b/Bezel.gd index b26bff5..23de07e 100644 --- a/Bezel.gd +++ b/Bezel.gd @@ -10,18 +10,18 @@ func _draw(): draw_rect(Rect2(0, 0, x_margin, screen_height), bezel_color) draw_rect(Rect2(1920-x_margin, 0, x_margin, screen_height), bezel_color) - bezel_points = arc_point_list(screen_center, screen_height/2, 0, 90) + bezel_points = arc_point_list(screen_center, screen_height/2, 0, -90) bezel_points.push_back(Vector2(1920-x_margin, 0)) draw_polygon(bezel_points, bezel_colors) - bezel_points = arc_point_list(screen_center, screen_height/2, 90, 180) + bezel_points = arc_point_list(screen_center, screen_height/2, -90, -180) bezel_points.push_back(Vector2(x_margin, 0)) draw_polygon(bezel_points, bezel_colors) - bezel_points = arc_point_list(screen_center, screen_height/2, 180, 270) + bezel_points = arc_point_list(screen_center, screen_height/2, -180, -270) bezel_points.push_back(Vector2(x_margin, screen_height)) draw_polygon(bezel_points, bezel_colors) - bezel_points = arc_point_list(screen_center, screen_height/2, 270, 360) + bezel_points = arc_point_list(screen_center, screen_height/2, -270, -360) bezel_points.push_back(Vector2(1920-x_margin, screen_height)) draw_polygon(bezel_points, bezel_colors) diff --git a/FileLoader.gd b/FileLoader.gd index b0ea617..f13ae6e 100644 --- a/FileLoader.gd +++ b/FileLoader.gd @@ -6,6 +6,9 @@ class SRT: const ID_BREAK := 4 const ID_HOLD := 2 const ID_SLIDE_END := 128 + const ID3_SLIDE_CHORD := 0 # Straight line + const ID3_SLIDE_ARC_CW := 1 + const ID3_SLIDE_ARC_ACW := 2 static func load_file(filename): var file = File.new() @@ -16,6 +19,7 @@ class SRT: var notes = [] var beats_per_measure := 4 var length = file.get_len() + var slide_idxs = {} while (file.get_position() < (length-2)): var noteline = file.get_csv_line() var time_hit := (float(noteline[0]) + float(noteline[1])) * beats_per_measure @@ -31,16 +35,63 @@ class SRT: ID_BREAK: notes.push_back(Note.make_break(time_hit, column)) ID_SLIDE_END: - pass # id2 is slide ID + # id2 is slide ID + if id2 in slide_idxs: + notes[slide_idxs[id2]].column_release = column _: if id2 == 0: notes.push_back(Note.make_tap(time_hit, column)) else: # id2 is slide ID, id3 is slide pattern # In order to properly declare the slide, we need the paired endcap which may not be the next note - notes.push_back(Note.make_slide(time_hit, duration, column, column)) + slide_idxs[id2] = len(notes) + notes.push_back(Note.make_slide(time_hit, duration, column, -1)) + match id3: + ID3_SLIDE_CHORD: + notes[slide_idxs[id2]].slide_type = Note.SlideType.CHORD + ID3_SLIDE_ARC_CW: + notes[slide_idxs[id2]].slide_type = Note.SlideType.ARC_CW + ID3_SLIDE_ARC_ACW: + notes[slide_idxs[id2]].slide_type = Note.SlideType.ARC_ACW + _: + print("Unknown slide type: ", id3) return notes + class SRB: - func load_file(filename): + static func load_file(filename): pass + + +class Test: + static func stress_pattern(): + var notes = [] + for bar in range(8): + notes.push_back(Note.make_hold(bar*4, 1, bar%8)) + for i in range(1, 8): + notes.push_back(Note.make_tap(bar*4 + (i/2.0), (bar + i)%8)) + notes.push_back(Note.make_tap(bar*4 + (7/2.0), (bar + 3)%8)) + for bar in range(8, 16): + notes.push_back(Note.make_hold(bar*4, 2, bar%8)) + for i in range(1, 8): + notes.push_back(Note.make_tap(bar*4 + (i/2.0), (bar + i)%8)) + notes.push_back(Note.make_tap(bar*4 + ((i+0.5)/2.0), (bar + i)%8)) + notes.push_back(Note.make_slide(bar*4 + ((i+1)/2.0), 1, (bar + i)%8, 0)) + for bar in range(16, 24): + notes.push_back(Note.make_hold(bar*4, 2, bar%8)) + notes.push_back(Note.make_hold(bar*4, 1, (bar+1)%8)) + for i in range(2, 8): + notes.push_back(Note.make_tap(bar*4 + (i/2.0), (bar + i)%8)) + notes.push_back(Note.make_hold(bar*4 + ((i+1)/2.0), 0.5, (bar + i)%8)) + for bar in range(24, 32): + notes.push_back(Note.make_hold(bar*4, 1, bar%8)) + for i in range(1, 32): + notes.push_back(Note.make_tap(bar*4 + (i/8.0), (bar + i)%8)) + if (i%2) > 0: + notes.push_back(Note.make_tap(bar*4 + (i/8.0), (bar + i + 4)%8)) + for bar in range(32, 48): + notes.push_back(Note.make_hold(bar*4, 1, bar%8)) + for i in range(1, 32): + notes.push_back(Note.make_tap(bar*4 + (i/8.0), (bar + i)%8)) + notes.push_back(Note.make_tap(bar*4 + (i/8.0), (bar + i + 3)%8)) + return notes \ No newline at end of file diff --git a/lbl_main.gd b/InputHandler.gd similarity index 54% rename from lbl_main.gd rename to InputHandler.gd index 8628b9c..5cbf48e 100644 --- a/lbl_main.gd +++ b/InputHandler.gd @@ -1,50 +1,65 @@ extends Label -var touch_points = {} # array containing all points touched on the screen +var touch_points = {} # dict containing all points touched on the screen +var touch_positions = [] # array of above var fingers = 0 setget set_fingers # setter for show fingers number on screen var txt_ball = preload("res://assets/ball.png") # preload our ball texture var default_font = preload("res://assets/NotoSans.tres") # point to godot standard font + + +func _init(): + pass + func _ready(): set_process_unhandled_input(true) # process user input + set_fingers(0) + ########################################################################## # draw fingers points on screen func _draw(): - var touch_positions = PoolVector2Array() # draw points for i in touch_points: var point = touch_points[i] - if point.pressed: - touch_positions.push_back(point.position) - # DRAW POINTS ################################################ - draw_texture(txt_ball, point.position - Vector2(24, 24)) - draw_string(default_font, point.position - Vector2(24, 24), str(i)) - if len(touch_positions) > 1: - for i in range(len(touch_positions)-1): - # Draw line - draw_line(touch_positions[i], touch_positions[i+1], Color(1,1,1,1)) +# if point.pressed: + # DRAW POINTS ################################################ + draw_texture(txt_ball, point.position - Vector2(24, 24)) + draw_string(default_font, point.position - Vector2(24, 24), str(i)) +# if len(touch_positions) > 1: +# for i in range(len(touch_positions)-1): +# # Draw line +# draw_line(touch_positions[i], touch_positions[i+1], Color(1,1,1,1)) + +func update_data(): + touch_positions.clear() + for i in touch_points: + touch_positions.push_back(touch_points[i].position) set_fingers(len(touch_positions)) + update() + ########################################################################## func _input(event): + # Unfortunately event.device does NOT differentiate touchscreen inputs on X11, Godot v3.1.1 + # As such, we'll need to do some fancy mapping for multiple inputs if (event is InputEventScreenDrag): touch_points[event.index] = {pressed = true, position = event.position} - if (event is InputEventScreenTouch): + elif (event is InputEventScreenTouch): if event.pressed: if not touch_points.has(event.index): touch_points[event.index] = {} touch_points[event.index].position = event.position # update position - touch_points[event.index].pressed = event.pressed # update "pressed" flag +# touch_points[event.index].pressed = event.pressed # update "pressed" flag else: if touch_points.has(event.index): touch_points.erase(event.index) - update() + update_data() ########################################################################## # write how many fingers are tapping the screen func set_fingers(value): fingers = value if fingers > 0: - set_text(str(fingers)) + set_text("Fingers: " + str(fingers)) else: - set_text("0") \ No newline at end of file + set_text("Fingers: 0") \ No newline at end of file diff --git a/Note.gd b/Note.gd index e754064..2073daf 100644 --- a/Note.gd +++ b/Note.gd @@ -4,6 +4,7 @@ extends Node #class_name Note enum {NOTE_TAP, NOTE_HOLD, NOTE_SLIDE, NOTE_ARROW, NOTE_TOUCH, NOTE_TOUCH_HOLD} +enum SlideType {CHORD, ARC_CW, ARC_ACW} const DEATH_DELAY := 0.45 static func make_tap(time_hit: float, column: int) -> Dictionary: diff --git a/NoteHandler.gd b/NoteHandler.gd index 6060087..9ab9666 100644 --- a/NoteHandler.gd +++ b/NoteHandler.gd @@ -3,22 +3,35 @@ extends "res://main.gd" # This script will draw all note events. var tex := preload("res://assets/spritesheet-1024.png") +var tex_slide_arrow := preload("res://assets/slide-arrow-512.png") +var slide_trail_shadermaterial := preload("res://shaders/slidetrail.tres") -const first_column_angle_deg := -67.5 -var radial_col_angles := PoolRealArray() -var radial_unit_vectors := PoolVector2Array() +# Constants for the overall notefield +var RADIAL_COL_ANGLES := PoolRealArray() # ideally const +var RADIAL_UNIT_VECTORS := PoolVector2Array() # ideally const -const RING_LINE_SEGMENTS_PER_COLUMN := 12 -var RING_LINE_SEGMENTS_VECTORS := PoolVector2Array() +# ------------------------------------------------------ +# Ring segments is only for CPU drawing, superceded for now. +# ------------------------------------------------------ +#const RING_LINE_SEGMENTS_PER_COLUMN := 12 +#var RING_LINE_SEGMENTS_VECTORS := PoolVector2Array() +#const ring_segs := Rules.COLS * RING_LINE_SEGMENTS_PER_COLUMN +#const ring_seg_angle := 360.0/ring_segs +#var ring_line_segments_alphas = PoolRealArray() +#var ring_line_segments_widths = PoolRealArray() +func init_radial_values(): + for i in range(Rules.COLS): + var angle = deg2rad(fmod(Rules.FIRST_COLUMN_ANGLE_DEG + (i * Rules.COLS_ANGLE_DEG), 360.0)) + RADIAL_COL_ANGLES.push_back(angle) + RADIAL_UNIT_VECTORS.push_back(Vector2(cos(angle), sin(angle))) +# for i in range(ring_segs): +# var angle = deg2rad(Rules.FIRST_COLUMN_ANGLE_DEG + (i * ring_seg_angle)) +# RING_LINE_SEGMENTS_VECTORS.push_back(Vector2(cos(angle), sin(angle))) +# for i in range(ring_segs/4): +# var alpha := 1.0 - (i/float(ring_segs/4)) +# ring_line_segments_alphas.push_back(alpha) +# ring_line_segments_widths.push_back(lerp(alpha, 1.0, 0.5)) -const cols := 8 -const cols_angle := 360.0/cols -const ring_segs := cols * RING_LINE_SEGMENTS_PER_COLUMN -const ring_seg_angle := 360.0/ring_segs - -var sprite_size := 128 -var sprite_size2 := sprite_size/2 -const INNER_NOTE_CIRCLE_RATIO := 0.3 const SQRT2 := sqrt(2) const DEG45 := deg2rad(45.0) const DEG90 := deg2rad(90.0) @@ -27,10 +40,11 @@ const DEG135 := deg2rad(135.0) var time := 0.0 var t := 0.0 var bpm := 120.0 -var note_forecast_beats := 2.0 var active_notes := [] var all_notes := [] var next_note_to_load := 0 +var slide_trail_meshes := [] +var slide_trail_mesh_instances := [] # UV vertex arrays for our sprites # tap/star/arrow are 4-vertex 2-triangle simple squares @@ -42,8 +56,11 @@ const UV_ARRAY_HOLD := PoolVector2Array([ ]) const UV_ARRAY_STAR := PoolVector2Array([Vector2(0.5, 0), Vector2(1, 0), Vector2(0.5, 0.5), Vector2(1, 0.5)]) const UV_ARRAY_ARROW := PoolVector2Array([Vector2(0, 0), Vector2(0.5, 0), Vector2(0, 0.5), Vector2(0.5, 0.5)]) +# Slide trail arrow. Single tri. +const UV_ARRAY_SLIDE_ARROW := PoolVector2Array([Vector2(0, 0), Vector2(1, 0), Vector2(0, 1)]) +const UV_ARRAY_SLIDE_ARROW2 := PoolVector2Array([Vector2(1, 1), Vector2(0, 1), Vector2(1, 0)]) -# Normal vertex arrays for our sprites +# Normal vertex arrays for our sprites. Might be unnecessary? const DEFAULT_NORMAL := Vector3(0, 0, 1) var NORMAL_ARRAY_4 := PoolVector3Array([DEFAULT_NORMAL, DEFAULT_NORMAL, DEFAULT_NORMAL, DEFAULT_NORMAL]) var NORMAL_ARRAY_8 := PoolVector3Array([ @@ -51,90 +68,145 @@ var NORMAL_ARRAY_8 := PoolVector3Array([ DEFAULT_NORMAL, DEFAULT_NORMAL, DEFAULT_NORMAL, DEFAULT_NORMAL ]) -# Color definitions -const COLOR_TAP := Color(1, 0.15, 0.15, 1) -const COLOR_TAP2 := Color(0.75, 0.5, 0, 1) # High-score taps ("breaks" in maimai) -const COLOR_HOLD := Color(1, 0.15, 0.15, 1) -const COLOR_HOLD_HELD := Color(1, 1, 1, 1) -const COLOR_STAR := Color(0, 0, 1, 1) -const COLOR_DOUBLE := Color(1, 1, 0, 1) # When two (or more in master) hit events coincide - -var COLOR_ARRAY_TAP := PoolColorArray([COLOR_TAP, COLOR_TAP, COLOR_TAP, COLOR_TAP]) -var COLOR_ARRAY_TAP2 := PoolColorArray([COLOR_TAP2, COLOR_TAP2, COLOR_TAP2, COLOR_TAP2]) -var COLOR_ARRAY_HOLD := PoolColorArray([ - COLOR_HOLD, COLOR_HOLD, COLOR_HOLD, COLOR_HOLD, - COLOR_HOLD, COLOR_HOLD, COLOR_HOLD, COLOR_HOLD - ]) -var COLOR_ARRAY_HOLD_HELD := PoolColorArray([ - COLOR_HOLD_HELD, COLOR_HOLD_HELD, COLOR_HOLD_HELD, COLOR_HOLD_HELD, - COLOR_HOLD_HELD, COLOR_HOLD_HELD, COLOR_HOLD_HELD, COLOR_HOLD_HELD - ]) -var COLOR_ARRAY_STAR := PoolColorArray([COLOR_STAR, COLOR_STAR, COLOR_STAR, COLOR_STAR]) -var COLOR_ARRAY_DOUBLE_4 := PoolColorArray([COLOR_DOUBLE, COLOR_DOUBLE, COLOR_DOUBLE, COLOR_DOUBLE]) -var COLOR_ARRAY_DOUBLE_8 := PoolColorArray([ - COLOR_DOUBLE, COLOR_DOUBLE, COLOR_DOUBLE, COLOR_DOUBLE, - COLOR_DOUBLE, COLOR_DOUBLE, COLOR_DOUBLE, COLOR_DOUBLE - ]) - # Helper functions to generate meshes from vertex arrays -func make_tap_mesh(mesh: ArrayMesh, vertex_array, color_array = COLOR_ARRAY_TAP): +func make_tap_mesh(mesh: ArrayMesh, vertex_array, color_array = theme.COLOR_ARRAY_TAP): var arrays = [] arrays.resize(Mesh.ARRAY_MAX) arrays[Mesh.ARRAY_VERTEX] = vertex_array - arrays[Mesh.ARRAY_NORMAL] = NORMAL_ARRAY_4 +# arrays[Mesh.ARRAY_NORMAL] = NORMAL_ARRAY_4 arrays[Mesh.ARRAY_TEX_UV] = 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, vertex_array, color_array = COLOR_ARRAY_HOLD): +func make_hold_mesh(mesh: ArrayMesh, vertex_array, color_array = theme.COLOR_ARRAY_HOLD): var arrays = [] arrays.resize(Mesh.ARRAY_MAX) arrays[Mesh.ARRAY_VERTEX] = vertex_array - arrays[Mesh.ARRAY_NORMAL] = NORMAL_ARRAY_8 +# arrays[Mesh.ARRAY_NORMAL] = NORMAL_ARRAY_8 arrays[Mesh.ARRAY_TEX_UV] = 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, vertex_array, color_array = COLOR_ARRAY_STAR): +func make_star_mesh(mesh: ArrayMesh, vertex_array, color_array = theme.COLOR_ARRAY_STAR): var arrays = [] arrays.resize(Mesh.ARRAY_MAX) arrays[Mesh.ARRAY_VERTEX] = vertex_array - arrays[Mesh.ARRAY_NORMAL] = NORMAL_ARRAY_4 +# arrays[Mesh.ARRAY_NORMAL] = NORMAL_ARRAY_4 arrays[Mesh.ARRAY_TEX_UV] = 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 = COLOR_ARRAY_TAP): +func make_arrow_mesh(mesh: ArrayMesh, vertex_array, color_array = theme.COLOR_ARRAY_TAP): var arrays = [] arrays.resize(Mesh.ARRAY_MAX) arrays[Mesh.ARRAY_VERTEX] = vertex_array - arrays[Mesh.ARRAY_NORMAL] = NORMAL_ARRAY_4 +# arrays[Mesh.ARRAY_NORMAL] = NORMAL_ARRAY_4 arrays[Mesh.ARRAY_TEX_UV] = UV_ARRAY_ARROW arrays[Mesh.ARRAY_COLOR] = color_array mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLE_STRIP, arrays) -func make_tap_note(mesh: ArrayMesh, column: int, position: float, scale := 1.0, color_array := COLOR_ARRAY_TAP) -> ArrayMesh: - if position < INNER_NOTE_CIRCLE_RATIO: - scale *= position/INNER_NOTE_CIRCLE_RATIO - position = INNER_NOTE_CIRCLE_RATIO - var note_center = screen_center + (radial_unit_vectors[column] * position * receptor_ring_radius) - var dim = sprite_size2 * scale +const slide_arrows_per_unit_length := 10 +func make_slide_trail_mesh(note: Dictionary) -> 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() + # First we need to determine how many arrows to leave. + # Chord length is 2r*sin(theta/2) + # Arc length is r*theta (in rads) + # 18 for a 3chord in maimai + # 20 for a 4chord + # 6 per arc segment +1 for every receptor crossed over, ~7 per + var unit_length: float + var trail_length: int + match note.slide_type: + Note.SlideType.CHORD: + unit_length = 2*abs(sin(RADIAL_COL_ANGLES[note.column_release] - RADIAL_COL_ANGLES[note.column])) + Note.SlideType.ARC_CW: + unit_length = fposmod(RADIAL_COL_ANGLES[note.column_release] - RADIAL_COL_ANGLES[note.column], TAU) + Note.SlideType.ARC_ACW: + unit_length = fposmod(RADIAL_COL_ANGLES[note.column] - RADIAL_COL_ANGLES[note.column_release], TAU) + trail_length = int(floor(unit_length * slide_arrows_per_unit_length)) + vertices.resize(3*trail_length) +# uvs.resize(3*trail_length) + colors.resize(3*trail_length) + for i in trail_length: + uvs.append_array(UV_ARRAY_SLIDE_ARROW if i%2 else UV_ARRAY_SLIDE_ARROW2) + for j in 3: +# uvs[i*3+j] = UV_ARRAY_SLIDE_ARROW[j] if i%2 else UV_ARRAY_SLIDE_ARROW2[j] + colors[i*3+j] = Color(1.0, 1.0, 1.0, 1.0+float(i)) + + match note.slide_type: + Note.SlideType.CHORD: + var angle : float = RADIAL_UNIT_VECTORS[note.column].angle_to_point(RADIAL_UNIT_VECTORS[note.column_release]) + var start : Vector2 = RADIAL_UNIT_VECTORS[note.column] * theme.receptor_ring_radius + var end : Vector2 = RADIAL_UNIT_VECTORS[note.column_release] * theme.receptor_ring_radius + var uv1o : Vector2 = polar2cartesian(theme.sprite_size2, angle) + var uv2o : Vector2 = polar2cartesian(theme.sprite_size2, angle+PI/2.0) + var uv3o : Vector2 = polar2cartesian(theme.sprite_size2, angle-PI/2.0) + for i in trail_length: + var offset : Vector2 = lerp(start, end, (i+1)/float(trail_length)) + vertices[i*3] = offset + uv1o + vertices[i*3+1] = offset + uv2o + vertices[i*3+2] = offset + uv3o + Note.SlideType.ARC_CW: + var start_a : float = RADIAL_COL_ANGLES[note.column] + var end_a : float = RADIAL_COL_ANGLES[note.column_release] + if end_a < start_a: + end_a += TAU + for i in trail_length: + var circle_angle : float = lerp(start_a, end_a, (i+1)/float(trail_length)) + var angle : float = circle_angle + PI/2.0 + var offset : Vector2 = polar2cartesian(theme.receptor_ring_radius, circle_angle) + vertices[i*3] = offset + polar2cartesian(theme.sprite_size2, angle) + vertices[i*3+1] = offset + polar2cartesian(theme.sprite_size2, angle+PI/2.0) + vertices[i*3+2] = offset + polar2cartesian(theme.sprite_size2, angle-PI/2.0) + Note.SlideType.ARC_ACW: + var start_a : float = RADIAL_COL_ANGLES[note.column] + var end_a : float = RADIAL_COL_ANGLES[note.column_release] + if end_a > start_a: + end_a -= TAU + for i in trail_length: + var circle_angle : float = lerp(start_a, end_a, (i+1)/float(trail_length)) + var angle : float = circle_angle - PI/2.0 + var offset : Vector2 = polar2cartesian(theme.receptor_ring_radius, circle_angle) + vertices[i*3] = offset + polar2cartesian(theme.sprite_size2, angle) + vertices[i*3+1] = offset + polar2cartesian(theme.sprite_size2, angle+PI/2.0) + vertices[i*3+2] = offset + polar2cartesian(theme.sprite_size2, angle-PI/2.0) + + 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_tap_note(mesh: ArrayMesh, column: int, position: float, scale := 1.0, color_array := theme.COLOR_ARRAY_TAP) -> ArrayMesh: + if position < theme.INNER_NOTE_CIRCLE_RATIO: + scale *= position/theme.INNER_NOTE_CIRCLE_RATIO + position = theme.INNER_NOTE_CIRCLE_RATIO + var note_center = screen_center + (RADIAL_UNIT_VECTORS[column] * position * theme.receptor_ring_radius) + var dim = theme.sprite_size2 * scale var vertices = PoolVector2Array([note_center + Vector2(-dim, -dim), note_center + Vector2(dim, -dim), note_center + Vector2(-dim, dim), note_center + Vector2(dim, dim)]) make_tap_mesh(mesh, vertices, color_array) return mesh -func make_hold_note(mesh: ArrayMesh, column: int, position1: float, position2: float, scale := 1.0, color_array = COLOR_ARRAY_HOLD) -> ArrayMesh: - if position1 < INNER_NOTE_CIRCLE_RATIO: - scale *= position1/INNER_NOTE_CIRCLE_RATIO - position1 = INNER_NOTE_CIRCLE_RATIO - if position2 < INNER_NOTE_CIRCLE_RATIO: - position2 = INNER_NOTE_CIRCLE_RATIO - var note_center1 = screen_center + (radial_unit_vectors[column] * position1 * receptor_ring_radius) - var note_center2 = screen_center + (radial_unit_vectors[column] * position2 * receptor_ring_radius) - var dim = sprite_size2 * scale +func make_hold_note(mesh: ArrayMesh, column: int, position1: float, position2: float, scale := 1.0, color_array = theme.COLOR_ARRAY_HOLD) -> ArrayMesh: + if position1 < theme.INNER_NOTE_CIRCLE_RATIO: + scale *= position1/theme.INNER_NOTE_CIRCLE_RATIO + position1 = theme.INNER_NOTE_CIRCLE_RATIO + if position2 < theme.INNER_NOTE_CIRCLE_RATIO: + position2 = theme.INNER_NOTE_CIRCLE_RATIO + var note_center1 = screen_center + (RADIAL_UNIT_VECTORS[column] * position1 * theme.receptor_ring_radius) + var note_center2 = screen_center + (RADIAL_UNIT_VECTORS[column] * position2 * theme.receptor_ring_radius) + var dim = theme.sprite_size2 * scale var dim2 = dim * SQRT2 - var angle = radial_col_angles[column] + var angle = RADIAL_COL_ANGLES[column] var a1 = angle - DEG45 var a2 = angle + DEG45 var a3 = angle - DEG90 @@ -150,12 +222,12 @@ func make_hold_note(mesh: ArrayMesh, column: int, position1: float, position2: f make_hold_mesh(mesh, vertices, color_array) return mesh -func make_slide_note(mesh: ArrayMesh, column: int, position: float, scale := 1.0, color_array := COLOR_ARRAY_STAR) -> ArrayMesh: - if position < INNER_NOTE_CIRCLE_RATIO: - scale *= position/INNER_NOTE_CIRCLE_RATIO - position = INNER_NOTE_CIRCLE_RATIO - var note_center = screen_center + (radial_unit_vectors[column] * position * receptor_ring_radius) - var dim = sprite_size2 * scale * SQRT2 +func make_slide_note(mesh: ArrayMesh, column: int, position: float, scale := 1.0, color_array := theme.COLOR_ARRAY_STAR) -> ArrayMesh: + if position < theme.INNER_NOTE_CIRCLE_RATIO: + scale *= position/theme.INNER_NOTE_CIRCLE_RATIO + position = theme.INNER_NOTE_CIRCLE_RATIO + var note_center = screen_center + (RADIAL_UNIT_VECTORS[column] * position * theme.receptor_ring_radius) + var dim = theme.sprite_size2 * scale * SQRT2 var angle = deg2rad(fmod(t*270.0, 360.0)) var a1 = angle - DEG45 var a2 = angle + DEG45 @@ -168,28 +240,17 @@ func make_slide_note(mesh: ArrayMesh, column: int, position: float, scale := 1.0 make_star_mesh(mesh, vertices, color_array) return mesh -var ring_line_segments_alphas = PoolRealArray() -var ring_line_segments_widths = PoolRealArray() + +#---------------------------------------------------------------------------------------------------------------------------------------------- + func _init(): Input.set_mouse_mode(Input.MOUSE_MODE_HIDDEN) - for i in range(cols): - var angle = deg2rad(first_column_angle_deg + (i * cols_angle)) - radial_col_angles.push_back(angle) - radial_unit_vectors.push_back(Vector2(cos(angle), sin(angle))) - for i in range(ring_segs): - var angle = deg2rad(first_column_angle_deg + (i * ring_seg_angle)) - RING_LINE_SEGMENTS_VECTORS.push_back(Vector2(cos(angle), sin(angle))) - - for i in range(ring_segs/4): - var alpha := 1.0 - (i/float(ring_segs/4)) - ring_line_segments_alphas.push_back(alpha) - ring_line_segments_widths.push_back(lerp(alpha, 1.0, 0.5)) - + init_radial_values() func _draw(): var mesh := ArrayMesh.new() - var dots := PoolVector2Array() - var dots_dict := {} +# var dots := PoolVector2Array() +# var dots_dict := {} var noteline_data : Image = noteline_array_image.get_rect(Rect2(0, 0, 16, 16)) noteline_data.lock() @@ -197,31 +258,36 @@ func _draw(): var j := 0 for note in active_notes: - var position : float = (t+note_forecast_beats-note.time_hit)/note_forecast_beats - var note_center := screen_center + (radial_unit_vectors[note.column] * position * receptor_ring_radius) + var position : float = (t+theme.note_forecast_beats-note.time_hit)/theme.note_forecast_beats + var note_center := screen_center + (RADIAL_UNIT_VECTORS[note.column] * position * theme.receptor_ring_radius) # dots.push_back(note_center) # if not dots_dict.has(position): # dots_dict[position] = [] # dots_dict[position].push_back(note.column) - noteline_data.set_pixel(i%16, i/16, Color(position, note.column, radial_col_angles[note.column])) + noteline_data.set_pixel(i%16, i/16, Color(position, note.column, RADIAL_COL_ANGLES[note.column])) i += 1 match note.type: Note.NOTE_TAP: - var color = COLOR_ARRAY_DOUBLE_4 if note.double_hit else COLOR_ARRAY_TAP + var color = theme.COLOR_ARRAY_DOUBLE_4 if note.double_hit else theme.COLOR_ARRAY_TAP make_tap_note(mesh, note.column, position, 1, color) Note.NOTE_HOLD: - var color = COLOR_ARRAY_DOUBLE_8 if note.double_hit else COLOR_ARRAY_HOLD - var position_rel : float = (t+note_forecast_beats-note.time_release)/note_forecast_beats + var color = theme.COLOR_ARRAY_DOUBLE_8 if note.double_hit else theme.COLOR_ARRAY_HOLD + var position_rel : float = (t+theme.note_forecast_beats-note.time_release)/theme.note_forecast_beats if position_rel > 0: - var note_rel_center := screen_center + (radial_unit_vectors[note.column] * position_rel * receptor_ring_radius) + var note_rel_center := screen_center + (RADIAL_UNIT_VECTORS[note.column] * position_rel * theme.receptor_ring_radius) # dots.push_back(note_rel_center) - noteline_data.set_pixel(j%16, 15, Color(position_rel, note.column, radial_col_angles[note.column])) + noteline_data.set_pixel(j%16, 15, Color(position_rel, note.column, RADIAL_COL_ANGLES[note.column])) j += 1 - make_hold_note(mesh, note.column, position, position_rel, 1.0, COLOR_ARRAY_HOLD_HELD) + make_hold_note(mesh, note.column, position, position_rel, 1.0, theme.COLOR_ARRAY_HOLD_HELD) Note.NOTE_SLIDE: - var color = COLOR_ARRAY_DOUBLE_4 if note.double_hit else COLOR_ARRAY_STAR + var color = theme.COLOR_ARRAY_DOUBLE_4 if note.double_hit else theme.COLOR_ARRAY_STAR make_slide_note(mesh, note.column, position, 1.0, color) + noteline_data.unlock() + var noteline_data_tex = ImageTexture.new() + noteline_data_tex.create_from_image(noteline_data, 0) + $notelines.set_texture(noteline_data_tex) + # var dot_scale := 1.0 - abs(0.25-fmod(t+0.25, 0.5)) # var dot_inner := 6.0 * dot_scale # var dot_outer := 9.0 * dot_scale @@ -232,10 +298,6 @@ func _draw(): # var line_inner := 3.0 * dot_scale # var line_outer := 6.0 * dot_scale - noteline_data.unlock() - var noteline_data_tex = ImageTexture.new() - noteline_data_tex.create_from_image(noteline_data, 0) - $notelines.set_texture(noteline_data_tex) # for position in dots_dict: # for col in dots_dict[position]: @@ -243,17 +305,17 @@ func _draw(): # for i in range(ring_segs/4): # var alpha :float = ring_line_segments_alphas[i]*dot_scale # var width_scale : float = ring_line_segments_widths[i] -# draw_line(screen_center + RING_LINE_SEGMENTS_VECTORS[(c0+i)%ring_segs]*position*receptor_ring_radius, -# screen_center + RING_LINE_SEGMENTS_VECTORS[(c0+i+1)%ring_segs]*position*receptor_ring_radius, +# draw_line(screen_center + RING_LINE_SEGMENTS_VECTORS[(c0+i)%ring_segs]*position*theme.receptor_ring_radius, +# screen_center + RING_LINE_SEGMENTS_VECTORS[(c0+i+1)%ring_segs]*position*theme.receptor_ring_radius, # Color(1.0, 1.0, 0.65, alpha*0.8), line_inner*width_scale) -# draw_line(screen_center + RING_LINE_SEGMENTS_VECTORS[(c0+i)%ring_segs]*position*receptor_ring_radius, -# screen_center + RING_LINE_SEGMENTS_VECTORS[(c0+i+1)%ring_segs]*position*receptor_ring_radius, +# draw_line(screen_center + RING_LINE_SEGMENTS_VECTORS[(c0+i)%ring_segs]*position*theme.receptor_ring_radius, +# screen_center + RING_LINE_SEGMENTS_VECTORS[(c0+i+1)%ring_segs]*position*theme.receptor_ring_radius, # Color(1.0, 1.0, 0.65, alpha*0.2), line_outer*width_scale) -# draw_line(screen_center + RING_LINE_SEGMENTS_VECTORS[(c0-i)%ring_segs]*position*receptor_ring_radius, -# screen_center + RING_LINE_SEGMENTS_VECTORS[(c0-i-1)%ring_segs]*position*receptor_ring_radius, +# draw_line(screen_center + RING_LINE_SEGMENTS_VECTORS[(c0-i)%ring_segs]*position*theme.receptor_ring_radius, +# screen_center + RING_LINE_SEGMENTS_VECTORS[(c0-i-1)%ring_segs]*position*theme.receptor_ring_radius, # Color(1.0, 1.0, 0.65, alpha*0.8), line_inner*width_scale) -# draw_line(screen_center + RING_LINE_SEGMENTS_VECTORS[(c0-i)%ring_segs]*position*receptor_ring_radius, -# screen_center + RING_LINE_SEGMENTS_VECTORS[(c0-i-1)%ring_segs]*position*receptor_ring_radius, +# draw_line(screen_center + RING_LINE_SEGMENTS_VECTORS[(c0-i)%ring_segs]*position*theme.receptor_ring_radius, +# screen_center + RING_LINE_SEGMENTS_VECTORS[(c0-i-1)%ring_segs]*position*theme.receptor_ring_radius, # Color(1.0, 1.0, 0.65, alpha*0.2), line_outer*width_scale) # var alpha_array = PoolRealArray() @@ -270,11 +332,11 @@ func _draw(): # for i in range(ring_segs): # var alpha := min(alpha_array[i], 1.0)*dot_scale # var width_scale : float = lerp(min(alpha_array[i], 1.0), 1.0, 0.5) -# draw_line(screen_center + RING_LINE_SEGMENTS_VECTORS[i]*position*receptor_ring_radius, -# screen_center + RING_LINE_SEGMENTS_VECTORS[(i+1)%ring_segs]*position*receptor_ring_radius, +# draw_line(screen_center + RING_LINE_SEGMENTS_VECTORS[i]*position*theme.receptor_ring_radius, +# screen_center + RING_LINE_SEGMENTS_VECTORS[(i+1)%ring_segs]*position*theme.receptor_ring_radius, # Color(1.0, 1.0, 0.65, alpha*0.8), line_inner*width_scale) -# draw_line(screen_center + RING_LINE_SEGMENTS_VECTORS[i]*position*receptor_ring_radius, -# screen_center + RING_LINE_SEGMENTS_VECTORS[(i+1)%ring_segs]*position*receptor_ring_radius, +# draw_line(screen_center + RING_LINE_SEGMENTS_VECTORS[i]*position*theme.receptor_ring_radius, +# screen_center + RING_LINE_SEGMENTS_VECTORS[(i+1)%ring_segs]*position*theme.receptor_ring_radius, # Color(1.0, 1.0, 0.65, alpha*0.2), line_outer*width_scale) $meshinstance.set_mesh(mesh) @@ -291,13 +353,13 @@ func _ready(): all_notes = [] next_note_to_load = 0 - $meshinstance.material.set_shader_param("star_color", COLOR_STAR) - $meshinstance.material.set_shader_param("held_color", COLOR_HOLD_HELD) + $meshinstance.material.set_shader_param("star_color", theme.COLOR_STAR) + $meshinstance.material.set_shader_param("held_color", theme.COLOR_HOLD_HELD) $meshinstance.material.set_shader_param("bps", bpm/60.0) $meshinstance.material.set_shader_param("screen_size", get_viewport().get_size()) $meshinstance.set_texture(tex) - var rec_scale1 = (float(screen_height)/float(receptor_ring_radius))*0.5 + var rec_scale1 = (float(screen_height)/float(theme.receptor_ring_radius))*0.5 var uv_array_playfield := PoolVector2Array([Vector2(-1.0, -1.0)*rec_scale1, Vector2(-1.0, 1.0)*rec_scale1, Vector2(1.0, -1.0)*rec_scale1, Vector2(1.0, 1.0)*rec_scale1]) var vertex_array_playfield := PoolVector2Array([ Vector2(x_margin, screen_height), Vector2(x_margin, 0.0), @@ -317,37 +379,13 @@ func _ready(): # Format: first 15 rows are for hit events, last row is for releases only (no ring glow) all_notes = FileLoader.SRT.load_file("res://songs/199_cirno_master.srt") +# all_notes = FileLoader.Test.stress_pattern() bpm = 175.0 -# for bar in range(8): -# all_notes.push_back(Note.make_hold(bar*4, 1, bar%8)) -# for i in range(1, 8): -# all_notes.push_back(Note.make_tap(bar*4 + (i/2.0), (bar + i)%8)) -# all_notes.push_back(Note.make_tap(bar*4 + (7/2.0), (bar + 3)%8)) -# for bar in range(8, 16): -# all_notes.push_back(Note.make_hold(bar*4, 2, bar%8)) -# for i in range(1, 8): -# all_notes.push_back(Note.make_tap(bar*4 + (i/2.0), (bar + i)%8)) -# all_notes.push_back(Note.make_tap(bar*4 + ((i+0.5)/2.0), (bar + i)%8)) -# all_notes.push_back(Note.make_slide(bar*4 + ((i+1)/2.0), 1, (bar + i)%8, 0)) -# for bar in range(16, 24): -# all_notes.push_back(Note.make_hold(bar*4, 2, bar%8)) -# all_notes.push_back(Note.make_hold(bar*4, 1, (bar+1)%8)) -# for i in range(2, 8): -# all_notes.push_back(Note.make_tap(bar*4 + (i/2.0), (bar + i)%8)) -# all_notes.push_back(Note.make_hold(bar*4 + ((i+1)/2.0), 0.5, (bar + i)%8)) -# for bar in range(24, 32): -# all_notes.push_back(Note.make_hold(bar*4, 1, bar%8)) -# for i in range(1, 32): -# all_notes.push_back(Note.make_tap(bar*4 + (i/8.0), (bar + i)%8)) -# if (i%2) > 0: -# all_notes.push_back(Note.make_tap(bar*4 + (i/8.0), (bar + i + 4)%8)) -# for bar in range(32, 48): -# all_notes.push_back(Note.make_hold(bar*4, 1, bar%8)) -# for i in range(1, 32): -# all_notes.push_back(Note.make_tap(bar*4 + (i/8.0), (bar + i)%8)) -# all_notes.push_back(Note.make_tap(bar*4 + (i/8.0), (bar + i + 3)%8)) Note.process_doubles(all_notes) + for note in all_notes: + if note.type == Note.NOTE_SLIDE: + slide_trail_meshes.push_back(make_slide_trail_mesh(note)) func game_time(realtime: float) -> float: return time * bpm / 60.0 @@ -355,13 +393,12 @@ func game_time(realtime: float) -> float: # Called every frame. 'delta' is the elapsed time since the previous frame. func _process(delta): $meshinstance.material.set_shader_param("bps", bpm/60.0) - $meshinstance.material.set_shader_param("screen_size", get_viewport().get_size()) $notelines.material.set_shader_param("bps", bpm/60.0) var t_old := game_time(time) time += delta t = game_time(time) - if (t >= 0) and (t_old < 0): + if (t_old < 0) and (t >= 0): get_node("/root/main/video").play() # Clean out expired notes @@ -374,11 +411,20 @@ func _process(delta): if next_note_to_load >= len(all_notes): # All notes have been loaded, maybe do something break - if all_notes[next_note_to_load].time_hit > (t + note_forecast_beats): + if all_notes[next_note_to_load].time_hit > (t + theme.note_forecast_beats): # Next chronological note isn't ready to load yet break # Next chronological note is ready to load, load it active_notes.push_back(all_notes[next_note_to_load]) + if active_notes[-1].type == Note.NOTE_SLIDE: + slide_trail_mesh_instances.push_back(MeshInstance2D.new()) + slide_trail_mesh_instances[-1].set_mesh(slide_trail_meshes.pop_front()) + slide_trail_mesh_instances[-1].set_position(screen_center) + add_child(slide_trail_mesh_instances[-1]) + slide_trail_mesh_instances[-1].set_material(slide_trail_shadermaterial) + slide_trail_mesh_instances[-1].material.set_shader_param("trail_progress", 0.0) + slide_trail_mesh_instances[-1].set_texture(tex_slide_arrow) + next_note_to_load += 1 # DEBUG: Reset after all notes are done diff --git a/Receptors.gd b/Receptors.gd index 50e16e7..67f1d0b 100644 --- a/Receptors.gd +++ b/Receptors.gd @@ -8,8 +8,8 @@ var receptor_color := Color.blue func _draw(): # Receptor ring - var receptor_circle := arc_point_list(screen_center, receptor_ring_radius, 0.0, 360.0, 360) - var receptor_centers := arc_point_list(screen_center, receptor_ring_radius, 22.5, 360.0-22.5, 7) + var receptor_circle := arc_point_list(screen_center, theme.receptor_ring_radius, 0.0, 360.0, 360) + var receptor_centers := arc_point_list(screen_center, theme.receptor_ring_radius, Rules.FIRST_COLUMN_ANGLE_DEG, Rules.FIRST_COLUMN_ANGLE_DEG+360.0-Rules.COLS_ANGLE_DEG, Rules.COLS) # Shadows for i in range(len(receptor_circle)-1): diff --git a/Rules.gd b/Rules.gd new file mode 100644 index 0000000..373c59c --- /dev/null +++ b/Rules.gd @@ -0,0 +1,8 @@ +extends Node + +const COLS := 8 +const COLS_ANGLE_DEG := 360.0/COLS +const COLS_ANGLE_RAD := COLS_ANGLE_DEG * TAU/360.0 # deg2rad isn't a const function which is completely stupid +const FIRST_COLUMN_ANGLE_DEG := (COLS_ANGLE_DEG/2.0 if !(COLS%2) else 0.0) - 90.0 #-67.5 + +const COLS_TOUCH_ARC_DEG := 240.0/COLS diff --git a/main.gd b/main.gd index 924ed71..c2d0f68 100644 --- a/main.gd +++ b/main.gd @@ -1,18 +1,16 @@ extends Node2D -# Declare member variables here. Examples: +# member variables var screen_height := 1080 var x_margin := (1920 - screen_height)/2 var screen_center := Vector2(1920/2, screen_height/2) -var receptor_ring_radius := 460 - func arc_point_list(center: Vector2, radius: float, angle_from:=0.0, angle_to:=360.0, points:=90) -> PoolVector2Array: var point_list = PoolVector2Array() - for i in range(points + 1): - # positive Y going down makes for confusing angle plane. I prefer to work CCW as in mathematics. - var angle = -deg2rad(angle_from + i * (angle_to - angle_from) / points) - point_list.push_back(center + Vector2(cos(angle), sin(angle)) * radius) + for i in range(points): + var angle = deg2rad(angle_from + i * (angle_to - angle_from) / (points-1)) +# point_list.push_back(center + Vector2(cos(angle), sin(angle)) * radius) + point_list.push_back(center + polar2cartesian(radius, angle)) return point_list # Called when the node enters the scene tree for the first time. diff --git a/main.tscn b/main.tscn index 7cedffa..5317290 100644 --- a/main.tscn +++ b/main.tscn @@ -1,17 +1,18 @@ -[gd_scene load_steps=12 format=2] +[gd_scene load_steps=13 format=2] [ext_resource path="res://main.gd" type="Script" id=1] -[ext_resource path="res://songs/cirno_9th_anniversary_best_cpu1_3M.webm" type="VideoStream" id=2] -[ext_resource path="res://Receptors.gd" type="Script" id=3] -[ext_resource path="res://NoteHandler.gd" type="Script" id=4] -[ext_resource path="res://shaders/notelines.shader" type="Shader" id=5] -[ext_resource path="res://shaders/notemesh.shader" type="Shader" id=6] -[ext_resource path="res://Bezel.gd" type="Script" id=7] -[ext_resource path="res://assets/NotoSans.tres" type="DynamicFont" id=8] -[ext_resource path="res://lbl_main.gd" type="Script" id=9] +[ext_resource path="res://songs/cirno_1080p_rt_cpu1_3M.webm" type="VideoStream" id=2] +[ext_resource path="res://video.gd" type="Script" id=3] +[ext_resource path="res://Receptors.gd" type="Script" id=4] +[ext_resource path="res://NoteHandler.gd" type="Script" id=5] +[ext_resource path="res://shaders/notelines.shader" type="Shader" id=6] +[ext_resource path="res://shaders/notemesh.shader" type="Shader" id=7] +[ext_resource path="res://Bezel.gd" type="Script" id=8] +[ext_resource path="res://assets/NotoSans.tres" type="DynamicFont" id=9] +[ext_resource path="res://InputHandler.gd" type="Script" id=10] [sub_resource type="ShaderMaterial" id=1] -shader = ExtResource( 5 ) +shader = ExtResource( 6 ) shader_param/line_color = Plane( 0.8, 0.8, 1, 0.8 ) shader_param/line_color_double = Plane( 1, 1, 0.6, 0.9 ) shader_param/dot_color = Plane( 1, 1, 1, 0.8 ) @@ -23,7 +24,7 @@ shader_param/dot_fullbright_thickness = 0.013 shader_param/max_angle = 1.0708 [sub_resource type="ShaderMaterial" id=2] -shader = ExtResource( 6 ) +shader = ExtResource( 7 ) shader_param/bps = null shader_param/star_color = null shader_param/held_color = null @@ -33,7 +34,6 @@ shader_param/screen_size = null script = ExtResource( 1 ) [node name="video" type="VideoPlayer" parent="."] -anchor_right = 0.37 margin_left = 420.0 margin_right = 1500.0 margin_bottom = 1080.0 @@ -43,15 +43,16 @@ rect_pivot_offset = Vector2( 540, 540 ) mouse_filter = 2 stream = ExtResource( 2 ) volume_db = -11.6 +script = ExtResource( 3 ) __meta__ = { "_edit_use_anchors_": false } [node name="Receptors" type="Node2D" parent="."] -script = ExtResource( 3 ) +script = ExtResource( 4 ) [node name="NoteHandler" type="Node2D" parent="."] -script = ExtResource( 4 ) +script = ExtResource( 5 ) [node name="notelines" type="MeshInstance2D" parent="NoteHandler"] material = SubResource( 1 ) @@ -60,11 +61,11 @@ material = SubResource( 1 ) material = SubResource( 2 ) [node name="Bezel" type="Node2D" parent="."] -script = ExtResource( 7 ) +script = ExtResource( 8 ) -[node name="lbl_main" type="Label" parent="."] +[node name="InputHandler" type="Label" parent="."] margin_right = 424.0 margin_bottom = 216.0 -custom_fonts/font = ExtResource( 8 ) +custom_fonts/font = ExtResource( 9 ) text = "Fingers on the screen:" -script = ExtResource( 9 ) +script = ExtResource( 10 ) diff --git a/project.godot b/project.godot index 99d0bf3..8f7ab48 100644 --- a/project.godot +++ b/project.godot @@ -29,6 +29,8 @@ channel_disable_time=5.0 Note="*res://Note.gd" FileLoader="*res://FileLoader.gd" +Rules="*res://Rules.gd" +theme="*res://theme.gd" [debug] @@ -53,5 +55,6 @@ singletons=[ "res://addons/videodecoder.gdnlib" ] [rendering] +environment/default_clear_color=Color( 0, 0, 0, 1 ) quality/filters/msaa=1 environment/default_environment="res://default_env.tres" diff --git a/shaders/notemesh.shader b/shaders/notemesh.shader index 1cc9f41..941353c 100644 --- a/shaders/notemesh.shader +++ b/shaders/notemesh.shader @@ -11,6 +11,10 @@ uniform vec2 screen_size; void fragment() { vec4 sample = texture(TEXTURE, UV); + + //Not sure if this helps or hurts performance + //if (sample.a <= 0.0) discard; + float scale = sample.r; float dist = distance(FRAGCOORD.xy, screen_size/2.0); float dist_norm = dist*1.8 / screen_size.y; diff --git a/shaders/slidetrail.shader b/shaders/slidetrail.shader new file mode 100644 index 0000000..0fc4156 --- /dev/null +++ b/shaders/slidetrail.shader @@ -0,0 +1,14 @@ +shader_type canvas_item; +//render_mode blend_premul_alpha; + +uniform float trail_progress = 0.0; +uniform float bps = 1.0; + +// The idea here is to create a static mesh for each slide trail at scorefile load. +// Since we need to be able to hide parts of the trail that we have passed, +// we need to do that in this shader. +// We don't need vertex alpha normally so we can just set that to large whole numbers +// on each arrow (1.0, 2.0, 3.0, ... 50.0) and then use a uniform progress float. +void vertex() { + COLOR.a = clamp(COLOR.a-trail_progress, 0.0, 1.0); +} diff --git a/shaders/slidetrail.tres b/shaders/slidetrail.tres new file mode 100644 index 0000000..b57cfcb --- /dev/null +++ b/shaders/slidetrail.tres @@ -0,0 +1,8 @@ +[gd_resource type="ShaderMaterial" load_steps=2 format=2] + +[ext_resource path="res://shaders/slidetrail.shader" type="Shader" id=1] + +[resource] +shader = ExtResource( 1 ) +shader_param/trail_progress = 0.0 +shader_param/bps = 1.0 diff --git a/theme.gd b/theme.gd new file mode 100644 index 0000000..91c9a96 --- /dev/null +++ b/theme.gd @@ -0,0 +1,33 @@ +extends Node + +var receptor_ring_radius := 460 +var note_forecast_beats := 2.0 +const INNER_NOTE_CIRCLE_RATIO := 0.3 + +var sprite_size := 128 +var sprite_size2 := sprite_size/2 + +# Color definitions +const COLOR_TAP := Color(1, 0.15, 0.15, 1) +const COLOR_TAP2 := Color(0.75, 0.5, 0, 1) # High-score taps ("breaks" in maimai) +const COLOR_HOLD := Color(1, 0.15, 0.15, 1) +const COLOR_HOLD_HELD := Color(1, 1, 1, 1) +const COLOR_STAR := Color(0, 0, 1, 1) +const COLOR_DOUBLE := Color(1, 1, 0, 1) # When two (or more in master) hit events coincide + +var COLOR_ARRAY_TAP := PoolColorArray([COLOR_TAP, COLOR_TAP, COLOR_TAP, COLOR_TAP]) +var COLOR_ARRAY_TAP2 := PoolColorArray([COLOR_TAP2, COLOR_TAP2, COLOR_TAP2, COLOR_TAP2]) +var COLOR_ARRAY_HOLD := PoolColorArray([ + COLOR_HOLD, COLOR_HOLD, COLOR_HOLD, COLOR_HOLD, + COLOR_HOLD, COLOR_HOLD, COLOR_HOLD, COLOR_HOLD + ]) +var COLOR_ARRAY_HOLD_HELD := PoolColorArray([ + COLOR_HOLD_HELD, COLOR_HOLD_HELD, COLOR_HOLD_HELD, COLOR_HOLD_HELD, + COLOR_HOLD_HELD, COLOR_HOLD_HELD, COLOR_HOLD_HELD, COLOR_HOLD_HELD + ]) +var COLOR_ARRAY_STAR := PoolColorArray([COLOR_STAR, COLOR_STAR, COLOR_STAR, COLOR_STAR]) +var COLOR_ARRAY_DOUBLE_4 := PoolColorArray([COLOR_DOUBLE, COLOR_DOUBLE, COLOR_DOUBLE, COLOR_DOUBLE]) +var COLOR_ARRAY_DOUBLE_8 := PoolColorArray([ + COLOR_DOUBLE, COLOR_DOUBLE, COLOR_DOUBLE, COLOR_DOUBLE, + COLOR_DOUBLE, COLOR_DOUBLE, COLOR_DOUBLE, COLOR_DOUBLE + ]) diff --git a/video.gd b/video.gd new file mode 100644 index 0000000..e1e68b7 --- /dev/null +++ b/video.gd @@ -0,0 +1,13 @@ +extends VideoPlayer + +func _ready(): + pass + # I need to put videoplayer resizing logic somewhere else, this is placeholder + update_aspect_ratio(1440.0/1080.0) + +func update_aspect_ratio(ratio: float): + # e.g. for a 1920x1080 video you'd call update_aspect_ratio(1920.0/1080.0) + # e.g. for a 1440x1080 video you'd call update_aspect_ratio(1440.0/1080.0) + var height = 1080/ratio + margin_top = (1080 - height)/2.0 + margin_bottom = margin_top + height