Unity类银河恶魔城学习记录11-19.20 p121 Armor item effect - p122 Item‘s cooldown explained源代码

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

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

FreezeEnemies_Effect.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;


[CreateAssetMenu(fileName = "Freeze enemies effect", menuName = "Data/Item effect/Freeze enemies")]
public class FreezeEnemies_Effect : ItemEffect
{
    [SerializeField] private float duration;

    public override void ExecuteEffect(Transform _respawnPosition)
    {
        PlayerStats playerStats = PlayerManager.instance.player.GetComponent<PlayerStats>();

        if (playerStats.currentHealth > playerStats.GetMaxHealthValue()*.1f)
            return;

        if (!Inventory.instance.CanUseArmor())
            return;

        Collider2D[] colliders = Physics2D.OverlapCircleAll(_respawnPosition.position, 2);
        foreach (var hit in colliders)
        {
            if (hit.GetComponent<Enemy>() != null)
            {
                hit.GetComponent<Enemy>()?.FreezeTimerFor(duration);//?是为了保证有这个组件
            }


        }
    }
}
Inventory.cs
using Newtonsoft.Json.Linq;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Inventory : MonoBehaviour
{
    public static Inventory instance;

    public List<ItemData> startingItem;

    public List<InventoryItem> equipment;//inventoryItems类型的列表
    public Dictionary<ItemData_Equipment, InventoryItem> equipmentDictionary;//以ItemData为Key寻找InventoryItem的字典

    public List<InventoryItem> inventory;//inventoryItems类型的列表
    public Dictionary<ItemData, InventoryItem> inventoryDictionary;//以ItemData为Key寻找InventoryItem的字典

    public List<InventoryItem> stash;
    public Dictionary<ItemData, InventoryItem> stashDictionary;

    [Header("Inventory UI")]

    [SerializeField] private Transform inventorySlotParent;
    [SerializeField] private Transform stashSlotParent;
    [SerializeField] private Transform equipmentSlotParent;


    private UI_itemSlot[] inventoryItemSlot;//UI Slot的数组
    private UI_itemSlot[] stashItemSlot;
    private UI_equipementSlots[] equipmentSlot;

    [Header("Items cooldown")]
    private float lastTimeUsedFlask;
    private float lastTimeUsedArmor;
    private float flaskCooldown;
    private float armorCooldown;

    private void Awake()
    {
        if (instance == null)
            instance = this;
        else
            Destroy(gameObject);
        //防止多次创建Inventory
    }

    public void Start()
    {
        inventory = new List<InventoryItem>();
        inventoryDictionary = new Dictionary<ItemData, InventoryItem>();


        stash = new List<InventoryItem>();
        stashDictionary = new Dictionary<ItemData, InventoryItem>();

        equipment = new List<InventoryItem>();
        equipmentDictionary = new Dictionary<ItemData_Equipment, InventoryItem>();


        inventoryItemSlot = inventorySlotParent.GetComponentsInChildren<UI_itemSlot>();//拿到的方式有点绕,显示拿到Canvas 里的 Inventory 然后通过GetComponentsInChildren拿到其下的使用UISlot
        stashItemSlot = stashSlotParent.GetComponentsInChildren<UI_itemSlot>();
        equipmentSlot = equipmentSlotParent.GetComponentsInChildren<UI_equipementSlots>();
        AddStartingItems();
    }

    private void AddStartingItems()
    {
        for (int i = 0; i < startingItem.Count; i++)
        {
            AddItem(startingItem[i]);
        }
    }//设置初始物品

    public void EquipItem(ItemData _item)
    {
        //解决在itemdata里拿不到子类equipment里的enum的问题
        ItemData_Equipment newEquipment = _item as ItemData_Equipment;//https://www.bilibili.com/read/cv15551811/
        //将父类转换为子类
        InventoryItem newItem = new InventoryItem(newEquipment);

        ItemData_Equipment oldEquipment = null;

        foreach (KeyValuePair<ItemData_Equipment, InventoryItem> item in equipmentDictionary)//这种方法可以同时拿到key和value保存到item里面
        {
            if (item.Key.equipmentType == newEquipment.equipmentType)//将拿到的key与转换成itemdata_equipment类型的_item的type对比拿到存在的key
            {
                oldEquipment = item.Key;//此key需保存在外部的data类型里
                //equipment.Remove(item.Value);
                //equipmentDictionary.Remove(item.Key);
            }
        }//好像用foreach里的value和key无法对外部的list和字典进行操作

        if (oldEquipment != null)
        {
            AddItem(oldEquipment);
            Unequipment(oldEquipment);
        }
            

        equipment.Add(newItem);
        equipmentDictionary.Add(newEquipment, newItem);
        RemoveItem(_item);
        newEquipment.AddModifiers();
        
    }//装备装备的函数

    public void Unequipment(ItemData_Equipment itemToRemove)//装备其他同类型的装备时。去除已装备的装备
    {
        if (equipmentDictionary.TryGetValue(itemToRemove, out InventoryItem value))
        {
            
            equipment.Remove(value);
            equipmentDictionary.Remove(itemToRemove);
            
            itemToRemove.RemoveModifiers();
            UpdateSlotUI();
        }
    }

    private void UpdateSlotUI()
    {

        for (int i = 0; i < equipmentSlot.Length; i++)
        {
            //此步骤用于将对应类型的武器插入对应的槽内
            foreach (KeyValuePair<ItemData_Equipment, InventoryItem> item in equipmentDictionary)//这种方法可以同时拿到key和value保存到item里面
            {
                if (item.Key.equipmentType == equipmentSlot[i].slotType)
                {
                    equipmentSlot[i].UpdateSlots(item.Value);
                }
            }

        }
        //解决出现UI没有跟着Inventory变化的bug
        for (int i = 0; i < inventoryItemSlot.Length;i++)
        {
            inventoryItemSlot[i].CleanUpSlot();
        }
        for (int i = 0; i < stashItemSlot.Length; i++)
        {
            stashItemSlot[i].CleanUpSlot();
        }

        for (int i = 0; i < inventory.Count; i++)
        {
            inventoryItemSlot[i].UpdateSlots(inventory[i]);
        }

        for (int i = 0; i < stash.Count; i++)
        {
            stashItemSlot[i].UpdateSlots(stash[i]);
        }
    }//更新UI函数

    public void AddItem(ItemData _item)
    {
        if (_item.itemType == ItemType.Equipment)
        {
            AddToInventory(_item);
        }
        else if (_item.itemType == ItemType.Material)
        {
            AddToStash(_item);
        }


        UpdateSlotUI();
    }//添加物体的函数

    private void AddToStash(ItemData _item)//向stash加物体的函数
    {
        if (stashDictionary.TryGetValue(_item, out InventoryItem value))//只有这种方法才能在查找到是否存在key对应value是否存在的同时,能够同时拿到value,其他方法的拿不到value
        {
            value.AddStack();
        }//字典的使用,通过ItemData类型的数据找到InventoryItem里的与之对应的同样类型的数据
        else//初始时由于没有相同类型的物体,故调用else是为了初始化库存,使其中含有一个基本的值
        {
            InventoryItem newItem = new InventoryItem(_item);
            stash.Add(newItem);//填进列表里只有一次
            stashDictionary.Add(_item, newItem);//同上
        }
    }

    private void AddToInventory(ItemData _item)
    {
        if (inventoryDictionary.TryGetValue(_item, out InventoryItem value))//只有这种方法才能在查找到是否存在key对应value是否存在的同时,能够同时拿到value,其他方法的拿不到value
        {
            value.AddStack();
        }//字典的使用,通过ItemData类型的数据找到InventoryItem里的与之对应的同样类型的数据
        else//初始时由于没有相同类型的物体,故调用else是为了初始化库存,使其中含有一个基本的值
        {
            InventoryItem newItem = new InventoryItem(_item);
            inventory.Add(newItem);//填进列表里只有一次
            inventoryDictionary.Add(_item, newItem);//同上
        }
    }//将物体存入Inventory的函数

    public void RemoveItem(ItemData _item)//将物体剔除Inventory的函数
    {
        if (inventoryDictionary.TryGetValue(_item, out InventoryItem value))
        {
            if (value.stackSize <= 1)
            {
                inventory.Remove(value);
                inventoryDictionary.Remove(_item);

            }
            else
                value.RemoveStack();
        }

        if (stashDictionary.TryGetValue(_item, out InventoryItem stashValue))
        {
            if (stashValue.stackSize <= 1)
            {
                stash.Remove(stashValue);
                stashDictionary.Remove(_item);
            }
            else
                stashValue.RemoveStack();
        }

        UpdateSlotUI();
    }
    public List<InventoryItem> GetEquipmentList() => equipment;
    public List<InventoryItem> GetStashList() => stash;

    public ItemData_Equipment GetEquipment(EquipmentType _Type)//通过Type找到对应的已装备装备的函数
    {
        ItemData_Equipment equipedItem = null;

        foreach (KeyValuePair<ItemData_Equipment, InventoryItem> item in equipmentDictionary)
            if (item.Key.equipmentType == _Type)
            {
                equipedItem = item.Key;
            }

        return equipedItem;
    }
    public void UseFlask()//使用药瓶设置冷却时间
    {
        ItemData_Equipment currentFlask = GetEquipment(EquipmentType.Flask);

        if (currentFlask == null)
            return;
        //使用药瓶设置冷却时间
        
        bool canUseFlask = Time.time > lastTimeUsedFlask + flaskCooldown;
        

        if(canUseFlask)
        {
            flaskCooldown = currentFlask.itemCooldown;
            currentFlask.Effect(null);
            lastTimeUsedFlask = Time.time;
        }
        else
        {
            Debug.Log("Flask is Cooldown");
        }
    }//使用药瓶函数

    public bool CanUseArmor()
    {
        ItemData_Equipment currentArmor = GetEquipment(EquipmentType.Armor);

        if(Time.time > lastTimeUsedArmor + armorCooldown)
        {
            lastTimeUsedArmor = Time.time;
            armorCooldown = currentArmor.itemCooldown;
            return true;
        }

        Debug.Log("Armor on cooldown");
        return false;
    }
}

   
PlayerStat.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerStats : CharacterStats
{
    private Player player;
    

    

    protected override void Start()
    {
        player = GetComponent<Player>();
        base.Start();
    }
    public override void DoDamage(CharacterStats _targetStats)
    {
        base.DoDamage(_targetStats);

    }
    public override void TakeDamage(int _damage)
    {
        base.TakeDamage(_damage);
    }
    protected override void Die()
    {
        base.Die();
        player.Die();
        GetComponent<PlayerItemDrop>()?.GenerateDrop();
    }
    protected override void DecreaseHealthBy(int _damage)
    {
        base.DecreaseHealthBy(_damage);
        ItemData_Equipment currentArmor = Inventory.instance.GetEquipment(EquipmentType.Armor);
        
            if(currentArmor != null)
            {
                currentArmor.Effect(player.transform);
            }
        
    }
}
Enemy.cs
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;

public class Enemy : Entity
{
    [SerializeField] protected LayerMask whatIsPlayer;
    [Header("Stun Info")]
    public float stunnedDuration;//stunned持续时间
    public Vector2 stunnedDirection;//stunned改变后的速度
    protected bool canBeStunned;//判断是否可以被反击
    [SerializeField] protected GameObject counterImage;//一个代表着是否可以被反击的信号

    [Header("Move Info")]
    public float moveSpeed;
    public float idleTime;
    public float battleTime;//多久能从battle状态中退出来
    private float defaultMoveSpeed;

    [Header("Attack Info")]
    public float attackDistance;
    public float attackCooldown;//攻击冷却
    [HideInInspector] public float lastTimeAttacked;//最后一次攻击的时间
    

    #region 类
    public EnemyStateMachine stateMachine { get; private set; }

    public string lastingAnimBoolName{ get; private set; }

    public virtual void AssignLastAnimName(string _animBoolName)
    {
        lastingAnimBoolName = _animBoolName;
    }
    #endregion

    protected override void Awake()
    {
        base.Awake();
        stateMachine = new EnemyStateMachine();
        defaultMoveSpeed = moveSpeed;

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

    }


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

        stateMachine.currentState.Update();

        //Debug.Log(IsPlayerDetected().collider.gameObject.name + "I see");//这串代码会报错,可能使版本的物体,因为在没有找到Player的时候物体是空的,NULL,你想让他在控制台上显示就报错了
    }
    public override void SlowEntityBy(float _slowPercentage, float _slowDuration)
    {
        base.SlowEntityBy(_slowPercentage, _slowDuration);
        moveSpeed = moveSpeed * (1 - _slowPercentage);
        anim.speed = anim.speed * (1 - _slowPercentage);

        Invoke("ReturnDefaultSpeed", _slowDuration);

    }

    protected override void ReturnDefaultSpeed()
    {
        base.ReturnDefaultSpeed();
        moveSpeed = defaultMoveSpeed;

    }
    public virtual void FreezeTime(bool _timeFrozen)
    {
        if(_timeFrozen)
        {
            moveSpeed = 0;
            anim.speed = 0;
        }
        else
        {
            moveSpeed = defaultMoveSpeed;
            anim.speed = 1;
        }
    }
    public virtual void FreezeTimerFor(float _duration) => StartCoroutine(FreezeTimeCoroutine(_duration));
    protected virtual IEnumerator FreezeTimeCoroutine(float _seconds)
    {
        FreezeTime(true);

        yield return new WaitForSeconds(_seconds);

        FreezeTime(false);
    }
    #region Counter Attack Window
    public virtual void OpenCounterAttackWindow()//打开可以反击的信号的函数
    {
        canBeStunned = true;
        counterImage.SetActive(true);
    }
    public virtual void CloseCounterAttackWindow()//关闭可以反击的信号的函数
    {
        canBeStunned = false;
        counterImage.SetActive(false);
    }
    #endregion


    
    public virtual bool CanBeStunned()//这里的主要目的是完成在被反击过后能立刻关闭提示窗口
    {
        if (canBeStunned)
        {
            CloseCounterAttackWindow();
            return true;
        }
        return false;

    }
    public virtual void AnimationFinishTrigger() => stateMachine.currentState.AnimationFinishTrigger();//动画完成时调用的函数,与Player相同
    public virtual RaycastHit2D IsPlayerDetected() => Physics2D.Raycast(wallCheck.position, Vector2.right * facingDir, 7, whatIsPlayer);//用于从射线投射获取信息的结构。
    //该函数的返回值可以变,可以只返回bool,也可以是碰到的结构

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

        Gizmos.color = Color.yellow;//把线改成黄色
        Gizmos.DrawLine(transform.position, new Vector3(transform.position.x + attackDistance * facingDir, transform.position.y));//用来判别是否进入attackState的线
    }


}

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值