Files
FutureMen/Assets/Scripts/Ai/AIController.cs
2025-09-05 18:18:20 +08:00

293 lines
8.3 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;
public class AIController : MonoBehaviour
{
public AudioClip introAudio;//开场白音频
//添加动画参数
public string waveAnimationTrigger = "Wave";//打招呼动画触发器
public string leaveAnimationTrigger = "Leave";//离开动画触发器
//添加:打招呼动画旋转角度
public float waveRotationAngle = 90f; // 打招呼时相对于玩家的旋转角度
//添加:旋转过渡参数
public float rotationDuration = 1.5f;//旋转过渡时间
//添加介绍完成事件
public event Action OnIntroductionComplete;
private AudioSource audioSource;
private NavMeshAgent navAgent;
private Animator animator;
private bool isIntroductionStarted = false;
private Transform playerTransform;
private Coroutine introductionCoroutine;
private bool hasIntroductionCompleted = false;//添加标志位
//文本变量
public TMP_Text speedTxt;
private const float TxtSpeed = 1; //文字显示时间
private void Awake()
{
audioSource= GetComponent<AudioSource>();
if(audioSource == null)
{
audioSource = gameObject.AddComponent<AudioSource>();
}
navAgent = GetComponent<NavMeshAgent>();
if(navAgent == null)
{
Debug.LogError("自动寻路组件不在AI身上");
}
animator = GetComponent<Animator>();
}
private void Start()
{
FindPlayer();
//初始时隐藏文本
if (speedTxt != null)
{
speedTxt.gameObject.SetActive(false);
}
}
//动态查找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组件
PlayerController playerController = FindObjectOfType<PlayerController>();
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("开始介绍开场白");
//播放打招呼动画
if (animator != null && !string.IsNullOrEmpty(waveAnimationTrigger))
{
//面向玩家
transform.LookAt(playerTransform);
//旋转到打招呼方向 - 修正朝向问题
//计算正确的旋转方向向左旋转90度
transform.Rotate(Vector3.up, waveRotationAngle);
animator.SetTrigger(waveAnimationTrigger);
Debug.Log("播放打招呼动画");
//同时播放开场白音频
if (introAudio != null)
{
//只在打招呼的时候显示文本
if (speedTxt != null)
{
speedTxt.gameObject.SetActive(true);
StartTxt("欢迎来到魔力队长的未来世界,宇宙的凶恶生物正源源不断的\r\n侵入我们的领地让我们携手努力拯救这个世界保护人们不再受到伤害\r\n");
}
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
{
////等待动画播放一会儿再开始音频
//yield return new WaitForSeconds(12f);
//如果没有音频等待12秒后隐藏文本
yield return new WaitForSeconds(10f);//减少等待时间,因为不需要等待音频
if (speedTxt != null)
{
HideTxt();
}
yield return new WaitForSeconds(2f);//再等待两秒
}
}
else
{
Debug.LogError("AI身上没有介绍音频");
yield return new WaitForSeconds(3f);
}
//播放离开动画
if (animator != null && !string.IsNullOrEmpty(leaveAnimationTrigger))
{
//修改在播放离开动画前让AI背对玩家
if (playerTransform != null)
{
//计算背对玩家的方向
Vector3 leftDirection = playerTransform.right;
leftDirection.y = 0;//保持水平方向
if (leftDirection != Vector3.zero)
{
////旋转到背对玩家的方向
//transform.rotation = Quaternion.LookRotation(leftDirection);
//平滑旋转到左侧离开的方向
Quaternion targetRotation = Quaternion.LookRotation(leftDirection);
yield return StartCoroutine(SmoothRotate(targetRotation, rotationDuration));
}
}
animator.SetTrigger(leaveAnimationTrigger);
Debug.Log("播放离开动画");
//等待离开动画播放
yield return new WaitForSeconds(6f);
}
//触发介绍完成事件
hasIntroductionCompleted = true;
OnIntroductionComplete?.Invoke();
Debug.Log("AI介绍完成准备离开");
//禁用AI角色
gameObject.SetActive(false);
//可选销毁AI对象
//Destroy(gameObject);
}
//添加平滑旋转协程
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;
//使用DoTween实现文字的渐隐效果
speedTxt.DOFade(0f, TxtSpeed).SetEase(Ease.Linear).OnComplete(() =>
{
speedTxt.gameObject.SetActive(false);
cb?.Invoke();
});//渐隐到完全透明
}
private void OnDestroy()
{
//清理协程
if (introductionCoroutine != null)
{
StopCoroutine(introductionCoroutine);
}
}
}