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.html
newClone.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);
}
else
instance = 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.html
foreach (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;//每次反击只产生一个clone
player.skill.parry.MakeMirageOnParry(hit.transform);
}
}
}
}
if(stateTimer<0||triggerCalled)//当反击动画结束或反击可以持续的时间结束后回到idleState
{
stateMachine.ChangeState(player.idleState);
}
}
}