178 lines
4.9 KiB
C#
178 lines
4.9 KiB
C#
using System.Collections.Generic;
|
||
using asap.core;
|
||
using UnityEngine;
|
||
using Game;
|
||
|
||
namespace PinballUncountable
|
||
{
|
||
public class PinballUncountableDome : MonoBehaviour
|
||
{
|
||
[SerializeField] private Rigidbody2D[] balls;
|
||
[Range(0f, 1f)][SerializeField] private float xRange = 1f;
|
||
[SerializeField] private float yRange = 15f;
|
||
|
||
[Header("Baked Replay (optional, no physics)")]
|
||
[Tooltip("若赋值则使用烘焙轨迹回放;否则小球保持静止,不进行实时物理")]
|
||
[SerializeField] private PinballUncountableDomeBakedData bakedData;
|
||
|
||
private const float FrameInterval = 0.02f; // 50fps,与 SimBall 一致
|
||
private PinballUncountableFrameData[][] _replayFrames;
|
||
private float _replayStartTime;
|
||
private bool _isReplaying;
|
||
private Collider2D[] _ballColliders;
|
||
private bool _bakePhysicsCollisionEnabled = true;
|
||
|
||
private void Awake()
|
||
{
|
||
CacheBallColliders();
|
||
ApplyCollisionMode();
|
||
}
|
||
|
||
public void Kick(bool block = false)
|
||
{
|
||
if (block)
|
||
{
|
||
return;
|
||
}
|
||
_bakePhysicsCollisionEnabled = false;
|
||
ApplyCollisionMode();
|
||
GContext.Publish(new EventUISound("audio_ui_eventUncountablePinball_cowboy_pinball_anim"));
|
||
|
||
if (bakedData != null && bakedData.variants != null && bakedData.variants.Length > 0)
|
||
{
|
||
StartBakedReplay();
|
||
return;
|
||
}
|
||
|
||
StopBalls();
|
||
}
|
||
|
||
private void StartBakedReplay()
|
||
{
|
||
var variant = bakedData.variants[Random.Range(0, bakedData.variants.Length)];
|
||
if (variant?.trajectories == null || variant.trajectories.Length == 0)
|
||
{
|
||
StopBalls();
|
||
return;
|
||
}
|
||
|
||
int ballCount = Mathf.Min(balls.Length, variant.trajectories.Length);
|
||
_replayFrames = new PinballUncountableFrameData[ballCount][];
|
||
for (int i = 0; i < ballCount; i++)
|
||
{
|
||
_replayFrames[i] = PinballUncountableDomeBakedData.ToFrameData(variant.trajectories[i]);
|
||
if (_replayFrames[i] == null || _replayFrames[i].Length == 0)
|
||
{
|
||
StopBalls();
|
||
return;
|
||
}
|
||
}
|
||
|
||
for (int i = 0; i < balls.Length; i++)
|
||
{
|
||
var rb = balls[i];
|
||
rb.simulated = false;
|
||
rb.velocity = Vector2.zero;
|
||
if (i < _replayFrames.Length && _replayFrames[i].Length > 0)
|
||
rb.transform.position = _replayFrames[i][0].Position;
|
||
}
|
||
|
||
foreach (var ball in balls)
|
||
{
|
||
var trail = ball.GetComponentInChildren<TrailRenderer>();
|
||
if (trail != null) trail.Clear();
|
||
}
|
||
|
||
_replayStartTime = Time.time;
|
||
_isReplaying = true;
|
||
}
|
||
|
||
public void StopBalls()
|
||
{
|
||
_isReplaying = false;
|
||
_replayFrames = null;
|
||
foreach (var ball in balls)
|
||
{
|
||
if (ball == null)
|
||
continue;
|
||
|
||
ball.velocity = Vector2.zero;
|
||
ball.angularVelocity = 0f;
|
||
ball.simulated = false;
|
||
}
|
||
}
|
||
|
||
private void Update()
|
||
{
|
||
if (!_isReplaying || _replayFrames == null || balls == null)
|
||
return;
|
||
|
||
float elapsed = Time.time - _replayStartTime;
|
||
float frameFloat = elapsed / FrameInterval;
|
||
int frameIndex = (int)frameFloat;
|
||
|
||
bool anyStillPlaying = false;
|
||
for (int i = 0; i < _replayFrames.Length && i < balls.Length; i++)
|
||
{
|
||
var frames = _replayFrames[i];
|
||
var ball = balls[i];
|
||
|
||
if (frameIndex >= frames.Length - 1)
|
||
{
|
||
ball.transform.position = frames[frames.Length - 1].Position;
|
||
continue;
|
||
}
|
||
|
||
anyStillPlaying = true;
|
||
int nextFrame = frameIndex + 1;
|
||
float t = frameFloat - frameIndex;
|
||
ball.transform.position = Vector2.Lerp(frames[frameIndex].Position, frames[nextFrame].Position, t);
|
||
}
|
||
|
||
if (!anyStillPlaying)
|
||
{
|
||
StopBalls();
|
||
}
|
||
}
|
||
|
||
public void SetBakePhysicsCollisionEnabled(bool enabled)
|
||
{
|
||
_bakePhysicsCollisionEnabled = enabled;
|
||
CacheBallColliders();
|
||
ApplyCollisionMode();
|
||
}
|
||
|
||
private void CacheBallColliders()
|
||
{
|
||
if (balls == null || balls.Length == 0)
|
||
{
|
||
_ballColliders = System.Array.Empty<Collider2D>();
|
||
return;
|
||
}
|
||
|
||
var colliders = new List<Collider2D>();
|
||
foreach (var ball in balls)
|
||
{
|
||
if (ball == null)
|
||
continue;
|
||
|
||
colliders.AddRange(ball.GetComponentsInChildren<Collider2D>(true));
|
||
}
|
||
|
||
_ballColliders = colliders.ToArray();
|
||
}
|
||
|
||
private void ApplyCollisionMode()
|
||
{
|
||
if (_ballColliders == null)
|
||
return;
|
||
|
||
foreach (var collider in _ballColliders)
|
||
{
|
||
if (collider != null)
|
||
collider.enabled = _bakePhysicsCollisionEnabled;
|
||
}
|
||
}
|
||
}
|
||
} // namespace PinballUncountable
|