Judgement times are in realtime not gametime

This commit is contained in:
Luke Hubmayer-Werner 2019-11-20 17:57:18 +10:30
parent 9ffd8d57c5
commit 447566dc73
4 changed files with 37 additions and 18 deletions

View File

@ -5,7 +5,7 @@ extends Node
enum {NOTE_TAP, NOTE_HOLD, NOTE_SLIDE, NOTE_ARROW, NOTE_TOUCH, NOTE_TOUCH_HOLD} enum {NOTE_TAP, NOTE_HOLD, NOTE_SLIDE, NOTE_ARROW, NOTE_TOUCH, NOTE_TOUCH_HOLD}
enum SlideType {CHORD, ARC_CW, ARC_ACW} enum SlideType {CHORD, ARC_CW, ARC_ACW}
const DEATH_DELAY := 0.45 const DEATH_DELAY := 1.0 # This is touchy with the judgement windows and variable bpm.
class NoteBase: class NoteBase:
var time_hit: float var time_hit: float

View File

@ -27,10 +27,13 @@ var t := 0.0
var bpm := 120.0 var bpm := 120.0
var sync_offset_video := 0.0 # Time in seconds to the first beat var sync_offset_video := 0.0 # Time in seconds to the first beat
var sync_offset_audio := 0.0 # Time in seconds to the first beat var sync_offset_audio := 0.0 # Time in seconds to the first beat
var active_notes := [] var active_notes := []
var active_judgement_texts := []
var all_notes := [] var all_notes := []
var next_note_to_load := 0 var next_note_to_load := 0
var active_judgement_texts := []
var scores := {}
var slide_trail_meshes := {} var slide_trail_meshes := {}
var slide_trail_mesh_instances := {} var slide_trail_mesh_instances := {}
@ -76,8 +79,16 @@ const TextJudgement := {
-2: TextWord.GOOD + TextStyle.ARC_EARLY, -2: TextWord.GOOD + TextStyle.ARC_EARLY,
3: TextWord.ALMOST + TextStyle.ARC_LATE, 3: TextWord.ALMOST + TextStyle.ARC_LATE,
-3: TextWord.ALMOST + TextStyle.ARC_EARLY, -3: TextWord.ALMOST + TextStyle.ARC_EARLY,
"MISS": TextWord.MISS + TextStyle.ARC
} }
func initialise_scores():
scores = {}
for type in [Note.NOTE_TAP, Note.NOTE_HOLD, Note.NOTE_SLIDE]:
scores[type] = {}
for key in TextJudgement:
scores[type][key] = 0
func make_text_mesh(mesh: ArrayMesh, text_id: int, pos: Vector2, angle: float, alpha:=1.0, scale:=1.0): func make_text_mesh(mesh: ArrayMesh, text_id: int, pos: Vector2, angle: float, alpha:=1.0, scale:=1.0):
var r := GameTheme.judge_text_size2 * scale var r := GameTheme.judge_text_size2 * scale
var vertex_array := PoolVector2Array([ var vertex_array := PoolVector2Array([
@ -223,6 +234,7 @@ func make_slide_trail_mesh(note) -> ArrayMesh:
#---------------------------------------------------------------------------------------------------------------------------------------------- #----------------------------------------------------------------------------------------------------------------------------------------------
func activate_note(note, judgement): func activate_note(note, judgement):
active_judgement_texts.append({col=note.column, judgement=judgement, time=t}) active_judgement_texts.append({col=note.column, judgement=judgement, time=t})
scores[note.type][judgement] += 1
note.time_activated = t note.time_activated = t
match note.type: match note.type:
@ -238,7 +250,7 @@ func button_pressed(col):
continue continue
if note.time_activated != INF: if note.time_activated != INF:
continue continue
var hit_delta = t - note.time_hit var hit_delta = (t - note.time_hit) * 60.0/bpm # Judgement times are in seconds not gametime
if hit_delta >= 0.0: if hit_delta >= 0.0:
if hit_delta > Rules.JUDGEMENT_TIMES_POST[-1]: if hit_delta > Rules.JUDGEMENT_TIMES_POST[-1]:
continue # missed continue # missed
@ -293,16 +305,16 @@ func _draw():
scale *= position/GameTheme.INNER_NOTE_CIRCLE_RATIO scale *= position/GameTheme.INNER_NOTE_CIRCLE_RATIO
position = GameTheme.INNER_NOTE_CIRCLE_RATIO position = GameTheme.INNER_NOTE_CIRCLE_RATIO
var note_center = (GameTheme.RADIAL_UNIT_VECTORS[note.column] * position * GameTheme.receptor_ring_radius) var note_center = (GameTheme.RADIAL_UNIT_VECTORS[note.column] * position * GameTheme.receptor_ring_radius)
var color: PoolColorArray
match note.type: match note.type:
Note.NOTE_TAP: Note.NOTE_TAP:
var color: PoolColorArray if note.time_hit >= t:
if note.time_activated == INF:
color = GameTheme.color_array_tap(1.0, note.double_hit) color = GameTheme.color_array_tap(1.0, note.double_hit)
else: else:
color = GameTheme.color_array_tap(lerp(1.0, 0.0, (note.time_death-t)/Note.DEATH_DELAY), note.double_hit) color = GameTheme.color_array_tap(clamp((note.time_death-t)/Note.DEATH_DELAY, 0.0, 1.0), note.double_hit)
make_tap_mesh(mesh, note_center, scale, color) make_tap_mesh(mesh, note_center, scale, color)
Note.NOTE_HOLD: Note.NOTE_HOLD:
var color = GameTheme.COLOR_ARRAY_DOUBLE_8 if note.double_hit else GameTheme.COLOR_ARRAY_HOLD color = GameTheme.COLOR_ARRAY_DOUBLE_8 if note.double_hit else GameTheme.COLOR_ARRAY_HOLD
if note.is_held: if note.is_held:
color = GameTheme.COLOR_ARRAY_HOLD_HELD color = GameTheme.COLOR_ARRAY_HOLD_HELD
var position_rel : float = (t+GameTheme.note_forecast_beats-note.time_release)/GameTheme.note_forecast_beats var position_rel : float = (t+GameTheme.note_forecast_beats-note.time_release)/GameTheme.note_forecast_beats
@ -315,7 +327,7 @@ func _draw():
var note_center_rel = (GameTheme.RADIAL_UNIT_VECTORS[note.column] * position_rel * GameTheme.receptor_ring_radius) var note_center_rel = (GameTheme.RADIAL_UNIT_VECTORS[note.column] * position_rel * GameTheme.receptor_ring_radius)
make_hold_mesh(mesh, note_center, note_center_rel, scale, GameTheme.RADIAL_COL_ANGLES[note.column], color) make_hold_mesh(mesh, note_center, note_center_rel, scale, GameTheme.RADIAL_COL_ANGLES[note.column], color)
Note.NOTE_SLIDE: Note.NOTE_SLIDE:
var color = GameTheme.COLOR_ARRAY_DOUBLE_4 if note.double_hit else GameTheme.COLOR_ARRAY_STAR color = GameTheme.COLOR_ARRAY_DOUBLE_4 if note.double_hit else GameTheme.COLOR_ARRAY_STAR
var angle = fmod(t/note.duration, 1.0)*TAU var angle = fmod(t/note.duration, 1.0)*TAU
make_star_mesh(mesh, note_center, scale, angle, color) make_star_mesh(mesh, note_center, scale, angle, color)
var trail_alpha := 1.0 var trail_alpha := 1.0
@ -358,6 +370,7 @@ func _init():
Input.set_mouse_mode(Input.MOUSE_MODE_HIDDEN) Input.set_mouse_mode(Input.MOUSE_MODE_HIDDEN)
GameTheme.init_radial_values() GameTheme.init_radial_values()
make_text_UVs() make_text_UVs()
initialise_scores()
# Called when the node enters the scene tree for the first time. # Called when the node enters the scene tree for the first time.
func _ready(): func _ready():
@ -444,6 +457,7 @@ func _process(delta):
get_node("/root/main/video").set_stream_position(vt_delta) get_node("/root/main/video").set_stream_position(vt_delta)
# Clean out expired notes # Clean out expired notes
var miss_time: float = Rules.JUDGEMENT_TIMES_POST[-1] * bpm/60.0
for i in range(len(active_notes)-1, -1, -1): for i in range(len(active_notes)-1, -1, -1):
var note = active_notes[i] var note = active_notes[i]
if note.time_death < t: if note.time_death < t:
@ -451,6 +465,11 @@ func _process(delta):
$SlideTrailHandler.remove_child(slide_trail_mesh_instances[note.slide_id]) $SlideTrailHandler.remove_child(slide_trail_mesh_instances[note.slide_id])
slide_trail_mesh_instances.erase(note.slide_id) slide_trail_mesh_instances.erase(note.slide_id)
active_notes.remove(i) active_notes.remove(i)
elif note.time_activated == INF:
if ((t-note.time_hit) > miss_time) and not note.missed:
active_judgement_texts.append({col=note.column, judgement="MISS", time=t})
scores[note.type]["MISS"] += 1
note.missed = true
# Clean out expired judgement texts # Clean out expired judgement texts
# By design they will always be in order so we can ignore anything past the first index # By design they will always be in order so we can ignore anything past the first index
@ -480,9 +499,9 @@ func _process(delta):
next_note_to_load += 1 next_note_to_load += 1
# DEBUG: Reset after all notes are done # DEBUG: Reset after all notes are done
if (len(active_notes) < 1) and (next_note_to_load >= len(all_notes)) and (time > 10.0) and not get_node("/root/main/video").is_playing(): # if (len(active_notes) < 1) and (next_note_to_load >= len(all_notes)) and (time > 10.0) and not get_node("/root/main/video").is_playing():
time = -10.0 # time = -10.0
next_note_to_load = 0 # next_note_to_load = 0
# Redraw # Redraw
$meshinstance.material.set_shader_param("screen_size", get_viewport().get_size()) $meshinstance.material.set_shader_param("screen_size", get_viewport().get_size())

View File

@ -9,9 +9,9 @@ const COLS_TOUCH_ARC_DEG := 240.0/COLS
const JUDGEMENT_STRINGS := ["Perfect", "Great", "Good", "Almost"] const JUDGEMENT_STRINGS := ["Perfect", "Great", "Good", "Almost"]
const JUDGEMENT_TIERS := 4 const JUDGEMENT_TIERS := 4
const JUDGEMENT_TIMES_PRE := [0.040, 0.090, 0.135, 0.180] const JUDGEMENT_TIMES_PRE := [0.040, 0.090, 0.135, 0.175]
const JUDGEMENT_TIMES_POST := [0.040, 0.090, 0.135, 0.180] const JUDGEMENT_TIMES_POST := [0.040, 0.090, 0.135, 0.175]
const JUDGEMENT_TIMES_RELEASE_PRE := [0.050, 0.090, 0.135, 0.180] const JUDGEMENT_TIMES_RELEASE_PRE := [0.050, 0.090, 0.135, 0.175]
const JUDGEMENT_TIMES_RELEASE_POST := [0.100, 0.140, 0.155, 0.230] # Small grace period const JUDGEMENT_TIMES_RELEASE_POST := [0.100, 0.140, 0.155, 0.225] # Small grace period
const JUDGEMENT_TIMES_SLIDE_PRE := [0.090, 0.135, 0.180, 0.230] # Small grace period, sort-of const JUDGEMENT_TIMES_SLIDE_PRE := [0.090, 0.135, 0.180, 0.225] # Small grace period, sort-of
const JUDGEMENT_TIMES_SLIDE_POST := [0.090, 0.135, 0.180, 0.230] const JUDGEMENT_TIMES_SLIDE_POST := [0.090, 0.135, 0.180, 0.225]

View File

@ -42,5 +42,5 @@ void fragment() {
COLOR.rgb = mix(COLOR.rgb, vec3(1.0), bright_scale); // Preserve white outlines COLOR.rgb = mix(COLOR.rgb, vec3(1.0), bright_scale); // Preserve white outlines
} }
COLOR.a = texture(TEXTURE, UV).a; COLOR.a = clamp(COLOR.a*texture(TEXTURE, UV).a, 0.0, 1.0);
} }