using DG.Tweening; using Knife.Effects.SimpleController; using System; using System.Collections; using System.Collections.Generic; using TMPro; using UnityEngine; using UnityEngine.AI; using UnityEngine.UI; public class AIController : MonoBehaviour { public AudioClip introAudio;//开场白音频 //动画参数 public string waveAnimationTrigger = "Wave";//打招呼动画触发器 public string leaveAnimationTrigger = "Leave";//离开动画触发器 //旋转过渡参数 public float rotationDuration = 1.5f;//旋转过渡时间 public float spawnDistance = 2f;//生成距离 public float rotationSmoothness = 5f;//旋转平滑度 //添加文字显示参数 public float charDisplayDelay = 0.5f;//每个字符显示的延迟时间 //介绍完成事件 public event Action OnIntroductionComplete; private AudioSource audioSource; private Animator animator; private bool isIntroductionStarted = false; private Transform playerTransform; private Coroutine introductionCoroutine; private Coroutine textDisplayCoroutine; private bool hasIntroductionCompleted = false;//添加标志位 private bool isDuringIntroduction = false;//标记是否在介绍期间 //文本变量 public TMP_Text speedTxt; public TMP_Text banben; private const float TxtSpeed = 1; //文字显示时间 public Image dialogBoxImage;//对话框图像 //特殊旋转角度 private Quaternion specialRotationOffset;//特殊旋转偏转 private void Awake() { audioSource = GetComponent(); if (audioSource == null) { audioSource = gameObject.AddComponent(); } animator = GetComponent(); //修改:设置特殊旋转偏移 specialRotationOffset = Quaternion.Euler(0, 90, 0); } private void Start() { FindPlayer(); //初始时隐藏文本 if (speedTxt != null) { speedTxt.gameObject.SetActive(false); } //初始时隐藏对话框 if (dialogBoxImage != null) { dialogBoxImage.gameObject.SetActive(false); } banben.text = $"v{Application.version}"; } private void Update() { //在介绍期间实时面向玩家 if (isDuringIntroduction && playerTransform != null) { FacePlayerWithOffset(); } } //动态查找Player private void FindPlayer() { //通过GameManager获取Player if (GameManager.Ins != null && GameManager.Ins.player != null) { playerTransform = GameManager.Ins.player.transform; Debug.Log("在GameManager中找到Player"); return; } //通过标签查找Player GameObject playerObj = GameObject.FindGameObjectWithTag("Player"); if (playerObj != null) { playerTransform = playerObj.transform; Debug.Log("找到Player标签"); return; } //通过类型查找Player组件 Player playerController = FindObjectOfType(); if (playerController != null) { playerTransform = playerController.transform; Debug.Log("找到player组件"); return; } Debug.LogError("Player没有找到,请重试"); StartCoroutine(RetryFindPlayer()); } private IEnumerator RetryFindPlayer() { yield return new WaitForSeconds(1f); FindPlayer(); } public void StartIntroduction() { if (isIntroductionStarted) return; //确保我们有Player引用 if (playerTransform == null) { FindPlayer(); if (playerTransform == null) { Debug.LogError("不能开始介绍,玩家参考是空的"); return; } } isIntroductionStarted = true; Debug.Log("AI介绍开始"); //停止任何现有的协程 if (introductionCoroutine != null) { StopCoroutine(introductionCoroutine); } //启动开场白协程 introductionCoroutine = StartCoroutine(IntroductionRoutine()); } private IEnumerator IntroductionRoutine() { Debug.Log("开始介绍开场白"); isDuringIntroduction = true; //初始面向玩家 FacePlayerWithOffset(); //应用特殊旋转 if (playerTransform != null) { //计算面向玩家的方向 Vector3 directionToPlayer = playerTransform.position - transform.position; directionToPlayer.y = 0;//保持水平方向 if (directionToPlayer != Vector3.zero) { //先面向玩家 Quaternion lookAtPlayer = Quaternion.LookRotation(directionToPlayer); //应用特殊旋转偏移 Quaternion targetRotation = lookAtPlayer * specialRotationOffset; //平滑旋转到目标角度 yield return StartCoroutine(SmoothRotate(targetRotation, rotationDuration)); } } //播放打招呼动画 if (animator != null && !string.IsNullOrEmpty(waveAnimationTrigger)) { animator.SetTrigger(waveAnimationTrigger); Debug.Log("播放打招呼动画"); //同时播放开场白音频 if (introAudio != null) { //只在打招呼的时候显示文本 if (speedTxt != null) { speedTxt.gameObject.SetActive(true); string fullText = "欢迎来到魔力队长的未来世界,宇宙的凶恶生物正源源不断的侵入我们的领地,让我们携手努力拯救这个世界,保护人们不再受到伤害!"; textDisplayCoroutine = StartCoroutine(DisplayTextCharByChar(fullText)); //等待文字开始显示后再播放声音 yield return new WaitForSeconds(0.5f); } Debug.Log("玩家音频播放:" + introAudio.name); audioSource.clip = introAudio; audioSource.Play(); //等待音频播放,但在结束前2秒隐藏文本 float audioLength = introAudio.length; yield return new WaitForSeconds(audioLength - 2f);//提前两秒 //音频播放完毕后隐藏文本 if (speedTxt != null) { HideTxt(); } //等待剩余的2秒音频播放时间 yield return new WaitForSeconds(2f); Debug.Log("介绍音频完成"); } else { //如果没有音频,等待12秒后隐藏文本 yield return new WaitForSeconds(10f);//减少等待时间,因为不需要等待音频 if (speedTxt != null) { HideTxt(); } yield return new WaitForSeconds(2f);//再等待两秒 } } else { Debug.LogError("AI身上没有介绍音频"); yield return new WaitForSeconds(3f); } //介绍结束,停止实时面向 isDuringIntroduction = false; //播放离开动画 if (animator != null && !string.IsNullOrEmpty(leaveAnimationTrigger)) { //等待一段时间后播放离开动画 yield return new WaitForSeconds(2f); //旋转180度 Quaternion targetRotation = transform.rotation * Quaternion.Euler(0, 180, 0); yield return StartCoroutine(SmoothRotate(targetRotation, rotationDuration)); animator.SetTrigger(leaveAnimationTrigger); Debug.Log("播放离开动画"); //等待离开动画播放 yield return new WaitForSeconds(2f); } //触发介绍完成事件 hasIntroductionCompleted = true; OnIntroductionComplete?.Invoke(); Debug.Log("AI介绍完成,准备离开"); //禁用AI角色 gameObject.SetActive(false); } //逐字显示文本的协程 private IEnumerator DisplayTextCharByChar(string fullText) { if (speedTxt == null) yield break; //激活并显示对话框 if (dialogBoxImage != null) { dialogBoxImage.gameObject.SetActive(true); //设置对话框初始透明度为0 dialogBoxImage.color = new Color(dialogBoxImage.color.r, dialogBoxImage.color.g, dialogBoxImage.color.b, 0f); //对话框渐显 dialogBoxImage.DOFade(1f, TxtSpeed).SetEase(Ease.Linear); } //初始时设置文字的透明度为0(完全透明) speedTxt.color = new Color(speedTxt.color.r, speedTxt.color.g, speedTxt.color.b, 0f); //先渐显文本背景 speedTxt.DOFade(1f, TxtSpeed).SetEase(Ease.Linear); yield return new WaitForSeconds(TxtSpeed); //逐字显示文本 speedTxt.text = "";//清空文本 for (int i = 0; i < fullText.Length; i++) { speedTxt.text += fullText[i]; yield return new WaitForSeconds(charDisplayDelay); } } //实时面向玩家 private void FacePlayerWithOffset() { if (playerTransform == null) return; //计算面向玩家的方向 Vector3 directionToPlayer = playerTransform.position - transform.position; directionToPlayer.y = 0;//保持水平方向 if (directionToPlayer != Vector3.zero) { //计算面向玩家的旋转 Quaternion lookRotation = Quaternion.LookRotation(directionToPlayer); //应用特殊旋转偏移 Quaternion targetRotation = lookRotation * specialRotationOffset; //平滑旋转到目标角度 transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, Time.deltaTime * rotationSmoothness); } } //平滑旋转协程 private IEnumerator SmoothRotate(Quaternion targetRotation, float duration) { float elapsedTime = 0f; Quaternion startRotation = transform.rotation; while (elapsedTime < duration) { transform.rotation = Quaternion.Slerp(startRotation, targetRotation, elapsedTime / duration); elapsedTime += Time.deltaTime; yield return null; } //确保最终旋转到目标角度 transform.rotation = targetRotation; } public void StartTxt(string txt, Action cb = null) { if (speedTxt == null) return; speedTxt.text = txt; //初始时设置文字的透明度为0(完全透明) speedTxt.color = new Color(speedTxt.color.r, speedTxt.color.g, speedTxt.color.b, 0f); // 使用DoTween实现文字的渐显效果 speedTxt.DOFade(1f, TxtSpeed).SetEase(Ease.Linear).OnComplete(() => { cb?.Invoke(); }); // 渐显到完全不透明,使用线性缓动效果 } //隐藏文本的方法 public void HideTxt(Action cb = null) { if (speedTxt == null) return; //停止任何正在进行的文本显示协程 if (textDisplayCoroutine != null) { StopCoroutine(textDisplayCoroutine); } //创建序列来同时隐藏文本和对话框 Sequence hideSequence = DOTween.Sequence(); //添加文本渐隐到序列 if (speedTxt != null) { hideSequence.Join(speedTxt.DOFade(0f, TxtSpeed).SetEase(Ease.Linear)); } //添加对话框渐隐到序列 if (dialogBoxImage != null) { hideSequence.Join(dialogBoxImage.DOFade(0f, TxtSpeed).SetEase(Ease.Linear)); } //序列完成后隐藏游戏对象并调用回调 hideSequence.OnComplete(() => { if (speedTxt != null) { speedTxt.gameObject.SetActive(false); } if (dialogBoxImage != null) { dialogBoxImage.gameObject.SetActive(false); } cb?.Invoke(); }); } private void OnDestroy() { //清理协程 if (introductionCoroutine != null) { StopCoroutine(introductionCoroutine); } if (textDisplayCoroutine != null) { StopCoroutine(textDisplayCoroutine); } // 清理所有Tween动画 if (speedTxt != null) { speedTxt.DOKill(); } if (dialogBoxImage != null) { dialogBoxImage.DOKill(); } } }