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
This commit is contained in:
CrbnsCat10n
2026-04-12 17:24:27 +08:00
parent 0e6bf1dcad
commit 778d68fd00
14 changed files with 154 additions and 38 deletions

BIN
.DS_Store vendored Normal file

Binary file not shown.

BIN
Audio/track.mp3 Normal file

Binary file not shown.

19
Audio/track.mp3.import Normal file
View File

@@ -0,0 +1,19 @@
[remap]
importer="mp3"
type="AudioStreamMP3"
uid="uid://767hle7lvb6b"
path="res://.godot/imported/track.mp3-200430bc283eed98be8a5eaa80a158a9.mp3str"
[deps]
source_file="res://Audio/track.mp3"
dest_files=["res://.godot/imported/track.mp3-200430bc283eed98be8a5eaa80a158a9.mp3str"]
[params]
loop=false
loop_offset=0
bpm=0
beat_count=0
bar_beats=4

View File

@@ -1,30 +1,52 @@
{ {
"MusicPath": "res://Audio/track.mp3",
"BPM": 120, "BPM": 120,
"Offset": 0.5, "Offset": 0.0,
"TicksPerBeat": 480, "TicksPerBeat": 480.0,
"TempoPoints": [
{
"Tick": 0,
"BPM": 120
}
],
"RelativeSpeedPoints": [
{
"Tick": 0,
"Speed": 20.0,
"IsLinear": false
}
],
"AbsoluteSpeedPoints": [
{
"Tick": 0,
"Speed": 1.0,
"IsLinear": false
}
],
"Events": [ "Events": [
{ {
"$type": "Onrinto.Chart.ChartEvent", "$type": "Onrinto.Chart.ChartEvent",
"Type": "Beat", "Type": "Beat",
"Tick": 1000, "Tick": 0,
"Position": {"x": 1.0, "y": 0.0} "Position": { "X": 0.0, "Y": 0.0 }
}, },
{ {
"$type": "Onrinto.Chart.AnimatedEvent", "$type": "Onrinto.Chart.ChartEvent",
"Type": "Catch", "Type": "Beat",
"Tick": 2000, "Tick": 480,
"Position": {"x": 0.0, "y": 0.0}, "Position": { "X": -2.0, "Y": 0.0 }
"AniType": "Sin", },
"In_Out": 1, {
"AniStartTime": 1500, "$type": "Onrinto.Chart.ChartEvent",
"AniEndTime": 2000, "Type": "Beat",
"RelativeSpeed": 1.5, "Tick": 960,
"StartPosition": {"x": -2.0, "y": 4.0}, "Position": { "X": 2.0, "Y": 0.0 }
"EndPosition": {"x": 2.0, "y": 3.0} },
{
"$type": "Onrinto.Chart.ChartEvent",
"Type": "Beat",
"Tick": 1440,
"Position": { "X": 0.0, "Y": 0.0 }
} }
],
"RelativeSpeedPoints": [
{ "Tick": 0, "Speed": 1.0 , "IsLinear": false},
{ "Tick": 5000, "Speed": 2.0, "IsLinear": true }
] ]
} }

View File

@@ -1,4 +1,4 @@
<Project Sdk="Godot.NET.Sdk/4.6.1"> <Project Sdk="Godot.NET.Sdk/4.6.2">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net8.0</TargetFramework> <TargetFramework>net8.0</TargetFramework>
<TargetFramework Condition=" '$(GodotTargetPlatform)' == 'android' ">net9.0</TargetFramework> <TargetFramework Condition=" '$(GodotTargetPlatform)' == 'android' ">net9.0</TargetFramework>

View File

@@ -0,0 +1,7 @@
<Project Sdk="Godot.NET.Sdk/4.6.1">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework Condition=" '$(GodotTargetPlatform)' == 'android' ">net9.0</TargetFramework>
<EnableDynamicLoading>true</EnableDynamicLoading>
</PropertyGroup>
</Project>

View File

@@ -2,6 +2,7 @@
[ext_resource type="PackedScene" uid="uid://n8na6nkfmnme" path="res://Scenes/Audio/audio_stream_player.tscn" id="1_5xcqo"] [ext_resource type="PackedScene" uid="uid://n8na6nkfmnme" path="res://Scenes/Audio/audio_stream_player.tscn" id="1_5xcqo"]
[ext_resource type="Script" uid="uid://bmanbpeqbrkk1" path="res://Scripts/Core/TrackGenerator.cs" id="2_gayhk"] [ext_resource type="Script" uid="uid://bmanbpeqbrkk1" path="res://Scripts/Core/TrackGenerator.cs" id="2_gayhk"]
[ext_resource type="PackedScene" uid="uid://dqp4hku6gudds" path="res://Scenes/Prefabs/beat.tscn" id="3_gayhk"]
[node name="Level" type="Node3D" unique_id=2071595859] [node name="Level" type="Node3D" unique_id=2071595859]
@@ -9,3 +10,7 @@
[node name="Track" type="Node3D" parent="." unique_id=923723651] [node name="Track" type="Node3D" parent="." unique_id=923723651]
script = ExtResource("2_gayhk") script = ExtResource("2_gayhk")
NotePrefab = ExtResource("3_gayhk")
[node name="Camera3D" type="Camera3D" parent="." unique_id=381050533]
transform = Transform3D(-1, 2.262668e-08, -8.444392e-08, 0, 0.9659258, 0.25881904, 8.742278e-08, 0.25881904, -0.9659258, 0, 3, -7)

BIN
Scripts/.DS_Store vendored Normal file

Binary file not shown.

View File

@@ -3,10 +3,13 @@ using Onrinto.Chart;
public partial class GameManager : Node3D public partial class GameManager : Node3D
{ {
public TrackData CurrentTrack { get; private set; } [Export] public float VisibleDistance = 150.0f;
[Export] public float PlayerSpeed = 1.5f;
public TrackData CurrentTrack { get; set; }
public static GameManager Instance { get; private set; } public static GameManager Instance { get; private set; }
public float CurrentAbsoluteSpeed { get; private set; } public float CurrentAbsoluteSpeed { get; private set; }
public float FinalSpeed => CurrentAbsoluteSpeed * PlayerSpeed;
public float CurrentAbsZ { get; private set; } public float CurrentAbsZ { get; private set; }
private int absoluteSpeedPointIndexArrow = 0; private int absoluteSpeedPointIndexArrow = 0;
@@ -23,6 +26,11 @@ public partial class GameManager : Node3D
return; return;
} }
if(absoluteSpeedPointIndexArrow > 0 && time < CurrentTrack.TickToSeconds(points[absoluteSpeedPointIndexArrow].Tick))
{
absoluteSpeedPointIndexArrow = 0;
}
for(int i = absoluteSpeedPointIndexArrow; i < points.Count - 1; i++) for(int i = absoluteSpeedPointIndexArrow; i < points.Count - 1; i++)
{ {
double pointTime_from = CurrentTrack.TickToSeconds(points[i].Tick); double pointTime_from = CurrentTrack.TickToSeconds(points[i].Tick);
@@ -33,10 +41,17 @@ public partial class GameManager : Node3D
absoluteSpeedPointIndexArrow = i; absoluteSpeedPointIndexArrow = i;
if(points[i].IsLinear) if(points[i].IsLinear)
{
if (pointTime_to <= pointTime_from)
{
CurrentAbsoluteSpeed = points[i].Speed;
}
else
{ {
double t = (time - pointTime_from) / (pointTime_to - pointTime_from); double t = (time - pointTime_from) / (pointTime_to - pointTime_from);
CurrentAbsoluteSpeed = Mathf.Lerp(points[i].Speed, points[i + 1].Speed, (float)t); CurrentAbsoluteSpeed = Mathf.Lerp(points[i].Speed, points[i + 1].Speed, (float)t);
} }
}
else else
{ {
CurrentAbsoluteSpeed = points[i].Speed; CurrentAbsoluteSpeed = points[i].Speed;

View File

@@ -10,7 +10,21 @@ public partial class MusicClock : AudioStreamPlayer
public override void _Ready() public override void _Ready()
{ {
Instance = this; Instance = this;
if (Stream == null) GD.PrintErr("MusicClock: No Audio File?"); }
public void LoadMusic(string path)
{
if (string.IsNullOrEmpty(path)) return;
var stream = GD.Load<AudioStream>(path);
if (stream != null)
{
Stream = stream;
}
else
{
GD.PrintErr($"Failed to load music at: {path}");
}
} }
public override void _Process(double delta) public override void _Process(double delta)

View File

@@ -4,7 +4,6 @@ using Onrinto.Chart;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
using System.Linq; using System.Linq;
using System.Collections.Generic; using System.Collections.Generic;
using System.Security.Cryptography.X509Certificates;
public partial class TrackGenerator : Node3D public partial class TrackGenerator : Node3D
{ {
@@ -12,6 +11,8 @@ public partial class TrackGenerator : Node3D
List<ChartEvent> _notes = new List<ChartEvent>(); List<ChartEvent> _notes = new List<ChartEvent>();
[Export] public PackedScene NotePrefab; [Export] public PackedScene NotePrefab;
private int _spawnIndex = 0;
// Called when the node enters the scene tree for the first time. // Called when the node enters the scene tree for the first time.
public override void _Ready() public override void _Ready()
{ {
@@ -44,21 +45,46 @@ public partial class TrackGenerator : Node3D
} }
_notes = track.Events.OrderBy(e => e.Tick).ToList(); // Ensure events are sorted by time. _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) { private void spawnNote(ChartEvent e) {
var noteInstance = NotePrefab.Instantiate<NoteObject>(); var noteInstance = NotePrefab.Instantiate<NoteObject>();
float speed = 20.0f; noteInstance.Initialize(e);
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); AddChild(noteInstance);
} }
// Called every frame. 'delta' is the elapsed time since the previous frame. // Called every frame. 'delta' is the elapsed time since the previous frame.
public override void _Process(double delta) 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;
}
} }
} }

View File

@@ -13,7 +13,7 @@ public class TempoPoint
public float BPM { get; set; } public float BPM { get; set; }
[JsonConstructor] [JsonConstructor]
public TempoPoint(double tick, float bpm, bool isLinear) public TempoPoint(double tick, float bpm)
{ {
Tick = tick; Tick = tick;
BPM = bpm; BPM = bpm;
@@ -46,7 +46,7 @@ public class ChartEvent
public double Tick { get; set; } public double Tick { get; set; }
public Vector2 Position { get; set; } public Vector2 Position { get; set; }
public double HitTime { get; set; } public double HitTime { get; set; }
public double HitAbsZ { get; set; } public float HitAbsZ { get; set; }
public ChartEvent(EventType type, double tick, Vector2 position) public ChartEvent(EventType type, double tick, Vector2 position)
{ {

View File

@@ -6,6 +6,7 @@ namespace Onrinto.Chart;
public class TrackData public class TrackData
{ {
public string MusicPath { get; set; }
public int BPM { get; set; } public int BPM { get; set; }
public double Offset { get; set; } public double Offset { get; set; }
public double TicksPerBeat { get; set; } public double TicksPerBeat { get; set; }
@@ -107,6 +108,10 @@ public class TrackData
if(point.IsLinear && idx < speedPoints.Count - 1) if(point.IsLinear && idx < speedPoints.Count - 1)
{ {
double nextTime = TickToSeconds(speedPoints[idx + 1].Tick); double nextTime = TickToSeconds(speedPoints[idx + 1].Tick);
if (nextTime <= pointTime)
{
return cachedZ + (float)deltaTime * point.Speed;
}
float t = (float)((time - pointTime) / (nextTime - pointTime)); float t = (float)((time - pointTime) / (nextTime - pointTime));
float currentSpeed = Mathf.Lerp(point.Speed, speedPoints[idx + 1].Speed, t); float currentSpeed = Mathf.Lerp(point.Speed, speedPoints[idx + 1].Speed, t);
return cachedZ + (float)deltaTime * (point.Speed + currentSpeed) * 0.5f; return cachedZ + (float)deltaTime * (point.Speed + currentSpeed) * 0.5f;

View File

@@ -4,12 +4,15 @@ using Onrinto.Chart;
public partial class NoteObject : Node3D public partial class NoteObject : Node3D
{ {
private double _hitSeconds; private double _hitSeconds;
private float _hitAbsZ;
private bool _isHit = false; private bool _isHit = false;
private bool _initialized = false; private bool _initialized = false;
public void Initialize(ChartEvent chartEvent, double hitSeconds, float initialZ) public void Initialize(ChartEvent chartEvent)
{ {
_hitSeconds = hitSeconds; _hitSeconds = chartEvent.HitTime;
_hitAbsZ = chartEvent.HitAbsZ;
float initialZ = _hitAbsZ - GameManager.Instance.CurrentAbsZ;
Position = new Vector3(chartEvent.Position.X, chartEvent.Position.Y, initialZ); Position = new Vector3(chartEvent.Position.X, chartEvent.Position.Y, initialZ);
_initialized = true; _initialized = true;
@@ -26,14 +29,14 @@ public partial class NoteObject : Node3D
{ {
if (!_initialized) return; if (!_initialized) return;
float speed = 20.0f; // Scroll speed
double _currentTime = MusicClock.Instance.CurrentTime; double _currentTime = MusicClock.Instance.CurrentTime;
float newZ = (float)((_hitSeconds - _currentTime) * speed); float newZ = (float)((_hitAbsZ - GameManager.Instance.CurrentAbsZ) * GameManager.Instance.FinalSpeed);
Position = new Vector3(Position.X, Position.Y, newZ); // Update Z position Position = new Vector3(Position.X, Position.Y, newZ); // Update Z position
if(_hitSeconds - _currentTime < -0.5) QueueFree(); // Remove note if(_hitSeconds - _currentTime < -0.5) QueueFree(); // Remove note
// Toggle visibility instead of removing
Visible = (newZ >= 0 && newZ <= GameManager.Instance.VisibleDistance);
} }
} }