Add EventBus, SpeedRunManager, and GhostManager; implement ghost recording and playback features
This commit is contained in:
31
scripts/Events/GhostEventHandler.cs
Normal file
31
scripts/Events/GhostEventHandler.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
using Godot;
|
||||
using Mr.BrickAdventures.Autoloads;
|
||||
|
||||
namespace Mr.BrickAdventures.scripts.Events;
|
||||
|
||||
[GlobalClass]
|
||||
public partial class GhostEventHandler : Node
|
||||
{
|
||||
private GhostManager _ghostManager;
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
_ghostManager = GetNode<GhostManager>("/root/GhostManager");
|
||||
var eventBus = GetNode<EventBus>("/root/EventBus");
|
||||
|
||||
eventBus.LevelStarted += OnLevelStarted;
|
||||
eventBus.LevelCompleted += OnLevelCompleted;
|
||||
}
|
||||
|
||||
private void OnLevelStarted(int levelIndex, Node currentScene)
|
||||
{
|
||||
GD.Print($"GhostEventHandler: Level {levelIndex} started.");
|
||||
_ghostManager.StartRecording(levelIndex);
|
||||
_ghostManager.SpawnGhostPlayer(levelIndex, currentScene);
|
||||
}
|
||||
|
||||
private void OnLevelCompleted(int levelIndex, Node currentScene, double completionTime)
|
||||
{
|
||||
_ghostManager.StopRecording(true, completionTime);
|
||||
}
|
||||
}
|
1
scripts/Events/GhostEventHandler.cs.uid
Normal file
1
scripts/Events/GhostEventHandler.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://dkqeys6lsf04v
|
23
scripts/Events/SpeedRunEventHandler.cs
Normal file
23
scripts/Events/SpeedRunEventHandler.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using Godot;
|
||||
using Mr.BrickAdventures.Autoloads;
|
||||
|
||||
namespace Mr.BrickAdventures.scripts.Events;
|
||||
|
||||
[GlobalClass]
|
||||
public partial class SpeedRunEventHandler : Node
|
||||
{
|
||||
private SpeedRunManager _speedRunManager;
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
_speedRunManager = GetNode<SpeedRunManager>("/root/SpeedRunManager");
|
||||
var eventBus = GetNode<EventBus>("/root/EventBus");
|
||||
|
||||
eventBus.LevelCompleted += OnLevelCompleted;
|
||||
}
|
||||
|
||||
private void OnLevelCompleted(int levelIndex, Node currentScene, double completionTime)
|
||||
{
|
||||
_speedRunManager.Split();
|
||||
}
|
||||
}
|
1
scripts/Events/SpeedRunEventHandler.cs.uid
Normal file
1
scripts/Events/SpeedRunEventHandler.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://bysxvcvt00t04
|
9
scripts/GhostFrame.cs
Normal file
9
scripts/GhostFrame.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using Godot;
|
||||
|
||||
namespace Mr.BrickAdventures.scripts;
|
||||
|
||||
public partial class GhostFrame : GodotObject
|
||||
{
|
||||
public double Timestamp { get; set; }
|
||||
public Vector2 Position { get; set; }
|
||||
}
|
1
scripts/GhostFrame.cs.uid
Normal file
1
scripts/GhostFrame.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://d2vth3yveucti
|
48
scripts/GhostPlayer.cs
Normal file
48
scripts/GhostPlayer.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
using System.Collections.Generic;
|
||||
using Godot;
|
||||
|
||||
namespace Mr.BrickAdventures.scripts;
|
||||
|
||||
[GlobalClass]
|
||||
public partial class GhostPlayer : Node2D
|
||||
{
|
||||
private List<GhostFrame> _playbackData = [];
|
||||
private double _startTime = 0;
|
||||
private int _currentFrameIndex = 0;
|
||||
private bool _isPlaying = false;
|
||||
|
||||
public void StartPlayback(List<GhostFrame> playbackData)
|
||||
{
|
||||
_playbackData = playbackData;
|
||||
_startTime = Time.GetTicksMsec() / 1000.0;
|
||||
_currentFrameIndex = 0;
|
||||
_isPlaying = true;
|
||||
SetProcess(true);
|
||||
}
|
||||
|
||||
public override void _PhysicsProcess(double delta)
|
||||
{
|
||||
if (!_isPlaying || _playbackData.Count == 0) return;
|
||||
|
||||
var currentTime = (Time.GetTicksMsec() / 1000.0) - _startTime;
|
||||
|
||||
while (_currentFrameIndex + 1 < _playbackData.Count && _playbackData[_currentFrameIndex + 1].Timestamp <= currentTime)
|
||||
{
|
||||
_currentFrameIndex++;
|
||||
}
|
||||
|
||||
if (_currentFrameIndex + 1 >= _playbackData.Count)
|
||||
{
|
||||
GlobalPosition = _playbackData[_currentFrameIndex].Position;
|
||||
_isPlaying = false;
|
||||
QueueFree();
|
||||
return;
|
||||
}
|
||||
|
||||
var frameA = _playbackData[_currentFrameIndex];
|
||||
var frameB = _playbackData[_currentFrameIndex + 1];
|
||||
var t = (currentTime - frameA.Timestamp) / (frameB.Timestamp - frameA.Timestamp);
|
||||
|
||||
GlobalPosition = frameA.Position.Lerp(frameB.Position, (float)t);
|
||||
}
|
||||
}
|
1
scripts/GhostPlayer.cs.uid
Normal file
1
scripts/GhostPlayer.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://cr4bfcpo27e7t
|
26
scripts/UI/SpeedRunHud.cs
Normal file
26
scripts/UI/SpeedRunHud.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using Godot;
|
||||
using Mr.BrickAdventures.Autoloads;
|
||||
|
||||
namespace Mr.BrickAdventures.scripts.UI;
|
||||
|
||||
[GlobalClass]
|
||||
public partial class SpeedRunHud : Control
|
||||
{
|
||||
[Export] private Label _timerLabel;
|
||||
|
||||
private SpeedRunManager _speedRunManager;
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
_speedRunManager = GetNode<SpeedRunManager>("/root/SpeedRunManager");
|
||||
|
||||
_speedRunManager.TimeUpdated += OnTimerUpdated;
|
||||
|
||||
Visible = _speedRunManager.IsVisible;
|
||||
}
|
||||
|
||||
private void OnTimerUpdated(double totalTime, double levelTime)
|
||||
{
|
||||
_timerLabel.Text = SpeedRunManager.FormatTime(totalTime);
|
||||
}
|
||||
}
|
1
scripts/UI/SpeedRunHud.cs.uid
Normal file
1
scripts/UI/SpeedRunHud.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://0jfdx0hufs55
|
Reference in New Issue
Block a user