Files
MRSnowWhite/Assets/_SnowWhite/Scripts/Cutscene/CrystalStatueGroup.cs

535 lines
14 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 UnityEngine;
using System.Collections.Generic;
using DG.Tweening;
/// <summary>
/// 水晶雕像组 - 管理5个雕像的组
/// 包含1个目标雕像和4个正常雕像
/// </summary>
public class CrystalStatueGroup : MonoBehaviour
{
#region
[Header("雕像引用")]
[Tooltip("组内所有雕像(包括目标和正常雕像)")]
public CrystalStatue[] statues;
[Header("目标雕像")]
[Tooltip("目标雕像引用(场景中已配置)")]
public CrystalStatue targetStatue;
[Header("升起/下沉动画")]
[Tooltip("升起高度(从地下升起的距离)")]
public float riseHeight = 0.5f;
[Tooltip("升起动画时长")]
public float riseDuration = 0.8f;
[Tooltip("下沉动画时长")]
public float sinkDuration = 0.5f;
[Tooltip("雕像出现间隔(错开效果)")]
public float staggerDelay = 0.1f;
[Header("随机旋转")]
[Tooltip("是否启用随机旋转")]
public bool enableRandomRotation = true;
[Tooltip("旋转角度份数360度分成几份")]
public int rotationDivisions = 5;
[Header("调试")]
public bool debugMode = true;
#endregion
#region
/// <summary>
/// 当前组是否激活
/// </summary>
public bool IsGroupActive { get; private set; } = false;
/// <summary>
/// 组内是否所有雕像已碎裂
/// </summary>
public bool IsAllBroken { get; private set; } = false;
// 回调
/// <summary>
/// 目标雕像被击碎回调
/// </summary>
public System.Action<CrystalStatueGroup> OnTargetBroken;
/// <summary>
/// 错误雕像被击碎回调
/// </summary>
public System.Action<CrystalStatueGroup> OnWrongStatueBroken;
#endregion
#region Unity生命周期
private void Awake()
{
// 如果没有配置雕像,尝试从子物体获取
if (statues == null || statues.Length == 0)
{
statues = GetComponentsInChildren<CrystalStatue>();
}
}
private void Start()
{
// 初始状态为隐藏
//gameObject.SetActive(false);
}
#endregion
#region
/// <summary>
/// 激活雕像组(升起动画)
/// </summary>
public void ActivateGroup()
{
if (debugMode)
Debug.Log($"[CrystalStatueGroup] 激活雕像组: {name}");
IsGroupActive = true;
IsAllBroken = false;
// 显示组
gameObject.SetActive(true);
// 同步位置到玩家
SyncPositionToPlayer();
// 应用随机旋转
ApplyRandomRotation();
// 播放升起动画
PlayRiseAnimation();
// 初始化所有雕像
foreach (var statue in statues)
{
if (statue != null)
{
// 判断是否为目标雕像
bool isTarget = (statue == targetStatue);
statue.Initialize(isTarget);
// 注册碎裂回调
statue.OnStatueBroken = OnStatueBrokenHandler;
}
}
if (debugMode)
{
if (targetStatue != null)
Debug.Log($"[CrystalStatueGroup] 目标雕像: {targetStatue.name}");
else
Debug.LogWarning($"[CrystalStatueGroup] 未配置目标雕像!");
}
}
/// <summary>
/// 隐藏雕像组(下沉动画)
/// </summary>
public void DeactivateGroup()
{
if (debugMode)
Debug.Log($"[CrystalStatueGroup] 隐藏雕像组: {name}");
// 播放下沉动画,动画结束后隐藏
PlaySinkAnimation(() =>
{
IsGroupActive = false;
gameObject.SetActive(false);
// 清除回调
foreach (var statue in statues)
{
if (statue != null)
{
statue.OnStatueBroken = null;
}
}
});
}
/// <summary>
/// 立即隐藏(无动画)
/// </summary>
public void DeactivateGroupImmediate()
{
if (debugMode)
Debug.Log($"[CrystalStatueGroup] 立即隐藏雕像组: {name}");
IsGroupActive = false;
gameObject.SetActive(false);
// 清除回调
foreach (var statue in statues)
{
if (statue != null)
{
statue.OnStatueBroken = null;
}
}
}
/// <summary>
/// 同步位置到玩家中心
/// </summary>
public void SyncPositionToPlayer()
{
if (GameLocal.Ins != null && GameLocal.Ins.self != null)
{
Vector3 playerPos = GameLocal.Ins.self.transform.position;
// 只同步XZ平面保持Y轴不变
transform.position = new Vector3(playerPos.x, transform.position.y, playerPos.z);
if (debugMode)
Debug.Log($"[CrystalStatueGroup] 同步位置到玩家: {transform.position}");
}
}
/// <summary>
/// 重置组内所有雕像
/// </summary>
public void ResetGroup()
{
foreach (var statue in statues)
{
if (statue != null)
{
statue.Reset();
}
}
IsAllBroken = false;
}
/// <summary>
/// 让所有未碎裂的雕像播放狞笑
/// </summary>
public void PlayAllEvilLaugh()
{
foreach (var statue in statues)
{
if (statue != null && !statue.IsBroken())
{
statue.PlayEvilLaugh();
}
}
}
/// <summary>
/// 让所有未碎裂的雕像消失
/// </summary>
public void DisappearAllStatues(float duration = 0.5f)
{
foreach (var statue in statues)
{
if (statue != null && !statue.IsBroken())
{
statue.ForceDisappear(duration);
}
}
}
/// <summary>
/// 检查是否所有雕像都已碎裂
/// </summary>
public bool CheckAllBroken()
{
foreach (var statue in statues)
{
if (statue != null && !statue.IsBroken())
{
return false;
}
}
return true;
}
/// <summary>
/// 启用所有雕像的击打功能
/// </summary>
public void EnableHit()
{
foreach (var statue in statues)
{
if (statue != null)
{
statue.SetCanHit(true);
}
}
if (debugMode)
Debug.Log($"[CrystalStatueGroup] 启用击打");
}
/// <summary>
/// 禁用所有雕像的击打功能
/// </summary>
public void DisableHit()
{
foreach (var statue in statues)
{
if (statue != null)
{
statue.SetCanHit(false);
}
}
if (debugMode)
Debug.Log($"[CrystalStatueGroup] 禁用击打");
}
/// <summary>
/// 设置是否允许显示裂痕语音期间为false特效出现后为true
/// </summary>
public void SetCanShowCrack(bool value)
{
foreach (var statue in statues)
{
if (statue != null)
{
statue.SetCanShowCrack(value);
}
}
if (debugMode)
Debug.Log($"[CrystalStatueGroup] 设置裂痕显示: {value}");
}
#endregion
#region
/// <summary>
/// 应用随机Y轴旋转
/// 将360度分成rotationDivisions份随机选择一个角度
/// </summary>
private void ApplyRandomRotation()
{
if (!enableRandomRotation)
return;
// 计算每份的角度
float anglePerDivision = 360f / rotationDivisions;
// 随机选择一个份数0到rotationDivisions-1
int randomDivision = Random.Range(0, rotationDivisions);
// 计算最终角度
float randomAngle = randomDivision * anglePerDivision;
// 应用Y轴旋转
transform.rotation = Quaternion.Euler(0f, randomAngle, 0f);
if (debugMode)
Debug.Log($"[CrystalStatueGroup] 随机旋转: {randomAngle}度 (第{randomDivision + 1}/{rotationDivisions}份)");
}
/// <summary>
/// 播放升起动画(雕像从地下升起)
/// </summary>
private void PlayRiseAnimation()
{
for (int i = 0; i < statues.Length; i++)
{
if (statues[i] == null)
continue;
CrystalStatue statue = statues[i];
Transform statueTransform = statue.transform;
// 保存目标位置
Vector3 targetPosition = statueTransform.position;
// 设置初始位置(在地下)
statueTransform.position = targetPosition - Vector3.up * riseHeight;
// 初始缩放为0
statueTransform.localScale = Vector3.zero;
// 计算延迟时间(错开出现)
float delay = i * staggerDelay;
// 使用DOTween播放升起动画
Sequence riseSeq = DOTween.Sequence();
// 延迟开始
riseSeq.SetDelay(delay);
// 同时执行缩放和位移动画
riseSeq.Join(statueTransform.DOScale(Vector3.one, riseDuration)
.SetEase(Ease.OutBack));
riseSeq.Join(statueTransform.DOMoveY(targetPosition.y, riseDuration)
.SetEase(Ease.OutQuad));
if (debugMode)
Debug.Log($"[CrystalStatueGroup] 雕像 {statue.name} 升起动画,延迟: {delay}s");
}
}
/// <summary>
/// 播放下沉动画(雕像沉入地下)
/// </summary>
/// <param name="onComplete">动画完成回调</param>
private void PlaySinkAnimation(System.Action onComplete = null)
{
int completedCount = 0;
int totalStatues = 0;
for (int i = 0; i < statues.Length; i++)
{
if (statues[i] == null || statues[i].IsBroken())
continue;
totalStatues++;
}
if (totalStatues == 0)
{
onComplete?.Invoke();
return;
}
for (int i = 0; i < statues.Length; i++)
{
if (statues[i] == null || statues[i].IsBroken())
continue;
CrystalStatue statue = statues[i];
Transform statueTransform = statue.transform;
// 计算延迟时间(错开下沉,逆序)
float delay = (statues.Length - 1 - i) * staggerDelay;
// 使用DOTween播放下沉动画
Sequence sinkSeq = DOTween.Sequence();
// 延迟开始
sinkSeq.SetDelay(delay);
// 同时执行缩放和位移动画
sinkSeq.Join(statueTransform.DOScale(Vector3.zero, sinkDuration)
.SetEase(Ease.InBack));
sinkSeq.Join(statueTransform.DOMoveY(
statueTransform.position.y - riseHeight,
sinkDuration)
.SetEase(Ease.InQuad));
// 动画完成计数
sinkSeq.OnComplete(() =>
{
completedCount++;
if (completedCount >= totalStatues)
{
onComplete?.Invoke();
}
});
if (debugMode)
Debug.Log($"[CrystalStatueGroup] 雕像 {statue.name} 下沉动画");
}
}
/// <summary>
/// 雕像碎裂处理
/// </summary>
private void OnStatueBrokenHandler(CrystalStatue statue, bool isTarget)
{
if (debugMode)
Debug.Log($"[CrystalStatueGroup] 雕像碎裂: {statue.name}, 是否目标: {isTarget}");
// 禁用组内其他雕像的击打功能(一旦有雕像碎裂,不能再敲其他雕像)
DisableHitForOtherStatues(statue);
if (isTarget)
{
// 目标雕像被击碎
OnTargetBroken?.Invoke(this);
}
else
{
// 错误雕像被击碎
OnWrongStatueBroken?.Invoke(this);
}
// 检查是否所有雕像都已碎裂
if (CheckAllBroken())
{
IsAllBroken = true;
}
}
/// <summary>
/// 禁用除指定雕像外的所有雕像击打功能
/// </summary>
private void DisableHitForOtherStatues(CrystalStatue excludedStatue)
{
foreach (var statue in statues)
{
if (statue != null && statue != excludedStatue && !statue.IsBroken())
{
statue.SetCanHit(false);
}
}
if (debugMode)
Debug.Log($"[CrystalStatueGroup] 禁用其他雕像击打功能");
}
#endregion
#region
#if UNITY_EDITOR
[ContextMenu("自动获取雕像引用")]
private void AutoGetStatues()
{
statues = GetComponentsInChildren<CrystalStatue>();
Debug.Log($"[CrystalStatueGroup] 获取到 {statues.Length} 个雕像");
}
[ContextMenu("测试:激活组")]
private void TestActivate()
{
ActivateGroup();
}
[ContextMenu("测试:隐藏组")]
private void TestDeactivate()
{
DeactivateGroup();
}
[ContextMenu("测试:重置组")]
private void TestReset()
{
ResetGroup();
}
[ContextMenu("测试:狞笑")]
private void TestEvilLaugh()
{
PlayAllEvilLaugh();
}
[ContextMenu("测试:消失")]
private void TestDisappear()
{
DisappearAllStatues();
}
#endif
#endregion
}