new file: .editorconfig
new file: .gitattributes new file: Charts/track.json new file: ProjectOnrinto.csproj new file: ProjectOnrinto.sln new file: Scenes/Audio/audio_stream_player.tscn new file: Scenes/Game/level.tscn new file: Scenes/Prefabs/beat.tscn new file: Scripts/Core/GameManager.cs new file: Scripts/Core/GameManager.cs.uid new file: Scripts/Core/MusicClock.cs new file: Scripts/Core/MusicClock.cs.uid new file: Scripts/Core/TrackGenerator.cs new file: Scripts/Core/TrackGenerator.cs.uid new file: Scripts/Data/ChartEvent.cs new file: Scripts/Data/ChartEvent.cs.uid new file: Scripts/Data/JsonConverter.cs new file: Scripts/Data/JsonConverter.cs.uid new file: Scripts/Data/TrackData.cs new file: Scripts/Data/TrackData.cs.uid new file: Scripts/GameObjects/NoteObject.cs new file: Scripts/GameObjects/NoteObject.cs.uid new file: icon.svg new file: icon.svg.import new file: project.godot
This commit is contained in:
71
Scripts/Core/GameManager.cs
Normal file
71
Scripts/Core/GameManager.cs
Normal file
@@ -0,0 +1,71 @@
|
||||
using Godot;
|
||||
using Onrinto.Chart;
|
||||
|
||||
public partial class GameManager : Node3D
|
||||
{
|
||||
public TrackData CurrentTrack { get; private set; }
|
||||
public static GameManager Instance { get; private set; }
|
||||
|
||||
public float CurrentAbsoluteSpeed { get; private set; }
|
||||
public float CurrentAbsZ { get; private set; }
|
||||
|
||||
private int absoluteSpeedPointIndexArrow = 0;
|
||||
|
||||
private void UpdateAbsoluteState(double time)
|
||||
{
|
||||
var points = CurrentTrack.AbsoluteSpeedPoints;
|
||||
if(points == null || points.Count == 0) return;
|
||||
|
||||
double firstPointTime = CurrentTrack.TickToSeconds(points[0].Tick);
|
||||
if(time < firstPointTime)
|
||||
{
|
||||
CurrentAbsoluteSpeed = points[0].Speed;
|
||||
return;
|
||||
}
|
||||
|
||||
for(int i = absoluteSpeedPointIndexArrow; i < points.Count - 1; i++)
|
||||
{
|
||||
double pointTime_from = CurrentTrack.TickToSeconds(points[i].Tick);
|
||||
double pointTime_to = CurrentTrack.TickToSeconds(points[i + 1].Tick);
|
||||
|
||||
if(time >= pointTime_from && time < pointTime_to)
|
||||
{
|
||||
absoluteSpeedPointIndexArrow = i;
|
||||
|
||||
if(points[i].IsLinear)
|
||||
{
|
||||
double t = (time - pointTime_from) / (pointTime_to - pointTime_from);
|
||||
CurrentAbsoluteSpeed = Mathf.Lerp(points[i].Speed, points[i + 1].Speed, (float)t);
|
||||
}
|
||||
else
|
||||
{
|
||||
CurrentAbsoluteSpeed = points[i].Speed;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
absoluteSpeedPointIndexArrow = points.Count - 1;
|
||||
CurrentAbsoluteSpeed = points[^1].Speed;
|
||||
}
|
||||
|
||||
// Called when the node enters the scene tree for the first time.
|
||||
public override void _Ready()
|
||||
{
|
||||
if (Instance != null){ QueueFree(); return; }
|
||||
Instance = this;
|
||||
|
||||
ProcessPriority = -100;
|
||||
}
|
||||
|
||||
// Called every frame. 'delta' is the elapsed time since the previous frame.
|
||||
public override void _Process(double delta)
|
||||
{
|
||||
double tNow = MusicClock.Instance.CurrentTime;
|
||||
|
||||
if(CurrentTrack == null) return;
|
||||
|
||||
UpdateAbsoluteState(tNow);
|
||||
CurrentAbsZ = CurrentTrack.GetZ(tNow, CurrentTrack.RelativeSpeedPoints, CurrentTrack.RelativeZTable);
|
||||
}
|
||||
}
|
||||
1
Scripts/Core/GameManager.cs.uid
Normal file
1
Scripts/Core/GameManager.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://ch71v2vkldtbd
|
||||
26
Scripts/Core/MusicClock.cs
Normal file
26
Scripts/Core/MusicClock.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using Godot;
|
||||
|
||||
public partial class MusicClock : AudioStreamPlayer
|
||||
{
|
||||
public static MusicClock Instance {get; private set; }
|
||||
|
||||
private double currentTime;
|
||||
public double CurrentTime { get; private set; }
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
Instance = this;
|
||||
if (Stream == null) GD.PrintErr("MusicClock: No Audio File?");
|
||||
}
|
||||
|
||||
public override void _Process(double delta)
|
||||
{
|
||||
if(!Playing) return;
|
||||
|
||||
double rawTime = GetPlaybackPosition();
|
||||
double delay = AudioServer.GetTimeSinceLastMix();
|
||||
double latency = AudioServer.GetOutputLatency();
|
||||
|
||||
CurrentTime = rawTime + delay - latency;
|
||||
}
|
||||
}
|
||||
1
Scripts/Core/MusicClock.cs.uid
Normal file
1
Scripts/Core/MusicClock.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://d1ct3oyh0fr1s
|
||||
64
Scripts/Core/TrackGenerator.cs
Normal file
64
Scripts/Core/TrackGenerator.cs
Normal file
@@ -0,0 +1,64 @@
|
||||
using Godot;
|
||||
using System.Text.Json;
|
||||
using Onrinto.Chart;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
|
||||
public partial class TrackGenerator : Node3D
|
||||
{
|
||||
TrackData track = new TrackData();
|
||||
List<ChartEvent> _notes = new List<ChartEvent>();
|
||||
[Export] public PackedScene NotePrefab;
|
||||
|
||||
// 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.
|
||||
}
|
||||
|
||||
private void spawnNote(ChartEvent e) {
|
||||
var noteInstance = NotePrefab.Instantiate<NoteObject>();
|
||||
|
||||
float speed = 20.0f;
|
||||
double hitTime = (double)(e.Tick / track.TicksPerBeat * 60.0 / track.BPM);
|
||||
float initialZ = (float)(hitTime * speed);
|
||||
|
||||
noteInstance.Initialize(e, hitTime, initialZ); // Initial Z position
|
||||
AddChild(noteInstance);
|
||||
}
|
||||
// Called every frame. 'delta' is the elapsed time since the previous frame.
|
||||
public override void _Process(double delta)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
1
Scripts/Core/TrackGenerator.cs.uid
Normal file
1
Scripts/Core/TrackGenerator.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://bmanbpeqbrkk1
|
||||
Reference in New Issue
Block a user