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:
BIN
Audio/track.mp3
Normal file
BIN
Audio/track.mp3
Normal file
Binary file not shown.
19
Audio/track.mp3.import
Normal file
19
Audio/track.mp3.import
Normal 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
|
||||||
@@ -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 }
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -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>
|
||||||
|
|||||||
7
ProjectOnrinto.csproj.old
Normal file
7
ProjectOnrinto.csproj.old
Normal 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>
|
||||||
@@ -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
BIN
Scripts/.DS_Store
vendored
Normal file
Binary file not shown.
@@ -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);
|
||||||
@@ -34,8 +42,15 @@ public partial class GameManager : Node3D
|
|||||||
|
|
||||||
if(points[i].IsLinear)
|
if(points[i].IsLinear)
|
||||||
{
|
{
|
||||||
double t = (time - pointTime_from) / (pointTime_to - pointTime_from);
|
if (pointTime_to <= pointTime_from)
|
||||||
CurrentAbsoluteSpeed = Mathf.Lerp(points[i].Speed, points[i + 1].Speed, (float)t);
|
{
|
||||||
|
CurrentAbsoluteSpeed = points[i].Speed;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
double t = (time - pointTime_from) / (pointTime_to - pointTime_from);
|
||||||
|
CurrentAbsoluteSpeed = Mathf.Lerp(points[i].Speed, points[i + 1].Speed, (float)t);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user