275 lines
6.9 KiB
C#
275 lines
6.9 KiB
C#
using System;
|
||
using DG.Tweening;
|
||
using DragonLi.Core;
|
||
using System.Collections;
|
||
using UnityEngine;
|
||
|
||
/// <summary>
|
||
/// 硬币状态
|
||
/// </summary>
|
||
public enum CoinState
|
||
{
|
||
/// <summary>
|
||
/// 可收集状态
|
||
/// </summary>
|
||
Collectable,
|
||
/// <summary>
|
||
/// 在玩家面前
|
||
/// </summary>
|
||
PlayerFront,
|
||
/// <summary>
|
||
/// 飞向硬币台
|
||
/// </summary>
|
||
FlyingToPlatform,
|
||
/// <summary>
|
||
/// 在硬币台上
|
||
/// </summary>
|
||
OnPlatform,
|
||
/// <summary>
|
||
/// 飞向猴子
|
||
/// </summary>
|
||
FlyingToMonkey
|
||
}
|
||
|
||
/// <summary>
|
||
/// 硬币对象
|
||
/// </summary>
|
||
public class Coin : MonoBehaviour
|
||
{
|
||
[Header("基础设置")]
|
||
[SerializeField] private float rotateSpeed = 180f; // 旋转速度(度/秒)
|
||
[SerializeField] private float frontDuration = 2.5f; // 在玩家面前停留时长
|
||
[SerializeField] private float flyDuration = 1.5f; // 飞行时长
|
||
|
||
[Header("特效")]
|
||
[SerializeField] private ParticleSystem collectEffect; // 收集特效
|
||
[SerializeField] private ParticleSystem trailEffect; // 飞行轨迹特效
|
||
|
||
public CoinState CurrentState { get; private set; } = CoinState.Collectable;
|
||
public int CoinID { get; set; } // 硬币ID(0-7)
|
||
|
||
private Transform coinSlot; // 当前所在的插槽位置
|
||
|
||
private void Start()
|
||
{
|
||
// 硬币初始旋转
|
||
StartCoroutine(AutoRotate());
|
||
}
|
||
|
||
/// <summary>
|
||
/// 自动旋转(可收集状态)
|
||
/// </summary>
|
||
private IEnumerator AutoRotate()
|
||
{
|
||
while (CurrentState == CoinState.Collectable)
|
||
{
|
||
transform.Rotate(Vector3.up, rotateSpeed * Time.deltaTime);
|
||
yield return null;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 被收集
|
||
/// </summary>
|
||
public void OnCollected()
|
||
{
|
||
if (CurrentState != CoinState.Collectable)
|
||
{
|
||
Debug.LogWarning($"硬币 {CoinID} 已经被收集过了!");
|
||
return;
|
||
}
|
||
|
||
CurrentState = CoinState.PlayerFront;
|
||
|
||
// 播放收集音效
|
||
GameManager.Ins.PlaySound2DRPC("1.6");
|
||
|
||
// 播放收集特效
|
||
if (collectEffect != null)
|
||
{
|
||
collectEffect.Play();
|
||
}
|
||
|
||
// 开始移动到玩家面前的序列
|
||
StartCoroutine(MoveToFrontSequence());
|
||
}
|
||
|
||
/// <summary>
|
||
/// 移动到玩家面前的序列
|
||
/// </summary>
|
||
private IEnumerator MoveToFrontSequence()
|
||
{
|
||
// 计算目标位置(玩家前方1米处,视线高度略低)
|
||
Vector3 playerPos = GameLocal.Ins.self.transform.position;
|
||
Vector3 playerForward = GameLocal.Ins.self.transform.forward;
|
||
|
||
Vector3 targetPos = playerPos + playerForward * 1f;
|
||
targetPos.y = playerPos.y - 0.3f;
|
||
|
||
// 移动到目标位置
|
||
transform.DOMove(targetPos, 0.5f).SetEase(Ease.OutBack);
|
||
transform.DORotate(Vector3.zero, 0.3f);
|
||
|
||
yield return new WaitForSeconds(0.5f);
|
||
|
||
// 旋转展示
|
||
float rotationTime = 0f;
|
||
while (rotationTime < frontDuration)
|
||
{
|
||
transform.Rotate(Vector3.up, 360 * Time.deltaTime / frontDuration);
|
||
rotationTime += Time.deltaTime;
|
||
yield return null;
|
||
}
|
||
|
||
// 停止旋转并飞向硬币台
|
||
FlyToPlatform();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 飞向硬币台
|
||
/// </summary>
|
||
private void FlyToPlatform()
|
||
{
|
||
CurrentState = CoinState.FlyingToPlatform;
|
||
|
||
// 获取下一个空插槽
|
||
int slotIndex = CoinManager.Ins.GetNextSlotIndex();
|
||
if (slotIndex < 0)
|
||
{
|
||
Debug.LogError("没有可用的硬币插槽!");
|
||
return;
|
||
}
|
||
|
||
// 设置硬币ID
|
||
CoinID = slotIndex;
|
||
|
||
// 通知硬币台
|
||
CoinPlatform.Ins.PlaceCoin(this, slotIndex);
|
||
|
||
// 获取目标插槽位置
|
||
Transform targetSlot = CoinPlatform.Ins.GetSlotPosition(slotIndex);
|
||
if (targetSlot == null)
|
||
{
|
||
Debug.LogError($"插槽 {slotIndex} 不存在!");
|
||
return;
|
||
}
|
||
|
||
coinSlot = targetSlot;
|
||
|
||
// 启用轨迹特效
|
||
if (trailEffect != null)
|
||
{
|
||
trailEffect.Play();
|
||
}
|
||
|
||
// 飞向插槽
|
||
transform.DOMove(targetSlot.position, flyDuration)
|
||
.SetEase(Ease.OutBack)
|
||
.OnComplete(() => {
|
||
OnArrivedAtPlatform();
|
||
});
|
||
}
|
||
|
||
/// <summary>
|
||
/// 到达硬币台
|
||
/// </summary>
|
||
private void OnArrivedAtPlatform()
|
||
{
|
||
CurrentState = CoinState.OnPlatform;
|
||
|
||
// 停止轨迹特效
|
||
if (trailEffect != null)
|
||
{
|
||
trailEffect.Stop();
|
||
}
|
||
|
||
// 在插槽位置持续旋转
|
||
StartCoroutine(RotateOnPlatform());
|
||
}
|
||
|
||
/// <summary>
|
||
/// 在硬币台上旋转
|
||
/// </summary>
|
||
private IEnumerator RotateOnPlatform()
|
||
{
|
||
while (CurrentState == CoinState.OnPlatform)
|
||
{
|
||
transform.RotateAround(coinSlot.position, Vector3.up, 60 * Time.deltaTime);
|
||
yield return null;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 飞向猴子(隐藏事件)
|
||
/// </summary>
|
||
public void FlyToMonkey(Transform monkeyPosition, float delay = 0f)
|
||
{
|
||
StartCoroutine(FlyToMonkeyCoroutine(monkeyPosition, delay));
|
||
}
|
||
|
||
private IEnumerator FlyToMonkeyCoroutine(Transform monkeyPosition, float delay)
|
||
{
|
||
yield return new WaitForSeconds(delay);
|
||
|
||
CurrentState = CoinState.FlyingToMonkey;
|
||
|
||
// 播放飞升音效
|
||
GameManager.Ins.PlaySound2DRPC("1.22");
|
||
|
||
// 启用轨迹特效
|
||
if (trailEffect != null)
|
||
{
|
||
trailEffect.Play();
|
||
}
|
||
|
||
// 飞向猴子
|
||
transform.DOMove(monkeyPosition.position, 2f)
|
||
.SetEase(Ease.InOutQuad)
|
||
.OnComplete(() => {
|
||
OnArrivedAtMonkey();
|
||
});
|
||
}
|
||
|
||
/// <summary>
|
||
/// 到达猴子
|
||
/// </summary>
|
||
private void OnArrivedAtMonkey()
|
||
{
|
||
// 停止轨迹特效
|
||
if (trailEffect != null)
|
||
{
|
||
trailEffect.Stop();
|
||
}
|
||
|
||
// 播放消失特效
|
||
if (collectEffect != null)
|
||
{
|
||
collectEffect.Play();
|
||
}
|
||
|
||
// 延迟后销毁
|
||
StartCoroutine(DestroyAfterDelay(0.5f));
|
||
}
|
||
|
||
private IEnumerator DestroyAfterDelay(float delay)
|
||
{
|
||
yield return new WaitForSeconds(delay);
|
||
Destroy(gameObject);
|
||
}
|
||
|
||
private void OnTriggerEnter(Collider other)
|
||
{
|
||
if (other.CompareTag("RightHand"))
|
||
{
|
||
OnCollected();
|
||
GetComponent<Collider>().enabled = false;
|
||
}
|
||
|
||
}
|
||
|
||
private void OnDestroy()
|
||
{
|
||
// 清理DOTween动画
|
||
transform.DOKill();
|
||
}
|
||
} |