Bootstrap

Unity类银河战士恶魔城学习总结(P133 Merge skill tree with Parry skill把技能树和格挡技能相组合)

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

教程源地址:https://www.udemy.com/course/2d-rpg-alexdev/

完成了技能树上的格挡技能的UI逻辑

Parry_SKill.cs

核心功能

代码主要围绕以下功能展开:

(1)技能解锁
  • 通过绑定解锁按钮的点击事件(onClick),来解锁技能。
  • 每个技能都依赖一个 UI_SKillTreeSlot(可能是一个技能树的 UI 元素),通过检测其 unlocked 属性判断技能是否解锁成功。
(2)技能效果

a. 使用技能 (UseSkill)

  • 在技能使用时,检查特定效果是否已解锁,并执行对应功能。
  • 恢复生命值的功能:

b. 格挡幻影 (MakeMirageOnParry)

  • 如果 parrtWithMirageUnlocked 解锁,生成一个幻影(类似分身):
UI逻辑:

UI_SKillTreeSlot 是解锁按钮的一个组件,应该包括:

  • 一个布尔变量 unlocked 表示当前技能是否解锁。
  • 一个 Button 组件用作解锁触发点。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class Parry_SKill : Skill
{
    [Header("反击")]//parry
    [SerializeField] private UI_SKillTreeSlot parryUnlockButton;
    public bool parryUnlocked{ get; private set; }

    [Header("反击恢复")]//Parry restor
    [SerializeField] private UI_SKillTreeSlot restorUnlockButton;
    [Range(0f,1f)]
    [SerializeField] private float restoreHealthPercentage;
    public bool restorUnlocked{ get; private set; }

    [Header("格挡幻影")]//Parry mirrage
    [SerializeField] private UI_SKillTreeSlot parrtWithMirageUnlockButton;
    public bool parrtWithMirageUnlocked { get; private set; }


    public override void UseSkill()
    {
        base.UseSkill();

        if(restorUnlocked)
        {
            int restoreAmount = Mathf.RoundToInt(player.stats.GetMaxHealthValue() * restoreHealthPercentage);
            player.stats.IncreaseHealthBy(restoreAmount);

        }
    }


    protected override void Start()
    {
        base.Start();

        parryUnlockButton.GetComponent<Button>().onClick.AddListener(UnlockParry);
        restorUnlockButton.GetComponent<Button>().onClick.AddListener(UnlockParryRestor);
        parrtWithMirageUnlockButton.GetComponent<Button>().onClick.AddListener(UnlockParrtWithMirage);
    }


    private void UnlockParry()
    {
        if (parryUnlockButton.unlocked)
            parryUnlocked = true;
    }

    private void UnlockParryRestor()
    {
        if (restorUnlockButton.unlocked)
            restorUnlocked = true;
    }

    private void UnlockParrtWithMirage()
    {
        if (parrtWithMirageUnlockButton.unlocked)
            parrtWithMirageUnlocked = true;
    }


    public void MakeMirageOnParry(Transform _respawnTransform)
    {
        if (parrtWithMirageUnlocked)
            SkillManager.instance.clone.CreateCloneWithDelay(_respawnTransform);
    }
}

PlayerGroundedState.cs

修改了格挡技能Q的逻辑判断

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerGroundedState : PlayerState
{
    public PlayerGroundedState(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())
            stateMachine.ChangeState(player.aimSword);

        if (Input.GetKeyDown(KeyCode.Q) && player.skill.parry.parryUnlocked)
            stateMachine.ChangeState(player.counterAttack);

        if (Input.GetKeyDown(KeyCode.Mouse0))//GetKeyDown改成GetKey按住就可以攻击了
            stateMachine.ChangeState(player.primaryAttack);

        if (!player.IsGroundDetected())
            stateMachine.ChangeState(player.airState);

        if (Input.GetKeyDown(KeyCode.Space) && player.IsGroundDetected())
            stateMachine.ChangeState(player.jumpState);
    }

    private bool HasNoSword()
    {
        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;

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;
        player.anim.SetBool("SuccessfulCounterAttack", false);

    }

    public override void Exit()
    {
        base.Exit();
    }

    public override void Update()
    {
        base.Update();

        player.SetZeroVelocity();

        Collider2D[] colliders = Physics2D.OverlapCircleAll(player.attackCheck.position, player.attackCheckRadius);//这行代码在 Unity 中用于检测一个圆形区域内的所有碰撞体,并返回它们的数组。


        foreach (var hit in colliders)//foreach循环是一个迭代器,它可以遍历数组、集合、列表、字典等数据结构。攻击到敌人后,调用伤害函数
        {
            if (hit.GetComponent<Enemy>() != null)
            {
                if (hit.GetComponent<Enemy>().CanBeStunned())
                {
                    stateTimer = 10;//大于1的数,保证不会进入idle状态
                    player.anim.SetBool("SuccessfulCounterAttack", true);

                    player.skill.parry.UseSkill();


                    if (canCreateClone)
                    {
                        canCreateClone = false; 
                        player.skill.parry.MakeMirageOnParry(hit.transform);
                    }
                }
            }
        }

        if (stateTimer < 0 || triggerCalled)
            stateMachine.ChangeState(player.idleState);

    }
}

Dash_Skill.cs

修改了一些变量

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;


//2024年11月19日添加解锁技能逻辑
public class Dash_Skill : Skill
{
    [Header("Dash")]
    [SerializeField] private UI_SKillTreeSlot dashUnlockButton;
    public bool dashUnlocked { get; private set; }

    [Header("Clone on dash")]
    [SerializeField] private UI_SKillTreeSlot cloneOnDashUnlockButton;
    public bool cloneOmDashUnlocked { get; private set; }

    [Header("Clone on arrival")]
    [SerializeField] private UI_SKillTreeSlot cloneOnArrivalUnlockButton;
    public bool cloneOnArrivalUnlocked { get; private set; }


    public override void UseSkill()
    {
        base.UseSkill();
    }

    protected override void Start()
    {
        base.Start();

        dashUnlockButton.GetComponent<Button>().onClick.AddListener(UnlockDash);
        cloneOnDashUnlockButton.GetComponent<Button>().onClick.AddListener(UnlockCloneOnDash);
        cloneOnArrivalUnlockButton.GetComponent<Button>().onClick.AddListener(UnlockCloneOnArrival);
        
    }


    private void UnlockDash()
    {
        if (dashUnlockButton.unlocked)   
            dashUnlocked = true;
    }

    private void UnlockCloneOnDash()
    {
        if (cloneOnDashUnlockButton.unlocked)
            cloneOmDashUnlocked = true;

    }

    private void UnlockCloneOnArrival()
    {
        if (cloneOnArrivalUnlockButton.unlocked)
            cloneOnArrivalUnlocked = true;
    }

    public void CloneOnDash()
    {
        if (cloneOmDashUnlocked)
            SkillManager.instance.clone.CreateClone(player.transform, Vector3.zero);
    }

    public void CloneOnArrival()
    {
        if (cloneOnArrivalUnlocked)
            SkillManager.instance.clone.CreateClone(player.transform, Vector3.zero);
    }

}

;