293 lines
8.3 KiB
C#
293 lines
8.3 KiB
C#
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);
|
||
}
|
||
}
|
||
}
|