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

2024-09-12
79看过
编写AIController脚本,用于AI的控制,攻击范围的主要逻辑为检测AI和玩家的距离,并设定一个追逐距离。
设定玩家的标签为player,玩家身上也需要挂载生命值脚本,修改Fighter脚本,把Attack方法和CanAttack的CombatTarget修改成Gameobject,这样就可以让AI也调用该脚本

还需将PlayerController报错的地方修改成gameobject。具体详情参考视频,代码供参考

AIController:

  1. using RPG.Combat;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using UnityEngine;
  5. namespace RPG.Control
  6. {
  7.     //AI的控制
  8.     public class AIController : MonoBehaviour
  9.     {
  10.         [SerializeField] float chaseDistance = 5f;// 设定追逐范围的距离
  11.         Fighter fighter;
  12.         GameObject player;
  13.         private void Start()
  14.         {
  15.             fighter = GetComponent<Fighter>();
  16.             player = GameObject.FindWithTag("Player");// 找到标签为“Player”的游戏对象
  17.         }
  18.         private void Update()
  19.         {
  20.            
  21.             // 如果和玩家的距离小于设定的追逐范围 并且可以攻击玩家
  22.             if (InAttackRangeOfPlayer()&& fighter.CanAttack(player))   
  23.             {
  24.                 fighter.Attack(player);//对玩家进行攻击
  25.                 print("可以攻击");
  26.             }
  27.             else
  28.             {
  29.                 fighter.Cancel();//取消攻击
  30.             }
  31.            
  32.         }
  33.         private bool InAttackRangeOfPlayer() // 检测是否在攻击范围内
  34.         {
  35.             float distanceToPlayer = Vector3.Distance(player.transform.position,transform.position); // 计算并返回玩家和当前对象之间的距离
  36.             return distanceToPlayer < chaseDistance;//返回两者之间距离是否小于追逐距离
  37.         }
  38.     }
  39. }
复制代码
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 = 0;//攻击后的时间统计
  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);
  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. }
复制代码
PlayerController:
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. using RPG.Movement;
  5. using RPG.Combat;
  6. //角色的控制
  7. namespace RPG.Control
  8. {
  9.    
  10.     public class PlayerController : MonoBehaviour
  11.     {
  12.         private Mover mover;
  13.         private void Start()
  14.         {
  15.             mover = GetComponent<Mover>();
  16.         }
  17.         private void Update()
  18.         {
  19.             if (InteractWithCombat()) return;
  20.             if (InteractWithMovement()) return;
  21.             
  22.         }
  23.         
  24.         
  25.         private bool InteractWithCombat()// 战斗交互
  26.         {
  27.             RaycastHit[] hits = Physics.RaycastAll(GetMouseRay());
  28.             foreach (RaycastHit hit in hits)
  29.             {
  30.                 CombatTarget target = hit.transform.GetComponent<CombatTarget>();//被射线击中的物体获取战斗目标组件
  31.                 if(target == null) continue;//如果目标为空,继续执行
  32.                
  33.                 if (!GetComponent<Fighter>().CanAttack(target.gameObject))//如果可以攻击该目标,继续执行
  34.                 {
  35.                     continue;
  36.                 }
  37.                 if(Input.GetMouseButtonDown(0))//按下左键
  38.                 {
  39.                     GetComponent<Fighter>().Attack(target.gameObject);//攻击目标
  40.                 }
  41.                 return true;//射线找到目标
  42.             }
  43.             return false;//射线没有找到目标  ActionScheduler
  44.         }
  45.         // 移动和交互
  46.         private bool InteractWithMovement()
  47.         {
  48.             RaycastHit hit;//存储射线碰撞的信息
  49.             bool hasHit = Physics.Raycast(GetMouseRay(), out hit); //通过射线检测是否有接触到碰撞物体
  50.             if (hasHit)//如果有检测到
  51.             {
  52.                 if (Input.GetMouseButton(0))//如果按下鼠标左键
  53.                 {
  54.                     mover.StartMoveAction(hit.point);
  55.                     
  56.                 }
  57.                 return true;
  58.             }
  59.             return false;
  60.         }
  61.         
  62.         //创建射线
  63.         private static Ray GetMouseRay()
  64.         {
  65.             return Camera.main.ScreenPointToRay(Input.mousePosition);
  66.         }
  67.     }
  68. }
复制代码


回复

举报

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

本版积分规则

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