Unity类银河恶魔城学习记录12-14 p136 Merge Skill Tree with Sword skill源代码

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

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

CharacterStats.cs
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting.Antlr3.Runtime.Misc;
using UnityEngine;
public enum StatType
{strength,agility,intelligence,vitality,damage,critChance,critPower,Health,armor,evasion,magicResistance,fireDamage,iceDamage,lightingDamage
}
public class CharacterStats : MonoBehaviour
{private EntityFX fx;[Header("Major stats")]public Stat strength; // 力量 增伤1点 爆伤增加 1% 物抗public Stat agility;// 敏捷 闪避 1% 闪避几率增加 1%public Stat intelligence;// 1 点 魔法伤害 1点魔抗 public Stat vitality;//加血的[Header("Offensive stats")]public Stat damage;public Stat critChance;      // 暴击率public Stat critPower;       //150% 爆伤[Header("Defensive stats")]public Stat Health;public Stat armor;public Stat evasion;//闪避值public Stat magicResistance;[Header("Magic stats")]public Stat fireDamage;public Stat iceDamage;public Stat lightingDamage;public bool isIgnited;  // 持续烧伤public bool isChilded;  // 削弱护甲 20%public bool isShocked;  // 降低敌人命中率[SerializeField] private float ailmentsDuration = 4;private float ignitedTimer;private float chilledTimer;private float shockedTimer;private float igniteDamageCooldown = .3f;private float ignitedDamageTimer;private int igniteDamage;[SerializeField] private GameObject shockStrikePrefab;private int shockDamage;public System.Action onHealthChanged;//使角色在Stat里调用UI层的函数//此函数调用了更新HealthUI函数public bool isDead { get; private set; }private bool isVulnerable;//脆弱效果[SerializeField] public int currentHealth;protected virtual void Start(){critPower.SetDefaultValue(150);//设置默认爆伤currentHealth = GetMaxHealthValue();fx = GetComponent<EntityFX>();}public void MakeVulnerableFor(float _duration) => StartCoroutine(VulnerableCorutine(_duration));//脆弱效果函数private IEnumerator VulnerableCorutine(float _duration){isVulnerable = true;yield return new WaitForSeconds(_duration);isVulnerable = false;}protected virtual void Update(){//所有的状态都设置上默认持续时间,持续过了就结束状态ignitedTimer -= Time.deltaTime;chilledTimer -= Time.deltaTime;shockedTimer -= Time.deltaTime;ignitedDamageTimer -= Time.deltaTime;if (ignitedTimer < 0)isIgnited = false;if (chilledTimer < 0)isChilded = false;if (shockedTimer < 0)isShocked = false;//被点燃后,出现多段伤害后点燃停止if(isIgnited)ApplyIgnitedDamage();}public virtual void IncreaseStatBy(int _modifier, float _duration,Stat _statToModify){StartCoroutine(StatModCoroutine(_modifier, _duration, _statToModify));}private IEnumerator StatModCoroutine(int _modifier, float _duration, Stat _statToModify){_statToModify.AddModifier(_modifier);yield return new WaitForSeconds(_duration);_statToModify.RemoveModifier(_modifier);}public virtual void DoDamage(CharacterStats _targetStats)//计算后造成伤害函数{if (TargetCanAvoidAttack(_targetStats))设置闪避{return;}int totleDamage = damage.GetValue() + strength.GetValue();//爆伤设置if (CanCrit()){totleDamage = CalculateCriticalDamage(totleDamage);}totleDamage = CheckTargetArmor(_targetStats, totleDamage);//设置防御_targetStats.TakeDamage(totleDamage);DoMagicaDamage(_targetStats); // 可以去了也可以不去}protected virtual void Die(){isDead = true;}public virtual void TakeDamage(int _damage)//造成伤害是出特效{fx.StartCoroutine("FlashFX");//IEnumertor本质就是将一个函数分块执行,只有满足某些条件才能执行下一段代码,此函数有StartCoroutine调用//https://www.zhihu.com/tardis/bd/art/504607545?source_id=1001DecreaseHealthBy(_damage);GetComponent<Entity>().DamageImpact();if (currentHealth < 0 && !isDead)Die();}public virtual void IncreaseHealthBy(int _amount)//添加回血函数{currentHealth += _amount;if (currentHealth > GetMaxHealthValue())currentHealth = GetMaxHealthValue();if (onHealthChanged != null)onHealthChanged();}protected virtual void DecreaseHealthBy(int _damage)//此函数用来改变当前生命值,不调用特效{if (isVulnerable)_damage = Mathf.RoundToInt(_damage * 1.1f);currentHealth -= _damage;if (onHealthChanged != null){onHealthChanged();}}#region Magical damage and ailementsprivate void ApplyIgnitedDamage(){if (ignitedDamageTimer < 0 ){DecreaseHealthBy(igniteDamage);if (currentHealth < 0 && !isDead)Die();ignitedDamageTimer = igniteDamageCooldown;}}被点燃后,出现多段伤害后点燃停止public virtual void DoMagicaDamage(CharacterStats _targetStats)//法伤计算和造成元素效果调用的地方{int _fireDamage = fireDamage.GetValue();int _iceDamage = iceDamage.GetValue();int _lightingDamage = lightingDamage.GetValue();int totleMagicalDamage = _fireDamage + _iceDamage + _lightingDamage + intelligence.GetValue();totleMagicalDamage = CheckTargetResistance(_targetStats, totleMagicalDamage);_targetStats.TakeDamage(totleMagicalDamage);//防止循环在所有元素伤害为0时出现死循环if (Mathf.Max(_fireDamage, _iceDamage, _lightingDamage) <= 0)return;//让元素效果取决与伤害//为了防止出现元素伤害一致而导致无法触发元素效果//循环判断触发某个元素效果AttemptyToApplyAilement(_targetStats, _fireDamage, _iceDamage, _lightingDamage);}private  void AttemptyToApplyAilement(CharacterStats _targetStats, int _fireDamage, int _iceDamage, int _lightingDamage){bool canApplyIgnite = _fireDamage > _iceDamage && _fireDamage > _lightingDamage;bool canApplyChill = _iceDamage > _lightingDamage && _iceDamage > _fireDamage;bool canApplyShock = _lightingDamage > _fireDamage && _lightingDamage > _iceDamage;while (!canApplyIgnite && !canApplyChill && !canApplyShock){if (Random.value < .25f){canApplyIgnite = true;Debug.Log("Ignited");_targetStats.ApplyAilments(canApplyIgnite, canApplyChill, canApplyShock);return;}if (Random.value < .35f){canApplyChill = true;Debug.Log("Chilled");_targetStats.ApplyAilments(canApplyIgnite, canApplyChill, canApplyShock);return;}if (Random.value < .55f){canApplyShock = true;Debug.Log("Shocked");_targetStats.ApplyAilments(canApplyIgnite, canApplyChill, canApplyShock);return;}}if (canApplyIgnite){_targetStats.SetupIgniteDamage(Mathf.RoundToInt(_fireDamage * .2f));}if (canApplyShock)_targetStats.SetupShockStrikeDamage(Mathf.RoundToInt(_lightingDamage * .1f));//给点燃伤害赋值_targetStats.ApplyAilments(canApplyIgnite, canApplyChill, canApplyShock);}//造成元素效果public void ApplyAilments(bool _ignite, bool _chill, bool _shock)//判断异常状态{bool canApplyIgnite = !isIgnited && !isChilded && !isShocked;bool canApplyChill = !isIgnited && !isChilded && !isShocked;bool canApplyShock = !isIgnited && !isChilded;//使当isShock为真时Shock里的函数仍然可以调用if (_ignite && canApplyIgnite){isIgnited = _ignite;ignitedTimer = ailmentsDuration;fx.IgniteFxFor(ailmentsDuration);}if (_chill && canApplyChill){isChilded = _chill;chilledTimer = ailmentsDuration;float slowPercentage = .2f;GetComponent<Entity>().SlowEntityBy(slowPercentage, ailmentsDuration);fx.ChillFxFor(ailmentsDuration);}if (_shock && canApplyShock){if(!isShocked){ApplyShock(_shock);}else{if (GetComponent<Player>() != null)//防止出现敌人使玩家进入shock状态后也出现闪电return;HitNearestTargetWithShockStrike();}//isShock为真时反复执行的函数为寻找最近的敌人,创建闪电实例并传入数据}}public void ApplyShock(bool _shock){if (isShocked)return;isShocked = _shock;shockedTimer = ailmentsDuration;fx.ShockFxFor(ailmentsDuration);}//触电变色效果private void HitNearestTargetWithShockStrike(){Collider2D[] colliders = Physics2D.OverlapCircleAll(transform.position, 25);//找到环绕自己的所有碰撞器float closestDistance = Mathf.Infinity;//正无穷大的表示形式(只读)Transform closestEnemy = null;//https://docs.unity3d.com/cn/current/ScriptReference/Mathf.Infinity.htmlforeach (var hit in colliders){if (hit.GetComponent<Enemy>() != null && Vector2.Distance(transform.position, hit.transform.position) > 1)// 防止最近的敌人就是Shock状态敌人自己{float distanceToEnemy = Vector2.Distance(transform.position, hit.transform.position);//拿到与敌人之间的距离if (distanceToEnemy < closestDistance)//比较距离,如果离得更近,保存这个敌人的位置,更改最近距离{closestDistance = distanceToEnemy;closestEnemy = hit.transform;}}if (closestEnemy == null)closestEnemy = transform;}if (closestEnemy != null){GameObject newShockStrike = Instantiate(shockStrikePrefab, transform.position, Quaternion.identity);newShockStrike.GetComponent<ShockStrike_Controller>().Setup(shockDamage, closestEnemy.GetComponent<CharacterStats>());}}//给最近的敌人以雷劈public void SetupIgniteDamage(int _damage) => igniteDamage = _damage;//给点燃伤害赋值public void SetupShockStrikeDamage(int _damage) => shockDamage = _damage;//雷电伤害赋值#endregion#region Stat calculationsprivate int CheckTargetResistance(CharacterStats _targetStats, int totleMagicalDamage)//法抗计算{totleMagicalDamage -= _targetStats.magicResistance.GetValue() + (_targetStats.intelligence.GetValue() * 3);totleMagicalDamage = Mathf.Clamp(totleMagicalDamage, 0, int.MaxValue);return totleMagicalDamage;}private static int CheckTargetArmor(CharacterStats _targetStats, int totleDamage)//防御计算{//被冰冻后,角色护甲减少if (_targetStats.isChilded)totleDamage -= Mathf.RoundToInt(_targetStats.armor.GetValue() * .8f);elsetotleDamage -= _targetStats.armor.GetValue();totleDamage = Mathf.Clamp(totleDamage, 0, int.MaxValue);return totleDamage;}public virtual void OnEvasion(){}//可继承成功闪避触发的函数private bool TargetCanAvoidAttack(CharacterStats _targetStats)//闪避计算{int totleEvation = _targetStats.evasion.GetValue() + _targetStats.agility.GetValue();//我被麻痹后//敌人的闪避率提升if (isShocked)totleEvation += 20;if (Random.Range(0, 100) < totleEvation){_targetStats.OnEvasion();return true;}return false;}private bool CanCrit()//判断是否暴击{int totleCriticalChance = critChance.GetValue() + agility.GetValue();if (Random.Range(0, 100) <= totleCriticalChance){return true;}return false;}private int CalculateCriticalDamage(int _damage)//计算暴击后伤害{float totleCirticalPower = (critPower.GetValue() + strength.GetValue()) * .01f;float critDamage = _damage * totleCirticalPower;return Mathf.RoundToInt(critDamage);//返回舍入为最近整数的}public int GetMaxHealthValue(){return Health.GetValue() + vitality.GetValue() * 10;}//统计生命值函数public  Stat GetStats(StatType _statType){if (_statType == StatType.strength) return strength;else if (_statType == StatType.agility) return agility;else if (_statType == StatType.intelligence) return intelligence;else if (_statType == StatType.vitality) return vitality;else if (_statType == StatType.damage) return damage;else if (_statType == StatType.critChance) return critChance;else if (_statType == StatType.critPower) return critPower;else if (_statType == StatType.Health) return Health;else if (_statType == StatType.armor) return armor;else if (_statType == StatType.evasion) return evasion;else if (_statType == StatType.magicResistance) return magicResistance;else if (_statType == StatType.fireDamage) return fireDamage;else if (_statType == StatType.iceDamage) return iceDamage;else if (_statType == StatType.lightingDamage) return lightingDamage;return null;}#endregion
}
Sword_Skill_Controller.cs
using System.Collections;
using System.Collections.Generic;
using Unity.Burst.CompilerServices;
using UnityEngine;public class Sword_Skill_Controller : MonoBehaviour
{private float returnSpeed;private bool isReturning;private Animator anim;private Rigidbody2D rb;private CircleCollider2D cd;private Player player;private bool canRotate = true;private float freezeTimeDuration;[Header("Piece info")][SerializeField] float pierceAmount;[Header("Bounce info")]private float bounceSpeed;//设置弹跳速度private bool isBouncing;//判断是否可以弹跳private int bounceAmount;//弹跳的次数public List<Transform> enemyTargets;//保存所有在剑范围内的敌人的列表private int targetIndex;//设置targetIndex作为敌人计数器[Header("Spin info")]private float maxTravelDistance;//最大攻击距离private float spinDuration;//持续时间private float spinTimer;//计时器private bool wasStopped;//是否停止private bool isSpinning;private float hitTimer;private float hitColldown;private float spinDirection;//用来不断推进剑在x轴上移动的值private void Awake(){anim = GetComponentInChildren<Animator>();rb = GetComponent<Rigidbody2D>();cd = GetComponent<CircleCollider2D>();}private void DestroyMe(){Destroy(gameObject);}public void ReturnSword(){rb.constraints = RigidbodyConstraints2D.FreezeAll;//修复剑只要不触碰到物体就无法收回的bug//rb.isKinematic = false;transform.parent = null;isReturning = true;}public void SetupSword(Vector2 _dir,float _gravityScale,Player _player,float _freezeTimeDuration,float _returnSpeed){player = _player;rb.velocity = _dir;rb.gravityScale = _gravityScale;freezeTimeDuration = _freezeTimeDuration;returnSpeed = _returnSpeed;if(pierceAmount <= 0)anim.SetBool("Rotation", true); //其次在pierceAmount > 0时不启动旋转动画spinDirection = Mathf.Clamp(rb.velocity.x, -1, 1);用来不断推进剑在x轴上移动的值//Mathf.Clamp,当剑使向右飞的时候,direction为1,反之为-1//https://docs.unity3d.com/cn/current/ScriptReference/Mathf.Clamp.htmlInvoke("DestroyMe",7);//在一定时间后自动销毁剑}public void SetupBounce(bool _isBouncing,int _bounceAmount,float _bounceSpeed){isBouncing = _isBouncing;bounceAmount = _bounceAmount;bounceSpeed = _bounceSpeed;}public void SetupPierce(int _pierceAomunt){pierceAmount = _pierceAomunt;}public void SetupSpin(bool _isSpinning, float _maxTravelDistance,float _spinDuration,float _hitCooldown){isSpinning = _isSpinning;maxTravelDistance = _maxTravelDistance;spinDuration = _spinDuration;hitColldown = _hitCooldown;}private void Update(){if (canRotate)transform.right = rb.velocity;//使武器随着速度而改变朝向if (isReturning){transform.position = Vector2.MoveTowards(transform.position, player.transform.position, returnSpeed * Time.deltaTime);//从原来的位置返回到player的位置//并且随着时间增加而增加速度if (Vector2.Distance(transform.position, player.transform.position) < 1)//当剑与player的距离小于一定距离,清除剑{player.CatchTheSword();}}BounceLogic();SpinLogic();}private void SpinLogic(){if (isSpinning)//首先当isSpining为true才可进入{if (Vector2.Distance(player.transform.position, transform.position) > maxTravelDistance && !wasStopped)//当剑与角色到达最大攻击距离,stop为true,停止剑运动,给剑一个倒计时{StopWhenSpinning();}if (wasStopped)//当stop为true,倒计时过了,回归角色{spinTimer -= Time.deltaTime;                                                                    //spinDirection一直是1或者-1,但position是变化的transform.position = Vector2.MoveTowards(transform.position, new Vector2(transform.position.x + spinDirection, transform.position.y), 1.5f * Time.deltaTime);//让剑在x轴上移动的函数if (spinTimer < 0){isReturning = true;isSpinning = false;}hitTimer -= Time.deltaTime;if (hitTimer < 0){hitTimer = hitColldown;Collider2D[] colliders = Physics2D.OverlapCircleAll(transform.position, 1);foreach (var hit in colliders){if (hit.GetComponent<Enemy>() != null){hit.GetComponent<Enemy>().DamageImpact();}}}}}}private void StopWhenSpinning(){wasStopped = true;rb.constraints = RigidbodyConstraints2D.FreezeAll;spinTimer = spinDuration;}private void BounceLogic(){if (isBouncing && enemyTargets.Count > 0){transform.position = Vector2.MoveTowards(transform.position, enemyTargets[targetIndex].position, bounceSpeed * Time.deltaTime);//3.当可以弹跳且列表内数量大于0,调用ToWords,这将使剑能够跳到敌人身上if (Vector2.Distance(transform.position, enemyTargets[targetIndex].position) < .1f){enemyTargets[targetIndex].GetComponent<Enemy>().DamageImpact();targetIndex++;bounceAmount--;//设置弹跳次数if (bounceAmount <= 0){isBouncing = false;isReturning = true;}//这样会使当弹跳次数为0时,返回到角色手中if (targetIndex >= enemyTargets.Count){targetIndex = 0;}}//利用与目标距离的判断,使剑接近目标距离时切换到下一个目标。//且如果所有目标都跳完了,切回第一个}}private void OnTriggerEnter2D(Collider2D collision)//传入碰到的物体的碰撞器{if (isReturning){return;}//修复在返回时扔出时没有碰到任何物体,但返回时碰到了物体导致剑的一些性质发生改变的问题,及回来的时候调用了OnTriggerEnter2Dif(collision.GetComponent<Enemy>()!=null){Enemy enemy = collision.GetComponent<Enemy>();SwordSkillDamage(enemy);}SetupTargetsForBounce(collision);StuckInto(collision);}//打开IsTrigger时才可使用该函数private void SwordSkillDamage(Enemy enemy){EnemyStats enemyStats = enemy.GetComponent<EnemyStats>();player.stats.DoDamage(enemyStats);if(player.skill.sword.timeStopUnlocked)enemy.FreezeTimerFor(freezeTimeDuration);if (player.skill.sword.vulnerableUnlocked)enemyStats.MakeVulnerableFor(freezeTimeDuration);//调用脆弱效果函数ItemData_Equipment equipment = Inventory.instance.GetEquipment(EquipmentType.Amulet);if (equipment != null){equipment.Effect(enemy.transform);}}//造成伤害函数private void SetupTargetsForBounce(Collider2D collision){if (collision.GetComponent<Enemy>() != null)//首先得碰到敌人,只有碰到敌人才会跳{if (isBouncing && enemyTargets.Count <= 0){Collider2D[] colliders = Physics2D.OverlapCircleAll(transform.position, 10);foreach (var hit in colliders){if (hit.GetComponent<Enemy>() != null){enemyTargets.Add(hit.transform);}}}}}//https://docs.unity3d.com/cn/current/ScriptReference/Collider2D.OnTriggerEnter2D.htmlprivate void StuckInto(Collider2D collision){if(pierceAmount > 0 && collision.GetComponent<Enemy>()!= null)//本质就是能穿过敌人,在amount>0时不执行能让剑卡在敌人里的语句就行{pierceAmount--;return;}if (isSpinning){StopWhenSpinning();return;}//防止卡在敌人身上canRotate = false;cd.enabled = false;//相当于关闭碰撞后触发函数。//https://docs.unity3d.com/cn/current/ScriptReference/Collision2D-enabled.htmlrb.isKinematic = true;//开启物理学反应 https://docs.unity3d.com/cn/current/ScriptReference/Rigidbody2D-isKinematic.htmlrb.constraints = RigidbodyConstraints2D.FreezeAll;//冻结所有移动if (isBouncing&&enemyTargets.Count>0)//修复剑卡不到墙上的bugreturn;//终止对动画的改变和终止附在敌人上transform.parent = collision.transform;//设置sword的父组件为碰撞到的物体anim.SetBool("Rotation", false);}}

Sword_Skill.cs
using UnityEngine;
using UnityEngine.UI;public enum SwordType
{Regular,Bounce,Pierce,Spin
}public class Sword_Skill : Skill
{public SwordType swordType = SwordType.Regular;//创建应一个enum列表,后面用来判断切换状态[Header("Skill Info")][SerializeField] private UI_SkillTreeSlot swordUnlockButton;public bool swordUnlocked;[SerializeField] private GameObject swordPrefab;//sword预制体[SerializeField] private Vector2 launchForce;//发射力度[SerializeField] private float swordGravity;//发射体的重力[SerializeField] private float freezeTimeDuration;[SerializeField] private float returnSpeed;[Header("Bounce Info")][SerializeField] private UI_SkillTreeSlot bounceUnlockButton;[SerializeField] private int bounceAmount;[SerializeField] private float bounceGravity;[SerializeField] private float bounceSpeed;[Header("Pierce info")][SerializeField] private UI_SkillTreeSlot pierceUnlockButton;[SerializeField] private int pierceAmount;[SerializeField] private float pierceGravity;[Header("Spin info")][SerializeField] private UI_SkillTreeSlot spinUnlockButton;[SerializeField] private float hitCooldown = .35f;//攻击冷却[SerializeField] private float maxTravelDistance = 7;//最大攻击距离[SerializeField] private float spinDuration = 2;//持续时间[SerializeField] private float spinGravity = 1;[Header("Passive skills")][SerializeField] private UI_SkillTreeSlot timeStopUnlockButton;public bool timeStopUnlocked { get; private set; }[SerializeField] private UI_SkillTreeSlot vulnerableUnlockButton;public bool vulnerableUnlocked{ get; private set; }[Header("Aim dots")][SerializeField] private int numberOfDots;//需要的点的数量[SerializeField] private float spaceBetweenDots;//相隔的距离[SerializeField] private GameObject dotPrefab;//dot预制体[SerializeField] private Transform dotsParent;//不是很懂private GameObject[] dots;//dot组private Vector2 finalDir;protected override void Start(){base.Start();GenerateDots();//生成点函数SetupGravity();swordUnlockButton.GetComponent<Button>().onClick.AddListener(UnlockSword);timeStopUnlockButton.GetComponent<Button>().onClick.AddListener(UnlockTimeStop);vulnerableUnlockButton.GetComponent<Button>().onClick.AddListener(UnlockVulnerable);bounceUnlockButton.GetComponent<Button>().onClick.AddListener(UnlockBounce);pierceUnlockButton.GetComponent<Button>().onClick.AddListener(UnlockPierce);spinUnlockButton.GetComponent<Button>().onClick.AddListener(UnlockSpin);}private void SetupGravity()//每个剑的状态都对应了不同的剑重力{if (swordType == SwordType.Pierce){swordGravity = pierceGravity;}if (swordType == SwordType.Bounce){swordGravity = bounceGravity;}if (swordType == SwordType.Spin){swordGravity = spinGravity;}}protected override void Update(){base.Update();if (Input.GetKeyUp(KeyCode.Mouse1)){finalDir = new Vector2(AimDirection().normalized.x * launchForce.x, AimDirection().normalized.y * launchForce.y);//将位移量改为单位向量分别与力度的x,y相乘作为finalDir}if (Input.GetKey(KeyCode.Mouse1)){for (int i = 0; i < dots.Length; i++){dots[i].transform.position = DotsPosition(i * spaceBetweenDots);//用循环为每个点以返回值赋值(传入值为每个点的顺序i*点间距}}}public void CreateSword(){GameObject newSword = Instantiate(swordPrefab, player.transform.position, transform.rotation);//创造实例,初始位置为此时player的位置Sword_Skill_Controller newSwordScript = newSword.GetComponent<Sword_Skill_Controller>();//获得Controllerif (swordType == SwordType.Bounce){newSwordScript.SetupBounce(true, bounceAmount, returnSpeed);}else if (swordType == SwordType.Pierce){newSwordScript.SetupPierce(pierceAmount);}else if (swordType == SwordType.Spin){newSwordScript.SetupSpin(true, maxTravelDistance, spinDuration, hitCooldown);}newSwordScript.SetupSword(finalDir, swordGravity, player, freezeTimeDuration, bounceSpeed);//调用Controller里的SetupSword函数,给予其速度和重力和player实例player.AssignNewSword(newSword);//调用在player中保存通过此方法创造出的sword实例DotsActive(false);//关闭点的显示}#region Unlock Regionprivate void UnlockTimeStop(){if (timeStopUnlockButton.unlocked)timeStopUnlocked = true;}private void UnlockVulnerable(){if (vulnerableUnlockButton.unlocked)vulnerableUnlocked = true;}private void UnlockSword(){if (swordUnlockButton.unlocked){swordUnlocked = true;swordType = SwordType.Regular;}}private void UnlockBounce(){if (bounceUnlockButton.unlocked)swordType = SwordType.Bounce;}private void UnlockPierce(){if (pierceUnlockButton.unlocked)swordType = SwordType.Pierce;}private void UnlockSpin(){if (spinUnlockButton.unlocked)swordType = SwordType.Spin;}#endregion#region Aim regionpublic Vector2 AimDirection(){Vector2 playerPosition = player.transform.position;//拿到玩家此时的位置Vector2 mousePosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);//https://docs.unity3d.com/cn/current/ScriptReference/Camera.ScreenToWorldPoint.html//大概就是返回屏幕上括号里的参数的位置,这里返回了鼠标的位置//拿到此时鼠标的位置Vector2 direction = mousePosition - playerPosition;//获得距离的绝对向量return direction;//返回距离向量}public void DotsActive(bool _isActive){for (int i = 0; i < dots.Length; i++){dots[i].SetActive(_isActive);//设置每个点是否显示函数}}private void GenerateDots()//生成点函数{dots = new GameObject[numberOfDots];//为dot赋予实例数量for (int i = 0; i < numberOfDots; i++){dots[i] = Instantiate(dotPrefab, player.transform.position, Quaternion.identity, dotsParent);//对象与世界轴或父轴完全对齐//https://docs.unity3d.com/cn/current/ScriptReference/Quaternion-identity.htmldots[i].SetActive(false);//关闭dot}}private Vector2 DotsPosition(float t)//传入顺序相关的点间距{Vector2 position = (Vector2)player.transform.position +new Vector2(AimDirection().normalized.x * launchForce.x,AimDirection().normalized.y * launchForce.y) * t  //基本间距+ .5f * (Physics2D.gravity * swordGravity) * (t * t)//重力影响;//t是控制之间点间距的return position;//返回位置}//设置点间距函数#endregion}
PlayerGroundState.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//GroundState用于保证只有在Idle和Move这两个地面状态下才能调用某些函数,并且稍微减少一点代码量
public class PlayerGroundState : PlayerState
{public PlayerGroundState(Player _player, PlayerStateMachine _stateMachine, string _animBoolName) : base(_player, _stateMachine, _animBoolName){}public override void Enter(){base.Enter();}public override void Exit(){base.Exit();}public override void Update(){base.Update();if(Input.GetKeyDown(KeyCode.R)){stateMachine.ChangeState(player.blackhole);}if(Input.GetKeyDown(KeyCode.Mouse1)&&HasNoSword()&&player.skill.sword.swordUnlocked)//点击右键进入瞄准状态,当sword存在时,不能进入aim状态{stateMachine.ChangeState(player.aimSword);}if (Input.GetKeyDown(KeyCode.Q) && player.skill.parry.parryUnlocked)//摁Q进入反击状态{stateMachine.ChangeState(player.counterAttack);}if(Input.GetKeyDown(KeyCode.Mouse0))//p38 2.从ground进入攻击状态{stateMachine.ChangeState(player.primaryAttack);}if(player.IsGroundDetected()==false){stateMachine.ChangeState(player.airState);}// 写这个是为了防止在空中直接切换为moveState了。if (Input.GetKeyDown(KeyCode.Space) && player.IsGroundDetected()){stateMachine.ChangeState(player.jumpState);}//空格切换为跳跃状态}private bool HasNoSword()//用这个函数同时控制了是否能进入aimSword和如果sword存在便使他回归player的功能{if(!player.sword){return true;}player.sword.GetComponent<Sword_Skill_Controller>().ReturnSword();return false;}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/309263.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

代码随想录算法训练营第三十七天|738.单调递增的数字、968.监控二叉树

代码随想录算法训练营第三十七天|738.单调递增的数字、968.监控二叉树 738.单调递增的数字 当且仅当每个相邻位数上的数字 x 和 y 满足 x < y 时&#xff0c;我们称这个整数是单调递增的。 给定一个整数 n &#xff0c;返回 小于或等于 n 的最大数字&#xff0c;且数字呈…

Finetuning vs. Prompting:大语言模型两种使用方式

目录 前言1. 对于大型语言模型的两种不同期待2. Finetune(专才)3. Prompt(通才)3.1 In-context Learning3.2 Instruction-tuning3.3 Chain of Thought(COT) Prompting3.4 用机器来找Prompt 总结参考 前言 这里和大家分享下关于大语言模型的两种使用方式&#xff0c;一种是 Fine…

英语技术会议常用语

个人整理。 自我介绍&#xff1a; Hello everyone, Im [Your Name], and Im excited to be here today. I work as [Your Position] at [Your Company/Organization], where I focus on [Brief Description of Your Role or Expertise]. Im looking forward to our discussion…

数据库数据恢复—Sql Server数据库文件丢失如何恢复数据?

服务器数据恢复环境&#xff1a; 一台安装windows server操作系统的服务器。一组由8块硬盘组建的RAID5&#xff0c;划分LUN供这台服务器使用。 在windows服务器内装有SqlServer数据库。存储空间LUN划分了两个逻辑分区。 服务器故障&初检&#xff1a; 由于未知原因&#xf…

Android 13 aosp 预置三方应用apk

前提条件 编译启动 launch 选择了 sdk_pc_x86_64-userdebug 该版本 添加一个三方预置应用 Android_source/vendor/third_party/MdmLib/MdmLib.apk 配置三方应用对应的Android.mk Android_source/vendor/third_party/MdmLib/Android.mk LOCAL_PATH : $(call my-dir)include $(CL…

配置香橙派摄像头服务每次开机自动启动

目录 1.创建一个mjpg.sh脚本 2.在脚本中添加以下内容 3.增加可执行权限 4.在/etc/xdg/autostart/下创建mjpg.desktop 文件输入以下内容 1.创建一个mjpg.sh脚本 touch mjpg.sh 2.在脚本中添加以下内容 #!/bin/bash cd /home/orangepi/Myorangepi/zhinenglajitong/mjpg-stre…

数据可视化-ECharts Html项目实战(11)

在之前的文章中&#xff0c;我们学习了如何在ECharts中特殊图表的双y图以及自定义形状词云图。想了解的朋友可以查看这篇文章。同时&#xff0c;希望我的文章能帮助到你&#xff0c;如果觉得我的文章写的不错&#xff0c;请留下你宝贵的点赞&#xff0c;谢谢。 数据可视化-ECh…

Linux(Ubuntu) 查看并删除使用【dpkg】安装的软件【mysql 8.3安装失败---原因调查】

目录 ■前言 ■查看安装的软件 ■删除安装的软件 正常删除&#xff08;dpkg -r xxxxName&#xff09; 问题解决&#xff1a;use --purge to remove them too ■其他调查信息 命令 图片1 图片2 图片3 图片4 ■前言 安装Mysql8.3失败 我的服务器-CSDN博客 ■查看安…

绿联HDMI延长器40265使用AG7120芯片放大器方案

HDMI延长器和放大器 延长器&#xff1a;主要用于HDMI线的延长&#xff0c;有HDMI对接头方式延长&#xff0c;或HDMI公头加HDMI母头的HDMI线进行延长&#xff0c;或通过网线方式延长&#xff0c;早期为双网线&#xff0c;目前已发展为单网线&#xff0c;需要注意的是&#xff0…

第四百五十三回

文章目录 1. 问题描述2. 优化方法2.1 缩小范围2.2 替代方法 3. 示例代码4. 内容总结 我们在上一章回中介绍了"如何获取AppBar的高度"相关的内容&#xff0c;本章回中将介绍关于MediaQuery的优化.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1. 问题描述 我们在…

CleanMyMac一键释放Mac潜力的智能助手

在数字化时代&#xff0c;我们的Mac电脑承载着日益增多的数据和文件&#xff0c;使得系统性能逐渐下降&#xff0c;运行缓慢。为了解决这个问题&#xff0c;我们需要一款能够深度清理、优化Mac性能的软件。CleanMyMac&#xff0c;作为Mac系统清理领域的佼佼者&#xff0c;凭借其…

【opencv】示例-stereo_match.cpp 立体匹配:通过对左右视图图像进行处理来生成视差图和点云数据...

/** stereo_match.cpp* calibration** 创建者 Victor Eruhimov&#xff0c;日期为 2010年1月18日。* 版权所有 2010 Argus Corp.**/#include "opencv2/calib3d/calib3d.hpp" // 导入OpenCV相机标定和三维重建相关的头文件 #include "opencv2/imgproc.hpp&qu…

最优算法100例之47-从尾到头打印单链表

专栏主页:计算机专业基础知识总结(适用于期末复习考研刷题求职面试)系列文章https://blog.csdn.net/seeker1994/category_12585732.html 题目描述 从尾到头打印单链表 题解报告 方法1:头插法逆置单链表然后依次打印;注意此处是不带头结点的单链表,带头节点的操作稍微有…

为什么光伏探勘测绘需要无人机?

随着全球对可再生能源需求的不断增长&#xff0c;光伏产业也迎来了快速发展的机遇。光伏电站作为太阳能发电的主要形式之一&#xff0c;其建设前期的探勘测绘工作至关重要。在这一过程中&#xff0c;无人机技术的应用正逐渐展现出其独特的优势。那么&#xff0c;为什么光伏探勘…

【opencv】示例-travelsalesman.cpp 使用模拟退火算法求解旅行商问题

// 载入 OpenCV 的核心头文件 #include <opencv2/core.hpp> // 载入 OpenCV 的图像处理头文件 #include <opencv2/imgproc.hpp> // 载入 OpenCV 的高层GUI(图形用户界面)头文件 #include <opencv2/highgui.hpp> // 载入 OpenCV 的机器学习模块头文件 #includ…

【C语言__结构体__复习篇3】

目录 前言 一、结构体基础知识 1.1 结构体的语法形式 1.2 创建结构体变量 1.3 结构体变量的初始化 1.4 点(.)操作符和箭头(->)操作符 二、匿名结构体 三、结构体自引用 四、结构体内存对齐 4.1 内存对齐的规则 4.2 出现结构体内存对齐的原因 4.3 修改默认对齐数 五、结…

【网站项目】面向企事业单位的项目申报小程序

&#x1f64a;作者简介&#xff1a;拥有多年开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0c;帮助大学选题。赠送开题报告模板&#xff…

数据结构之排序

一、排序的概念及其应用 1、排序的概念 排序&#xff1a;所谓排序&#xff0c;就是使一串记录&#xff0c;按照其中的某个或某些关键字的大小&#xff0c;递增或递减的排列起来的操作。 稳定性&#xff1a;假定在待排序的记录序列中&#xff0c;存在多个具有相同的关键字的记…

宝塔面板Docker+Uwsgi+Nginx+SSL部署Django项目

这次为大家带来的是从零开始搭建一个django项目并将它部署到linux服务器上。大家可以按照我的步骤一步步操作&#xff0c;最终可以完成部署。 步骤1&#xff1a;在某个文件夹中创建一个django项目 安装django pip install django创建一个django项目将其命名为djangoProject …