Alex教程每一P的教程原代码加上我自己的理解初步理解写的注释,可供学习Alex教程的人参考
此代码仅为较上一P有所改变的代码
【Unity教程】从0编程制作类银河恶魔城游戏_哔哩哔哩_bilibili
Parry_Skill.cs
using UnityEngine;
using UnityEngine.UI;public class Parry_Skill : Skill
{[Header("Perry")][SerializeField] private UI_SkillTreeSlot parryUnlockButton;public bool parryUnlocked { get; private set; }[Header("Restore Health")][SerializeField] private UI_SkillTreeSlot restoreUnlockButton;[Range(0f, 1f)][SerializeField] private float restoreHealthPerentage;public bool restoreUnlocked{ get; private set; }[Header("Parry Mirage")][SerializeField] private UI_SkillTreeSlot parryWithUnlockButton;public bool parryWithMirageUnlocked { get; private set; }public override void UseSkill(){base.UseSkill();if (restoreUnlocked){int restoreAmount = Mathf.RoundToInt(player.stats.GetMaxHealthValue() * restoreHealthPerentage);player.stats.IncreaseHealthBy(restoreAmount);}}protected override void Start(){base.Start();parryUnlockButton.GetComponent<Button>().onClick.AddListener(UnlockParry);restoreUnlockButton.GetComponent<Button>().onClick.AddListener(UnlockParryRestore);parryWithUnlockButton.GetComponent<Button>().onClick.AddListener(UnlockParryWithMirage);}private void UnlockParry(){Debug.Log(2);if (parryUnlockButton.unlocked){parryUnlocked = true;}}private void UnlockParryRestore(){if (restoreUnlockButton.unlocked){restoreUnlocked = true;}}private void UnlockParryWithMirage(){if (parryWithUnlockButton.unlocked){parryWithMirageUnlocked = true;}}public void MakeMirageOnParry(Transform _transform){if (parryWithMirageUnlocked)player.skill.clone.CanCreateCloneWithDelay(_transform);}
}
Clone_Skill.cs
using System.Collections;
using UnityEngine;public class Clone_Skill : Skill
{[Header("Clone Info")][SerializeField] private GameObject clonePrefab;//克隆原型[SerializeField] private float cloneDuration;//克隆持续时间[SerializeField] private bool canAttack;// 判断是否可以攻击[Header("Clone can duplicate")][SerializeField] private bool canDuplicateClone;[SerializeField] private float chanceToDuplicate;[Header("Crystal instead of clone")]public bool crystalInsteadOfClone;public void CreateClone(Transform _clonePosition, Vector3 _offset)//传入克隆位置{if (crystalInsteadOfClone){SkillManager.instance.crystal.CreateCrystal();return;}//让所有的生成克隆的技能都变成生成水晶GameObject newClone = Instantiate(clonePrefab);//创建新的克隆//克隆 original 对象并返回克隆对象。//https://docs.unity3d.com/cn/current/ScriptReference/Object.Instantiate.htmlnewClone.GetComponent<Clone_Skill_Controller>().SetupClone(_clonePosition, cloneDuration, canAttack, _offset, FindClosestEnemy(newClone.transform), canDuplicateClone, chanceToDuplicate, player);//调试clone的位置,同时调试克隆持续时间 //Controller绑在克隆原型上的,所以用GetComponent }//反击后产生一个克隆背刺敌人public void CanCreateCloneWithDelay(Transform _enemyTransform){StartCoroutine(CreateDelayCoroutine(_enemyTransform, new Vector3(1 * player.facingDir, 0, 0)));}//整个延迟生成private IEnumerator CreateDelayCoroutine(Transform _enemyTransform, Vector3 _offset){yield return new WaitForSeconds(.4f);CreateClone(_enemyTransform, _offset);}
}
SkillManager.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class SkillManager : MonoBehaviour
{public static SkillManager instance;public Dash_Skill dash { get; private set; }public Clone_Skill clone { get; private set; }public Sword_Skill sword { get; private set; }public Blackhole_Skill blackhole { get; private set; }public Crystal_Skill crystal { get; private set; }public Parry_Skill parry { get; private set; }private void Awake(){if (instance != null){// Destroy(instance.gameObject);}elseinstance = this;}private void Start(){dash = GetComponent<Dash_Skill>();clone = GetComponent<Clone_Skill>();sword = GetComponent<Sword_Skill>();blackhole = GetComponent<Blackhole_Skill>();crystal = GetComponent<Crystal_Skill>();parry = GetComponent<Parry_Skill>();}
}
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())//点击右键进入瞄准状态,当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;}
}
PlayerCounterAttackState.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//从Ground里摁Q进入
public class PlayerCounterAttackState : PlayerState
{private bool canCreateClone;public PlayerCounterAttackState(Player _player, PlayerStateMachine _stateMachine, string _animBoolName) : base(_player, _stateMachine, _animBoolName){}public override void Enter(){base.Enter();canCreateClone = true;stateTimer = player.counterAttackDuration;//设置Counter在没有成功的情况下可以保持的时间player.anim.SetBool("SuccessfulCounterAttack", false);//默认失败}public override void Exit(){base.Exit();}public override void Update(){base.Update();player.SetZeroVelocity();// 修复在Counter时还能移动的问题Collider2D[] colliders = Physics2D.OverlapCircleAll(player.attackCheck.position, player.attackCheckRadius);//创建一个碰撞器组,保存所有圈所碰到的碰撞器//https://docs.unity3d.com/2022.3/Documentation/ScriptReference/Physics2D.OverlapCircleAll.htmlforeach (var hit in colliders)//https://blog.csdn.net/m0_52358030/article/details/121722077{if (hit.GetComponent<Enemy>() != null){if(hit.GetComponent<Enemy>().CanBeStunned()){stateTimer = 10;//只要比1大就行,防止成功反击的动画还没完就进入idleState了player.anim.SetBool("SuccessfulCounterAttack", true);//使进入成功反击动画player.skill.parry.UseSkill();//设置反击回血if (canCreateClone){canCreateClone = false;//每次反击只产生一个cloneplayer.skill.parry.MakeMirageOnParry(hit.transform);}}}}if(stateTimer<0||triggerCalled)//当反击动画结束或反击可以持续的时间结束后回到idleState{stateMachine.ChangeState(player.idleState);}}
}