2026-02-01 23:17:51 +08:00
|
|
|
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()
|
2026-02-04 00:04:17 +08:00
|
|
|
note.id = note_id
|
|
|
|
|
note.hit_beat = notes.beat_at(note_id)
|
2026-02-01 23:17:51 +08:00
|
|
|
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()
|
2026-02-04 00:04:17 +08:00
|
|
|
note.start_id = note_id
|
|
|
|
|
note.hit_beat = notes.beat_at(note_id)
|
2026-02-01 23:17:51 +08:00
|
|
|
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:
|
2026-02-04 00:04:17 +08:00
|
|
|
var note: TapNote = _note_visuals.get(note_id) as TapNote
|
|
|
|
|
if note == null:
|
|
|
|
|
return
|
|
|
|
|
pool.return_tap(note)
|
2026-02-01 23:17:51 +08:00
|
|
|
|
|
|
|
|
func _remove_visual_for_hold_start_at(note_id: int) -> void:
|
2026-02-04 00:04:17 +08:00
|
|
|
var note: HoldNote = _note_visuals.get(note_id) as HoldNote
|
|
|
|
|
if note == null:
|
|
|
|
|
return
|
|
|
|
|
note.start_id = -1
|
|
|
|
|
if note.end_id < 0:
|
|
|
|
|
pool.return_hold(note)
|
2026-02-01 23:17:51 +08:00
|
|
|
|
|
|
|
|
func _remove_visual_for_hold_end_at(note_id: int) -> void:
|
2026-02-04 00:04:17 +08:00
|
|
|
var note: HoldNote = _note_visuals.get(note_id) as HoldNote
|
|
|
|
|
if note == null:
|
|
|
|
|
return
|
|
|
|
|
note.end_id = -1
|
|
|
|
|
if note.start_id < 0:
|
|
|
|
|
pool.return_hold(note)
|