Udemy-Unity制作类暗黑破坏神游戏记录-P60

2024-09-14
60看过
设置AI自动巡逻,追逐玩家时,分别为不同的移动速度,由于我们使用的自动寻路,所以在脚本中通过一个变量来设置navMeshAgent的速度,这样我们可以通过变量来自定义玩家和AI的速度,在移动逻辑部分,设置一个浮点值。通过浮点值来设置AI在巡逻时为行走状态,追逐玩家时为跑步状态。
移动部分因为动画资源和教程不同,所以使用了寻路时的速度/10,然后把这个速度传给动画状态机做动画的更新

Mover:

  1. using RPG.Combat;
  2. using RPG.Core;
  3. using System.Collections;
  4. using System.Collections.Generic;
  5. using UnityEngine;
  6. using UnityEngine.AI;
  7. using UnityEngine.UI;
  8. //角色的移动
  9. namespace RPG.Movement
  10. {
  11.     public class Mover : MonoBehaviour,IAction
  12.     {
  13.         
  14.         [SerializeField] float maxSpeed = 6f;//最大速度
  15.         private NavMeshAgent navMeshAgent;
  16.         
  17.         Animator animator;
  18.         Health health;
  19.         CapsuleCollider capsuleCollider;
  20.         private void Start()
  21.         {
  22.             animator = GetComponent<Animator>();
  23.             navMeshAgent = GetComponent<NavMeshAgent>();
  24.             health = GetComponent<Health>();
  25.             capsuleCollider = GetComponent<CapsuleCollider>();
  26.         }
  27.         private void Update()
  28.         {
  29.             if (health.IsDead())
  30.             {
  31.                 capsuleCollider.enabled = false;//关闭碰撞
  32.                 navMeshAgent.enabled = false;//关闭寻路
  33.             }
  34.             
  35.             UpdateAnimator();
  36.         }
  37.         /// <summary>
  38.         /// 开始移动行为
  39.         /// </summary>
  40.         /// <param name="destination">移动的位置</param>
  41.         public void StartMoveAction(Vector3 destination,float speedFraction)
  42.         {
  43.             GetComponent<ActionScheduler>().StartAction(this);
  44.             
  45.             MoveTo(destination,speedFraction);
  46.         }
  47.         /// <summary>
  48.         /// 寻路移动到射线检测点
  49.         /// </summary>
  50.         /// <param name="hit"></param>
  51.         public void MoveTo(Vector3 destination,float speedFraction)
  52.         {
  53.             navMeshAgent.destination = destination;//获取寻路目的地 = 射线碰撞的点
  54.             navMeshAgent.speed = maxSpeed * Mathf.Clamp01(speedFraction);//设置速度的浮动值
  55.             navMeshAgent.isStopped = false;
  56.         }
  57.         /// <summary>
  58.         /// 停止寻路
  59.         /// </summary>
  60.         public void Cancel()
  61.         {
  62.             navMeshAgent.isStopped = true;
  63.         }
  64.         
  65.         /// <summary>
  66.         /// 动画更新
  67.         /// </summary>
  68.         private void UpdateAnimator()
  69.         {
  70.             Vector3 velocity = navMeshAgent.velocity;//创建寻路速度
  71.             Vector3 localVelocity = transform.InverseTransformDirection(velocity);// 将世界向前变换到本地空间:
  72.             float speed = localVelocity.z;
  73.             //print("AI"+speed);
  74.              animator.SetFloat("forwardSpeed", speed/10);
  75.            
  76.         }
  77.         
  78.     }
  79. }
复制代码
AIController:

  1. using RPG.Combat;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using UnityEngine;
  5. using RPG.Movement;
  6. using RPG.Core;
  7. using System;
  8. namespace RPG.Control
  9. {
  10.     //AI的控制
  11.     public class AIController : MonoBehaviour
  12.     {
  13.         [SerializeField] float chaseDistance = 5f;// 设定追逐范围的距离
  14.         [SerializeField] float suspicionTime = 4f;//丢失目标后原地等待时间
  15.         [SerializeField] float waypointDwellTime = 3f;//倒地巡逻点之后等待时间
  16.         [SerializeField] PatrolPath patrolPath;//巡逻点
  17.         [SerializeField] float waypointTolerance = 1f;//到达巡逻点允许的误差范围
  18.         [Range(0f, 1f)]
  19.         [SerializeField] float patrolSpeedFraction = 0.5f;//设置巡逻时的移动速度百分比
  20.       
  21.         float timeSinceLastSawPlayer = Mathf.Infinity;//最后一次看见玩家的时间 时间计时器 设置无限大
  22.         float timeSinceArrivedAtWaypoint = Mathf.Infinity;//到达巡逻点后 时间计时器 设置无限大
  23.         int currentWaypointIndex = 0;//当前巡逻点数量
  24.         Vector3 guardPosition;//默认位置
  25.         //组件
  26.         Fighter fighter;
  27.         Health health;
  28.         Mover mover;
  29.         GameObject player;
  30.         
  31.         
  32.         private void Start()
  33.         {
  34.             fighter = GetComponent<Fighter>();
  35.             health = GetComponent<Health>();
  36.             player = GameObject.FindWithTag("Player");// 找到标签为“Player”的游戏对象
  37.             mover = GetComponent<Mover>();
  38.             guardPosition = transform.position;
  39.         }
  40.         private void Update()
  41.         {
  42.             if (health.IsDead()) return;//如果角色已经死亡,则跳出
  43.             // 如果和玩家的距离小于追逐范围 并且可以攻击玩家
  44.             if (InAttackRangeOfPlayer() && fighter.CanAttack(player))
  45.             {
  46.                 AttackBehaviour();//开始攻击
  47.             }
  48.             else if (timeSinceLastSawPlayer < suspicionTime )//失去对玩家的视线后,怀疑时间
  49.             {
  50.                 SuspicionBehaviour();//原地待机
  51.             }
  52.             else
  53.             {
  54.                 PatrolBehaviour();//进入巡逻
  55.             }
  56.             UpdateTimes();
  57.         }
  58.         private void UpdateTimes()//计时器更新
  59.         {
  60.             timeSinceLastSawPlayer += Time.deltaTime;
  61.             timeSinceArrivedAtWaypoint += Time.deltaTime;
  62.         }
  63.         private void PatrolBehaviour()//巡逻行为
  64.         {
  65.             Vector3 nectPoition = guardPosition; // 默认巡逻点设为守卫的起始位置
  66.             if (patrolPath != null)// 如果存在巡逻路径
  67.             {
  68.                 if(AtWaypoint())// 如果到达当前巡逻点
  69.                 {
  70.                     timeSinceArrivedAtWaypoint = 0f;//重置巡逻计时器为0
  71.                     CycleWaypoint();// 切换到下一个巡逻点
  72.                   
  73.                 }
  74.                 nectPoition = GetCurrentWaypoint();// 获取当前巡逻点的位置
  75.             }
  76.             
  77.             if(timeSinceArrivedAtWaypoint >waypointDwellTime)//如果计时器大于巡逻的待机时间
  78.             {
  79.                 mover.StartMoveAction(nectPoition,patrolSpeedFraction);// 开始移动到当前巡逻点,设定巡逻时的移动速度,默认设定为0.5
  80.             }
  81.             
  82.            
  83.         }
  84.       
  85.         private bool AtWaypoint()// 检查是否到达巡逻点
  86.         {
  87.             // 计算当前位置与当前巡逻点之间的距离
  88.             float distanceToWaypoint = Vector3.Distance(transform.position,GetCurrentWaypoint());
  89.             return distanceToWaypoint <waypointTolerance; // 判断是否小于允许的误差范围
  90.         }
  91.         private void CycleWaypoint()// 切换到下一个巡逻点
  92.         {
  93.             // 更新当前巡逻点的索引
  94.             currentWaypointIndex = patrolPath.GetNextIndex(currentWaypointIndex);
  95.         }
  96.         private Vector3 GetCurrentWaypoint()// 获取当前巡逻点的位置
  97.         {
  98.             // 从巡逻路径中获取当前巡逻点的位置
  99.             return patrolPath.GetWaypoint(currentWaypointIndex);
  100.         }
  101.         private void SuspicionBehaviour()//丢失目标后,取消当前任何行为
  102.         {
  103.             GetComponent<ActionScheduler>().CancelCurrentAction();
  104.         }
  105.         private void AttackBehaviour()//攻击行为
  106.         {
  107.             timeSinceLastSawPlayer = 0;//重置为0
  108.             fighter.Attack(player);//对玩家进行攻击
  109.         }
  110.         private bool InAttackRangeOfPlayer() // 检测是否在攻击范围内
  111.         {
  112.             float distanceToPlayer = Vector3.Distance(player.transform.position,transform.position); // 计算并返回玩家和当前对象之间的距离
  113.             return distanceToPlayer < chaseDistance;//返回两者之间距离是否小于追逐距离
  114.         }
  115.         private void OnDrawGizmosSelected()//绘制线框球体
  116.         {
  117.             Gizmos.color = Color.yellow;
  118.             Gizmos.DrawWireSphere(transform.position, chaseDistance);
  119.         }
  120.     }
  121. }
复制代码
Fighter:

  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. using RPG.Movement;
  5. using RPG.Core;
  6. namespace RPG.Combat
  7. {
  8.     //攻击
  9.     public class Fighter : MonoBehaviour, IAction
  10.     {
  11.         [SerializeField] float weaponRange = 2f;// 武器范围,表示武器可以攻击的最大距离
  12.         [SerializeField] float timeBetweenAttacks = 1f;//攻击间隔时间
  13.         [SerializeField] float weaponDamage = 5f;//武器伤害
  14.         Health target;// 当前攻击的目标
  15.         float timeSinceLastAttack = Mathf.Infinity;//上次攻击的时间为 为无穷大
  16.         private Mover mover;// 用于移动角色的 Mover 组件
  17.         private bool isInRange;// 标记目标是否在攻击范围内
  18.         private Animator animator;
  19.         private void Start()
  20.         {
  21.             mover = GetComponent<Mover>();// 获取 Mover 组件
  22.             animator = GetComponent<Animator>();//获取动画组件
  23.            
  24.         }
  25.         private void Update()
  26.         {
  27.             timeSinceLastAttack += Time.deltaTime;//设置攻击后的时间统计累加
  28.            
  29.             if (target == null) return;// 如果目标为空,则不进行任何操作
  30.             if (target.IsDead()) return;//如果目标已经死亡,直接return
  31.             if (!GetIsInRange()) // 如果目标不在攻击范围内,则移动到目标位置
  32.             {
  33.                 mover.MoveTo(target.transform.position,1f);//设置战斗时百分比为1
  34.                
  35.             }
  36.             else
  37.             {
  38.                 mover.Cancel(); // 目标在攻击范围内,取消移动,并触发攻击动画
  39.                 AttackBehaviour();
  40.             }
  41.         }
  42.         private void AttackBehaviour()//攻击行为
  43.         {
  44.             transform.LookAt(target.transform.position);//攻击时面向敌人
  45.             if (timeSinceLastAttack > timeBetweenAttacks)//任何时候都大于攻击间隔
  46.             {
  47.                 TriggerAttack();
  48.                 timeSinceLastAttack = 0;//重置攻击后的时间为0
  49.             }
  50.         }
  51.         
  52.         private void TriggerAttack()//动画状态机 攻击触发
  53.         {
  54.             animator.ResetTrigger("stopAttack");
  55.             animator.SetTrigger("attack");
  56.         }
  57.         // 动画事件:攻击时触发的事件
  58.         private void Hit()
  59.         {
  60.            if (target == null) return;
  61.             target.TakeDamage(weaponDamage);//造成伤害
  62.         }
  63.         private bool GetIsInRange()// 检查目标是否在攻击范围内
  64.         {
  65.             return Vector3.Distance(transform.position, target.transform.position) < weaponRange;
  66.         }
  67.         public bool CanAttack(GameObject combatTarget)//检测是否可以攻击
  68.         {
  69.             if(combatTarget == null) //如果攻击目标为空 跳出
  70.             {
  71.                 return false;
  72.             }
  73.             Health targetToTest = combatTarget.GetComponent<Health>();//获取目标的生命组件
  74.             return targetToTest != null && !targetToTest.IsDead();//目标不为空,并且没有死亡
  75.         }
  76.         public void Attack(GameObject combatTarget)//攻击
  77.         {
  78.             
  79.             GetComponent<ActionScheduler>().StartAction(this); // 启动当前动作并设置目标
  80.             target = combatTarget.GetComponent<Health>();//获取目标的生命组件
  81.         }
  82.         public void Cancel()//取消
  83.         {
  84.             StopAttack();//调用停止攻击
  85.             target = null;//清除目标
  86.         }
  87.         private void StopAttack()//动画状态机 停止攻击
  88.         {
  89.             animator.ResetTrigger("attack");//重置攻击
  90.             animator.SetTrigger("stopAttack");//播放暂停攻击
  91.         }
  92.     }
  93. }
复制代码



回复

举报

 
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表