Refactored Library scan, Note construction. Preparing for StepMania charts.
This commit is contained in:
parent
8088ea097d
commit
703edb9656
218
FileLoader.gd
218
FileLoader.gd
|
@ -1,6 +1,70 @@
|
||||||
#extends Object
|
#extends Object
|
||||||
extends Node
|
extends Node
|
||||||
|
|
||||||
|
var userroot := "user://" if OS.get_name() != "Android" else "/storage/emulated/0/RhythmGame/"
|
||||||
|
# The following would probably work. One huge caveat is that permission needs to be manually granted by the user in app settings as we can't use OS.request_permission("WRITE_EXTERNAL_STORAGE")
|
||||||
|
# "/storage/emulated/0/Android/data/au.ufeff.rhythmgame/"
|
||||||
|
# "/sdcard/Android/data/au.ufeff.rhythmgame/"
|
||||||
|
|
||||||
|
func directory_list(directory: String, hidden: bool) -> Dictionary:
|
||||||
|
# Sadly there's no filelist sugar so we make our own
|
||||||
|
var output = {folders=[], files=[], err=OK}
|
||||||
|
var dir = Directory.new()
|
||||||
|
output.err = dir.open(directory)
|
||||||
|
if output.err != OK:
|
||||||
|
print_debug('Failed to open directory: ' + directory + '(Error code '+output.err+')')
|
||||||
|
return output
|
||||||
|
output.err = dir.list_dir_begin(true, !hidden)
|
||||||
|
if output.err != OK:
|
||||||
|
print_debug('Failed to begin listing directory: ' + directory + '(Error code '+output.err+')')
|
||||||
|
return output
|
||||||
|
|
||||||
|
var item = dir.get_next()
|
||||||
|
while (item != ''):
|
||||||
|
if dir.current_is_dir():
|
||||||
|
output['folders'].append(item)
|
||||||
|
else:
|
||||||
|
output['files'].append(item)
|
||||||
|
item = dir.get_next()
|
||||||
|
dir.list_dir_end()
|
||||||
|
return output
|
||||||
|
|
||||||
|
func scan_library():
|
||||||
|
print("Scanning library")
|
||||||
|
var rootdir = userroot + "songs"
|
||||||
|
var dir = Directory.new()
|
||||||
|
var err = dir.make_dir_recursive(rootdir)
|
||||||
|
if err != OK:
|
||||||
|
print_debug("An error occurred while trying to create the songs directory: ", err)
|
||||||
|
return err
|
||||||
|
|
||||||
|
var songslist = directory_list(rootdir, false)
|
||||||
|
if songslist.err != OK:
|
||||||
|
print("An error occurred when trying to access the songs directory: ", songslist.err)
|
||||||
|
return songslist.err
|
||||||
|
|
||||||
|
var song_defs = {}
|
||||||
|
var song_images = {}
|
||||||
|
var genres = {}
|
||||||
|
dir.open(rootdir)
|
||||||
|
for key in songslist.folders:
|
||||||
|
if dir.file_exists(key + "/song.json"):
|
||||||
|
song_defs[key] = FileLoader.load_folder("%s/%s" % [rootdir, key])
|
||||||
|
print("Loaded song directory: %s" % key)
|
||||||
|
song_images[key] = FileLoader.load_image("%s/%s/%s" % [rootdir, key, song_defs[key]["tile_filename"]])
|
||||||
|
if song_defs[key]["genre"] in genres:
|
||||||
|
genres[song_defs[key]["genre"]].append(key)
|
||||||
|
else:
|
||||||
|
genres[song_defs[key]["genre"]] = [key]
|
||||||
|
else:
|
||||||
|
print("Found non-song directory: " + key)
|
||||||
|
for file in songslist.files:
|
||||||
|
print("Found file: " + file)
|
||||||
|
|
||||||
|
return {song_defs=song_defs, song_images=song_images, genres=genres}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class SRT:
|
class SRT:
|
||||||
const TAP_DURATION := 0.062500
|
const TAP_DURATION := 0.062500
|
||||||
const ID_BREAK := 4
|
const ID_BREAK := 4
|
||||||
|
@ -65,6 +129,160 @@ class SRB:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class SM:
|
||||||
|
# Stepmania simfile
|
||||||
|
|
||||||
|
const NOTE_VALUES = {
|
||||||
|
'0': 'None',
|
||||||
|
'1': 'Tap',
|
||||||
|
'2': 'HoldStart',
|
||||||
|
'3': 'HoldRollEnd',
|
||||||
|
'4': 'RollStart',
|
||||||
|
'M': 'Mine',
|
||||||
|
# These three are less likely to show up anywhere, no need to implement
|
||||||
|
'K': 'Keysound',
|
||||||
|
'L': 'Lift',
|
||||||
|
'F': 'Fake',
|
||||||
|
}
|
||||||
|
|
||||||
|
const CHART_DIFFICULTIES = {
|
||||||
|
'Beginner': 0,
|
||||||
|
'Easy': 1,
|
||||||
|
'Medium': 2,
|
||||||
|
'Hard': 3,
|
||||||
|
'Challenge': 4,
|
||||||
|
'Edit': 5,
|
||||||
|
# Some will just write whatever for special difficulties, but we should at least color-code these standard ones
|
||||||
|
}
|
||||||
|
|
||||||
|
const TAG_TRANSLATIONS = {
|
||||||
|
'#TITLE': 'title',
|
||||||
|
'#SUBTITLE': 'subtitle',
|
||||||
|
'#ARTIST': 'artist',
|
||||||
|
'#TITLETRANSLIT': 'title_transliteration',
|
||||||
|
'#SUBTITLETRANSLIT': 'subtitle_transliteration',
|
||||||
|
'#ARTISTTRANSLIT': 'artist_transliteration',
|
||||||
|
'#GENRE': 'genre',
|
||||||
|
'#CREDIT': 'chart_author',
|
||||||
|
'#BANNER': 'image_banner',
|
||||||
|
'#BACKGROUND': 'image_background',
|
||||||
|
'#LYRICSPATH': '',
|
||||||
|
'#CDTITLE': 'image_cd_title',
|
||||||
|
'#MUSIC': 'audio_filelist',
|
||||||
|
'#OFFSET': 'audio_offsets',
|
||||||
|
'#SAMPLESTART': 'audio_preview_times',
|
||||||
|
'#SAMPLELENGTH': 'audio_preview_times',
|
||||||
|
'#SELECTABLE': '',
|
||||||
|
'#BPMS': 'bpm_values',
|
||||||
|
'#STOPS': '',
|
||||||
|
'#BGCHANGES': '',
|
||||||
|
'#KEYSOUNDS': '',
|
||||||
|
}
|
||||||
|
|
||||||
|
static func load_chart(lines):
|
||||||
|
var metadata = {}
|
||||||
|
var notes = []
|
||||||
|
|
||||||
|
assert(lines[0].begins_with('#NOTES:'))
|
||||||
|
metadata['chart_type'] = lines[1].strip_edges().rstrip(':')
|
||||||
|
metadata['description'] = lines[2].strip_edges().rstrip(':')
|
||||||
|
metadata['difficulty_str'] = lines[3].strip_edges().rstrip(':')
|
||||||
|
metadata['numerical_meter'] = lines[4].strip_edges().rstrip(':')
|
||||||
|
metadata['groove_radar'] = lines[5].strip_edges().rstrip(':')
|
||||||
|
|
||||||
|
# Measures are separated by lines that start with a comma
|
||||||
|
# Each line has a state for each of the pads, e.g. '0000' for none pressed
|
||||||
|
# The lines become even subdivisions of the measure, so if there's 4 lines everything represents a 1/4 beat, if there's 8 lines everything represents a 1/8 beat etc.
|
||||||
|
# For this reason it's probably best to just have a float for beat-within-measure rather than integer beats.
|
||||||
|
var measures = [[]]
|
||||||
|
for i in range(6, len(lines)):
|
||||||
|
var line = lines[i].strip_edges()
|
||||||
|
if line.begins_with(','):
|
||||||
|
measures.append([])
|
||||||
|
elif line.begins_with(';'):
|
||||||
|
break
|
||||||
|
elif len(line) > 0:
|
||||||
|
measures[-1].append(line)
|
||||||
|
|
||||||
|
var ongoing_holds = {}
|
||||||
|
var num_notes := 0
|
||||||
|
var num_jumps := 0
|
||||||
|
var num_hands := 0
|
||||||
|
var num_holds := 0
|
||||||
|
var num_rolls := 0
|
||||||
|
var num_mines := 0
|
||||||
|
|
||||||
|
for measure in range(len(measures)):
|
||||||
|
var m_lines = measures[measure]
|
||||||
|
var m_length = len(m_lines) # Divide out all lines by this
|
||||||
|
for beat in m_length:
|
||||||
|
var line : String = m_lines[beat]
|
||||||
|
# Jump check at a line-level (check for multiple 1/2/4s)
|
||||||
|
var hits : int = line.count('1') + line.count('2') + line.count('4')
|
||||||
|
# Hand/quad check more complex as need to check hold/roll state as well
|
||||||
|
# TODO: are they exclusive? Does quad override hand override jump? SM5 doesn't have quads and has hands+jumps inclusive
|
||||||
|
var total_pressed : int = hits + len(ongoing_holds)
|
||||||
|
var jump : bool = hits >= 2
|
||||||
|
var hand : bool = total_pressed >= 3
|
||||||
|
# var quad : bool = total_pressed >= 4
|
||||||
|
num_notes += hits
|
||||||
|
num_jumps += int(jump)
|
||||||
|
num_hands += int(hand)
|
||||||
|
var time = measure + beat/float(m_length)
|
||||||
|
for col in len(line):
|
||||||
|
match line[col]:
|
||||||
|
'1':
|
||||||
|
notes.append(Note.make_tap(time, col))
|
||||||
|
'2': # Hold
|
||||||
|
ongoing_holds[col] = len(notes)
|
||||||
|
notes.append(Note.make_tap(time, col))
|
||||||
|
'4': # Roll
|
||||||
|
ongoing_holds[col] = len(notes)
|
||||||
|
notes.append(Note.make_tap(time, col))
|
||||||
|
'3': # End Hold/Roll
|
||||||
|
assert(ongoing_holds.has(col))
|
||||||
|
notes[ongoing_holds[col]].set_time_release(time)
|
||||||
|
'M': # Mine
|
||||||
|
num_mines += 1
|
||||||
|
pass
|
||||||
|
metadata['num_notes'] = num_notes
|
||||||
|
metadata['num_jumps'] = num_jumps
|
||||||
|
metadata['num_hands'] = num_hands
|
||||||
|
metadata['num_holds'] = num_holds
|
||||||
|
metadata['num_rolls'] = num_rolls
|
||||||
|
metadata['num_mines'] = num_mines
|
||||||
|
return [metadata, notes]
|
||||||
|
|
||||||
|
static func load_file(filename):
|
||||||
|
# Technically, declarations end with a semicolon instead of a linebreak.
|
||||||
|
# This is a PITA to do correctly in GDScript and the files in our collection are well-behaved with linebreaks anyway, so we won't bother.
|
||||||
|
var file := File.new()
|
||||||
|
var err := file.open(filename, File.READ)
|
||||||
|
if err != OK:
|
||||||
|
print(err)
|
||||||
|
return err
|
||||||
|
var length = file.get_len()
|
||||||
|
var lines = [[]] # First list will be header, then every subsequent one is a chart
|
||||||
|
while (file.get_position() < (length-1)): # Could probably replace this with file.eof_reached()
|
||||||
|
var line : String = file.read_line()
|
||||||
|
if line.begins_with('#NOTES'): # Split to a new list for each chart definition
|
||||||
|
lines.append([])
|
||||||
|
lines[-1].append(line)
|
||||||
|
file.close()
|
||||||
|
|
||||||
|
var metadata = {}
|
||||||
|
for line in lines[0]:
|
||||||
|
var tokens = line.rstrip(';').split(':')
|
||||||
|
if TAG_TRANSLATIONS.has(tokens[0]):
|
||||||
|
metadata[TAG_TRANSLATIONS[tokens[0]]] = tokens[1]
|
||||||
|
var charts = []
|
||||||
|
|
||||||
|
for i in range(1, len(lines)):
|
||||||
|
charts.append(load_chart(lines[i]))
|
||||||
|
|
||||||
|
return charts
|
||||||
|
|
||||||
|
|
||||||
class Test:
|
class Test:
|
||||||
static func stress_pattern():
|
static func stress_pattern():
|
||||||
var notes = []
|
var notes = []
|
||||||
|
|
|
@ -35,11 +35,15 @@ func _ready():
|
||||||
# connect("button_pressed", self, "print_pressed")
|
# connect("button_pressed", self, "print_pressed")
|
||||||
$"/root".connect("size_changed", self, "resize")
|
$"/root".connect("size_changed", self, "resize")
|
||||||
$VsyncButton.connect("toggled", self, "update_vsync")
|
$VsyncButton.connect("toggled", self, "update_vsync")
|
||||||
|
$FilterSlider.connect("value_changed", self, "update_filter")
|
||||||
resize()
|
resize()
|
||||||
|
|
||||||
func update_vsync(setting: bool):
|
func update_vsync(setting: bool):
|
||||||
OS.vsync_enabled = setting
|
OS.vsync_enabled = setting
|
||||||
|
|
||||||
|
func update_filter(alpha: float):
|
||||||
|
GameTheme.screen_filter_min_alpha = alpha
|
||||||
|
|
||||||
func print_pressed(col: int):
|
func print_pressed(col: int):
|
||||||
print("Pressed %d"%col)
|
print("Pressed %d"%col)
|
||||||
|
|
||||||
|
|
39
Menu.gd
39
Menu.gd
|
@ -33,41 +33,14 @@ var GenreFont := preload("res://assets/MenuGenreFont.tres")
|
||||||
var ScoreFont := preload("res://assets/MenuScoreFont.tres")
|
var ScoreFont := preload("res://assets/MenuScoreFont.tres")
|
||||||
var snd_interact := preload("res://assets/softclap.wav")
|
var snd_interact := preload("res://assets/softclap.wav")
|
||||||
|
|
||||||
var userroot := "user://" if OS.get_name() != "Android" else "/storage/emulated/0/RhythmGame/"
|
var userroot : String = FileLoader.userroot
|
||||||
# The following would probably work. One huge caveat is that permission needs to be manually granted by the user in app settings as we can't use OS.request_permission("WRITE_EXTERNAL_STORAGE")
|
|
||||||
# "/storage/emulated/0/Android/data/au.ufeff.rhythmgame/"
|
|
||||||
# "/sdcard/Android/data/au.ufeff.rhythmgame/"
|
|
||||||
|
|
||||||
func scan_library():
|
func scan_library():
|
||||||
print("Scanning library")
|
var results = FileLoader.scan_library()
|
||||||
var rootdir = userroot + "songs"
|
song_defs = results.song_defs
|
||||||
var dir = Directory.new()
|
song_images = results.song_images
|
||||||
var err = dir.make_dir_recursive(rootdir)
|
genres = results.genres
|
||||||
if err != OK:
|
|
||||||
print("An error occurred while trying to create the songs directory: ", err)
|
|
||||||
return err
|
|
||||||
err = dir.open(rootdir)
|
|
||||||
if err == OK:
|
|
||||||
dir.list_dir_begin(true, true)
|
|
||||||
var key = dir.get_next()
|
|
||||||
while (key != ""):
|
|
||||||
if dir.current_is_dir():
|
|
||||||
if dir.file_exists(key + "/song.json"):
|
|
||||||
song_defs[key] = FileLoader.load_folder("%s/%s" % [rootdir, key])
|
|
||||||
print("Loaded song directory: %s" % key)
|
|
||||||
song_images[key] = FileLoader.load_image("%s/%s/%s" % [rootdir, key, song_defs[key]["tile_filename"]])
|
|
||||||
if song_defs[key]["genre"] in genres:
|
|
||||||
genres[song_defs[key]["genre"]].append(key)
|
|
||||||
else:
|
|
||||||
genres[song_defs[key]["genre"]] = [key]
|
|
||||||
else:
|
|
||||||
print("Found non-song directory: " + key)
|
|
||||||
else:
|
|
||||||
print("Found file: " + key)
|
|
||||||
key = dir.get_next()
|
|
||||||
dir.list_dir_end()
|
|
||||||
else:
|
|
||||||
print("An error occurred when trying to access the songs directory: ", err)
|
|
||||||
|
|
||||||
func save_score():
|
func save_score():
|
||||||
var rootdir = userroot + "scores"
|
var rootdir = userroot + "scores"
|
||||||
|
|
65
Note.gd
65
Note.gd
|
@ -3,44 +3,70 @@ extends Node
|
||||||
|
|
||||||
#class_name Note
|
#class_name Note
|
||||||
|
|
||||||
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, NOTE_ROLL}
|
||||||
enum SlideType {CHORD, ARC_CW, ARC_ACW}
|
enum SlideType {CHORD, ARC_CW, ARC_ACW}
|
||||||
const DEATH_DELAY := 1.0 # This is touchy with the judgement windows and variable bpm.
|
const DEATH_DELAY := 1.0 # This is touchy with the judgement windows and variable bpm.
|
||||||
const RELEASE_SCORE_TYPES := [NOTE_HOLD, NOTE_SLIDE, NOTE_TOUCH_HOLD]
|
const RELEASE_SCORE_TYPES := [NOTE_HOLD, NOTE_SLIDE, NOTE_TOUCH_HOLD, NOTE_ROLL]
|
||||||
|
const NOTE_TAP1 = 0
|
||||||
|
|
||||||
class NoteBase:
|
class NoteBase:
|
||||||
var time_hit: float
|
var time_hit: float setget set_time_hit
|
||||||
var time_death: float
|
var time_death: float
|
||||||
var column: int
|
var column: int
|
||||||
var double_hit := false
|
var double_hit := false
|
||||||
var time_activated := INF
|
var time_activated := INF
|
||||||
var missed := false
|
var missed := false
|
||||||
|
|
||||||
|
func set_time_hit(value: float):
|
||||||
|
time_hit = value
|
||||||
|
time_death = time_hit + DEATH_DELAY
|
||||||
|
|
||||||
class NoteTap extends NoteBase:
|
class NoteTap extends NoteBase:
|
||||||
var type := NOTE_TAP
|
var type := NOTE_TAP
|
||||||
func _init(time_hit: float, column: int):
|
func _init(time_hit: float, column: int):
|
||||||
self.time_hit = time_hit
|
self.time_hit = time_hit
|
||||||
self.time_death = time_hit + DEATH_DELAY
|
|
||||||
self.column = column
|
self.column = column
|
||||||
|
|
||||||
class NoteHold extends NoteBase:
|
class NoteHoldBase extends NoteBase:
|
||||||
var type := NOTE_HOLD
|
var time_release: float setget set_time_release
|
||||||
var time_release: float
|
|
||||||
var time_released := INF
|
var time_released := INF
|
||||||
var duration: float
|
var duration: float setget set_duration
|
||||||
var is_held: bool
|
var is_held: bool
|
||||||
func _init(time_hit: float, duration: float, column: int):
|
func _init(time_hit: float, duration: float, column: int):
|
||||||
self.time_hit = time_hit
|
self.time_hit = time_hit
|
||||||
self.duration = duration
|
self.duration = duration
|
||||||
self.time_release = time_hit + duration
|
|
||||||
self.time_death = time_release + DEATH_DELAY
|
|
||||||
self.column = column
|
self.column = column
|
||||||
self.is_held = false
|
self.is_held = false
|
||||||
|
|
||||||
|
func set_time_hit(value: float):
|
||||||
|
time_hit = value
|
||||||
|
time_release = time_hit + duration
|
||||||
|
time_death = time_release + DEATH_DELAY
|
||||||
|
|
||||||
|
func set_time_release(value: float):
|
||||||
|
time_release = value
|
||||||
|
time_death = time_release + DEATH_DELAY
|
||||||
|
duration = time_release - time_hit
|
||||||
|
|
||||||
|
func set_duration(value: float):
|
||||||
|
duration = value
|
||||||
|
time_release = time_hit + duration
|
||||||
|
time_death = time_release + DEATH_DELAY
|
||||||
|
|
||||||
|
class NoteHold extends NoteHoldBase:
|
||||||
|
var type := NOTE_HOLD
|
||||||
|
func _init(time_hit: float, duration: float, column: int).(time_hit, duration, column):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class NoteRoll extends NoteHoldBase:
|
||||||
|
var type := NOTE_ROLL
|
||||||
|
func _init(time_hit: float, duration: float, column: int).(time_hit, duration, column):
|
||||||
|
pass
|
||||||
|
|
||||||
class NoteSlide extends NoteBase:
|
class NoteSlide extends NoteBase:
|
||||||
var type := NOTE_SLIDE
|
var type := NOTE_SLIDE
|
||||||
var time_release: float
|
var time_release: float setget set_time_release
|
||||||
var duration: float
|
var duration: float setget set_duration
|
||||||
var column_release: int
|
var column_release: int
|
||||||
var slide_type: int
|
var slide_type: int
|
||||||
var slide_id: int
|
var slide_id: int
|
||||||
|
@ -59,6 +85,21 @@ class NoteSlide extends NoteBase:
|
||||||
self.values = {}
|
self.values = {}
|
||||||
update_slide_variables()
|
update_slide_variables()
|
||||||
|
|
||||||
|
func set_time_hit(value: float):
|
||||||
|
time_hit = value
|
||||||
|
time_release = time_hit + duration
|
||||||
|
time_death = time_release + DEATH_DELAY
|
||||||
|
|
||||||
|
func set_time_release(value: float):
|
||||||
|
time_release = value
|
||||||
|
time_death = time_release + DEATH_DELAY
|
||||||
|
duration = time_release - time_hit
|
||||||
|
|
||||||
|
func set_duration(value: float):
|
||||||
|
duration = value
|
||||||
|
time_release = time_hit + duration
|
||||||
|
time_death = time_release + DEATH_DELAY
|
||||||
|
|
||||||
func update_slide_variables():
|
func update_slide_variables():
|
||||||
match slide_type:
|
match slide_type:
|
||||||
Note.SlideType.CHORD:
|
Note.SlideType.CHORD:
|
||||||
|
|
|
@ -646,16 +646,21 @@ func _process(delta):
|
||||||
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:
|
||||||
if note.type == Note.NOTE_SLIDE:
|
match note.type:
|
||||||
SlideTrailHandler.remove_child(slide_trail_mesh_instances[note.slide_id])
|
Note.NOTE_HOLD:
|
||||||
slide_trail_mesh_instances.erase(note.slide_id)
|
scores[-Note.NOTE_HOLD][3] += 1
|
||||||
var idx = active_slide_trails.find(note)
|
active_judgement_texts.append({col=note.column, judgement=3, time=t})
|
||||||
if idx >= 0:
|
SFXPlayer.play(SFXPlayer.Type.NON_POSITIONAL, self, snd_judgement[3], db_judgement[3])
|
||||||
active_slide_trails.remove(idx)
|
Note.NOTE_SLIDE:
|
||||||
active_judgement_texts.append({col=note.column_release, judgement="MISS", time=t})
|
SlideTrailHandler.remove_child(slide_trail_mesh_instances[note.slide_id])
|
||||||
scores[-Note.NOTE_SLIDE]["MISS"] += 1
|
slide_trail_mesh_instances.erase(note.slide_id)
|
||||||
note.missed_slide = true
|
var idx = active_slide_trails.find(note)
|
||||||
SFXPlayer.play(SFXPlayer.Type.NON_POSITIONAL, self, snd_judgement["MISS"], db_judgement["MISS"])
|
if idx >= 0:
|
||||||
|
active_slide_trails.remove(idx)
|
||||||
|
active_judgement_texts.append({col=note.column_release, judgement="MISS", time=t})
|
||||||
|
scores[-Note.NOTE_SLIDE]["MISS"] += 1
|
||||||
|
note.missed_slide = true
|
||||||
|
SFXPlayer.play(SFXPlayer.Type.NON_POSITIONAL, self, snd_judgement["MISS"], db_judgement["MISS"])
|
||||||
active_notes.remove(i)
|
active_notes.remove(i)
|
||||||
elif note.time_activated == INF:
|
elif note.time_activated == INF:
|
||||||
if ((t-note.time_hit) > miss_time) and not note.missed:
|
if ((t-note.time_hit) > miss_time) and not note.missed:
|
||||||
|
|
15
main.tscn
15
main.tscn
|
@ -198,6 +198,21 @@ step = 0.01
|
||||||
value = 1.0
|
value = 1.0
|
||||||
tick_count = 3
|
tick_count = 3
|
||||||
ticks_on_borders = true
|
ticks_on_borders = true
|
||||||
|
__meta__ = {
|
||||||
|
"_edit_use_anchors_": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[node name="FilterSlider" type="HSlider" parent="InputHandler"]
|
||||||
|
margin_left = 16.0
|
||||||
|
margin_top = 400.0
|
||||||
|
margin_right = 316.0
|
||||||
|
margin_bottom = 416.0
|
||||||
|
max_value = 1.0
|
||||||
|
step = 0.01
|
||||||
|
value = 0.2
|
||||||
|
__meta__ = {
|
||||||
|
"_edit_use_anchors_": false
|
||||||
|
}
|
||||||
|
|
||||||
[node name="VsyncButton" type="CheckButton" parent="InputHandler"]
|
[node name="VsyncButton" type="CheckButton" parent="InputHandler"]
|
||||||
margin_left = 4.0
|
margin_left = 4.0
|
||||||
|
|
Loading…
Reference in New Issue