499 lines
13 KiB
C#
499 lines
13 KiB
C#
using UnityEngine;
|
||
using BehaviorDesigner.Runtime;
|
||
using DG.Tweening;
|
||
using DarkTonic.MasterAudio;
|
||
using DragonLi.Core;
|
||
|
||
/// <summary>
|
||
/// 魔镜控制器 - 挂载到魔镜预制体上
|
||
/// 配合行为树使用,控制魔镜的动画、音频、移动和传送门变换
|
||
/// </summary>
|
||
public class Mirror : MonoBehaviour
|
||
{
|
||
[Header("组件引用")]
|
||
public Animator animator;
|
||
public AudioSource audioSource;
|
||
public Renderer mirrorRenderer;
|
||
public ParticleSystem portalParticles;
|
||
public GameObject portalEffect;
|
||
|
||
[Header("行为树")]
|
||
public BehaviorTree behaviorTree;
|
||
|
||
[Header("动画参数")]
|
||
public string talkAnimParam = "Talk";
|
||
public string idleAnimParam = "Idle";
|
||
public string transformAnimParam = "Transform";
|
||
|
||
[Header("移动配置")]
|
||
public float flyToPlayerDistance = 2f;
|
||
public float moveSpeed = 3f;
|
||
|
||
[Header("传送门配置")]
|
||
public Color portalGlowColor = new Color(0.5f, 0.8f, 1f, 1f);
|
||
public float portalTransformDuration = 2f;
|
||
|
||
[Header("调试模式")]
|
||
public bool debugMode = true;
|
||
|
||
// 私有变量
|
||
private Material mirrorMaterial;
|
||
private Color originalColor;
|
||
private Tweener currentTween;
|
||
|
||
// 状态
|
||
public enum MirrorState
|
||
{
|
||
Idle,
|
||
Talking,
|
||
FlyingToPlayer,
|
||
Transforming,
|
||
Portal,
|
||
Disappeared
|
||
}
|
||
|
||
public MirrorState currentState = MirrorState.Idle;
|
||
|
||
private void Awake()
|
||
{
|
||
if (animator == null)
|
||
animator = GetComponent<Animator>();
|
||
|
||
if (audioSource == null)
|
||
audioSource = GetComponent<AudioSource>();
|
||
|
||
if (behaviorTree == null)
|
||
behaviorTree = GetComponent<BehaviorTree>();
|
||
|
||
if (mirrorRenderer != null)
|
||
{
|
||
mirrorMaterial = mirrorRenderer.material;
|
||
originalColor = mirrorMaterial.HasProperty("_Color") ? mirrorMaterial.color : Color.white;
|
||
}
|
||
}
|
||
|
||
private void Start()
|
||
{
|
||
currentState = MirrorState.Idle;
|
||
|
||
// 初始隐藏传送门效果
|
||
if (portalEffect != null)
|
||
portalEffect.SetActive(false);
|
||
|
||
if (portalParticles != null)
|
||
portalParticles.Stop();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 播放动画
|
||
/// </summary>
|
||
public void PlayAnimation(string animParam)
|
||
{
|
||
if (animator != null && !string.IsNullOrEmpty(animParam))
|
||
{
|
||
animator.SetTrigger(animParam);
|
||
|
||
if (debugMode)
|
||
Debug.Log($"[Mirror] 播放动画: {animParam}");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 播放说话动画
|
||
/// </summary>
|
||
public void PlayTalkAnim()
|
||
{
|
||
currentState = MirrorState.Talking;
|
||
PlayAnimation(talkAnimParam);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 播放待机动画
|
||
/// </summary>
|
||
public void PlayIdleAnim()
|
||
{
|
||
currentState = MirrorState.Idle;
|
||
PlayAnimation(idleAnimParam);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 播放变换动画
|
||
/// </summary>
|
||
public void PlayTransformAnim()
|
||
{
|
||
PlayAnimation(transformAnimParam);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 播放音频(通过MasterAudio)
|
||
/// </summary>
|
||
public void PlayAudio(string audioName)
|
||
{
|
||
if (!string.IsNullOrEmpty(audioName))
|
||
{
|
||
MasterAudio.PlaySound3DAtTransform(audioName, transform);
|
||
|
||
if (debugMode)
|
||
Debug.Log($"[Mirror] 播放音频: {audioName}");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 停止当前音频
|
||
/// </summary>
|
||
public void StopAudio()
|
||
{
|
||
MasterAudio.StopAllSoundsOfTransform(transform);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 转向玩家
|
||
/// </summary>
|
||
public void TurnToPlayer(float duration = 1f)
|
||
{
|
||
if (GameLocal.Ins == null || GameLocal.Ins.self == null)
|
||
{
|
||
Debug.LogWarning("[Mirror] 无法找到玩家");
|
||
return;
|
||
}
|
||
|
||
Transform playerTransform = GameLocal.Ins.self.transform;
|
||
Vector3 direction = playerTransform.position - transform.position;
|
||
direction.y = 0;
|
||
|
||
if (direction != Vector3.zero)
|
||
{
|
||
Quaternion targetRotation = Quaternion.LookRotation(direction);
|
||
|
||
if (currentTween != null)
|
||
currentTween.Kill();
|
||
|
||
currentTween = transform.DORotateQuaternion(targetRotation, duration);
|
||
|
||
if (debugMode)
|
||
Debug.Log("[Mirror] 转向玩家");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 飞向玩家
|
||
/// </summary>
|
||
public void FlyToPlayer(float duration = 2f, System.Action onComplete = null)
|
||
{
|
||
if (GameLocal.Ins == null || GameLocal.Ins.self == null)
|
||
{
|
||
Debug.LogWarning("[Mirror] 无法找到玩家");
|
||
onComplete?.Invoke();
|
||
return;
|
||
}
|
||
|
||
currentState = MirrorState.FlyingToPlayer;
|
||
|
||
Transform playerTransform = GameLocal.Ins.self.transform;
|
||
|
||
// 计算目标位置(玩家前方)
|
||
Vector3 targetPos = playerTransform.position + playerTransform.forward * flyToPlayerDistance;
|
||
targetPos.y = transform.position.y;
|
||
|
||
if (currentTween != null)
|
||
currentTween.Kill();
|
||
|
||
Sequence sequence = DOTween.Sequence();
|
||
sequence.Join(transform.DOMove(targetPos, duration).SetEase(Ease.OutQuad));
|
||
sequence.Join(transform.DOLookAt(playerTransform.position, duration * 0.5f));
|
||
sequence.OnComplete(() =>
|
||
{
|
||
currentState = MirrorState.Idle;
|
||
onComplete?.Invoke();
|
||
|
||
if (debugMode)
|
||
Debug.Log("[Mirror] 飞向玩家完成");
|
||
});
|
||
}
|
||
|
||
/// <summary>
|
||
/// 变换为传送门
|
||
/// </summary>
|
||
public void TransformToPortal(float duration = 2f, System.Action onComplete = null)
|
||
{
|
||
currentState = MirrorState.Transforming;
|
||
|
||
// 播放变换动画
|
||
PlayTransformAnim();
|
||
|
||
// 播放粒子效果
|
||
if (portalParticles != null)
|
||
portalParticles.Play();
|
||
|
||
// 发光效果
|
||
if (mirrorMaterial != null)
|
||
{
|
||
float elapsedTime = 0f;
|
||
|
||
DOTween.To(
|
||
() => 0f,
|
||
t =>
|
||
{
|
||
if (mirrorMaterial.HasProperty("_Color"))
|
||
{
|
||
mirrorMaterial.color = Color.Lerp(originalColor, portalGlowColor, t);
|
||
}
|
||
if (mirrorMaterial.HasProperty("_EmissionColor"))
|
||
{
|
||
float intensity = Mathf.Lerp(0f, 2f, t);
|
||
mirrorMaterial.SetColor("_EmissionColor", portalGlowColor * intensity);
|
||
}
|
||
},
|
||
1f,
|
||
duration
|
||
).OnComplete(() =>
|
||
{
|
||
currentState = MirrorState.Portal;
|
||
|
||
// 显示传送门效果
|
||
if (portalEffect != null)
|
||
portalEffect.SetActive(true);
|
||
|
||
onComplete?.Invoke();
|
||
|
||
if (debugMode)
|
||
Debug.Log("[Mirror] 传送门变换完成");
|
||
});
|
||
}
|
||
else
|
||
{
|
||
currentState = MirrorState.Portal;
|
||
onComplete?.Invoke();
|
||
}
|
||
|
||
CoroutineTaskManager.Instance.WaitSecondTodo(() =>
|
||
{
|
||
FadeOut(2, () =>
|
||
{
|
||
GameManager.Ins.StartCutscene(1);
|
||
});
|
||
}, 2f);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 发光效果
|
||
/// </summary>
|
||
public void Glow(float intensity = 1f, float duration = 1f)
|
||
{
|
||
if (mirrorMaterial != null && mirrorMaterial.HasProperty("_EmissionColor"))
|
||
{
|
||
DOTween.To(
|
||
() => mirrorMaterial.GetColor("_EmissionColor").r,
|
||
x => mirrorMaterial.SetColor("_EmissionColor", portalGlowColor * x),
|
||
intensity,
|
||
duration
|
||
);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 渐隐消失
|
||
/// </summary>
|
||
public void FadeOut(float duration = 1f, System.Action onComplete = null)
|
||
{
|
||
var renderers = GetComponentsInChildren<Renderer>();
|
||
|
||
if (renderers.Length > 0)
|
||
{
|
||
DOTween.To(
|
||
() => 1f,
|
||
alpha =>
|
||
{
|
||
foreach (var renderer in renderers)
|
||
{
|
||
var mat = renderer.material;
|
||
if (mat.HasProperty("_Color"))
|
||
{
|
||
Color color = mat.color;
|
||
color.a = alpha;
|
||
mat.color = color;
|
||
}
|
||
}
|
||
},
|
||
0f,
|
||
duration
|
||
).OnComplete(() =>
|
||
{
|
||
currentState = MirrorState.Disappeared;
|
||
gameObject.SetActive(false);
|
||
onComplete?.Invoke();
|
||
|
||
if (debugMode)
|
||
Debug.Log("[Mirror] 渐隐消失完成");
|
||
});
|
||
}
|
||
else
|
||
{
|
||
currentState = MirrorState.Disappeared;
|
||
gameObject.SetActive(false);
|
||
onComplete?.Invoke();
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 缩放消失
|
||
/// </summary>
|
||
public void ScaleAndDisappear(float duration = 0.5f, System.Action onComplete = null)
|
||
{
|
||
if (currentTween != null)
|
||
currentTween.Kill();
|
||
|
||
transform.DOScale(Vector3.zero, duration)
|
||
.SetEase(Ease.InBack)
|
||
.OnComplete(() =>
|
||
{
|
||
currentState = MirrorState.Disappeared;
|
||
gameObject.SetActive(false);
|
||
onComplete?.Invoke();
|
||
|
||
if (debugMode)
|
||
Debug.Log("[Mirror] 缩放消失完成");
|
||
});
|
||
}
|
||
|
||
/// <summary>
|
||
/// 移动到指定位置
|
||
/// </summary>
|
||
public void MoveTo(Vector3 targetPos, float duration = 2f, System.Action onComplete = null)
|
||
{
|
||
if (currentTween != null)
|
||
currentTween.Kill();
|
||
|
||
currentTween = transform.DOMove(targetPos, duration)
|
||
.SetEase(Ease.OutQuad)
|
||
.OnComplete(() =>
|
||
{
|
||
onComplete?.Invoke();
|
||
|
||
if (debugMode)
|
||
Debug.Log($"[Mirror] 移动完成到: {targetPos}");
|
||
});
|
||
}
|
||
|
||
/// <summary>
|
||
/// 停止所有动作
|
||
/// </summary>
|
||
public void StopAllActions()
|
||
{
|
||
if (currentTween != null)
|
||
currentTween.Kill();
|
||
|
||
//StopAudio();
|
||
|
||
if (portalParticles != null && portalParticles.isPlaying)
|
||
portalParticles.Stop();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 初始化魔镜
|
||
/// </summary>
|
||
public void Init()
|
||
{
|
||
currentState = MirrorState.Idle;
|
||
|
||
// 重置材质
|
||
if (mirrorMaterial != null && mirrorMaterial.HasProperty("_Color"))
|
||
{
|
||
mirrorMaterial.color = originalColor;
|
||
}
|
||
|
||
// 重置缩放
|
||
transform.localScale = Vector3.one;
|
||
|
||
// 隐藏传送门效果
|
||
if (portalEffect != null)
|
||
portalEffect.SetActive(false);
|
||
|
||
if (portalParticles != null)
|
||
portalParticles.Stop();
|
||
|
||
// 显示魔镜
|
||
gameObject.SetActive(true);
|
||
|
||
if (debugMode)
|
||
Debug.Log("[Mirror] 初始化完成");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 启动行为树
|
||
/// </summary>
|
||
public void StartBehaviorTree()
|
||
{
|
||
if (behaviorTree != null)
|
||
{
|
||
behaviorTree.EnableBehavior();
|
||
|
||
if (debugMode)
|
||
Debug.Log("[Mirror] 启动行为树");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 停止行为树
|
||
/// </summary>
|
||
public void StopBehaviorTree()
|
||
{
|
||
if (behaviorTree != null)
|
||
{
|
||
behaviorTree.DisableBehavior();
|
||
}
|
||
}
|
||
|
||
private void OnDestroy()
|
||
{
|
||
StopAllActions();
|
||
}
|
||
|
||
#region 编辑器辅助
|
||
|
||
#if UNITY_EDITOR
|
||
[ContextMenu("测试:播放说话动画")]
|
||
private void TestPlayTalkAnim()
|
||
{
|
||
PlayTalkAnim();
|
||
}
|
||
|
||
[ContextMenu("测试:转向玩家")]
|
||
private void TestTurnToPlayer()
|
||
{
|
||
TurnToPlayer();
|
||
}
|
||
|
||
[ContextMenu("测试:飞向玩家")]
|
||
private void TestFlyToPlayer()
|
||
{
|
||
FlyToPlayer();
|
||
}
|
||
|
||
[ContextMenu("测试:变换为传送门")]
|
||
private void TestTransformToPortal()
|
||
{
|
||
TransformToPortal();
|
||
}
|
||
|
||
[ContextMenu("测试:缩放消失")]
|
||
private void TestScaleAndDisappear()
|
||
{
|
||
ScaleAndDisappear();
|
||
}
|
||
|
||
[ContextMenu("测试:渐隐消失")]
|
||
private void TestFadeOut()
|
||
{
|
||
FadeOut();
|
||
}
|
||
|
||
[ContextMenu("测试:发光效果")]
|
||
private void TestGlow()
|
||
{
|
||
Glow(2f, 1f);
|
||
}
|
||
#endif
|
||
|
||
#endregion
|
||
} |