using System.Collections;
using System.Collections.Generic;
using BaseGames.Core;
using BaseGames.Core.Events;
using UnityEngine;
namespace BaseGames.World
{
///
/// 移动平台。Kinematic Rigidbody2D,支持三种移动模式。
///
/// 乘客跟随(Velocity 双缓冲方案):
/// - PassengerSensor(Trigger)通过 attachedRigidbody 检测乘客()。
/// - FixedUpdate(-300) 计算本帧期望位移 delta → SetPlatformDelta(delta) 写入乘客缓冲区。
/// - 乘客 FixedUpdate(-200) 换入缓冲速度;状态机 FixedUpdate(-100) 的 Move() 将其叠加到 velocity。
/// - 基于 velocity 驱动,与 RigidbodyInterpolation2D.Interpolate 完全兼容,无视觉抖动。
/// - 乘客离台时 OnLeavePlatform 继承垂直速度分量;水平分量已由 Move() 自然携带。
///
/// 此方案不修改 Transform 层级,与动画/摄像机/HitBox 系统完全兼容。
///
[DefaultExecutionOrder(-300)]
[RequireComponent(typeof(Rigidbody2D))]
public class MovingPlatform : MonoBehaviour
{
public enum MoveType { LinearAB, WayPoints, TriggeredLinear }
[Header("移动配置")]
[SerializeField] private MoveType _moveType = MoveType.LinearAB;
[SerializeField] private Transform[] _wayPoints;
[SerializeField] private float _speed = 3f;
[SerializeField] private float _waitAtEndpoint = 0.5f;
[Header("TriggeredLinear 模式")]
[SerializeField] private VoidEventChannelSO _activationChannel;
[Header("乘客检测")]
[SerializeField] private BoxCollider2D _passengerSensor; // isTrigger,检测乘客
[SerializeField] private LayerMask _passengerLayer; // 应包含 Player + Enemy 层
private Rigidbody2D _rb;
private readonly List _passengers = new();
private readonly List _passengerSnapshot = new(); // 迭代快照,防并发修改
private int _waypointIndex;
private bool _movingForward = true;
private bool _triggered;
private bool _waiting;
private Vector2 _frameVelocity; // 本帧实际速度,供离台时继承
private WaitForSeconds _waitForEndpoint;
private readonly CompositeDisposable _subs = new();
private void Awake()
{
_rb = GetComponent();
_rb.bodyType = RigidbodyType2D.Kinematic;
_rb.interpolation = RigidbodyInterpolation2D.Interpolate;
_waitForEndpoint = new WaitForSeconds(_waitAtEndpoint);
}
private void OnEnable()
{
_activationChannel?.Subscribe(OnTriggered).AddTo(_subs);
}
private void OnDisable()
{
_subs.Clear();
}
private void FixedUpdate()
{
if (_wayPoints == null || _wayPoints.Length == 0)
{
_frameVelocity = Vector2.zero;
return;
}
if (_moveType == MoveType.TriggeredLinear && !_triggered)
{
_frameVelocity = Vector2.zero;
return;
}
if (_waiting)
{
_frameVelocity = Vector2.zero;
return;
}
MoveAndBroadcast();
}
private void MoveAndBroadcast()
{
var target = (Vector2)_wayPoints[_waypointIndex].position;
var next = Vector2.MoveTowards(_rb.position, target, _speed * Time.fixedDeltaTime);
// 计算期望 delta(在 MovePosition 执行前,不依赖物理步骤是否完成)
Vector2 delta = next - _rb.position;
_frameVelocity = delta / Time.fixedDeltaTime;
// 先广播 delta,乘客在下一个 FixedUpdate(-200) 消费
_passengerSnapshot.Clear();
_passengerSnapshot.AddRange(_passengers);
foreach (var r in _passengerSnapshot)
r.SetPlatformDelta(delta);
_rb.MovePosition(next);
if (Vector2.Distance(_rb.position, target) < 0.02f)
StartCoroutine(WaitAndAdvance());
}
private IEnumerator WaitAndAdvance()
{
_waiting = true;
yield return _waitForEndpoint;
AdvanceWaypoint();
_waiting = false;
}
private void AdvanceWaypoint()
{
if (_moveType == MoveType.TriggeredLinear)
{
_waypointIndex = Mathf.Min(_waypointIndex + 1, _wayPoints.Length - 1);
if (_waypointIndex == _wayPoints.Length - 1)
_triggered = false;
return;
}
if (_moveType == MoveType.LinearAB)
{
_movingForward = !_movingForward;
_waypointIndex = _movingForward ? 1 : 0;
}
else // WayPoints
{
_waypointIndex = (_waypointIndex + 1) % _wayPoints.Length;
}
}
private void OnTriggered() => _triggered = true;
// ── Passenger Detection ───────────────────────────────────────────────
private void OnTriggerEnter2D(Collider2D other)
{
if (!IsPassengerLayer(other)) return;
// attachedRigidbody:若玩家碰撞体在子对象上,也能正确找到根对象上的 IPassengerReceiver
if (!other.attachedRigidbody) return;
if (!other.attachedRigidbody.TryGetComponent(out var receiver)) return;
if (!_passengers.Contains(receiver))
_passengers.Add(receiver);
}
private void OnTriggerExit2D(Collider2D other)
{
if (!other.attachedRigidbody) return;
if (!other.attachedRigidbody.TryGetComponent(out var receiver)) return;
if (!_passengers.Remove(receiver)) return;
// 继承平台垂直速度;水平速度已由 IPassengerReceiver.Move() 自然携带,无需重复叠加
receiver.OnLeavePlatform(_frameVelocity);
}
private bool IsPassengerLayer(Collider2D col)
=> (_passengerLayer.value & (1 << col.gameObject.layer)) != 0;
#if UNITY_EDITOR
private void OnDrawGizmos()
{
if (_wayPoints == null || _wayPoints.Length < 2) return;
Gizmos.color = new Color(1f, 0.8f, 0f, 0.8f);
for (int i = 0; i < _wayPoints.Length - 1; i++)
{
if (_wayPoints[i] != null && _wayPoints[i + 1] != null)
Gizmos.DrawLine(_wayPoints[i].position, _wayPoints[i + 1].position);
}
}
#endif
}
}