Files
MRFishingMaster/Assets/_FishingMaster/Scripts/Statue/DriftBottle.cs

198 lines
5.1 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;
using DragonLi.Core;
using FluffyUnderware.Curvy;
using FluffyUnderware.Curvy.Controllers;
using UnityEngine;
using Random = UnityEngine.Random;
/// <summary>
/// 漂流瓶状态
/// </summary>
public enum DriftBottleState
{
Alive, // 存活状态
Captured, // 已被捕捉
Removed // 已移除
}
/// <summary>
/// 漂流瓶 - 海底雕像事件的核心物品
/// 沿路径游动,被击中后掉落雕像碎片
/// </summary>
public class DriftBottle : MonoBehaviour
{
[Header("组件引用")]
public Collider bottleCollider;
public Transform modelRoot;
public ParticleSystem fragmentEffect;
[Header("移动配置")]
public float moveSpeed = 1.5f;
public float swimAmplitude = 0.1f;
public float swimFrequency = 2f;
// 私有变量
private SplineController controller;
private DriftBottleState state = DriftBottleState.Alive;
private bool unregisterCalled = false;
private Vector3 baseScale;
private float swimOffset;
// 事件
public event Action<DriftBottle> OnBottleCaptured;
private void Awake()
{
if (modelRoot == null)
modelRoot = transform.GetChild(0);
baseScale = modelRoot.localScale;
swimOffset = Random.Range(0f, Mathf.PI * 2f);
}
/// <summary>
/// 初始化漂流瓶 - 不绑定特定碎片,击中时由管理器决定
/// </summary>
public void Init(CurvySpline spline)
{
state = DriftBottleState.Alive;
if (spline == null)
{
Debug.LogError("[DriftBottle] Init 失败spline 为 null");
return;
}
// 设置控制器
controller = GetComponent<SplineController>();
if (controller == null)
{
controller = gameObject.AddComponent<SplineController>();
}
controller.enabled = true;
controller.Spline = spline;
controller.Speed = moveSpeed;
controller.Position = 0;
controller.Play();
controller.OnEndReached.AddListener((c) => OnSplineEnd());
// 注册到管理器
DriftBottleManager.Instance?.RegisterBottle(this);
}
private void Update()
{
if (state != DriftBottleState.Alive || modelRoot == null) return;
// 添加游动动画效果
float swimAnim = Mathf.Sin(Time.time * swimFrequency + swimOffset) * swimAmplitude;
modelRoot.localScale = baseScale * (1f + swimAnim);
// 轻微上下浮动
Vector3 pos = modelRoot.localPosition;
pos.y = Mathf.Sin(Time.time * swimFrequency * 0.5f + swimOffset) * 0.05f;
modelRoot.localPosition = pos;
}
/// <summary>
/// 被击中 - 通知管理器处理碎片分配
/// </summary>
public void OnHit(float gunLevel)
{
if (state != DriftBottleState.Alive)
return;
// 漂流瓶命中率计算
float actualHitRate = gunLevel * 0.8f;
float hitProbability = actualHitRate * 100f + 30f;
float randomValue = Random.Range(0f, 100f);
if (randomValue > hitProbability)
{
return;
}
// 进入捕捉状态
state = DriftBottleState.Captured;
// 停止移动
if (controller != null)
controller.enabled = false;
if (bottleCollider != null)
bottleCollider.enabled = false;
// 注销
SafeUnregister();
// 播放特效
PlayCaptureEffects();
// 通知管理器处理碎片分配(立即处理,不等飞行结束)
DriftBottleManager.Instance?.OnBottleCaptured(this);
}
/// <summary>
/// 播放捕获特效
/// </summary>
private void PlayCaptureEffects()
{
if (fragmentEffect != null)
fragmentEffect.gameObject.SetActive(false);
var animator = modelRoot.GetComponent<Animator>();
if(animator != null)
animator.SetBool("isDie", true);
// 播放音效
GameManager.Ins?.PlaySound3D("漂流瓶击碎", transform);
// 延迟销毁
CoroutineTaskManager.Instance.WaitSecondTodo(() =>
{
RemoveInternal();
}, 2.5f);
}
/// <summary>
/// 路径结束
/// </summary>
private void OnSplineEnd()
{
if (state != DriftBottleState.Alive)
return;
RemoveInternal();
}
/// <summary>
/// 移除内部处理
/// </summary>
private void RemoveInternal()
{
if (state == DriftBottleState.Removed)
return;
state = DriftBottleState.Removed;
SafeUnregister();
transform.parent = null;
Destroy(gameObject);
}
/// <summary>
/// 安全注销
/// </summary>
private void SafeUnregister()
{
if (unregisterCalled) return;
unregisterCalled = true;
DriftBottleManager.Instance?.UnregisterBottle(this);
}
/// <summary>
/// 获取当前状态
/// </summary>
public DriftBottleState GetState() => state;
}