Add note array and view.
This commit is contained in:
@@ -1,3 +1,5 @@
|
|||||||
|
## Class that packs an [AudioStream] with additional information
|
||||||
|
## to sync beats to it.
|
||||||
class_name Music extends Resource
|
class_name Music extends Resource
|
||||||
|
|
||||||
## Music AudioStream.
|
## Music AudioStream.
|
||||||
|
|||||||
21
rhythm_game/note/lane_view.gd
Normal file
21
rhythm_game/note/lane_view.gd
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
## A NoteView that stores notes that exist on a lane.
|
||||||
|
class_name LaneView extends NoteView
|
||||||
|
|
||||||
|
## The lane notes will be filtered by.
|
||||||
|
@export var lane: int
|
||||||
|
|
||||||
|
## Get the array this LaneView refers to.
|
||||||
|
func get_data() -> NoteSubset:
|
||||||
|
return _lane_notes
|
||||||
|
|
||||||
|
func update_current_beat(beat: float) -> void:
|
||||||
|
_current_beat = beat
|
||||||
|
_update_view_relative_to_notes(_lane_notes)
|
||||||
|
|
||||||
|
# ======== Implementation ======== #
|
||||||
|
var _lane_notes: NoteSubset
|
||||||
|
|
||||||
|
func _set_data(p_notes: NoteArray) -> void:
|
||||||
|
notes = p_notes
|
||||||
|
_lane_notes = NoteSubset.get_notes_in_lane(p_notes, lane)
|
||||||
|
_reset_view()
|
||||||
1
rhythm_game/note/lane_view.gd.uid
Normal file
1
rhythm_game/note/lane_view.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://cq818ut4pmunn
|
||||||
44
rhythm_game/note/note_array.gd
Normal file
44
rhythm_game/note/note_array.gd
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
## An array of notes, stored as arrays of data.
|
||||||
|
## Notes are assumed to be sorted in ascending order by beat.
|
||||||
|
class_name NoteArray extends Node
|
||||||
|
|
||||||
|
## The ID of the note at [param index].
|
||||||
|
func id_at(index: int) -> int:
|
||||||
|
return index
|
||||||
|
|
||||||
|
## The beat of the note at [param index].
|
||||||
|
func beat_at(index: int) -> float:
|
||||||
|
return _beats.get(index)
|
||||||
|
|
||||||
|
## The type of the note at [param index].
|
||||||
|
func type_at(index: int) -> Note.TYPE:
|
||||||
|
return _types.get(index)
|
||||||
|
|
||||||
|
## The lane of the note at [param index].
|
||||||
|
func lane_at(index: int) -> int:
|
||||||
|
return _lanes.get(index)
|
||||||
|
|
||||||
|
## The number of notes in the array.
|
||||||
|
func size() -> int:
|
||||||
|
return _beats.size()
|
||||||
|
|
||||||
|
## Remove all notes in the array.
|
||||||
|
func clear() -> void:
|
||||||
|
_beats = []
|
||||||
|
_types = []
|
||||||
|
_lanes = []
|
||||||
|
|
||||||
|
# ======= IMPLEMENTATION ======= #
|
||||||
|
var _beats: Array[float] = []
|
||||||
|
var _types: Array[Note.TYPE] = []
|
||||||
|
var _lanes: Array[int] = []
|
||||||
|
|
||||||
|
func _append_note(note: Note) -> void:
|
||||||
|
_beats.append(note.hit_beat)
|
||||||
|
_types.append(note.type)
|
||||||
|
_lanes.append(note.lane)
|
||||||
|
|
||||||
|
func _append_note_data(beat: float, type: Note.TYPE, lane: int) -> void:
|
||||||
|
_beats.append(beat)
|
||||||
|
_types.append(type)
|
||||||
|
_lanes.append(lane)
|
||||||
1
rhythm_game/note/note_array.gd.uid
Normal file
1
rhythm_game/note/note_array.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://8isyo4pxyj1r
|
||||||
25
rhythm_game/note/note_subset.gd
Normal file
25
rhythm_game/note/note_subset.gd
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
## Contain a subset of notes in a [NoteArray].
|
||||||
|
## Notes are expected to be sorted in ascending order by beat.
|
||||||
|
## The original index of a note can be found with [method id_at].
|
||||||
|
class_name NoteSubset extends NoteArray
|
||||||
|
|
||||||
|
## The array where notes in this subset come from.
|
||||||
|
var full_set: NoteArray
|
||||||
|
|
||||||
|
## The ID (index of note in full_set) of the note at [param index].
|
||||||
|
func id_at(index) -> int:
|
||||||
|
return _ids.get(index)
|
||||||
|
|
||||||
|
## Parse the given [param notes] and return a [class NoteSubset]
|
||||||
|
## containing only notes in [param lane].
|
||||||
|
static func get_notes_in_lane(notes: NoteArray, lane: int) -> NoteSubset:
|
||||||
|
var lane_notes: NoteSubset = NoteSubset.new()
|
||||||
|
lane_notes.full_set = notes
|
||||||
|
for i in range(notes.size( )):
|
||||||
|
if notes.lane_at(i) == lane:
|
||||||
|
lane_notes._ids.append(i)
|
||||||
|
lane_notes.append_note_data(notes.beat_at(i), notes.type_at(i), lane)
|
||||||
|
return lane_notes
|
||||||
|
|
||||||
|
## ====== IMPLEMENTATION ====== #
|
||||||
|
var _ids: Array[int] = []
|
||||||
1
rhythm_game/note/note_subset.gd.uid
Normal file
1
rhythm_game/note/note_subset.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://dhaxabkmyajjv
|
||||||
19
rhythm_game/note/note_view.gd
Normal file
19
rhythm_game/note/note_view.gd
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
## Gets a range of notes in a NoteData relative to a current beat.
|
||||||
|
class_name NoteView extends View
|
||||||
|
|
||||||
|
## The full set of notes.
|
||||||
|
@export var notes: NoteArray = null: set = _set_notes
|
||||||
|
|
||||||
|
## Get the array this NoteView refers to.
|
||||||
|
func get_data() -> NoteArray:
|
||||||
|
return notes
|
||||||
|
|
||||||
|
func update_current_beat(beat: float) -> void:
|
||||||
|
_current_beat = beat
|
||||||
|
_update_view_relative_to_notes(notes)
|
||||||
|
|
||||||
|
# ======= IMPLEMENTATION ======= #
|
||||||
|
|
||||||
|
func _set_notes(p_notes: NoteArray) -> void:
|
||||||
|
notes = p_notes
|
||||||
|
_reset_view()
|
||||||
1
rhythm_game/note/note_view.gd.uid
Normal file
1
rhythm_game/note/note_view.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://c7h7ue6kjgoha
|
||||||
68
rhythm_game/note/view.gd
Normal file
68
rhythm_game/note/view.gd
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
## Abstract class representing a range of notes in some kind of array,
|
||||||
|
## expressed by a beginning index and an ending index: [begin, end).
|
||||||
|
@abstract class_name View extends Node
|
||||||
|
|
||||||
|
## Get the array this View refers to.
|
||||||
|
@abstract func get_data() -> Variant
|
||||||
|
|
||||||
|
## Update the view to be relative to beat.
|
||||||
|
## Can be connected to a beat update signal.
|
||||||
|
@abstract func update_current_beat(beat: float) -> void
|
||||||
|
|
||||||
|
## Beginning of the range relative to te current beat where notes will be visible.
|
||||||
|
## Any notes where (hit_beat < current_beat + offset_begin) will NOT be visible.
|
||||||
|
@export var offset_begin: float = -4.0
|
||||||
|
|
||||||
|
## End of the range relative to the current beat where notes will be visible.
|
||||||
|
## Any notes where (hit_beat > current_beat + offset_end) will NOT be visible.
|
||||||
|
@export var offset_end: float = 4.0
|
||||||
|
|
||||||
|
## Return the index to the first element.
|
||||||
|
func begin() -> int:
|
||||||
|
return _begin
|
||||||
|
|
||||||
|
## Return the index after the last element (equal to last index + 1).
|
||||||
|
func end() -> int:
|
||||||
|
return _end
|
||||||
|
|
||||||
|
## Size of the range encompassed by begin() and end().
|
||||||
|
func size() -> int:
|
||||||
|
return int(_begin >= 0) * _end - _begin
|
||||||
|
|
||||||
|
# ======= IMPLEMENETATION ======= #
|
||||||
|
var _begin: int = -1
|
||||||
|
var _end: int = -1
|
||||||
|
|
||||||
|
var _current_beat: float = -999
|
||||||
|
var _previous_beat: float = -999
|
||||||
|
|
||||||
|
func _reset_view() -> void:
|
||||||
|
_begin = -1
|
||||||
|
_end = -1
|
||||||
|
_current_beat = -999
|
||||||
|
_previous_beat = -999
|
||||||
|
|
||||||
|
## Update the view to match _current_beat.
|
||||||
|
func _update_view_relative_to_notes(notes: NoteArray) -> void:
|
||||||
|
var new_begin = _begin
|
||||||
|
var new_end = _end
|
||||||
|
if _current_beat > _previous_beat:
|
||||||
|
# Update forward.
|
||||||
|
while(new_begin < notes.size()) and (notes.beat_at(new_begin) < _current_beat + offset_begin):
|
||||||
|
new_begin += 1
|
||||||
|
while(new_end < notes.size()) and (notes.beat_at(new_end) <= _current_beat + offset_end):
|
||||||
|
new_end += 1
|
||||||
|
elif _current_beat < _previous_beat:
|
||||||
|
# Update backward.
|
||||||
|
while(new_begin >= 0) and (notes.beat_at(new_begin) >= _current_beat + offset_begin):
|
||||||
|
_begin -= 1
|
||||||
|
while(new_end >= 0) and (notes.beat_at(new_end) > _current_beat + offset_end):
|
||||||
|
new_end -= 1
|
||||||
|
if(new_begin != _begin):
|
||||||
|
new_begin += 1
|
||||||
|
if(new_end != _end):
|
||||||
|
new_end += 1
|
||||||
|
|
||||||
|
_begin = new_begin
|
||||||
|
_end = new_end
|
||||||
|
_previous_beat = _current_beat
|
||||||
1
rhythm_game/note/view.gd.uid
Normal file
1
rhythm_game/note/view.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://drrwatuw1yur
|
||||||
@@ -1,84 +0,0 @@
|
|||||||
#TODO Split class into two.
|
|
||||||
# One should be responsible for storing arrays of data, like a NoteData class?
|
|
||||||
# Another represents a slice of the data, NoteView.
|
|
||||||
# Before that, figure out how the part of a hold note between the hold start
|
|
||||||
# and hold end will be implemented.
|
|
||||||
class_name NoteLayout extends Node
|
|
||||||
|
|
||||||
## Controls at what beat notes are visible.
|
|
||||||
@export_group("Note View Offset")
|
|
||||||
## At what beat offset from the current beat will notes will be visible.
|
|
||||||
## Example, spawn = 4.0 means notes are spawned 4 beats before
|
|
||||||
## they are meant to be hit.
|
|
||||||
@export var spawn: float = 4.0
|
|
||||||
|
|
||||||
## At what beat offset from the current beat will notes be invisible.
|
|
||||||
## Example, despawn = 4.0 means notes are despawned 4 beats after
|
|
||||||
## they are meant to be hit.
|
|
||||||
@export var despawn: float = 4.0
|
|
||||||
|
|
||||||
|
|
||||||
## The index in notes of the first active note.
|
|
||||||
func start() -> int:
|
|
||||||
return _start
|
|
||||||
|
|
||||||
|
|
||||||
## The index in notes after the last active note.
|
|
||||||
func end() -> int:
|
|
||||||
return _end
|
|
||||||
|
|
||||||
|
|
||||||
func size() -> int:
|
|
||||||
return _beat.size()
|
|
||||||
|
|
||||||
|
|
||||||
func beat(index: int) -> float:
|
|
||||||
return _beat[index]
|
|
||||||
|
|
||||||
|
|
||||||
func lane(index: int) -> int:
|
|
||||||
return _lane[index]
|
|
||||||
|
|
||||||
|
|
||||||
func type(index: int) -> Note.TYPE:
|
|
||||||
return _type[index]
|
|
||||||
|
|
||||||
|
|
||||||
# ======= IMPLEMENTATION ======== #
|
|
||||||
|
|
||||||
# All notes in the chart, arranged by ascending beat.
|
|
||||||
var _beat: Array[float] = []
|
|
||||||
var _lane: Array[int] = []
|
|
||||||
var _type: Array[Note.TYPE] = []
|
|
||||||
|
|
||||||
var _start: int = 0
|
|
||||||
var _end: int = 0
|
|
||||||
|
|
||||||
|
|
||||||
func _push_note(_note: Note) -> void:
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
# TODO FIX THESE
|
|
||||||
func _update_forward(new_beat: float) -> void:
|
|
||||||
var spawn_beat = new_beat + spawn
|
|
||||||
|
|
||||||
while _end < size() and _beat[_end] <= spawn_beat:
|
|
||||||
_end += 1
|
|
||||||
|
|
||||||
var despawn_beat = new_beat - despawn
|
|
||||||
|
|
||||||
while _start < size() and _beat[_start] < despawn_beat:
|
|
||||||
_start += 1
|
|
||||||
|
|
||||||
# TODO FIX THESE
|
|
||||||
#func _update_backward(new_beat: float) -> void:
|
|
||||||
#var spawn_beat = new_beat + note_spawn_offset
|
|
||||||
#
|
|
||||||
#while _end >= 0 and _beat[_end] > spawn_beat:
|
|
||||||
#_end -= 1
|
|
||||||
#
|
|
||||||
#var despawn_beat = new_beat - note_despawn_offset
|
|
||||||
#
|
|
||||||
#while _start >= 0 and _beat[_start] < despawn_beat:
|
|
||||||
#_start -= 1
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
uid://dlnnbx2wvn66t
|
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
[gd_scene load_steps=10 format=3 uid="uid://dwro2d0482v0p"]
|
[gd_scene load_steps=11 format=3 uid="uid://dwro2d0482v0p"]
|
||||||
|
|
||||||
[ext_resource type="Script" uid="uid://dlnnbx2wvn66t" path="res://rhythm_game/note_layout.gd" id="1_cr5rn"]
|
|
||||||
[ext_resource type="Script" uid="uid://102cl75cfpgw" path="res://rhythm_game/music_sync/event_layout.gd" id="1_jnfl3"]
|
[ext_resource type="Script" uid="uid://102cl75cfpgw" path="res://rhythm_game/music_sync/event_layout.gd" id="1_jnfl3"]
|
||||||
[ext_resource type="Script" uid="uid://s16dt0bu0jrg" path="res://rhythm_game/music_sync/conductor.gd" id="2_62aw1"]
|
[ext_resource type="Script" uid="uid://s16dt0bu0jrg" path="res://rhythm_game/music_sync/conductor.gd" id="2_62aw1"]
|
||||||
[ext_resource type="AudioStream" uid="uid://btmy8ffph5gn3" path="res://chart/test_nibelungen/audio.mp3" id="3_txi6k"]
|
[ext_resource type="AudioStream" uid="uid://btmy8ffph5gn3" path="res://chart/test_nibelungen/audio.mp3" id="3_txi6k"]
|
||||||
@@ -8,6 +7,8 @@
|
|||||||
[ext_resource type="Script" uid="uid://rg6orh6kutai" path="res://resource_type/music.gd" id="5_nsyv8"]
|
[ext_resource type="Script" uid="uid://rg6orh6kutai" path="res://resource_type/music.gd" id="5_nsyv8"]
|
||||||
[ext_resource type="AudioStream" uid="uid://be8dyt7nfpffw" path="res://sfx/sfx_cowbell.ogg" id="6_ecbku"]
|
[ext_resource type="AudioStream" uid="uid://be8dyt7nfpffw" path="res://sfx/sfx_cowbell.ogg" id="6_ecbku"]
|
||||||
[ext_resource type="Script" uid="uid://bbpyym0kgujev" path="res://rhythm_game/metronome.gd" id="7_nsyv8"]
|
[ext_resource type="Script" uid="uid://bbpyym0kgujev" path="res://rhythm_game/metronome.gd" id="7_nsyv8"]
|
||||||
|
[ext_resource type="Script" uid="uid://8isyo4pxyj1r" path="res://rhythm_game/note/note_array.gd" id="9_10cpq"]
|
||||||
|
[ext_resource type="Script" uid="uid://c7h7ue6kjgoha" path="res://rhythm_game/note/note_view.gd" id="9_74aio"]
|
||||||
|
|
||||||
[sub_resource type="Resource" id="Resource_10cpq"]
|
[sub_resource type="Resource" id="Resource_10cpq"]
|
||||||
script = ExtResource("5_nsyv8")
|
script = ExtResource("5_nsyv8")
|
||||||
@@ -25,13 +26,18 @@ autostart = true
|
|||||||
music = SubResource("Resource_10cpq")
|
music = SubResource("Resource_10cpq")
|
||||||
metadata/_custom_type_script = "uid://s16dt0bu0jrg"
|
metadata/_custom_type_script = "uid://s16dt0bu0jrg"
|
||||||
|
|
||||||
[node name="NoteLayout" type="Node" parent="."]
|
|
||||||
script = ExtResource("1_cr5rn")
|
|
||||||
metadata/_custom_type_script = "uid://dlnnbx2wvn66t"
|
|
||||||
|
|
||||||
[node name="Metronome" type="AudioStreamPlayer" parent="."]
|
[node name="Metronome" type="AudioStreamPlayer" parent="."]
|
||||||
stream = ExtResource("6_ecbku")
|
stream = ExtResource("6_ecbku")
|
||||||
script = ExtResource("7_nsyv8")
|
script = ExtResource("7_nsyv8")
|
||||||
metadata/_custom_type_script = "uid://bbpyym0kgujev"
|
metadata/_custom_type_script = "uid://bbpyym0kgujev"
|
||||||
|
|
||||||
|
[node name="AllChartNotes" type="Node" parent="."]
|
||||||
|
script = ExtResource("9_10cpq")
|
||||||
|
metadata/_custom_type_script = "uid://8isyo4pxyj1r"
|
||||||
|
|
||||||
|
[node name="VisibleNotes" type="Node" parent="." node_paths=PackedStringArray("notes")]
|
||||||
|
script = ExtResource("9_74aio")
|
||||||
|
notes = NodePath("../AllChartNotes")
|
||||||
|
metadata/_custom_type_script = "uid://c7h7ue6kjgoha"
|
||||||
|
|
||||||
[connection signal="ticked" from="Conductor" to="Metronome" method="on_conductor_ticked"]
|
[connection signal="ticked" from="Conductor" to="Metronome" method="on_conductor_ticked"]
|
||||||
|
|||||||
Reference in New Issue
Block a user