Files
ft/Client/Assets/Scripts/UI/PinballUncountable/PinballUncountableDome.cs
2026-06-29 21:18:33 +08:00

178 lines
4.9 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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