Files
FutureMen2/Assets/AI/AIController.cs
2026-01-04 15:14:53 +08:00

414 lines
12 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 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;
private const float TxtSpeed = 1; //文字显示时间
public Image dialogBoxImage;//对话框图像
//特殊旋转角度
private Quaternion specialRotationOffset;//特殊旋转偏转
private void Awake()
{
audioSource = GetComponent<AudioSource>();
if (audioSource == null)
{
audioSource = gameObject.AddComponent<AudioSource>();
}
animator = GetComponent<Animator>();
//修改:设置特殊旋转偏移
specialRotationOffset = Quaternion.Euler(0, 90, 0);
}
private void Start()
{
FindPlayer();
//初始时隐藏文本
if (speedTxt != null)
{
speedTxt.gameObject.SetActive(false);
}
//初始时隐藏对话框
if (dialogBoxImage != null)
{
dialogBoxImage.gameObject.SetActive(false);
}
}
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<Player>();
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();
}
}
}