113 lines
3.8 KiB
C#
113 lines
3.8 KiB
C#
using asap.core;
|
|
using UnityEngine;
|
|
|
|
namespace PinballUncountable
|
|
{
|
|
public class PinballUncountableSimBall : MonoBehaviour
|
|
{
|
|
// [SerializeField] private GameObject fxTail;
|
|
[SerializeField] private TrailRenderer trailRenderer;
|
|
// public GameObject FxTail => fxTail;
|
|
private PinballUncountableFrameData[] _frames;
|
|
private float _startTime;
|
|
private bool _isPlaying;
|
|
private const float FrameInterval = 0.02f; // 50fps
|
|
private string _lastLoggedCollider = ""; // Track last logged collider to avoid spam
|
|
|
|
/// <summary>
|
|
/// 该小球从哪个 exit 出去
|
|
/// </summary>
|
|
public int ExitIdx { get; private set; }
|
|
|
|
/// <summary>
|
|
/// 回放完成时的回调,参数为小球实例和出口编号
|
|
/// </summary>
|
|
public System.Action<PinballUncountableSimBall, int> OnReplayFinished;
|
|
|
|
|
|
|
|
public void StartReplay(PinballUncountableFrameData[] frames, int exitIdx)
|
|
{
|
|
if (frames == null || frames.Length == 0)
|
|
{
|
|
Debug.LogError("Data error: Invalid data provided!");
|
|
return;
|
|
}
|
|
_frames = frames;
|
|
ExitIdx = exitIdx;
|
|
gameObject.SetActive(true);
|
|
StartReplay();
|
|
}
|
|
|
|
public async void StartReplay()
|
|
{
|
|
try
|
|
{
|
|
if (_frames == null || _frames.Length == 0)
|
|
{
|
|
Debug.LogError("BallReplay: No data to replay!");
|
|
return;
|
|
}
|
|
_startTime = Time.time;
|
|
_isPlaying = true;
|
|
await Awaiters.NextFrame;
|
|
trailRenderer.Clear();
|
|
}
|
|
catch (System.Exception e)
|
|
{
|
|
Debug.LogError(e);
|
|
}
|
|
}
|
|
|
|
public void StopReplay()
|
|
{
|
|
_isPlaying = false;
|
|
gameObject.SetActive(false);
|
|
}
|
|
|
|
private void Update()
|
|
{
|
|
if (!_isPlaying || _frames == null || _frames.Length == 0)
|
|
return;
|
|
|
|
float elapsed = Time.time - _startTime;
|
|
float frameFloat = elapsed / FrameInterval; // Convert to 50fps frame index
|
|
int frameIndex = (int)frameFloat;
|
|
|
|
// Stop condition: freeze at last position
|
|
if (frameIndex >= _frames.Length - 1)
|
|
{
|
|
transform.position = _frames[_frames.Length - 1].Position;
|
|
StopReplay();
|
|
// 通知系统回收对象,传递出口编号
|
|
OnReplayFinished?.Invoke(this, ExitIdx);
|
|
return;
|
|
}
|
|
|
|
int nextFrame = frameIndex + 1;
|
|
// if (nextFrame == 20)
|
|
// {
|
|
// fxTail.SetActive(true);
|
|
// }
|
|
float t = frameFloat - frameIndex; // Interpolation factor (0-1)
|
|
|
|
// Linear interpolation between current and next recorded frame
|
|
transform.position = Vector2.Lerp(_frames[frameIndex].Position, _frames[nextFrame].Position, t);
|
|
|
|
// Log collision if collider is present and different from last logged
|
|
string currentCollider = _frames[frameIndex].Collider;
|
|
if (!string.IsNullOrEmpty(currentCollider) && currentCollider != _lastLoggedCollider)
|
|
{
|
|
// Debug.Log($"[PinballUncountable] Collision with: {currentCollider}");
|
|
GContext.container.Resolve<Manager>().EventAggregator.Publish(new EventHitDisc { DiscName = currentCollider });
|
|
_lastLoggedCollider = currentCollider;
|
|
}
|
|
else if (string.IsNullOrEmpty(currentCollider) && !string.IsNullOrEmpty(_lastLoggedCollider))
|
|
{
|
|
// Reset when collision ends
|
|
_lastLoggedCollider = "";
|
|
}
|
|
}
|
|
}
|
|
}
|