Files
zeling_v2/Assets/Scripts/World/MovingPlatform.cs
2026-05-12 15:34:08 +08:00

145 lines
4.9 KiB
C#
Raw 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;
using System.Collections.Generic;
using BaseGames.Core.Events;
using UnityEngine;
namespace BaseGames.World
{
/// <summary>
/// 移动平台。Kinematic Rigidbody2D支持三种移动模式。
/// 乘客跟随OnTriggerEnter2D 时 SetParent离开时还原并附加速度。
/// </summary>
[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用于乘客 SetParent
private Rigidbody2D _rb;
private List<Transform> _passengers = new();
private int _waypointIndex;
private bool _movingForward = true;
private bool _triggered;
private bool _waiting;
private readonly CompositeDisposable _subs = new();
private void Awake()
{
_rb = GetComponent<Rigidbody2D>();
_rb.bodyType = RigidbodyType2D.Kinematic;
_rb.interpolation = RigidbodyInterpolation2D.Interpolate;
}
private void OnEnable()
{
_activationChannel?.Subscribe(OnTriggered).AddTo(_subs);
}
private void OnDisable()
{
_subs.Clear();
}
private void FixedUpdate()
{
if (_wayPoints == null || _wayPoints.Length == 0) return;
if (_moveType == MoveType.TriggeredLinear && !_triggered) return;
if (_waiting) return;
MoveTowardsNextWaypoint();
}
private void MoveTowardsNextWaypoint()
{
var target = (Vector2)_wayPoints[_waypointIndex].position;
var next = Vector2.MoveTowards(_rb.position, target, _speed * Time.fixedDeltaTime);
_rb.MovePosition(next);
if (Vector2.Distance(_rb.position, target) < 0.02f)
StartCoroutine(WaitAndAdvance());
}
private IEnumerator WaitAndAdvance()
{
_waiting = true;
yield return new WaitForSeconds(_waitAtEndpoint);
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 Pattern ─────────────────────────────────────────────────
private void OnTriggerEnter2D(Collider2D other)
{
if (!IsPassenger(other.gameObject)) return;
other.transform.SetParent(transform);
_passengers.Add(other.transform);
}
private void OnTriggerExit2D(Collider2D other)
{
if (!_passengers.Contains(other.transform)) return;
other.transform.SetParent(null);
_passengers.Remove(other.transform);
// 离开时附加平台速度,避免卡顿
var passengerRb = other.GetComponentInParent<Rigidbody2D>();
if (passengerRb != null)
passengerRb.AddForce(_rb.velocity, ForceMode2D.Impulse);
}
private static bool IsPassenger(GameObject go)
{
return go.CompareTag("Player") || go.CompareTag("Enemy");
}
#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
}
}