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

2024-09-29
126看过
制作经验值的获取,经验值的获取和生命值有关,当AI生命值为0,给予玩家一定的经验值,所以需要定义攻击者和被攻击者。

需要在处理伤害逻辑的方法中添加攻击者的输入。

Projectile

  1. using RPG.Resources;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using UnityEngine;
  5. namespace RPG.Combat
  6. {
  7.     // 定义远程射击类-主要用于发射出去的箭-魔法-
  8.     public class Projectile : MonoBehaviour
  9.     {
  10.         [SerializeField] float speed = 1;//箭矢射出的速度
  11.         [SerializeField] bool isHoming = true;//是否锁定目标
  12.         [SerializeField] GameObject hitEffect = null;//命中特效
  13.         [SerializeField] float maxLifeTime = 5f;//存在的最长时间
  14.         [SerializeField] float lifeAfterTImpact = 2f;//存在的时间
  15.         //[SerializeField] GameObject[] destoryOnHit = null;//删除的对象列表
  16.         Health target = null;//被攻击者
  17.         GameObject instigator = null;//攻击者
  18.         float damage = 0;
  19.         private void Start()
  20.         {
  21.             transform.LookAt(GetAimLocation());//让箭朝向目标位置
  22.         }
  23.         private void Update()
  24.         {
  25.             if (target == null)//如果攻击目标为空
  26.             {
  27.                 return;
  28.             }
  29.             if (isHoming)
  30.             {
  31.                 transform.LookAt(GetAimLocation());//让箭朝向目标位置
  32.             }
  33.             // 使用Translate方法让箭根据速度和时间增量来移动-- // Vector3.forward表示projectile的前向向量,speed是速度,Time.deltaTime是上一帧到当前帧的时间差
  34.             transform.Translate(Vector3.forward * speed * Time.deltaTime);
  35.         }
  36.         public void SetTarget(Health target, GameObject instigator, float damage)//设置目标
  37.         {
  38.             this.target = target;
  39.             this.damage = damage;
  40.             this.instigator = instigator;
  41.             Destroy(gameObject, maxLifeTime);//删除自身,防止当角色死亡后,最后一击的远程攻击一直存在,一定时间消失
  42.         }
  43.         private Vector3 GetAimLocation()//获取瞄准的目标位置
  44.         {
  45.             CapsuleCollider targetCapsule = target.GetComponent<CapsuleCollider>();//获取目标的碰撞组件
  46.             if (targetCapsule == null)//如果碰撞为空
  47.             {
  48.                 return target.transform.position;//返回目标坐标
  49.             }
  50.             // 如果有CapsuleCollider组件,则返回目标位置上方CapsuleCollider高度的一半处  -确保projectile瞄准的是目标的上半身或中心位置  
  51.             return target.transform.position + Vector3.up * targetCapsule.height / 2;
  52.         }
  53.         private void OnTriggerEnter(Collider other)
  54.         {
  55.             //print("箭的伤害:" + damage);
  56.             Health health = other.GetComponent<Health>();//获取碰撞触发的生命值组件  return
  57.             if (target != null && health != target) return;//如果目标不为空并且生命值不是攻击的目标 return
  58.             if (health == null || health.IsDead()) return;//如果生命值为空 或者角色已经死亡 return
  59.             target.TakeDamage(instigator,damage);//添加伤害
  60.            // speed = 0;//击中后速度为0
  61.             if (hitEffect != null || health.IsDead())//如果爆炸特效不为空 则实例化爆炸
  62.             {
  63.                 Instantiate(hitEffect, GetAimLocation(), transform.rotation);
  64.             }
  65.             //foreach (GameObject toDestory in destoryOnHit)// 遍历需要销毁的游戏对象列表
  66.             //{
  67.             //    Destroy(toDestory);// 销毁当前游戏对象
  68.             //}
  69.             Destroy(gameObject, lifeAfterTImpact);// 在碰撞后,延迟一段时间后销毁当前游戏对象
  70.         }
  71.     }
  72. }
复制代码
Fighter

  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. using RPG.Movement;
  5. using RPG.Core;
  6. using RPG.Saving;
  7. using RPG.Control;
  8. using RPG.Resources;
  9. namespace RPG.Combat
  10. {
  11.     //攻击
  12.     public class Fighter : MonoBehaviour, IAction
  13.     {
  14.       
  15.         [SerializeField] float timeBetweenAttacks = 1f;//攻击间隔时间
  16.       
  17.         [SerializeField] Transform rightHandTransform = null;//武器实例化的地方
  18.         [SerializeField] Transform leftHandTransform = null;//武器实例化的地方
  19.         [SerializeField] Weapon defaultWeapon = null;//设置默认武器脚本
  20.         
  21.         Health target;// 当前攻击的目标
  22.         float timeSinceLastAttack = Mathf.Infinity;//上次攻击的时间为 为无穷大
  23.         Weapon currentWeapon = null;
  24.         
  25.         private Mover mover;// 用于移动角色的 Mover 组件
  26.         private bool isInRange;// 标记目标是否在攻击范围内
  27.         private Animator animator;
  28.         private void Start()
  29.         {
  30.             mover = GetComponent<Mover>();// 获取 Mover 组件
  31.             animator = GetComponent<Animator>();//获取动画组件
  32.             //currentWeapon = defaultWeapon;
  33.             if (currentWeapon == null)
  34.             {
  35.                 EquipWeapon(defaultWeapon);
  36.             }
  37.             
  38.         }
  39.         private void Update()
  40.         {
  41.             timeSinceLastAttack += Time.deltaTime;//设置攻击后的时间统计累加
  42.            
  43.             if (target == null) return;// 如果目标为空,则不进行任何操作
  44.             if (target.IsDead()) return;//如果目标已经死亡,直接return
  45.             if (!GetIsInRange()) // 如果目标不在攻击范围内,则移动到目标位置
  46.             {
  47.                 mover.MoveTo(target.transform.position,1f);//设置战斗时百分比为1
  48.                
  49.             }
  50.             else
  51.             {
  52.                 mover.Cancel(); // 目标在攻击范围内,取消移动,并触发攻击动画
  53.                 AttackBehaviour();
  54.             }
  55.         }
  56.       
  57.       
  58.         private void AttackBehaviour()//攻击行为
  59.         {
  60.             transform.LookAt(target.transform.position);//攻击时面向敌人
  61.             if (timeSinceLastAttack > timeBetweenAttacks)//任何时候都大于攻击间隔
  62.             {
  63.                 TriggerAttack();
  64.                 timeSinceLastAttack = 0;//重置攻击后的时间为0
  65.             }
  66.         }
  67.         
  68.         private void TriggerAttack()//动画状态机 攻击触发
  69.         {
  70.             animator.ResetTrigger("stopAttack");
  71.             animator.SetTrigger("attack");
  72.         }
  73.         // 动画事件:攻击时触发的事件
  74.         private void Hit()
  75.         {
  76.            if (target == null) return;//如果目标为空,跳出
  77.            if(currentWeapon.HasProjectile())//如果当前武器为弓箭
  78.             {
  79.                 //发射箭矢
  80.                 currentWeapon.LacunchProjectile(rightHandTransform, leftHandTransform, target,gameObject);
  81.             }
  82.            else
  83.             {
  84.                 target.TakeDamage(gameObject, currentWeapon.GetDamage());//造成伤害
  85.             }
  86.         }
  87.         private void Shoot()//射击事件
  88.         {
  89.             Hit();
  90.         }
  91.         private bool GetIsInRange()// 检查目标是否在攻击范围内
  92.         {
  93.             return Vector3.Distance(transform.position, target.transform.position) < defaultWeapon.GetRange();
  94.         }
  95.         private void StopAttack()//动画状态机 停止攻击
  96.         {
  97.             animator.ResetTrigger("attack");//重置攻击
  98.             animator.SetTrigger("stopAttack");//播放暂停攻击
  99.         }
  100.         public void EquipWeapon(Weapon weapon)//实例化武器Projectile
  101.         {
  102.             currentWeapon = weapon;
  103.             defaultWeapon = weapon;
  104.             if (weapon == null) return;
  105.             // Animator anim = GetComponent<Animator>();
  106.             weapon.Spawn(rightHandTransform, leftHandTransform, animator);
  107.         }
  108.         public bool CanAttack(GameObject combatTarget)//检测是否可以攻击
  109.         {
  110.             if(combatTarget == null) //如果攻击目标为空 跳出
  111.             {
  112.                 return false;
  113.             }
  114.             Health targetToTest = combatTarget.GetComponent<Health>();//获取目标的生命组件
  115.             return targetToTest != null && !targetToTest.IsDead();//目标不为空,并且没有死亡
  116.         }
  117.         public void Attack(GameObject combatTarget)//攻击
  118.         {
  119.             
  120.             GetComponent<ActionScheduler>().StartAction(this); // 启动当前动作并设置目标
  121.             target = combatTarget.GetComponent<Health>();//获取目标的生命组件
  122.             
  123.         }
  124.         public void Cancel()//取消
  125.         {
  126.             StopAttack();//调用停止攻击
  127.             target = null;//清除目标
  128.             mover.Cancel();//取消移动
  129.         }
  130.         public Health GetTarget()
  131.         {
  132.             return target;
  133.         }
  134.       
  135.         //public object CaptureState()//捕获当前状态   返回当前武器的名字
  136.         //{
  137.         //    return currentWeapon.name;
  138.         //}
  139.         //public void RestoreState(object state)//重置状态,加载武器名字
  140.         //{
  141.         //    string weaponName = (string)state;
  142.         //    if (weaponName != null && weaponName != "")
  143.         //        EquipWeapon(Resources.Load<Weapon>(weaponName));
  144.         //}
  145.     }
  146. }
复制代码
Health

  1. using RPG.Control;
  2. using RPG.Core;
  3. using RPG.Saving;
  4. using RPG.Stats;
  5. using System;
  6. using System.Collections;
  7. using System.Collections.Generic;
  8. using UnityEngine;
  9. using UnityEngine.AI;
  10. // 处理生命值系统的脚本
  11. namespace RPG.Resources
  12. {
  13.     public class Health : MonoBehaviour, ISaveable
  14.     {
  15.         [SerializeField] float healthPoints = 100f;// 当前生命值,初始值为 100
  16.         
  17.         bool isDead = false;//是否死亡
  18.         bool isGetDamage = false;//是否追逐
  19.         Rigidbody rb;
  20.         private void Start()
  21.         {
  22.             healthPoints = GetComponent<BaseStats>().GetHealth();
  23.             rb = GetComponent<Rigidbody>();
  24.         }
  25.         //死亡方法,这个方法用于给角色判断,是否继续进行攻击
  26.         public bool IsDead()
  27.         {
  28.             return isDead;
  29.         }
  30.         // 处理受伤逻辑的方法
  31.         public void TakeDamage(GameObject instigator, float damage)
  32.         {
  33.             healthPoints = Mathf.Max(healthPoints - damage, 0);// 减少生命值,确保生命值不会低于 0
  34.             print(this.name+"生命值减少"+healthPoints);
  35.             isGetDamage = true;
  36.             
  37.             if (healthPoints == 0)//如果生命值等于0,
  38.             {
  39.                 Die();
  40.                 AwardExperience(instigator);//获取经验方法
  41.             }
  42.         }
  43.      
  44.         public bool HasGetDamage()//返回给AI控制器当前是否有获得伤害
  45.         {
  46.             
  47.             return isGetDamage;
  48.         }
  49.         public float  GetPercentage()//返回生命值的百分比
  50.         {
  51.             //返回当前生命值 / 基础状态中的获取生命值
  52.             return 100*healthPoints / GetComponent<BaseStats>().GetHealth();
  53.         }
  54.       
  55.         /// <summary>
  56.         /// 死亡逻辑
  57.         /// </summary>
  58.         private void Die()
  59.         {
  60.             if (isDead) return;//如果玩家已死亡,直接跳出该方法
  61.             isDead = true;
  62.             GetComponent<Animator>().SetTrigger("death");//播放死亡动画
  63.             GetComponent<ActionScheduler>().CancelCurrentAction();//设置当前行为为空
  64.             
  65.             rb.constraints = RigidbodyConstraints.FreezeAll;
  66.         }
  67.         private void AwardExperience(GameObject instigator)//获取经验
  68.         {
  69.             Experience experience = instigator.GetComponent<Experience>();//获取经验组件
  70.             if(experience == null) return;//如果经验组件为空
  71.             experience.GainExperience(GetComponent<BaseStats>().GetExperienceReward());//获得基础状态中的 获取经验奖励
  72.         }
  73.         // 捕获当前对象的生命值状态
  74.         public object CaptureState()
  75.         {
  76.             return healthPoints;// 返回生命值状态
  77.         }
  78.         public void  RestoreState(object state)
  79.         {
  80.             healthPoints = (float)state;
  81.             // 如果生命值为零,则调用死亡处理方法
  82.             if (healthPoints <= 0)
  83.             {
  84.                 Die() ;
  85.             }
  86.             
  87.         }
  88.     }
  89. }
复制代码
BaseStats

  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. namespace RPG.Stats
  5. {
  6.     // 基础状态类,用于存储和计算角色的基础属性
  7.     public class BaseStats : MonoBehaviour
  8.     {
  9.         [Range(1,99)]
  10.         [SerializeField] int startingLevel = 1; /// 角色的起始等级
  11.         [SerializeField] CharacterClass characterClass; /// 角色的职业
  12.         [SerializeField] Progression progression = null;/// 角色的属性成长系统
  13.         /// <summary>  
  14.         /// 获取角色的当前生命值。  
  15.         /// 该方法通过Progression类的GetHealth方法,根据角色的职业和起始等级来计算生命值。  
  16.         /// </summary>  
  17.         /// <returns>返回计算后的生命值。</returns>  
  18.         public float GetHealth()
  19.         {
  20.             return progression.GetHealth(characterClass,startingLevel);
  21.         }
  22.         public float GetExperienceReward()
  23.         {
  24.             return 10;
  25.         }
  26.     }
  27. }
复制代码
Experience

  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. namespace RPG.Resources
  5. {
  6.     public class Experience : MonoBehaviour
  7.     {
  8.         [SerializeField] float experiencePoints = 0;
  9.         public void GainExperience(float experience)// 获得经验
  10.         {
  11.             experiencePoints += experience;
  12.         }
  13.     }
  14. }
复制代码


回复

举报

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

本版积分规则

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