Unity类银河恶魔城学习记录12-17 p139 In game UI源代码

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

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

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

UI.cs
cs 复制代码
using UnityEngine;

public class UI : MonoBehaviour
{
    [SerializeField] private GameObject characterUI;
    [SerializeField] private GameObject skillTreeUI;
    [SerializeField] private GameObject craftUI;
    [SerializeField] private GameObject optionsUI;
    [SerializeField] private GameObject inGameUI;

    public UI_itemTooltip itemToolTip;
    public UI_statToolTip statToopTip;
    public Ui_SkillToolTip skillToolTip;

    public UI_CraftWindow craftWindow;
    public void Awake()
    {
        SwitchTo(skillTreeUI);//修复可能出现skill没法加载成功的bug
        
    }
    public void Start()
    {
        SwitchTo(inGameUI);
        itemToolTip.gameObject.SetActive(false);
        statToopTip.gameObject.SetActive(false);
    }

    private void Update()
    {
        if(Input.GetKeyDown(KeyCode.C))
        {
            SwitchWithKeyTo(characterUI);
        }

        if(Input.GetKeyDown(KeyCode.B))
        {
            SwitchWithKeyTo(craftUI);
        }

        if(Input.GetKeyDown(KeyCode.K))
        {
            SwitchWithKeyTo(skillTreeUI);
        }

        if(Input.GetKeyDown(KeyCode.O))
        {
            SwitchWithKeyTo(optionsUI);
        }    
    }

    public void SwitchTo(GameObject _menu)//切换窗口函数
    {
        for (int i = 0; i < transform.childCount; i++)
        {
            transform.GetChild(i).gameObject.SetActive(false);
        }

        if (_menu != null)
        {
            _menu.SetActive(true);
        }
    }

    public void SwitchWithKeyTo(GameObject _menu)//键盘切换窗口函数
    {
        if (_menu != null && _menu.activeSelf)//通过判断是否传入mune和mune是否激活来决定使设置为可视或不可使
        {
            _menu.SetActive(false);
            CheckForInGameUI();
            return;
        }
        SwitchTo(_menu);
    }

    private void CheckForInGameUI()//当其他UI不在时自动切换值InGameUI函数
    {
        for(int i = 0; i < transform.childCount; i++)
        {
            if (transform.GetChild(i).gameObject.activeSelf)
                return;
        }

        SwitchTo(inGameUI);
    }
}
UI_InGame.cs
cs 复制代码
using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

public class UI_InGame : MonoBehaviour
{
    [SerializeField] private PlayerStats playerStats;
    [SerializeField] Slider slider;

    [SerializeField] private Image dashImage;
    [SerializeField] private Image parryImage;
    [SerializeField] private Image crystalImage;
    [SerializeField] private Image swordImage;
    [SerializeField] private Image blackholeImage;
    [SerializeField] private Image flaskholeImage;

    [SerializeField] private TextMeshProUGUI currentSouls;

    private SkillManager skills;
    void Start() 
    {
        if(playerStats != null)
        {
            playerStats.onHealthChanged += UpdateHealthUI;
        }

        skills = SkillManager.instance;

        
    }

    // Update is called once per frame
    void Update()
    {
        currentSouls.text = PlayerManager.instance.GetCurrency().ToString("#,#");

        if(Input.GetKeyDown(KeyCode.LeftShift) && skills.dash.dashUnlocked)//使用技能后图标变黑
        {
            SetCoolDownOf(dashImage);
        }
        if (Input.GetKeyDown(KeyCode.Q) && skills.parry.parryUnlocked)
        {
            SetCoolDownOf(parryImage);
        }
        if (Input.GetKeyDown(KeyCode.F) && skills.crystal.crystalUnlocked)
        {
            SetCoolDownOf(crystalImage);
        }
        if (Input.GetKeyDown(KeyCode.Mouse1)&& skills.sword.swordUnlocked)
        {
            SetCoolDownOf(swordImage);
        }
        if (Input.GetKeyDown(KeyCode.R) && skills.blackhole.blackholeUnlocked)
        {
            SetCoolDownOf(blackholeImage);
        }
        if (Input.GetKeyDown(KeyCode.Alpha1) && Inventory.instance.GetEquipment(EquipmentType.Flask) != null)
        {
            SetCoolDownOf(flaskholeImage);
        }

        CheckCooldown(dashImage, skills.dash.cooldown);
        CheckCooldown(parryImage, skills.parry.cooldown);
        CheckCooldown(crystalImage, skills.crystal.cooldown);
        CheckCooldown(swordImage, skills.sword.cooldown);
        CheckCooldown(blackholeImage, skills.blackhole.cooldown);
        CheckCooldown(flaskholeImage, Inventory.instance.flaskCooldown);
    }

    private void UpdateHealthUI()//更新血量条函数,此函数由Event触发
    {
        slider.maxValue = playerStats.GetMaxHealthValue();
        slider.value = playerStats.currentHealth;
    }

    private void SetCoolDownOf(Image _image)//使用技能后使图标变黑的函数
    {
        if (_image.fillAmount <= 0)
            _image.fillAmount = 1;
    }

    private void CheckCooldown(Image _image,float _cooldown)//使图标根据cd逐渐变白的函数
    {
        if(_image.fillAmount > 0)
        {
            _image.fillAmount -= 1 / _cooldown * Time.deltaTime;
        }
    }
}
Inventory.cs
cs 复制代码
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;
    [SerializeField] private Transform statSlotParent;


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

    [Header("Items cooldown")]
    private float lastTimeUsedFlask;
    private float lastTimeUsedArmor;
    public float flaskCooldown { get; private set; }
    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>();
        statSlot = statSlotParent.GetComponentsInChildren<UI_statslot>();
        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();
        UpdateSlotUI();

    }//装备装备的函数

    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()//更新槽UI的函数
    {

        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]);

        }

        UpdateStatsUI();
    }

    public void UpdateStatsUI()//更新状态UI函数
    {
        for (int i = 0; i < statSlot.Length; i++)
        {
            statSlot[i].UpdateStatValueUI();
        }
    }

    public void AddItem(ItemData _item)//添加物体的函数
    {
        if (_item.itemType == ItemType.Equipment && CanAddItem())//修复Inventory数量大于Slot能存放的数量时报错的Bug
        {
            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);//同上
        }
        UpdateSlotUI();
    }

    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数量大于Slot能存放的数量时报错的Bug
    {
        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 bool CanAddItem()//通过Inventory数量和Slot能存放的数量进行对比,确定是否可以添加新的装备到装备槽
    {
        if (inventory.Count >= inventoryItemSlot.Length)
        {
            return false;
        }
        return true;
    }
    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;
    }

    public bool CanCraft(ItemData_Equipment _itemToCraft, List<InventoryItem> _requiredMaterials)
    {
        List<InventoryItem> materialsToRemove = new List<InventoryItem>();

        for (int i = 0; i < _requiredMaterials.Count; i++)
        {
            if (stashDictionary.TryGetValue(_requiredMaterials[i].data, out InventoryItem stashValue))//判断数量是否足够
            {
                if (stashValue.stackSize < _requiredMaterials[i].stackSize)
                {
                    Debug.Log("not enough materials");
                    return false;
                }
                else
                {
                    materialsToRemove.Add(stashValue);
                }

            }
            else
            {
                Debug.Log("not enough materials");
                return false;
            }
        }


        for (int i = 0; i < materialsToRemove.Count; i++)
        {
            RemoveItem(materialsToRemove[i].data);
        }

        AddItem(_itemToCraft);
        Debug.Log("Here is your item " + _itemToCraft.name);

        return true;
    }//检测材料足够制造对应装备的函数
}
Skill.cs
cs 复制代码
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using UnityEngine;

public class Skill : MonoBehaviour
{
    public float cooldown;
    protected float cooldownTimer;

    protected Player player;//拿到player
    
    protected virtual void Start()
    {
        player = PlayerManager.instance.player;//拿到player
    }
    protected virtual void Update()
    {
        cooldownTimer -= Time.deltaTime;
    }

    public virtual bool CanUseSkill()
    {
        if (cooldownTimer < 0)
        {
            UseSkill();
            cooldownTimer = cooldown;
            return true;
        }
        else
        {
            Debug.Log("Skill is on cooldown");
            return false;
        }

    }
    public virtual void UseSkill()
    {
        // do some skill thing
    }


    //整理能返回最近敌人位置的函数
    protected virtual Transform FindClosestEnemy(Transform _checkTransform)
    {
        Collider2D[] colliders = Physics2D.OverlapCircleAll(_checkTransform.position, 25);//找到环绕自己的所有碰撞器

        float closestDistance = Mathf.Infinity;//正无穷大的表示形式(只读)
        Transform closestEnemy = null;


        //https://docs.unity3d.com/cn/current/ScriptReference/Mathf.Infinity.html
        foreach (var hit in colliders)
        {
            if (hit.GetComponent<Enemy>() != null)
            {
                float distanceToEnemy = Vector2.Distance(_checkTransform.position, hit.transform.position);//拿到与敌人之间的距离
                if (distanceToEnemy < closestDistance)//比较距离,如果离得更近,保存这个敌人的位置,更改最近距离
                {
                    closestDistance = distanceToEnemy;
                    closestEnemy = hit.transform;
                }
            }
        }

        return closestEnemy;
       
    }

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

public class PlayerManager : MonoBehaviour
{
    public static PlayerManager instance;
    public Player player;//这是通过在外部设置了一个组件,让这个组件能够直接把Player找到,从而减少FInd的方式所带来的高负载

    public int currency;
    private void Awake()
    {
        if(instance != null)
        {
            Destroy(instance.gameObject);
        }
        else
        instance = this;
    }

    public bool HaveEnoughMoney(int _price)
    {
        if(_price > currency)
        {
            Debug.Log("Not enough money");
            return false;
        }

        currency -= _price;
        return true;
    }

    public int GetCurrency() => currency;
}
相关推荐
秃头佛爷2 小时前
Python学习大纲总结及注意事项
开发语言·python·学习
△曉風殘月〆3 小时前
WPF MVVM入门系列教程(二、依赖属性)
c#·wpf·mvvm
dayouziei4 小时前
java的类加载机制的学习
java·学习
逐·風5 小时前
unity关于自定义渲染、内存管理、性能调优、复杂物理模拟、并行计算以及插件开发
前端·unity·c#
_oP_i6 小时前
Unity Addressables 系统处理 WebGL 打包本地资源的一种高效方式
unity·游戏引擎·webgl
dsywws7 小时前
Linux学习笔记之vim入门
linux·笔记·学习
m0_656974748 小时前
C#中的集合类及其使用
开发语言·c#
晨曦_子画8 小时前
3种最难学习和最容易学习的 3 种编程语言
学习
九鼎科技-Leo8 小时前
了解 .NET 运行时与 .NET 框架:基础概念与相互关系
windows·c#·.net
城南vision8 小时前
Docker学习—Docker核心概念总结
java·学习·docker