diff --git a/rhythm_game/lane/lane.gd b/rhythm_game/lane/lane.gd index d5605dc..3d6d31c 100644 --- a/rhythm_game/lane/lane.gd +++ b/rhythm_game/lane/lane.gd @@ -4,6 +4,6 @@ class_name Lane extends Node2D func get_hit_pos() -> Vector2: return position - -func update(_beat: BeatUpdate) -> void: +## Should be connected to [signal NoteSpawner.notes_spawned]. +func update(beat: float) -> void: pass diff --git a/rhythm_game/note/view/lane_view.gd b/rhythm_game/note/view/lane_view.gd index b6f07db..e1e29ce 100644 --- a/rhythm_game/note/view/lane_view.gd +++ b/rhythm_game/note/view/lane_view.gd @@ -8,9 +8,9 @@ class_name LaneView extends NoteView func get_data() -> NoteSubset: return _lane_notes -func update_current_beat(beat: float) -> void: - _current_beat = beat - _update_view_relative_to_notes(_lane_notes) +func update(beat: float) -> void: + _update_view_relative_to_notes(_lane_notes, beat) + _previous_beat = beat # ======== Implementation ======== # var _lane_notes: NoteSubset @@ -18,4 +18,4 @@ 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() + reset_view() diff --git a/rhythm_game/note/view/note_view.gd b/rhythm_game/note/view/note_view.gd index 09d8661..3b109e4 100644 --- a/rhythm_game/note/view/note_view.gd +++ b/rhythm_game/note/view/note_view.gd @@ -8,12 +8,41 @@ class_name NoteView extends View func get_data() -> NoteArray: return notes -func update_current_beat(beat: float) -> void: - _current_beat = beat - _update_view_relative_to_notes(notes) +func update(beat: float) -> void: + _update_view_relative_to_notes(notes, beat) + _previous_beat = beat + +func reset_view() -> void: + super.reset_view() + _previous_beat = -999.0 # ======= IMPLEMENTATION ======= # +var _previous_beat: float = -999.0 func _set_notes(p_notes: NoteArray) -> void: notes = p_notes - _reset_view() + reset_view() + +## Update the view to match _current_beat. +func _update_view_relative_to_notes(p_notes: NoteArray, new_beat: float) -> void: + var new_begin = _begin + var new_end = _end + if new_beat > _previous_beat: + # Update forward. + while(new_begin < p_notes.size()) and (p_notes.beat_at(new_begin) < new_beat + offset_begin): + new_begin += 1 + while(new_end < p_notes.size()) and (p_notes.beat_at(new_end) <= new_beat + offset_end): + new_end += 1 + elif new_beat < _previous_beat: + # Update backward. + while(new_begin >= 0) and (p_notes.beat_at(new_begin) >= new_beat + offset_begin): + _begin -= 1 + while(new_end >= 0) and (p_notes.beat_at(new_end) > new_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 diff --git a/rhythm_game/note/view/view.gd b/rhythm_game/note/view/view.gd index d5dfcb4..c90a1ab 100644 --- a/rhythm_game/note/view/view.gd +++ b/rhythm_game/note/view/view.gd @@ -7,7 +7,12 @@ ## Update the view to be relative to beat. ## Can be connected to a beat update signal. -@abstract func update_current_beat(beat: float) -> void +@abstract func update(beat: float) -> void + +## Reset the view. +func reset_view() -> void: + _begin = -1 + _end = -1 ## 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. @@ -32,37 +37,3 @@ func size() -> int: # ======= 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 diff --git a/rhythm_game/note/visual/note_animator.gd b/rhythm_game/note/visual/note_animator.gd deleted file mode 100644 index 5753ef6..0000000 --- a/rhythm_game/note/visual/note_animator.gd +++ /dev/null @@ -1,27 +0,0 @@ -class_name NoteAnimator extends NoteView - -@export var pool: NotePool - -## TODO WARNING: This is currently only implemented for beat updates -## going forward in time. -func update_current_beat(beat: float) -> void: - var old_begin: int = _begin - var old_end: int = _end - super.update_current_beat(beat) # Update _begin and _end. - _update_note_visuals(old_begin, _begin) - _update_note_visuals(old_end, _end) - - -# ======== IMPLEMENTATION ======== # -var _note_map: Dictionary[int, NoteVisual] - -func _update_note_visuals(index_begin: int, index_end: int) -> void: - for i: int in range(index_begin, index_end): - # TODO: Either get or return node from pool, - # depending on if index_begin > or < than index_end. - pass - -func _set_notes(p_notes: NoteArray) -> void: - - notes = p_notes - _reset_view() diff --git a/rhythm_game/note/visual/note_pool.gd b/rhythm_game/note/visual/note_pool.gd index f72859a..4c56410 100644 --- a/rhythm_game/note/visual/note_pool.gd +++ b/rhythm_game/note/visual/note_pool.gd @@ -15,9 +15,21 @@ class_name NotePool extends Node @export var hold_skin: StringName = "default" func get_note(type: NoteVisual.TYPE) -> NoteVisual: - var note: NoteVisual - # TODO: Implement. - return note + match type: + NoteVisual.TYPE.TAP: + return get_tap() + NoteVisual.TYPE.HOLD: + return get_hold() + _: + return null + +func return_note(note: NoteVisual) -> void: + if note is TapNote: + note.reset() + return_tap(note as TapNote) + elif note is HoldNote: + note.reset() + return_hold(note as HoldNote) ## Get a tap note. Instantiates one if no free nodes are available. func get_tap() -> TapNote: diff --git a/rhythm_game/note/visual/note_spawner.gd b/rhythm_game/note/visual/note_spawner.gd new file mode 100644 index 0000000..8f1e0a1 --- /dev/null +++ b/rhythm_game/note/visual/note_spawner.gd @@ -0,0 +1,91 @@ +class_name NoteSpawner extends NoteView + +signal notes_spawned(beat: float) + +@export var lanes: Dictionary[int, Lane] + +@export var pool: NotePool + +## Spawn all the notes that should exist on this beat. +func update(beat: float) -> void: + var old_begin: int = _begin + var old_end: int = _end + _update_view_relative_to_notes(notes, beat) # Updates _begin and _end. + + if _previous_beat <= beat: + _set_note_visuals(old_end, _end) + _remove_note_visuals(old_begin, _begin) + else: + _remove_note_visuals(_end, old_end) + _set_note_visuals(_begin, old_begin) + + _previous_beat = beat + notes_spawned.emit(beat) + +# ======== IMPLEMENTATION ======== # +var _note_visuals: Dictionary[int, NoteVisual] # [Note ID, Note Visual] + +var _last_lane_holds: Dictionary[int, HoldNote] + +func _set_notes(p_notes: NoteArray) -> void: + super._set_notes(p_notes) + for note in _note_visuals.values(): + if note == null: + continue + pool.return_note(note) + +# TODO Finish implementation. +# Spawn or delete nodes in the range. +func _set_note_visuals(index_begin: int, index_end: int) -> void: + for note_id: int in range(index_begin, index_end): + match notes.type_at(note_id): + Note.TYPE.TAP: + _set_visual_for_tap_at(note_id) + Note.TYPE.HOLD_START: + _set_visual_for_hold_start_at(note_id) + Note.TYPE.HOLD_END: + _set_visual_for_hold_end_at(note_id) + +func _remove_note_visuals(index_begin: int, index_end: int) -> void: + for note_id: int in range(index_begin, index_end): + match notes.type_at(note_id): + Note.TYPE.TAP: + _remove_visual_for_tap_at(note_id) + Note.TYPE.HOLD_START: + _remove_visual_for_hold_start_at(note_id) + Note.TYPE.HOLD_END: + _remove_visual_for_hold_end_at(note_id) + +func _set_visual_for_tap_at(note_id: int) -> void: + var lane_id: int = notes.lane_at(note_id) + var lane: Lane = lanes[lane_id] + var note: TapNote = pool.get_tap() + lane.add_child(note) + _note_visuals[note_id] = note + +func _set_visual_for_hold_start_at(note_id: int) -> void: + var lane_id: int = notes.lane_at(note_id) + var lane: Lane = lanes[lane_id] + var note: HoldNote = pool.get_hold() + lane.add_child(note) + _note_visuals[note_id] = note + _last_lane_holds[lane_id] = note + +func _set_visual_for_hold_end_at(note_id: int) -> void: + var lane_id: int = notes.lane_at(note_id) + var lane: Lane = lanes[lane_id] + var note: HoldNote = _last_lane_holds[lane_id] + if note == null: + note = pool.get_hold() + lane.add_child(note) + _note_visuals[note_id] = note + _last_lane_holds[lane_id] = null + +func _remove_visual_for_tap_at(note_id: int) -> void: + pass + +func _remove_visual_for_hold_start_at(note_id: int) -> void: + pass + +func _remove_visual_for_hold_end_at(note_id: int) -> void: + pass diff --git a/rhythm_game/note/visual/note_animator.gd.uid b/rhythm_game/note/visual/note_spawner.gd.uid similarity index 100% rename from rhythm_game/note/visual/note_animator.gd.uid rename to rhythm_game/note/visual/note_spawner.gd.uid