当前位置:   article > 正文

Unity类银河恶魔城学习记录11-18 p120 Buff item effect源代码

Unity类银河恶魔城学习记录11-18 p120 Buff item effect源代码

Alex教程每一P的教程原代码加上我自己的理解初步理解写的注释,可供学习Alex教程的人参考
此代码仅为较上一P有所改变的代码

【Unity教程】从0编程制作类银河恶魔城游戏_哔哩哔哩_bilibili

Buff_Effcet.cs
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. public enum StatType
  5. {
  6. strength,
  7. agility,
  8. intelligence,
  9. vitality,
  10. damage,
  11. critChance,
  12. critPower,
  13. maxHealth,
  14. armor,
  15. evasion,
  16. magicResistance,
  17. fireDamage,
  18. iceDamage,
  19. lightingDamage
  20. }
  21. [CreateAssetMenu(fileName = "BUff effect", menuName = "Data/Item effect/Buff effect")]
  22. public class Buff_Effect :ItemEffect
  23. {
  24. private PlayerStats stats;
  25. [SerializeField] private StatType buffType;
  26. [SerializeField] private float buffDuration;
  27. [SerializeField] private int buffAmount;
  28. public override void ExecuteEffect(Transform _respawnPosition)
  29. {
  30. stats = PlayerManager.instance.player.GetComponent<PlayerStats>();
  31. stats.IncreaseStatBy(buffAmount, buffDuration, StatToModify());
  32. }
  33. private Stat StatToModify()
  34. {
  35. if (buffType == StatType.strength) return stats.strength;
  36. else if (buffType == StatType.agility) return stats.agility;
  37. else if (buffType == StatType.intelligence) return stats.intelligence;
  38. else if (buffType == StatType.vitality) return stats.vitality;
  39. else if (buffType == StatType.damage) return stats.damage;
  40. else if (buffType == StatType.critChance) return stats.critChance;
  41. else if (buffType == StatType.critPower) return stats.critPower;
  42. else if (buffType == StatType.maxHealth) return stats.maxHealth;
  43. else if (buffType == StatType.armor) return stats.armor;
  44. else if (buffType == StatType.evasion) return stats.evasion;
  45. else if (buffType == StatType.magicResistance) return stats.magicResistance;
  46. else if (buffType == StatType.fireDamage) return stats.fireDamage;
  47. else if (buffType == StatType.iceDamage) return stats.iceDamage;
  48. else if (buffType == StatType.lightingDamage) return stats.lightingDamage;
  49. return null;
  50. }
  51. }
CharacterStats.cs
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. public class CharacterStats : MonoBehaviour
  5. {
  6. private EntityFX fx;
  7. [Header("Major stats")]
  8. public Stat strength; // 力量 增伤1点 爆伤增加 1% 物抗
  9. public Stat agility;// 敏捷 闪避 1% 闪避几率增加 1%
  10. public Stat intelligence;// 1 点 魔法伤害 1点魔抗
  11. public Stat vitality;//加血的
  12. [Header("Offensive stats")]
  13. public Stat damage;
  14. public Stat critChance; // 暴击率
  15. public Stat critPower; //150% 爆伤
  16. [Header("Defensive stats")]
  17. public Stat maxHealth;
  18. public Stat armor;
  19. public Stat evasion;//闪避值
  20. public Stat magicResistance;
  21. [Header("Magic stats")]
  22. public Stat fireDamage;
  23. public Stat iceDamage;
  24. public Stat lightingDamage;
  25. public bool isIgnited; // 持续烧伤
  26. public bool isChilded; // 削弱护甲 20%
  27. public bool isShocked; // 降低敌人命中率
  28. [SerializeField] private float ailmentsDuration = 4;
  29. private float ignitedTimer;
  30. private float chilledTimer;
  31. private float shockedTimer;
  32. private float igniteDamageCooldown = .3f;
  33. private float ignitedDamageTimer;
  34. private int igniteDamage;
  35. [SerializeField] private GameObject shockStrikePrefab;
  36. private int shockDamage;
  37. public System.Action onHealthChanged;//使角色在Stat里调用UI层的函数
  38. //此函数调用了更新HealthUI函数
  39. public bool isDead { get; private set; }
  40. [SerializeField] public int currentHealth;
  41. protected virtual void Start()
  42. {
  43. critPower.SetDefaultValue(150);//设置默认爆伤
  44. currentHealth = GetMaxHealthValue();
  45. fx = GetComponent<EntityFX>();
  46. }
  47. protected virtual void Update()
  48. {
  49. //所有的状态都设置上默认持续时间,持续过了就结束状态
  50. ignitedTimer -= Time.deltaTime;
  51. chilledTimer -= Time.deltaTime;
  52. shockedTimer -= Time.deltaTime;
  53. ignitedDamageTimer -= Time.deltaTime;
  54. if (ignitedTimer < 0)
  55. isIgnited = false;
  56. if (chilledTimer < 0)
  57. isChilded = false;
  58. if (shockedTimer < 0)
  59. isShocked = false;
  60. //被点燃后,出现多段伤害后点燃停止
  61. if(isIgnited)
  62. ApplyIgnitedDamage();
  63. }
  64. public virtual void IncreaseStatBy(int _modifier, float _duration,Stat _statToModify)
  65. {
  66. StartCoroutine(StatModCoroutine(_modifier, _duration, _statToModify));
  67. }
  68. private IEnumerator StatModCoroutine(int _modifier, float _duration, Stat _statToModify)
  69. {
  70. _statToModify.AddModifier(_modifier);
  71. yield return new WaitForSeconds(_duration);
  72. _statToModify.RemoveModifier(_modifier);
  73. }
  74. public virtual void DoDamage(CharacterStats _targetStats)//计算后造成伤害函数
  75. {
  76. if (TargetCanAvoidAttack(_targetStats))设置闪避
  77. {
  78. return;
  79. }
  80. int totleDamage = damage.GetValue() + strength.GetValue();
  81. //爆伤设置
  82. if (CanCrit())
  83. {
  84. totleDamage = CalculateCriticalDamage(totleDamage);
  85. }
  86. totleDamage = CheckTargetArmor(_targetStats, totleDamage);//设置防御
  87. _targetStats.TakeDamage(totleDamage);
  88. DoMagicaDamage(_targetStats); // 可以去了也可以不去
  89. }
  90. protected virtual void Die()
  91. {
  92. isDead = true;
  93. }
  94. public virtual void TakeDamage(int _damage)//造成伤害是出特效
  95. {
  96. fx.StartCoroutine("FlashFX");//IEnumertor本质就是将一个函数分块执行,只有满足某些条件才能执行下一段代码,此函数有StartCoroutine调用
  97. //https://www.zhihu.com/tardis/bd/art/504607545?source_id=1001
  98. DecreaseHealthBy(_damage);
  99. GetComponent<Entity>().DamageImpact();
  100. if (currentHealth < 0 && !isDead)
  101. Die();
  102. }
  103. public virtual void IncreaseHealthBy(int _amount)//添加回血函数
  104. {
  105. currentHealth += _amount;
  106. if (currentHealth > GetMaxHealthValue())
  107. currentHealth = GetMaxHealthValue();
  108. if (onHealthChanged != null)
  109. onHealthChanged();
  110. }
  111. protected virtual void DecreaseHealthBy(int _damage)//此函数用来改变当前生命值,不调用特效
  112. {
  113. currentHealth -= _damage;
  114. if (onHealthChanged != null)
  115. {
  116. onHealthChanged();
  117. }
  118. }
  119. #region Magical damage and ailements
  120. private void ApplyIgnitedDamage()
  121. {
  122. if (ignitedDamageTimer < 0 )
  123. {
  124. DecreaseHealthBy(igniteDamage);
  125. if (currentHealth < 0 && !isDead)
  126. Die();
  127. ignitedDamageTimer = igniteDamageCooldown;
  128. }
  129. }被点燃后,出现多段伤害后点燃停止
  130. public virtual void DoMagicaDamage(CharacterStats _targetStats)//法伤计算和造成元素效果调用的地方
  131. {
  132. int _fireDamage = fireDamage.GetValue();
  133. int _iceDamage = iceDamage.GetValue();
  134. int _lightingDamage = lightingDamage.GetValue();
  135. int totleMagicalDamage = _fireDamage + _iceDamage + _lightingDamage + intelligence.GetValue();
  136. totleMagicalDamage = CheckTargetResistance(_targetStats, totleMagicalDamage);
  137. _targetStats.TakeDamage(totleMagicalDamage);
  138. //防止循环在所有元素伤害为0时出现死循环
  139. if (Mathf.Max(_fireDamage, _iceDamage, _lightingDamage) <= 0)
  140. return;
  141. //让元素效果取决与伤害
  142. //为了防止出现元素伤害一致而导致无法触发元素效果
  143. //循环判断触发某个元素效果
  144. AttemptyToApplyAilement(_targetStats, _fireDamage, _iceDamage, _lightingDamage);
  145. }
  146. private void AttemptyToApplyAilement(CharacterStats _targetStats, int _fireDamage, int _iceDamage, int _lightingDamage)
  147. {
  148. bool canApplyIgnite = _fireDamage > _iceDamage && _fireDamage > _lightingDamage;
  149. bool canApplyChill = _iceDamage > _lightingDamage && _iceDamage > _fireDamage;
  150. bool canApplyShock = _lightingDamage > _fireDamage && _lightingDamage > _iceDamage;
  151. while (!canApplyIgnite && !canApplyChill && !canApplyShock)
  152. {
  153. if (Random.value < .25f)
  154. {
  155. canApplyIgnite = true;
  156. Debug.Log("Ignited");
  157. _targetStats.ApplyAilments(canApplyIgnite, canApplyChill, canApplyShock);
  158. return;
  159. }
  160. if (Random.value < .35f)
  161. {
  162. canApplyChill = true;
  163. Debug.Log("Chilled");
  164. _targetStats.ApplyAilments(canApplyIgnite, canApplyChill, canApplyShock);
  165. return;
  166. }
  167. if (Random.value < .55f)
  168. {
  169. canApplyShock = true;
  170. Debug.Log("Shocked");
  171. _targetStats.ApplyAilments(canApplyIgnite, canApplyChill, canApplyShock);
  172. return;
  173. }
  174. }
  175. if (canApplyIgnite)
  176. {
  177. _targetStats.SetupIgniteDamage(Mathf.RoundToInt(_fireDamage * .2f));
  178. }
  179. if (canApplyShock)
  180. _targetStats.SetupShockStrikeDamage(Mathf.RoundToInt(_lightingDamage * .1f));
  181. //给点燃伤害赋值
  182. _targetStats.ApplyAilments(canApplyIgnite, canApplyChill, canApplyShock);
  183. }//造成元素效果
  184. public void ApplyAilments(bool _ignite, bool _chill, bool _shock)//判断异常状态
  185. {
  186. bool canApplyIgnite = !isIgnited && !isChilded && !isShocked;
  187. bool canApplyChill = !isIgnited && !isChilded && !isShocked;
  188. bool canApplyShock = !isIgnited && !isChilded;
  189. //使当isShock为真时Shock里的函数仍然可以调用
  190. if (_ignite && canApplyIgnite)
  191. {
  192. isIgnited = _ignite;
  193. ignitedTimer = ailmentsDuration;
  194. fx.IgniteFxFor(ailmentsDuration);
  195. }
  196. if (_chill && canApplyChill)
  197. {
  198. isChilded = _chill;
  199. chilledTimer = ailmentsDuration;
  200. float slowPercentage = .2f;
  201. GetComponent<Entity>().SlowEntityBy(slowPercentage, ailmentsDuration);
  202. fx.ChillFxFor(ailmentsDuration);
  203. }
  204. if (_shock && canApplyShock)
  205. {
  206. if(!isShocked)
  207. {
  208. ApplyShock(_shock);
  209. }
  210. else
  211. {
  212. if (GetComponent<Player>() != null)//防止出现敌人使玩家进入shock状态后也出现闪电
  213. return;
  214. HitNearestTargetWithShockStrike();
  215. }//isShock为真时反复执行的函数为寻找最近的敌人,创建闪电实例并传入数据
  216. }
  217. }
  218. public void ApplyShock(bool _shock)
  219. {
  220. if (isShocked)
  221. return;
  222. isShocked = _shock;
  223. shockedTimer = ailmentsDuration;
  224. fx.ShockFxFor(ailmentsDuration);
  225. }//触电变色效果
  226. private void HitNearestTargetWithShockStrike()
  227. {
  228. Collider2D[] colliders = Physics2D.OverlapCircleAll(transform.position, 25);//找到环绕自己的所有碰撞器
  229. float closestDistance = Mathf.Infinity;//正无穷大的表示形式(只读)
  230. Transform closestEnemy = null;
  231. //https://docs.unity3d.com/cn/current/ScriptReference/Mathf.Infinity.html
  232. foreach (var hit in colliders)
  233. {
  234. if (hit.GetComponent<Enemy>() != null && Vector2.Distance(transform.position, hit.transform.position) > 1)// 防止最近的敌人就是Shock状态敌人自己
  235. {
  236. float distanceToEnemy = Vector2.Distance(transform.position, hit.transform.position);//拿到与敌人之间的距离
  237. if (distanceToEnemy < closestDistance)//比较距离,如果离得更近,保存这个敌人的位置,更改最近距离
  238. {
  239. closestDistance = distanceToEnemy;
  240. closestEnemy = hit.transform;
  241. }
  242. }
  243. if (closestEnemy == null)
  244. closestEnemy = transform;
  245. }
  246. if (closestEnemy != null)
  247. {
  248. GameObject newShockStrike = Instantiate(shockStrikePrefab, transform.position, Quaternion.identity);
  249. newShockStrike.GetComponent<ShockStrike_Controller>().Setup(shockDamage, closestEnemy.GetComponent<CharacterStats>());
  250. }
  251. }//给最近的敌人以雷劈
  252. public void SetupIgniteDamage(int _damage) => igniteDamage = _damage;//给点燃伤害赋值
  253. public void SetupShockStrikeDamage(int _damage) => shockDamage = _damage;//雷电伤害赋值
  254. #endregion
  255. #region Stat calculations
  256. private int CheckTargetResistance(CharacterStats _targetStats, int totleMagicalDamage)//法抗计算
  257. {
  258. totleMagicalDamage -= _targetStats.magicResistance.GetValue() + (_targetStats.intelligence.GetValue() * 3);
  259. totleMagicalDamage = Mathf.Clamp(totleMagicalDamage, 0, int.MaxValue);
  260. return totleMagicalDamage;
  261. }
  262. private static int CheckTargetArmor(CharacterStats _targetStats, int totleDamage)//防御计算
  263. {
  264. //被冰冻后,角色护甲减少
  265. if (_targetStats.isChilded)
  266. totleDamage -= Mathf.RoundToInt(_targetStats.armor.GetValue() * .8f);
  267. else
  268. totleDamage -= _targetStats.armor.GetValue();
  269. totleDamage = Mathf.Clamp(totleDamage, 0, int.MaxValue);
  270. return totleDamage;
  271. }
  272. private bool TargetCanAvoidAttack(CharacterStats _targetStats)//闪避计算
  273. {
  274. int totleEvation = _targetStats.evasion.GetValue() + _targetStats.agility.GetValue();
  275. //我被麻痹后
  276. //敌人的闪避率提升
  277. if (isShocked)
  278. totleEvation += 20;
  279. if (Random.Range(0, 100) < totleEvation)
  280. {
  281. return true;
  282. }
  283. return false;
  284. }
  285. private bool CanCrit()//判断是否暴击
  286. {
  287. int totleCriticalChance = critChance.GetValue() + agility.GetValue();
  288. if (Random.Range(0, 100) <= totleCriticalChance)
  289. {
  290. return true;
  291. }
  292. return false;
  293. }
  294. private int CalculateCriticalDamage(int _damage)//计算暴击后伤害
  295. {
  296. float totleCirticalPower = (critPower.GetValue() + strength.GetValue()) * .01f;
  297. float critDamage = _damage * totleCirticalPower;
  298. return Mathf.RoundToInt(critDamage);//返回舍入为最近整数的
  299. }
  300. public int GetMaxHealthValue()
  301. {
  302. return maxHealth.GetValue() + vitality.GetValue() * 10;
  303. }//统计生命值函数
  304. #endregion
  305. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/凡人多烦事01/article/detail/375359
推荐阅读
相关标签
  

闽ICP备14008679号