Files
ProjectOnrinto_Godot/Scripts/Core/TrackGenerator.cs
CrbnsCat10n 778d68fd00 new file: .DS_Store
new file:   Audio/track.mp3
	new file:   Audio/track.mp3.import
	modified:   Charts/track.json
	modified:   Scenes/Game/level.tscn
	new file:   Scripts/.DS_Store
	modified:   Scripts/Core/GameManager.cs
	modified:   Scripts/Core/MusicClock.cs
	modified:   Scripts/Core/TrackGenerator.cs
	modified:   Scripts/Data/ChartEvent.cs
	modified:   Scripts/Data/TrackData.cs
	modified:   Scripts/GameObjects/NoteObject.cs
2026-04-12 17:24:27 +08:00

91 lines
2.5 KiB
C#

using Godot;
using System.Text.Json;
using Onrinto.Chart;
using System.Text.Json.Serialization;
using System.Linq;
using System.Collections.Generic;
public partial class TrackGenerator : Node3D
{
TrackData track = new TrackData();
List<ChartEvent> _notes = new List<ChartEvent>();
[Export] public PackedScene NotePrefab;
private int _spawnIndex = 0;
// Called when the node enters the scene tree for the first time.
public override void _Ready()
{
//Load chart data.
string chart_path = "res://Charts/track.json";
if (!FileAccess.FileExists(chart_path))
{
GD.PrintErr($"Can't find chart file: {chart_path}");
return;
}
using var file = FileAccess.Open(chart_path, FileAccess.ModeFlags.Read);
string json = file.GetAsText();
var options = new JsonSerializerOptions {
PropertyNameCaseInsensitive = true,
Converters = { new JsonStringEnumConverter(), new Vector2Converter() }
};
try {
track = JsonSerializer.Deserialize<TrackData>(json, options);
// foreach (var e in track.Events) {
// GD.Print($"事件时间: {e.Tick}, 类型: {e.GetType().Name}");
// if (e is AnimatedEvent ani) {
// GD.Print($" -> 这是一个动画音符开始位置: {ani.StartPosition}, 结束位置: {ani.EndPosition}");
// }
// }
} catch (JsonException ex) {
GD.PrintErr("Failed to parse chart JSON: " + ex.Message);
}
_notes = track.Events.OrderBy(e => e.Tick).ToList(); // Ensure events are sorted by time.
track.Initialize(); // Pre-calculate hit times and positions.
GameManager.Instance.CurrentTrack = track; // Set the current track in the game manager.
// Load and play music
if (!string.IsNullOrEmpty(track.MusicPath))
{
MusicClock.Instance.LoadMusic(track.MusicPath);
MusicClock.Instance.Play();
}
}
private void spawnNote(ChartEvent e) {
var noteInstance = NotePrefab.Instantiate<NoteObject>();
noteInstance.Initialize(e);
AddChild(noteInstance);
}
// Called every frame. 'delta' is the elapsed time since the previous frame.
public override void _Process(double delta)
{
if (track == null) return;
float currentZ = GameManager.Instance.CurrentAbsZ;
float spawnThreshold = GameManager.Instance.VisibleDistance;
while (_spawnIndex < _notes.Count)
{
var e = _notes[_spawnIndex];
float visualDist = (e.HitAbsZ - currentZ) * GameManager.Instance.FinalSpeed;
if (visualDist <= spawnThreshold)
{
// Only spawn if it hasn't been missed for too long
if (e.HitTime - MusicClock.Instance.CurrentTime >= -0.5)
{
spawnNote(e);
}
_spawnIndex++;
}
else break;
}
}
}