538 lines
14 KiB
C#
538 lines
14 KiB
C#
using UnityEngine;
|
|
using DarkTonic.MasterAudio;
|
|
using DG.Tweening;
|
|
using System;
|
|
|
|
/// <summary>
|
|
/// 水晶雕像控制器 - 单个雕像的控制逻辑
|
|
/// 包含血量、裂痕效果、击打反馈等功能
|
|
/// </summary>
|
|
public class CrystalStatue : MonoBehaviour
|
|
{
|
|
#region 配置
|
|
|
|
[Header("雕像类型")]
|
|
public StatueType statueType;
|
|
public bool isTarget; // 是否是目标雕像
|
|
|
|
[Header("血量配置")]
|
|
public int maxHealth = 3;
|
|
private int currentHealth;
|
|
|
|
[Header("裂痕效果")]
|
|
public Renderer statueRenderer;
|
|
public Material[] crackMaterials; // 0=正常, 1=裂痕1, 2=裂痕2, 3=碎裂前
|
|
public GameObject[] crackDecals; // 裂痕贴花对象
|
|
|
|
[Header("特效")]
|
|
public ParticleSystem hitParticle; // 击打粒子效果
|
|
public ParticleSystem breakParticle; // 碎裂粒子效果
|
|
public ParticleSystem evilLaughParticle; // 狞笑粒子效果(失败时)
|
|
|
|
[Header("音效")]
|
|
public string hitSound = "2.1"; // 击打音效
|
|
public string crackSound = "2.1"; // 裂痕音效
|
|
public string breakSound = "2.2"; // 碎裂音效
|
|
public string evilLaughSound = "2.3"; // 狞笑音效
|
|
|
|
[Header("动画")]
|
|
public Animator animator;
|
|
public string hitAnimTrigger = "Hit";
|
|
public string breakAnimTrigger = "Break";
|
|
public string evilLaughAnimTrigger = "EvilLaugh";
|
|
|
|
[Header("视觉效果")]
|
|
public GameObject heartObject; // 心脏显示对象(第三轮用)
|
|
public GameObject handsObject; // 双手显示对象(第二轮用)
|
|
public ParticleSystem specialEffect; // 特殊效果(心脏跳动/手部特效)
|
|
|
|
[Header("表情区分(第一轮用)")]
|
|
public GameObject evilFaceObject; // 邪恶表情对象
|
|
|
|
[Header("碎裂配置")]
|
|
public float breakDuration = 1f;
|
|
public float disappearDelay = 0.5f;
|
|
|
|
[Header("震动配置")]
|
|
public float hitShakeDuration = 0.2f; // 击打震动持续时间
|
|
public float hitShakeStrength = 0.1f; // 击打震动强度
|
|
public int hitShakeVibrato = 10; // 震动频率
|
|
public float hitShakeRandomness = 90f; // 震动随机性
|
|
|
|
[Header("调试")]
|
|
public bool debugMode = true;
|
|
|
|
#endregion
|
|
|
|
#region 状态
|
|
|
|
public enum StatueType
|
|
{
|
|
Normal, // 普通雕像
|
|
EvilFace, // 邪恶表情
|
|
EvilHands, // 恶毒双手
|
|
JealousHeart // 嫉妒之心
|
|
}
|
|
|
|
public enum StatueState
|
|
{
|
|
Idle,
|
|
Hit,
|
|
Breaking,
|
|
Broken,
|
|
EvilLaugh
|
|
}
|
|
|
|
public StatueState currentState = StatueState.Idle;
|
|
|
|
// 当前裂痕等级
|
|
private int crackLevel = 0;
|
|
|
|
// 是否可以被击打
|
|
private bool canHit = true;
|
|
|
|
// 事件回调
|
|
public Action<CrystalStatue, bool> OnStatueBroken; // 雕像碎裂回调(雕像, 是否是目标)
|
|
|
|
#endregion
|
|
|
|
#region Unity生命周期
|
|
|
|
private void Awake()
|
|
{
|
|
if (animator == null)
|
|
animator = GetComponent<Animator>();
|
|
|
|
if (statueRenderer == null)
|
|
statueRenderer = GetComponentInChildren<Renderer>();
|
|
}
|
|
|
|
private void Start()
|
|
{
|
|
currentHealth = maxHealth;
|
|
crackLevel = 0;
|
|
canHit = true;
|
|
currentState = StatueState.Idle;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region 初始化
|
|
|
|
/// <summary>
|
|
/// 初始化雕像
|
|
/// </summary>
|
|
public void Initialize(StatueType type, bool isTarget)
|
|
{
|
|
this.statueType = type;
|
|
this.isTarget = isTarget;
|
|
currentHealth = maxHealth;
|
|
crackLevel = 0;
|
|
canHit = true;
|
|
currentState = StatueState.Idle;
|
|
|
|
// 根据类型设置视觉效果
|
|
SetupVisualsByType();
|
|
|
|
if (debugMode)
|
|
Debug.Log($"[CrystalStatue] 初始化雕像: {type}, 是否目标: {isTarget}");
|
|
}
|
|
|
|
/// <summary>
|
|
/// 根据类型设置视觉效果
|
|
/// </summary>
|
|
private void SetupVisualsByType()
|
|
{
|
|
// 隐藏所有特殊部件
|
|
if (heartObject != null)
|
|
heartObject.SetActive(false);
|
|
if (handsObject != null)
|
|
handsObject.SetActive(false);
|
|
if (evilFaceObject != null)
|
|
evilFaceObject.SetActive(false);
|
|
if (specialEffect != null)
|
|
specialEffect.Stop();
|
|
if (isTarget)
|
|
{
|
|
// 根据类型显示对应部件
|
|
switch (statueType)
|
|
{
|
|
case StatueType.EvilFace:
|
|
// 第一轮:邪恶表情区分
|
|
// 目标雕像显示邪恶表情,非目标显示和善表情
|
|
if (isTarget)
|
|
{
|
|
// 邪恶表情
|
|
if (evilFaceObject != null)
|
|
evilFaceObject.SetActive(true);
|
|
if (debugMode)
|
|
Debug.Log("[CrystalStatue] 设置邪恶表情(目标雕像)");
|
|
}
|
|
else
|
|
{
|
|
if (debugMode)
|
|
Debug.Log("[CrystalStatue] 设置和善表情(非目标雕像)");
|
|
}
|
|
break;
|
|
|
|
case StatueType.EvilHands:
|
|
// 第二轮:恶毒双手区分
|
|
if (handsObject != null)
|
|
handsObject.SetActive(true);
|
|
if (specialEffect != null && isTarget)
|
|
specialEffect.Play();
|
|
break;
|
|
|
|
case StatueType.JealousHeart:
|
|
// 第三轮:嫉妒之心区分
|
|
if (heartObject != null)
|
|
heartObject.SetActive(true);
|
|
if (specialEffect != null && isTarget)
|
|
specialEffect.Play();
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
// 重置裂痕
|
|
UpdateCrackVisual(0);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region 击打处理
|
|
|
|
/// <summary>
|
|
/// 玩家击中雕像
|
|
/// </summary>
|
|
public void OnPlayerHit()
|
|
{
|
|
if (!canHit || currentState == StatueState.Broken)
|
|
{
|
|
if (debugMode)
|
|
Debug.Log("[CrystalStatue] 雕像不可被击打");
|
|
return;
|
|
}
|
|
|
|
currentState = StatueState.Hit;
|
|
currentHealth--;
|
|
crackLevel = maxHealth - currentHealth;
|
|
|
|
if (debugMode)
|
|
Debug.Log($"[CrystalStatue] 雕像被击打! 剩余血量: {currentHealth}, 裂痕等级: {crackLevel}");
|
|
|
|
// 播放击打音效
|
|
PlayHitSound();
|
|
|
|
// 播放击打特效
|
|
PlayHitEffect();
|
|
|
|
// 播放击打动画
|
|
PlayHitAnimation();
|
|
|
|
// 更新裂痕视觉效果
|
|
UpdateCrackVisual(crackLevel);
|
|
|
|
// 检查是否碎裂
|
|
if (currentHealth <= 0)
|
|
{
|
|
Break();
|
|
}
|
|
else
|
|
{
|
|
// 短暂冷却
|
|
canHit = false;
|
|
DOVirtual.DelayedCall(0.2f, () =>
|
|
{
|
|
canHit = true;
|
|
if (currentHealth > 0)
|
|
currentState = StatueState.Idle;
|
|
});
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 雕像碎裂
|
|
/// </summary>
|
|
public void Break()
|
|
{
|
|
currentState = StatueState.Breaking;
|
|
canHit = false;
|
|
|
|
if (debugMode)
|
|
Debug.Log($"[CrystalStatue] 雕像碎裂! 是否目标: {isTarget}");
|
|
|
|
// 播放碎裂音效
|
|
PlayBreakSound();
|
|
|
|
// 播放碎裂特效
|
|
PlayBreakEffect();
|
|
|
|
// 播放碎裂动画
|
|
PlayBreakAnimation();
|
|
|
|
// 延迟后触发回调
|
|
DOVirtual.DelayedCall(disappearDelay, () =>
|
|
{
|
|
currentState = StatueState.Broken;
|
|
OnStatueBroken?.Invoke(this, isTarget);
|
|
});
|
|
}
|
|
|
|
/// <summary>
|
|
/// 播放邪恶狞笑(失败时)
|
|
/// </summary>
|
|
public void PlayEvilLaugh()
|
|
{
|
|
currentState = StatueState.EvilLaugh;
|
|
|
|
if (debugMode)
|
|
Debug.Log("[CrystalStatue] 播放邪恶狞笑");
|
|
|
|
// 播放狞笑音效
|
|
PlayEvilLaughSound();
|
|
|
|
// 播放狞笑特效
|
|
if (evilLaughParticle != null)
|
|
evilLaughParticle.Play();
|
|
|
|
// 播放狞笑动画
|
|
if (animator != null)
|
|
animator.SetTrigger(evilLaughAnimTrigger);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 强制消失(其他雕像)
|
|
/// </summary>
|
|
public void ForceDisappear(float duration = 0.5f)
|
|
{
|
|
canHit = false;
|
|
|
|
// 缩放消失效果
|
|
transform.DOScale(Vector3.zero, duration)
|
|
.SetEase(Ease.InBack)
|
|
.OnComplete(() =>
|
|
{
|
|
currentState = StatueState.Broken;
|
|
gameObject.SetActive(false);
|
|
});
|
|
|
|
// 播放碎裂音效
|
|
PlayBreakSound();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region 音效播放
|
|
|
|
private void PlayHitSound()
|
|
{
|
|
if (!string.IsNullOrEmpty(hitSound))
|
|
{
|
|
MasterAudio.PlaySound3DAtTransform(hitSound, transform);
|
|
}
|
|
}
|
|
|
|
private void PlayBreakSound()
|
|
{
|
|
if (!string.IsNullOrEmpty(breakSound))
|
|
{
|
|
MasterAudio.PlaySound3DAtTransform(breakSound, transform);
|
|
}
|
|
}
|
|
|
|
private void PlayEvilLaughSound()
|
|
{
|
|
if (!string.IsNullOrEmpty(evilLaughSound))
|
|
{
|
|
MasterAudio.PlaySound3DAtTransform(evilLaughSound, transform);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region 视觉效果
|
|
|
|
private void PlayHitEffect()
|
|
{
|
|
if (hitParticle != null)
|
|
{
|
|
hitParticle.Play();
|
|
}
|
|
|
|
// 播放受击震动效果
|
|
PlayHitShake();
|
|
}
|
|
|
|
/// <summary>
|
|
/// 播放受击震动效果
|
|
/// </summary>
|
|
private void PlayHitShake()
|
|
{
|
|
// 使用DOShakePosition实现震动
|
|
transform.DOShakePosition(
|
|
hitShakeDuration,
|
|
hitShakeStrength,
|
|
hitShakeVibrato,
|
|
hitShakeRandomness,
|
|
false, // 不震Y轴
|
|
true // 随机方向
|
|
);
|
|
|
|
// 同时添加轻微的旋转震动
|
|
transform.DOShakeRotation(
|
|
hitShakeDuration,
|
|
hitShakeStrength * 10f, // 旋转幅度稍大
|
|
hitShakeVibrato / 2,
|
|
hitShakeRandomness,
|
|
true
|
|
);
|
|
}
|
|
|
|
private void PlayBreakEffect()
|
|
{
|
|
if (breakParticle != null)
|
|
{
|
|
breakParticle.Play();
|
|
}
|
|
}
|
|
|
|
private void PlayHitAnimation()
|
|
{
|
|
if (animator != null)
|
|
{
|
|
animator.SetTrigger(hitAnimTrigger);
|
|
}
|
|
}
|
|
|
|
private void PlayBreakAnimation()
|
|
{
|
|
if (animator != null)
|
|
{
|
|
animator.SetTrigger(breakAnimTrigger);
|
|
}
|
|
|
|
// 碎裂缩放效果
|
|
transform.DOScale(Vector3.zero, breakDuration)
|
|
.SetEase(Ease.InBack)
|
|
.OnComplete(() =>
|
|
{
|
|
gameObject.SetActive(false);
|
|
});
|
|
}
|
|
|
|
/// <summary>
|
|
/// 更新裂痕视觉效果
|
|
/// </summary>
|
|
private void UpdateCrackVisual(int level)
|
|
{
|
|
// 更新裂痕贴花
|
|
for (int i = 0; i < crackDecals.Length; i++)
|
|
{
|
|
if (crackDecals[i] != null)
|
|
{
|
|
crackDecals[i].SetActive(i < level);
|
|
}
|
|
}
|
|
|
|
// 更新材质(如果有多个裂痕材质)
|
|
if (crackMaterials != null && crackMaterials.Length > level && statueRenderer != null)
|
|
{
|
|
statueRenderer.material = crackMaterials[level];
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region 工具方法
|
|
|
|
/// <summary>
|
|
/// 获取当前血量
|
|
/// </summary>
|
|
public int GetCurrentHealth()
|
|
{
|
|
return currentHealth;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取裂痕等级
|
|
/// </summary>
|
|
public int GetCrackLevel()
|
|
{
|
|
return crackLevel;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 是否已碎裂
|
|
/// </summary>
|
|
public bool IsBroken()
|
|
{
|
|
return currentState == StatueState.Broken;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 重置雕像状态
|
|
/// </summary>
|
|
public void Reset()
|
|
{
|
|
currentHealth = maxHealth;
|
|
crackLevel = 0;
|
|
canHit = true;
|
|
currentState = StatueState.Idle;
|
|
|
|
// 重置缩放
|
|
transform.localScale = Vector3.one;
|
|
|
|
// 重置裂痕
|
|
UpdateCrackVisual(0);
|
|
|
|
// 显示对象
|
|
gameObject.SetActive(true);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 设置可击打状态
|
|
/// </summary>
|
|
public void SetCanHit(bool value)
|
|
{
|
|
canHit = value;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region 编辑器辅助
|
|
|
|
#if UNITY_EDITOR
|
|
[ContextMenu("测试:击打雕像")]
|
|
private void TestHit()
|
|
{
|
|
OnPlayerHit();
|
|
}
|
|
|
|
[ContextMenu("测试:碎裂雕像")]
|
|
private void TestBreak()
|
|
{
|
|
Break();
|
|
}
|
|
|
|
[ContextMenu("测试:播放狞笑")]
|
|
private void TestEvilLaugh()
|
|
{
|
|
PlayEvilLaugh();
|
|
}
|
|
|
|
[ContextMenu("测试:重置雕像")]
|
|
private void TestReset()
|
|
{
|
|
Reset();
|
|
}
|
|
|
|
[ContextMenu("测试:强制消失")]
|
|
private void TestForceDisappear()
|
|
{
|
|
ForceDisappear();
|
|
}
|
|
#endif
|
|
|
|
#endregion
|
|
} |