Project files (no assets/song files)
This commit is contained in:
commit
8aa139646e
|
@ -0,0 +1,3 @@
|
||||||
|
source_md5="32472f2c19639a6447e7a0cff0b3aa9c"
|
||||||
|
dest_md5="ebce88a89ad9ff81c75951272911a33b"
|
||||||
|
|
Binary file not shown.
|
@ -0,0 +1,3 @@
|
||||||
|
source_md5="8dd9ff1eebf38898a54579d8c01b0a88"
|
||||||
|
dest_md5="da70afec3c66d4e872db67f808e12edb"
|
||||||
|
|
Binary file not shown.
|
@ -0,0 +1,3 @@
|
||||||
|
source_md5="3573d33760ed5048bff51bb785b1356b"
|
||||||
|
dest_md5="67ba11a5d30fd946675bfac25802bd94"
|
||||||
|
|
Binary file not shown.
|
@ -0,0 +1,3 @@
|
||||||
|
source_md5="3573d33760ed5048bff51bb785b1356b"
|
||||||
|
dest_md5="67ba11a5d30fd946675bfac25802bd94"
|
||||||
|
|
Binary file not shown.
|
@ -0,0 +1,3 @@
|
||||||
|
source_md5="e00f36b6f082fa699e2b7a926ab510e1"
|
||||||
|
dest_md5="a5c53f0952668b57c4b2a19a4373e232"
|
||||||
|
|
Binary file not shown.
|
@ -0,0 +1,3 @@
|
||||||
|
source_md5="e00f36b6f082fa699e2b7a926ab510e1"
|
||||||
|
dest_md5="a5c53f0952668b57c4b2a19a4373e232"
|
||||||
|
|
Binary file not shown.
|
@ -0,0 +1,3 @@
|
||||||
|
source_md5="4357e1186d4059f7d05835592f280597"
|
||||||
|
dest_md5="18b79f19f1bbd977bc9f61b8d7bfb093"
|
||||||
|
|
Binary file not shown.
|
@ -0,0 +1,3 @@
|
||||||
|
source_md5="23af4b0ba3693869627fea51d208c99f"
|
||||||
|
dest_md5="f3e47875966345065cd62fcde1255e7b"
|
||||||
|
|
Binary file not shown.
|
@ -0,0 +1,3 @@
|
||||||
|
source_md5="23af4b0ba3693869627fea51d208c99f"
|
||||||
|
dest_md5="f3e47875966345065cd62fcde1255e7b"
|
||||||
|
|
Binary file not shown.
|
@ -0,0 +1,27 @@
|
||||||
|
extends "res://main.gd"
|
||||||
|
|
||||||
|
# Draw the bezel for radial gamemode
|
||||||
|
|
||||||
|
func _draw():
|
||||||
|
var bezel_color := Color.black
|
||||||
|
var bezel_colors := PoolColorArray([bezel_color])
|
||||||
|
var bezel_points: PoolVector2Array
|
||||||
|
|
||||||
|
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.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.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.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.push_back(Vector2(1920-x_margin, screen_height))
|
||||||
|
draw_polygon(bezel_points, bezel_colors)
|
|
@ -0,0 +1,46 @@
|
||||||
|
#extends Object
|
||||||
|
extends Node
|
||||||
|
|
||||||
|
class SRT:
|
||||||
|
const TAP_DURATION := 0.062500
|
||||||
|
const ID_BREAK := 4
|
||||||
|
const ID_HOLD := 2
|
||||||
|
const ID_SLIDE_END := 128
|
||||||
|
|
||||||
|
static func load_file(filename):
|
||||||
|
var file = File.new()
|
||||||
|
var err = file.open(filename, File.READ)
|
||||||
|
if err != OK:
|
||||||
|
print(err)
|
||||||
|
return err
|
||||||
|
var notes = []
|
||||||
|
var beats_per_measure := 4
|
||||||
|
var length = file.get_len()
|
||||||
|
while (file.get_position() < (length-2)):
|
||||||
|
var noteline = file.get_csv_line()
|
||||||
|
var time_hit := (float(noteline[0]) + float(noteline[1])) * beats_per_measure
|
||||||
|
var duration := float(noteline[2]) * beats_per_measure
|
||||||
|
var column := int(noteline[3])
|
||||||
|
var id := int(noteline[4])
|
||||||
|
var id2 := int(noteline[5])
|
||||||
|
var id3 := int(noteline[6])
|
||||||
|
|
||||||
|
match id:
|
||||||
|
ID_HOLD:
|
||||||
|
notes.push_back(Note.make_hold(time_hit, duration, column))
|
||||||
|
ID_BREAK:
|
||||||
|
notes.push_back(Note.make_break(time_hit, column))
|
||||||
|
ID_SLIDE_END:
|
||||||
|
pass # id2 is slide ID
|
||||||
|
_:
|
||||||
|
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))
|
||||||
|
return notes
|
||||||
|
|
||||||
|
class SRB:
|
||||||
|
func load_file(filename):
|
||||||
|
pass
|
|
@ -0,0 +1,37 @@
|
||||||
|
#extends Object
|
||||||
|
extends Node
|
||||||
|
|
||||||
|
#class_name Note
|
||||||
|
|
||||||
|
enum {NOTE_TAP, NOTE_HOLD, NOTE_SLIDE, NOTE_ARROW, NOTE_TOUCH, NOTE_TOUCH_HOLD}
|
||||||
|
const DEATH_DELAY := 0.45
|
||||||
|
|
||||||
|
static func make_tap(time_hit: float, column: int) -> Dictionary:
|
||||||
|
return {type=NOTE_TAP, time_hit=time_hit, time_death=time_hit+DEATH_DELAY, column=column, double_hit=false}
|
||||||
|
|
||||||
|
static func make_break(time_hit: float, column: int) -> Dictionary:
|
||||||
|
return {type=NOTE_TAP, time_hit=time_hit, time_death=time_hit+DEATH_DELAY, column=column, double_hit=false}
|
||||||
|
|
||||||
|
static func make_hold(time_hit: float, duration: float, column: int) -> Dictionary:
|
||||||
|
var time_release := time_hit + duration
|
||||||
|
return {type=NOTE_HOLD, time_hit=time_hit, time_release=time_release, time_death=time_release+DEATH_DELAY, column=column, double_hit=false}
|
||||||
|
|
||||||
|
static func make_slide(time_hit: float, duration: float, column: int, column_release: int) -> Dictionary:
|
||||||
|
var time_release := time_hit + duration
|
||||||
|
return {type=NOTE_SLIDE, time_hit=time_hit, time_release=time_release,
|
||||||
|
time_death=time_release+DEATH_DELAY, column=column, column_release=column_release, double_hit=false}
|
||||||
|
|
||||||
|
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}
|
||||||
|
|
||||||
|
static func make_touch_hold(time_hit: float, duration: float, location: Vector2) -> Dictionary:
|
||||||
|
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}
|
||||||
|
|
||||||
|
static func process_doubles(note_array: Array):
|
||||||
|
# Preprocess double hits
|
||||||
|
if len(note_array):
|
||||||
|
for i in range(len(note_array)-1):
|
||||||
|
if note_array[i].time_hit == note_array[i+1].time_hit:
|
||||||
|
note_array[i].double_hit = true
|
||||||
|
note_array[i+1].double_hit = true
|
|
@ -0,0 +1,393 @@
|
||||||
|
extends "res://main.gd"
|
||||||
|
|
||||||
|
# This script will draw all note events.
|
||||||
|
|
||||||
|
var tex := preload("res://assets/spritesheet-1024.png")
|
||||||
|
|
||||||
|
const first_column_angle_deg := -67.5
|
||||||
|
var radial_col_angles := PoolRealArray()
|
||||||
|
var radial_unit_vectors := PoolVector2Array()
|
||||||
|
|
||||||
|
const RING_LINE_SEGMENTS_PER_COLUMN := 12
|
||||||
|
var RING_LINE_SEGMENTS_VECTORS := PoolVector2Array()
|
||||||
|
|
||||||
|
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)
|
||||||
|
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
|
||||||
|
|
||||||
|
# UV vertex arrays for our sprites
|
||||||
|
# tap/star/arrow are 4-vertex 2-triangle simple squares
|
||||||
|
# hold is 8-vertex 6-triangle to enable stretching in the middle
|
||||||
|
const UV_ARRAY_TAP := PoolVector2Array([Vector2(0, 0.5), Vector2(0.5, 0.5), Vector2(0, 1), Vector2(0.5, 1)])
|
||||||
|
const UV_ARRAY_HOLD := PoolVector2Array([
|
||||||
|
Vector2(0.5, 0.5), Vector2(1, 0.5), Vector2(0.5, 0.75), Vector2(1, 0.75),
|
||||||
|
Vector2(0.5, 0.75), Vector2(1, 0.75), Vector2(0.5, 1), Vector2(1, 1)
|
||||||
|
])
|
||||||
|
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)])
|
||||||
|
|
||||||
|
# Normal vertex arrays for our sprites
|
||||||
|
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([
|
||||||
|
DEFAULT_NORMAL, DEFAULT_NORMAL, DEFAULT_NORMAL, DEFAULT_NORMAL,
|
||||||
|
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):
|
||||||
|
var arrays = []
|
||||||
|
arrays.resize(Mesh.ARRAY_MAX)
|
||||||
|
arrays[Mesh.ARRAY_VERTEX] = vertex_array
|
||||||
|
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):
|
||||||
|
var arrays = []
|
||||||
|
arrays.resize(Mesh.ARRAY_MAX)
|
||||||
|
arrays[Mesh.ARRAY_VERTEX] = vertex_array
|
||||||
|
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):
|
||||||
|
var arrays = []
|
||||||
|
arrays.resize(Mesh.ARRAY_MAX)
|
||||||
|
arrays[Mesh.ARRAY_VERTEX] = vertex_array
|
||||||
|
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):
|
||||||
|
var arrays = []
|
||||||
|
arrays.resize(Mesh.ARRAY_MAX)
|
||||||
|
arrays[Mesh.ARRAY_VERTEX] = vertex_array
|
||||||
|
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
|
||||||
|
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
|
||||||
|
var dim2 = dim * SQRT2
|
||||||
|
var angle = radial_col_angles[column]
|
||||||
|
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 vertices = PoolVector2Array([
|
||||||
|
note_center1 + dim2*Vector2(cos(a1), sin(a1)), note_center1 + dim2*Vector2(cos(a2), sin(a2)),
|
||||||
|
note_center1 + dim*Vector2(cos(a3), sin(a3)), note_center1 + dim*Vector2(cos(a4), sin(a4)),
|
||||||
|
note_center2 + dim*Vector2(cos(a3), sin(a3)), note_center2 + dim*Vector2(cos(a4), sin(a4)),
|
||||||
|
note_center2 + dim2*Vector2(cos(a5), sin(a5)), note_center2 + dim2*Vector2(cos(a6), sin(a6))
|
||||||
|
])
|
||||||
|
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
|
||||||
|
var angle = deg2rad(fmod(t*270.0, 360.0))
|
||||||
|
var a1 = angle - DEG45
|
||||||
|
var a2 = angle + DEG45
|
||||||
|
var a3 = angle - DEG135
|
||||||
|
var a4 = angle + DEG135
|
||||||
|
var vertices = PoolVector2Array([
|
||||||
|
note_center + dim*Vector2(cos(a1), sin(a1)), note_center + dim*Vector2(cos(a2), sin(a2)),
|
||||||
|
note_center + dim*Vector2(cos(a3), sin(a3)), note_center + dim*Vector2(cos(a4), sin(a4))
|
||||||
|
])
|
||||||
|
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))
|
||||||
|
|
||||||
|
|
||||||
|
func _draw():
|
||||||
|
var mesh := ArrayMesh.new()
|
||||||
|
var dots := PoolVector2Array()
|
||||||
|
var dots_dict := {}
|
||||||
|
|
||||||
|
var noteline_data : Image = noteline_array_image.get_rect(Rect2(0, 0, 16, 16))
|
||||||
|
noteline_data.lock()
|
||||||
|
var i := 0
|
||||||
|
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)
|
||||||
|
# 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]))
|
||||||
|
i += 1
|
||||||
|
match note.type:
|
||||||
|
Note.NOTE_TAP:
|
||||||
|
var color = COLOR_ARRAY_DOUBLE_4 if note.double_hit else 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
|
||||||
|
if position_rel > 0:
|
||||||
|
var note_rel_center := screen_center + (radial_unit_vectors[note.column] * position_rel * 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]))
|
||||||
|
j += 1
|
||||||
|
make_hold_note(mesh, note.column, position, position_rel, 1.0, COLOR_ARRAY_HOLD_HELD)
|
||||||
|
Note.NOTE_SLIDE:
|
||||||
|
var color = COLOR_ARRAY_DOUBLE_4 if note.double_hit else COLOR_ARRAY_STAR
|
||||||
|
make_slide_note(mesh, note.column, position, 1.0, color)
|
||||||
|
|
||||||
|
# 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
|
||||||
|
|
||||||
|
# for dot in dots:
|
||||||
|
# draw_circle(dot, dot_inner, Color(1.0, 1.0, 1.0, 0.60))
|
||||||
|
# draw_circle(dot, dot_outer, Color(1.0, 1.0, 1.0, 0.20))
|
||||||
|
|
||||||
|
# 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]:
|
||||||
|
# var c0 = col * RING_LINE_SEGMENTS_PER_COLUMN
|
||||||
|
# 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,
|
||||||
|
# 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,
|
||||||
|
# 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,
|
||||||
|
# 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,
|
||||||
|
# Color(1.0, 1.0, 0.65, alpha*0.2), line_outer*width_scale)
|
||||||
|
|
||||||
|
# var alpha_array = PoolRealArray()
|
||||||
|
# alpha_array.resize(ring_segs)
|
||||||
|
# for i in range(ring_segs):
|
||||||
|
# alpha_array[i] = 0.0
|
||||||
|
# for col in dots_dict[position]:
|
||||||
|
# var origin : int = col*RING_LINE_SEGMENTS_PER_COLUMN
|
||||||
|
# var affected_segs := ring_segs/4
|
||||||
|
# alpha_array[origin] = 1.0
|
||||||
|
# for i in range(affected_segs):
|
||||||
|
# alpha_array[(origin+i)%ring_segs] += 1.0 - i/float(affected_segs)
|
||||||
|
# alpha_array[(origin-i)%ring_segs] += 1.0 - i/float(affected_segs)
|
||||||
|
# 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,
|
||||||
|
# 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,
|
||||||
|
# Color(1.0, 1.0, 0.65, alpha*0.2), line_outer*width_scale)
|
||||||
|
|
||||||
|
$meshinstance.set_mesh(mesh)
|
||||||
|
# draw_mesh(mesh, tex)
|
||||||
|
|
||||||
|
var noteline_array_image := Image.new()
|
||||||
|
|
||||||
|
# Called when the node enters the scene tree for the first time.
|
||||||
|
func _ready():
|
||||||
|
t = 0.0
|
||||||
|
time = -2.0
|
||||||
|
bpm = 120.0
|
||||||
|
active_notes = []
|
||||||
|
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("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 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),
|
||||||
|
Vector2(x_margin+screen_height, screen_height), Vector2(x_margin+screen_height, 0.0)])
|
||||||
|
var mesh_playfield := ArrayMesh.new()
|
||||||
|
var arrays = []
|
||||||
|
arrays.resize(Mesh.ARRAY_MAX)
|
||||||
|
arrays[Mesh.ARRAY_VERTEX] = vertex_array_playfield
|
||||||
|
arrays[Mesh.ARRAY_NORMAL] = NORMAL_ARRAY_4
|
||||||
|
arrays[Mesh.ARRAY_TEX_UV] = uv_array_playfield
|
||||||
|
mesh_playfield.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLE_STRIP, arrays)
|
||||||
|
$notelines.set_mesh(mesh_playfield)
|
||||||
|
$notelines.material.set_shader_param("bps", bpm/60.0)
|
||||||
|
|
||||||
|
noteline_array_image.create(16, 16, false, Image.FORMAT_RGBF)
|
||||||
|
noteline_array_image.fill(Color(0.0, 0.0, 0.0))
|
||||||
|
# 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")
|
||||||
|
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)
|
||||||
|
|
||||||
|
func game_time(realtime: float) -> float:
|
||||||
|
return time * bpm / 60.0
|
||||||
|
|
||||||
|
# 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):
|
||||||
|
get_node("/root/main/video").play()
|
||||||
|
|
||||||
|
# Clean out expired notes
|
||||||
|
for i in range(len(active_notes)-1, -1, -1):
|
||||||
|
if active_notes[i].time_death < t:
|
||||||
|
active_notes.remove(i)
|
||||||
|
|
||||||
|
# Add new notes as necessary
|
||||||
|
while true:
|
||||||
|
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):
|
||||||
|
# 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])
|
||||||
|
next_note_to_load += 1
|
||||||
|
|
||||||
|
# DEBUG: Reset after all notes are done
|
||||||
|
if (len(active_notes) < 1) and (next_note_to_load >= len(all_notes)) and (time > 10.0):
|
||||||
|
time = fmod(time, 1.0) - 2.0
|
||||||
|
next_note_to_load = 0
|
||||||
|
# get_node("/root/main/video").set_stream_position(0.0)
|
||||||
|
# get_node("/root/main/video").play()
|
||||||
|
|
||||||
|
# Redraw
|
||||||
|
$meshinstance.material.set_shader_param("screen_size", get_viewport().get_size())
|
||||||
|
update()
|
|
@ -0,0 +1,24 @@
|
||||||
|
extends "res://main.gd"
|
||||||
|
|
||||||
|
var ring_px := 4
|
||||||
|
var receptor_px := 24
|
||||||
|
var shadow_px := 5
|
||||||
|
var shadow_color := Color.black
|
||||||
|
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)
|
||||||
|
|
||||||
|
# Shadows
|
||||||
|
for i in range(len(receptor_circle)-1):
|
||||||
|
draw_line(receptor_circle[i], receptor_circle[i+1], shadow_color, ring_px + shadow_px, true)
|
||||||
|
for i in range(len(receptor_centers)):
|
||||||
|
draw_circle(receptor_centers[i], (receptor_px + shadow_px)/2, shadow_color)
|
||||||
|
|
||||||
|
# Foregrounds
|
||||||
|
for i in range(len(receptor_circle)-1):
|
||||||
|
draw_line(receptor_circle[i], receptor_circle[i+1], receptor_color, ring_px, true)
|
||||||
|
for i in range(len(receptor_centers)):
|
||||||
|
draw_circle(receptor_centers[i], receptor_px/2, receptor_color)
|
|
@ -0,0 +1,7 @@
|
||||||
|
[gd_resource type="Environment" load_steps=2 format=2]
|
||||||
|
|
||||||
|
[sub_resource type="ProceduralSky" id=1]
|
||||||
|
|
||||||
|
[resource]
|
||||||
|
background_mode = 2
|
||||||
|
background_sky = SubResource( 1 )
|
|
@ -0,0 +1,50 @@
|
||||||
|
extends Label
|
||||||
|
|
||||||
|
var touch_points = {} # array containing all points touched on the screen
|
||||||
|
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 _ready():
|
||||||
|
set_process_unhandled_input(true) # process user input
|
||||||
|
|
||||||
|
##########################################################################
|
||||||
|
# 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))
|
||||||
|
set_fingers(len(touch_positions))
|
||||||
|
##########################################################################
|
||||||
|
func _input(event):
|
||||||
|
if (event is InputEventScreenDrag):
|
||||||
|
touch_points[event.index] = {pressed = true, position = event.position}
|
||||||
|
if (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
|
||||||
|
else:
|
||||||
|
if touch_points.has(event.index):
|
||||||
|
touch_points.erase(event.index)
|
||||||
|
update()
|
||||||
|
|
||||||
|
##########################################################################
|
||||||
|
# write how many fingers are tapping the screen
|
||||||
|
func set_fingers(value):
|
||||||
|
fingers = value
|
||||||
|
if fingers > 0:
|
||||||
|
set_text(str(fingers))
|
||||||
|
else:
|
||||||
|
set_text("0")
|
|
@ -0,0 +1,27 @@
|
||||||
|
extends Node2D
|
||||||
|
|
||||||
|
# Declare member variables here. Examples:
|
||||||
|
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)
|
||||||
|
return point_list
|
||||||
|
|
||||||
|
# Called when the node enters the scene tree for the first time.
|
||||||
|
#func _ready():
|
||||||
|
# pass # Replace with function body.
|
||||||
|
|
||||||
|
# Called every frame. 'delta' is the elapsed time since the previous frame.
|
||||||
|
#func _process(delta):
|
||||||
|
# pass
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,70 @@
|
||||||
|
[gd_scene load_steps=12 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]
|
||||||
|
|
||||||
|
[sub_resource type="ShaderMaterial" id=1]
|
||||||
|
shader = ExtResource( 5 )
|
||||||
|
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 )
|
||||||
|
shader_param/bps = 1.0
|
||||||
|
shader_param/line_thickness = 0.012
|
||||||
|
shader_param/line_thickness_min = 0.0
|
||||||
|
shader_param/dot_thickness = 0.033
|
||||||
|
shader_param/dot_fullbright_thickness = 0.013
|
||||||
|
shader_param/max_angle = 1.0708
|
||||||
|
|
||||||
|
[sub_resource type="ShaderMaterial" id=2]
|
||||||
|
shader = ExtResource( 6 )
|
||||||
|
shader_param/bps = null
|
||||||
|
shader_param/star_color = null
|
||||||
|
shader_param/held_color = null
|
||||||
|
shader_param/screen_size = null
|
||||||
|
|
||||||
|
[node name="main" type="Node2D"]
|
||||||
|
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
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
rect_pivot_offset = Vector2( 540, 540 )
|
||||||
|
mouse_filter = 2
|
||||||
|
stream = ExtResource( 2 )
|
||||||
|
volume_db = -11.6
|
||||||
|
__meta__ = {
|
||||||
|
"_edit_use_anchors_": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[node name="Receptors" type="Node2D" parent="."]
|
||||||
|
script = ExtResource( 3 )
|
||||||
|
|
||||||
|
[node name="NoteHandler" type="Node2D" parent="."]
|
||||||
|
script = ExtResource( 4 )
|
||||||
|
|
||||||
|
[node name="notelines" type="MeshInstance2D" parent="NoteHandler"]
|
||||||
|
material = SubResource( 1 )
|
||||||
|
|
||||||
|
[node name="meshinstance" type="MeshInstance2D" parent="NoteHandler"]
|
||||||
|
material = SubResource( 2 )
|
||||||
|
|
||||||
|
[node name="Bezel" type="Node2D" parent="."]
|
||||||
|
script = ExtResource( 7 )
|
||||||
|
|
||||||
|
[node name="lbl_main" type="Label" parent="."]
|
||||||
|
margin_right = 424.0
|
||||||
|
margin_bottom = 216.0
|
||||||
|
custom_fonts/font = ExtResource( 8 )
|
||||||
|
text = "Fingers on the screen:"
|
||||||
|
script = ExtResource( 9 )
|
|
@ -0,0 +1,57 @@
|
||||||
|
; Engine configuration file.
|
||||||
|
; It's best edited using the editor UI and not directly,
|
||||||
|
; since the parameters that go here are not all obvious.
|
||||||
|
;
|
||||||
|
; Format:
|
||||||
|
; [section] ; section goes between []
|
||||||
|
; param=value ; assign values to parameters
|
||||||
|
|
||||||
|
config_version=4
|
||||||
|
|
||||||
|
_global_script_classes=[ ]
|
||||||
|
_global_script_class_icons={
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
[application]
|
||||||
|
|
||||||
|
config/name="Rhythm"
|
||||||
|
run/main_scene="res://main.tscn"
|
||||||
|
config/icon="res://icon.png"
|
||||||
|
|
||||||
|
[audio]
|
||||||
|
|
||||||
|
output_latency=5
|
||||||
|
channel_disable_threshold_db=-100.0
|
||||||
|
channel_disable_time=5.0
|
||||||
|
|
||||||
|
[autoload]
|
||||||
|
|
||||||
|
Note="*res://Note.gd"
|
||||||
|
FileLoader="*res://FileLoader.gd"
|
||||||
|
|
||||||
|
[debug]
|
||||||
|
|
||||||
|
gdscript/warnings/unused_variable=false
|
||||||
|
gdscript/warnings/unused_class_variable=false
|
||||||
|
gdscript/warnings/unused_argument=false
|
||||||
|
gdscript/warnings/unused_signal=false
|
||||||
|
gdscript/warnings/return_value_discarded=false
|
||||||
|
gdscript/warnings/integer_division=false
|
||||||
|
|
||||||
|
[display]
|
||||||
|
|
||||||
|
window/size/width=1920
|
||||||
|
window/size/height=1080
|
||||||
|
window/handheld/orientation="sensor"
|
||||||
|
window/stretch/mode="2d"
|
||||||
|
window/stretch/aspect="keep_height"
|
||||||
|
|
||||||
|
[gdnative]
|
||||||
|
|
||||||
|
singletons=[ "res://addons/videodecoder.gdnlib" ]
|
||||||
|
|
||||||
|
[rendering]
|
||||||
|
|
||||||
|
quality/filters/msaa=1
|
||||||
|
environment/default_environment="res://default_env.tres"
|
|
@ -0,0 +1,134 @@
|
||||||
|
shader_type canvas_item;
|
||||||
|
render_mode blend_premul_alpha;
|
||||||
|
|
||||||
|
uniform vec4 line_color = vec4(0.8, 0.8, 1.0, 0.8);
|
||||||
|
uniform vec4 line_color_double = vec4(1.0, 1.0, 0.6, 0.9);
|
||||||
|
uniform vec4 dot_color = vec4(1.0, 1.0, 1.0, 0.8);
|
||||||
|
uniform float bps = 1.0;
|
||||||
|
uniform float line_thickness = 0.012;
|
||||||
|
uniform float line_thickness_min = 0.0;
|
||||||
|
uniform float dot_thickness = 0.033;
|
||||||
|
uniform float dot_fullbright_thickness = 0.013;
|
||||||
|
uniform float max_angle = 1.0708; //3.14159*0.5; //radians(90.0);
|
||||||
|
|
||||||
|
//void vertex() {
|
||||||
|
//}
|
||||||
|
|
||||||
|
float angle_diff(float a, float b) {
|
||||||
|
float d = mod((a - b), 6.28318);
|
||||||
|
if (d > 3.14159) d = 6.28318 - d;
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
//vec4 blend_over(vec4 a, vec4 b) {
|
||||||
|
// // Blend a over b, preserving transparency
|
||||||
|
// vec4 color;
|
||||||
|
//// color.rgb = (a.rgb*a.a + b.rgb*b.a*(1.0-a.a))/(a.a + b.a*(1.0-a.a));
|
||||||
|
//// color.a = min(a.a + b.a*(1.0-a.a), 1.0);
|
||||||
|
// color.a = min(mix(a.a, 1.0, b.a), 1.0);
|
||||||
|
// color.rgb = (a.rgb*a.a + b.rgb*b.a*(1.0-a.a))/color.a;
|
||||||
|
// return color;
|
||||||
|
//}
|
||||||
|
//vec4 blend_additive(vec4 a, vec4 b) {
|
||||||
|
// // Blend a over b, preserving transparency
|
||||||
|
// vec4 color;
|
||||||
|
// color.a = min(mix(a.a, 1.0, b.a), 1.0);
|
||||||
|
// color.rgb = mix(a.rgb, vec3(1.0), b.rgb*b.a*(1.0-a.a));
|
||||||
|
// return color;
|
||||||
|
//}
|
||||||
|
|
||||||
|
|
||||||
|
void fragment() {
|
||||||
|
float dist = distance(UV, vec2(0.0));
|
||||||
|
float angle = atan(-UV.y, UV.x);
|
||||||
|
float line_alpha = 0.0;
|
||||||
|
float line_double_alpha = 0.0;
|
||||||
|
float dot_alpha = 0.0;
|
||||||
|
|
||||||
|
// Iterate over all the notes and check distance to them
|
||||||
|
bool last_double = false;
|
||||||
|
for (int i=0; i<238; i++){
|
||||||
|
// x, y, z = distance, column, column_radians
|
||||||
|
vec3 sample = texelFetch(TEXTURE, ivec2(i%16, i/16), 0).xyz;
|
||||||
|
if (sample == vec3(0.0)) break;
|
||||||
|
float diff = abs(dist - sample.x);
|
||||||
|
// Short-circuit out if our radial difference is too high to matter in any case.
|
||||||
|
// We need the diff value calculated anyway so shouldn't add any overhead
|
||||||
|
// Assume dot_thickness is thickest uniform
|
||||||
|
if (diff > dot_thickness) continue;
|
||||||
|
|
||||||
|
// Check for dot distance
|
||||||
|
vec2 uv = sample.x * vec2(cos(sample.z), -sin(sample.z));
|
||||||
|
float dist2 = distance(UV, uv);
|
||||||
|
if (dist2 < dot_thickness){
|
||||||
|
//dot_alpha += (dot_thickness-dist2)/dot_thickness;
|
||||||
|
float w = dot_thickness - dot_fullbright_thickness;
|
||||||
|
dot_alpha += (w-max(dist2-dot_fullbright_thickness, 0.0))/w;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (last_double){ // Already processed lines in last sample
|
||||||
|
last_double = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
float diff_a = angle_diff(angle, sample.z);
|
||||||
|
// Check if this note is a double with the next one
|
||||||
|
vec3 sample2 = texelFetch(TEXTURE, ivec2((i+1)%16, (i+1)/16), 0).xyz;
|
||||||
|
if (sample.x == sample2.x){
|
||||||
|
// This note is a double!
|
||||||
|
last_double = true;
|
||||||
|
// Check for special case: directly opposite columns - full-thickness line 360°
|
||||||
|
if (sample.y == mod(sample2.y+4.0, 8.0)){
|
||||||
|
if (diff < line_thickness){
|
||||||
|
line_double_alpha += (line_thickness-diff)/line_thickness;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Find the smallest arc between them, make it fully thick
|
||||||
|
float diff_a2 = angle_diff(angle, sample2.z);
|
||||||
|
// if ((diff_a<1.5708) && (diff_a2<1.5708)){
|
||||||
|
if ((diff_a+diff_a2-0.0001) <= angle_diff(sample.z, sample2.z)){
|
||||||
|
if (diff < line_thickness){
|
||||||
|
line_double_alpha += (line_thickness-diff)/line_thickness;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Fringe
|
||||||
|
float diff_amin = min(diff_a, diff_a2);
|
||||||
|
if (diff_amin < max_angle){
|
||||||
|
float thickness = mix(line_thickness, line_thickness_min, diff_amin/max_angle);
|
||||||
|
if (diff < thickness){
|
||||||
|
line_double_alpha += (thickness-diff)/line_thickness;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (diff_a < max_angle){
|
||||||
|
float thickness = mix(line_thickness, line_thickness_min, diff_a/max_angle);
|
||||||
|
if (diff < thickness){
|
||||||
|
line_alpha += (thickness-diff)/line_thickness;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw release dots
|
||||||
|
for (int i=0; i<15; i++){
|
||||||
|
vec3 sample = texelFetch(TEXTURE, ivec2(i, 15), 0).xyz;
|
||||||
|
if (sample == vec3(0.0)) break;
|
||||||
|
vec2 uv = sample.x * vec2(cos(sample.z), -sin(sample.z));
|
||||||
|
float dist2 = distance(UV, uv);
|
||||||
|
if (dist2 < dot_thickness){
|
||||||
|
//dot_alpha += (dot_thickness-dist2)/dot_thickness;
|
||||||
|
float w = dot_thickness - dot_fullbright_thickness;
|
||||||
|
dot_alpha += (w-max(dist2-dot_fullbright_thickness, 0.0))/w;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
line_alpha = min(line_alpha, 1.0) * line_color.a;
|
||||||
|
line_double_alpha = min(line_double_alpha, 1.0) * line_color_double.a;
|
||||||
|
dot_alpha = min(dot_alpha, 1.0) * dot_color.a;
|
||||||
|
COLOR.rgb = (line_color_double.rgb*line_double_alpha) + (line_color.rgb*line_alpha) + (dot_color.rgb*dot_alpha);
|
||||||
|
COLOR.a = 0.0;
|
||||||
|
// COLOR.rgb = (line_color_double.rgb*line_double_alpha + line_color.rgb*line_alpha*(1.0-line_double_alpha))/(line_double_alpha + line_alpha*(1.0-line_double_alpha));
|
||||||
|
// COLOR.a = min(line_double_alpha + line_alpha*(1.0-line_double_alpha), 1.0);
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
shader_type canvas_item;
|
||||||
|
//render_mode unshaded;
|
||||||
|
|
||||||
|
uniform float bps;
|
||||||
|
uniform vec4 star_color : hint_color;
|
||||||
|
uniform vec4 held_color : hint_color;
|
||||||
|
uniform vec2 screen_size;
|
||||||
|
|
||||||
|
//void vertex() {
|
||||||
|
//}
|
||||||
|
|
||||||
|
void fragment() {
|
||||||
|
vec4 sample = texture(TEXTURE, UV);
|
||||||
|
float scale = sample.r;
|
||||||
|
float dist = distance(FRAGCOORD.xy, screen_size/2.0);
|
||||||
|
float dist_norm = dist*1.8 / screen_size.y;
|
||||||
|
if (COLOR.rgb == star_color.rgb){
|
||||||
|
// Star ripple
|
||||||
|
COLOR.rg += dist_norm*0.33;
|
||||||
|
COLOR.rgb *= mix(abs(0.5-mod(TIME*bps*2.0+dist_norm, 1.0)), 1.0, 0.75);
|
||||||
|
COLOR.rgb *= scale; // Preserve black outlines
|
||||||
|
} else if (COLOR.rgb == held_color.rgb){
|
||||||
|
// Hold note being held, flashy effects
|
||||||
|
COLOR.b *= mix(2.0*abs(0.5-mod(TIME*bps*2.0+dist_norm, 1.0)), 1.0, 0.35);
|
||||||
|
COLOR.g *= mix(1.0 - 2.0*abs(0.5-mod(TIME*bps*0.5+dist_norm, 1.0)), 0.0, 0.35);
|
||||||
|
COLOR.r *= mix(abs(0.5-mod(TIME*bps, 1.0)), 1.0, 0.85);
|
||||||
|
if (scale < 0.1){ // Make outlines WHITE
|
||||||
|
COLOR.rgb = vec3(mix(dist_norm, abs(0.5-mod(TIME*bps*8.0, 1.0)), 0.33));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
COLOR.gb += 0.1;
|
||||||
|
COLOR.rgb *= mix(abs(0.5-mod(TIME*bps, 1.0)), 1.0, 0.85);
|
||||||
|
COLOR.rgb *= scale; // Preserve black outlines
|
||||||
|
}
|
||||||
|
|
||||||
|
COLOR.a = texture(TEXTURE, UV).a;
|
||||||
|
if (sample.rgb == vec3(1.0)){
|
||||||
|
COLOR.rgb = vec3(1.0);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue