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

Alex教程每一P的教程原代码加上我自己的理解初步理解写的注释,可供学习Alex教程的人参考

此代码仅为较上一P有所改变的代码

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

同上一P

Player.cs
cs 复制代码
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;

public class Player : Entity
{
    [Header("Attack Details")]
    public Vector2[] attackMovement;//每个攻击时获得的速度组
    public float counterAttackDuration = .2f;
    


    public bool isBusy{ get; private set; }//防止在攻击间隔中进入move
    //
    [Header("Move Info")]
    public float moveSpeed;//定义速度,与xInput相乘控制速度的大小
    public float jumpForce;
    public float swordReturnImpact;//在player里设置swordReturnImpact作为击退的参数
    private float defaultMoveSpeed;
    private float defaultJumpForce;

    [Header("Dash Info")]
    [SerializeField] private float dashCooldown;
    private float dashUsageTimer;//为dash设置冷却时间,在一定时间内不能连续使用
    public float dashSpeed;//冲刺速度
    public float dashDuration;//持续时间
    private float defaultDashSpeed;

    public float dashDir { get; private set; }


    
    
    #region 定义States
    public PlayerStateMachine stateMachine { get; private set; }
    public PlayerIdleState idleState { get; private set; }
    public PlayerMoveState moveState { get; private set; }
    public PlayerJumpState jumpState { get; private set; }
    public PlayerAirState airState { get; private set; }
    public PlayerDashState dashState { get; private set; }
    public PlayerWallSlideState wallSlide { get; private set; }
    public PlayerWallJumpState wallJump { get; private set; }
    public PlayerDeadState deadState { get; private set; }
    


    public PlayerPrimaryAttackState primaryAttack { get; private set; }
    public PlayerCounterAttackState counterAttack { get; private set; }

    public PlayerAimSwordState aimSword { get; private set; }
    public PlayerCatchSwordState catchSword { get; private set; }
    public PlayerBlackholeState blackhole { get; private set; }


    public SkillManager skill { get; private set; }
    public GameObject sword{ get; private set; }//声明sword


   
    #endregion
    protected override void Awake()
    {

        base.Awake();
        stateMachine = new PlayerStateMachine();
        //通过构造函数,在构造时传递信息
        idleState = new PlayerIdleState(this, stateMachine, "Idle");
        moveState = new PlayerMoveState(this, stateMachine, "Move");
        jumpState = new PlayerJumpState(this, stateMachine, "Jump");
        airState = new PlayerAirState(this, stateMachine, "Jump");
        dashState = new PlayerDashState(this, stateMachine, "Dash");
        wallSlide = new PlayerWallSlideState(this, stateMachine, "WallSlide");
        wallJump = new PlayerWallJumpState(this, stateMachine, "Jump");//wallJump也是Jump动画
        deadState = new PlayerDeadState(this, stateMachine, "Die");


        primaryAttack = new PlayerPrimaryAttackState(this, stateMachine, "Attack");
        counterAttack = new PlayerCounterAttackState(this, stateMachine, "CounterAttack");

        aimSword = new PlayerAimSwordState(this,stateMachine, "AimSword");
        catchSword = new PlayerCatchSwordState(this, stateMachine, "CatchSword");
        blackhole = new PlayerBlackholeState(this, stateMachine, "Jump");

        //this 就是 Player这个类本身
    }//Awake初始化所以State,为所有State传入各自独有的参数,及animBool,以判断是否调用此动画(与animatoin配合完成)
    protected override void Start()
    {
        base.Start();
        stateMachine.Initialize(idleState);
        skill = SkillManager.instance;

        defaultMoveSpeed = moveSpeed;
        defaultJumpForce = jumpForce;
        defaultDashSpeed = dashSpeed;
        

    }

    protected override void Update()//在mano中update会自动刷新但其他没有mano的不会故,需要在这个updata中调用其他脚本中的函数stateMachine.currentState.update以实现 //stateMachine中的update

    {
        base.Update();
        stateMachine.currentState.Update();//反复调用CurrentState的Update函数
        CheckForDashInput();

        if(Input.GetKeyDown(KeyCode.F)&&skill.crystal.crystalUnlocked)
        {
            skill.crystal.CanUseSkill();
        }

        if(Input.GetKeyDown(KeyCode.Alpha1))//血瓶回血
        {
            Inventory.instance.UseFlask();
        }
        
    }
    public override void SlowEntityBy(float _slowPercentage, float flowDuration)//减缓一切速度函数
    {
        base.SlowEntityBy(_slowPercentage, flowDuration);
        moveSpeed = moveSpeed * (1 - _slowPercentage);
        jumpForce = jumpForce * (1 - _slowPercentage);
        dashSpeed = dashSpeed * (1 - _slowPercentage);
        anim.speed = anim.speed * (1 - _slowPercentage);

        Invoke("ReturnDefaultSpeed", flowDuration);

    }
    protected override void ReturnDefaultSpeed()//全部速度恢复正常函数
    {
        base.ReturnDefaultSpeed();

        moveSpeed = defaultMoveSpeed;
        jumpForce = defaultJumpForce;
        dashSpeed = defaultDashSpeed;
    }
    public void AssignNewSword(GameObject _newSword)//保持创造的sword实例的函数
    {
        sword = _newSword;
    }

    public void CatchTheSword()//通过player的CatchTheSword进入,及当剑消失的瞬间进入
    {
        stateMachine.ChangeState(catchSword);
        Destroy(sword);
    }
    
    public IEnumerator BusyFor(float _seconds)//https://www.zhihu.com/tardis/bd/art/504607545?source_id=1001
    {
        isBusy = true;
        yield return new WaitForSeconds(_seconds);
        isBusy = false;
    
    }//p39 4.防止在攻击间隔中进入move,通过设置busy值,在使用某些状态时,使其为busy为true,抑制其进入其他state
     //IEnumertor本质就是将一个函数分块执行,只有满足某些条件才能执行下一段代码,此函数有StartCoroutine调用
    public void AnimationTrigger() => stateMachine.currentState.AnimationFinishTrigger();
    //从当前状态拿到AnimationTrigger进行调用的函数

    public void CheckForDashInput()
    {

        
        if (IsWallDetected())
        {
            return;
        }//修复在wallslide可以dash的BUG

        if (skill.dash.dashUnlocked == false)
            return;

        if (Input.GetKeyDown(KeyCode.LeftShift) && skill.dash.CanUseSkill())//将DashTimer<0 的判断 改成DashSkill里的判断
        {

            
            dashDir = Input.GetAxisRaw("Horizontal");//设置一个值,可以将dash的方向改为你想要的方向而不是你的朝向
            if (dashDir == 0)
            {
                dashDir = facingDir;//只有当玩家没有控制方向时才使用默认朝向
            }
            stateMachine.ChangeState(dashState);
        }

    }//将Dash切换设置成一个函数,使其在所以情况下都能使用


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

        stateMachine.ChangeState(deadState);
    }
}
Crystal_Skill.cs
cs 复制代码
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.UI;

public class Crystal_Skill : Skill
{
    [SerializeField] private GameObject crystalPrefab;
    [SerializeField] private float crystalDuration;
    private GameObject currentCrystal;

    [Header("Crystal simple")]
    [SerializeField] private UI_SkillTreeSlot unlockedCrystalButton;
    public bool crystalUnlocked { get; private set; }

    [Header("Crystal mirage")]
    [SerializeField] private UI_SkillTreeSlot unlockedCloneInsteadButton;
    [SerializeField] private bool cloneInsteadOfCrystal = false;

    [Header("Explosive crystal")]
    [SerializeField] private UI_SkillTreeSlot unlockedExplosion;
    [SerializeField] private bool canExplode;

    [Header("Moving crystal")]
    [SerializeField] private UI_SkillTreeSlot unlockedMovingCrystalButton;
    [SerializeField] private bool canMoveToEnemy;
    [SerializeField] private float moveSpeed;

    [Header("Multi stacking crystal")]
    [SerializeField] private UI_SkillTreeSlot unlockedMultiStackButton;
    [SerializeField] private bool canUseMultiStacks;
    [SerializeField] private int amountOfStacks;
    [SerializeField] private float multiStackCooldown;
    [SerializeField] private List<GameObject> crystalLeft = new List<GameObject>();//水晶列表
    [SerializeField] private float useTimeWindow;
    
    
    public override bool CanUseSkill()
    {
        return base.CanUseSkill();
    }

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


        if (CanUseMultiCrystal())
            return;

        if (currentCrystal == null)
        {
            CreateCrystal();
        }
        else
        {
            //限制玩家在水晶可以移动时瞬移
            if (canMoveToEnemy)
                return;
            //爆炸前与角色交换位置
            Vector2 playerPos = player.transform.position;
            player.transform.position = currentCrystal.transform.position;
            currentCrystal.transform.position = playerPos;


            //水晶互换时在水晶处出现clone,水晶消失
            if (cloneInsteadOfCrystal)
            {
                SkillManager.instance.clone.CreateClone(currentCrystal.transform,Vector3.zero);
                Destroy(currentCrystal);
            }
            else
            {
                currentCrystal.GetComponent<Crystal_Skill_Controller>()?.FinishCrystal();
            }       
        }
    }

    public void CreateCrystal()//创建水晶函数
    {
        currentCrystal = Instantiate(crystalPrefab, player.transform.position, Quaternion.identity);

        Crystal_Skill_Controller currentCrystalScripts = currentCrystal.GetComponent<Crystal_Skill_Controller>();

        currentCrystalScripts.SetupCrystal(crystalDuration, canExplode, canMoveToEnemy, moveSpeed, FindClosestEnemy(currentCrystal.transform),player);

       
    }

    public void CurrentCrystalChooseRandomTarget() => currentCrystal.GetComponent<Crystal_Skill_Controller>().ChooseRandomEnemy();//选择随机敌人函数
   
    protected override void Start()
    {
        base.Start();
        unlockedCrystalButton.GetComponent<Button>().onClick.AddListener(UnlockCrystal);
        unlockedCloneInsteadButton.GetComponent<Button>().onClick.AddListener(UnlockCloneInstead);
        unlockedExplosion.GetComponent<Button>().onClick.AddListener(UnlockExplosion);
        unlockedMovingCrystalButton.GetComponent<Button>().onClick.AddListener(UnlockMovingCrystal);
        unlockedMultiStackButton.GetComponent<Button>().onClick.AddListener(UnlockedMultiStack);
    }

    protected override void Update()
    {
        base.Update();
    }

    private bool CanUseMultiCrystal()//将List里的东西实例化函数
    {
        if(canUseMultiStacks)
        {
            if(crystalLeft.Count > 0&&cooldownTimer<0)
            {
                if(crystalLeft.Count == amountOfStacks)
                {
                    Invoke("ResetAbility", useTimeWindow);// 设置自动补充水晶函数
                }

                cooldown = 0;
                GameObject crystalToSpawn = crystalLeft[crystalLeft.Count - 1];
                GameObject newCrystal = Instantiate(crystalToSpawn, player.transform.position, Quaternion.identity);

                crystalLeft.Remove(crystalToSpawn);

                newCrystal.GetComponent<Crystal_Skill_Controller>().SetupCrystal(crystalDuration, canExplode, canMoveToEnemy, moveSpeed, FindClosestEnemy(newCrystal.transform), player);

                //当水晶发射完设置冷却时间和使用补充水晶
                if (crystalLeft.Count<=0)
                {
                    cooldown = multiStackCooldown;

                    RefilCrystal();
                }
            }
            return true;
        }

        return false;
    }
    private void RefilCrystal()//给List填充Prefab函数
    {
        int amountToAdd = amountOfStacks - crystalLeft.Count;
        for (int i = 0;i < amountToAdd; i++)
        {
            crystalLeft.Add(crystalPrefab);
        }
    }

    private void ResetAbility()//自动补充水晶函数
    {
        

        if (cooldownTimer > 0)
            return;

        cooldown = multiStackCooldown;
        RefilCrystal();
    }
    #region Unlock skill region
    private void UnlockCrystal()
    {
        if (unlockedCrystalButton.unlocked)
            crystalUnlocked = true;
    }
    private void UnlockCloneInstead()
    {
        if (unlockedCloneInsteadButton.unlocked)
            cloneInsteadOfCrystal = true;
    }
    private void UnlockExplosion()
    {
        if (unlockedExplosion.unlocked)
            canExplode = true;
    }
    private void UnlockMovingCrystal()
    {
        if (unlockedMovingCrystalButton.unlocked)
            canMoveToEnemy = true;
    }
    private void UnlockedMultiStack()
    {
        if (unlockedMultiStackButton.unlocked)
            canUseMultiStacks = true;
    }
    #endregion
}
相关推荐
-一杯为品-1 分钟前
【51单片机】程序实验5&6.独立按键-矩阵按键
c语言·笔记·学习·51单片机·硬件工程
初九之潜龙勿用35 分钟前
C#校验画布签名图片是否为空白
开发语言·ui·c#·.net
风尚云网1 小时前
风尚云网前端学习:一个简易前端新手友好的HTML5页面布局与样式设计
前端·css·学习·html·html5·风尚云网
吾与谁归in2 小时前
【C#设计模式(13)——代理模式(Proxy Pattern)】
设计模式·c#·代理模式
吾与谁归in2 小时前
【C#设计模式(14)——责任链模式( Chain-of-responsibility Pattern)】
设计模式·c#·责任链模式
EterNity_TiMe_2 小时前
【论文复现】(CLIP)文本也能和图像配对
python·学习·算法·性能优化·数据分析·clip
sanguine__2 小时前
java学习-集合
学习
lxlyhwl2 小时前
【STK学习】part2-星座-目标可见性与覆盖性分析
学习
nbsaas-boot2 小时前
如何利用ChatGPT加速开发与学习:以BPMN编辑器为例
学习·chatgpt·编辑器
CV学术叫叫兽3 小时前
一站式学习:害虫识别与分类图像分割
学习·分类·数据挖掘