种田RPG游戏(五)

一、重新设置物品栏

1、打开Scripts-Inventory文件新建 ItemSlotData.cs

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

[System.Serializable]
//单独的类
public class ItemSlotData
{
    public ItemData itemData;//ItemData对象(收获的物品)
    public int quantity;//数量
    //构造函数:用于创建 ItemSlotData 实例
    public ItemSlotData(ItemData itemData, int quantity)
    {
        this.itemData = itemData;
        this.quantity = quantity;
        ValidateQuantity();
    }
    // 重载的构造函数:用于创建 ItemSlotData 实例,数量默认为1
    public ItemSlotData(ItemData itemData)
    {
        this.itemData = itemData;
        quantity = 1;
        ValidateQuantity();
    }
    // 增加数量,默认增加1
    public void AddQuantity()
    {
        AddQuantity(1);
    }
    //堆叠物品(根据传入的参数增加数量)
    public void AddQuantity(int amountToAdd)
    {
        quantity += amountToAdd;
    }
    //消耗物品:移除一个物品,将物品槽中的物品数-1
    public void Remove()
    {
        quantity--;
        ValidateQuantity();
    }
    // 检查数量是否小于等于0或物品数据是否为空,如果是则清空物品槽
    private void ValidateQuantity()
    {
        if (quantity <= 0 || itemData == null)
        {
            Empty();
        }
    }
    //直接清空物品槽,将物品数据和数量重置为默认值
    public void Empty()
    {
        itemData = null;
        quantity = 0;
    }
}

2、编辑InventoryManager.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using static InventorySlot;

public class InventoryManager : MonoBehaviour
{
    public static InventoryManager Instance { get; private set; }
    private void Awake()
    {
        if (Instance != null && Instance != this)
        {
            Destroy(this);
        }
        else
        {
            Instance = this;
        }
    }

    [Header("Tools")]
    //将ItemData类型更改为ItemSlots
    //重命名tools为toolSlots,重命名equippedTool为equippedToolSlot
    //将public更改为 private

    private ItemSlotData[] toolSlots = new ItemSlotData[8];
    private ItemSlotData equippedToolSlot = null;

    [Header("Items")]
    //将ItemData类型更改为ItemSlots
    //重命名items为itemSlots,equippedItem为equippedItemSlot
    private ItemSlotData[] itemSlots = new ItemSlotData[8];
    private ItemSlotData equippedItemSlot = null;

    public Transform handPoint;

    public void InventoryToHand(int slotIndex, InventorySlot.InventoryType inventoryType)
    {
        /*注释这个方法
        if (inventoryType == InventorySlot.InventoryType.Item)
        {
            ItemData itemToEquip = itemSlots[slotIndex];
            itemSlots[slotIndex] = equippedItemSlots;
            equippedItemSlots = itemToEquip;

            //调用收割作物的方法
            RenderHand();
        }
        else
        {
            ItemData toolToEquip = toolSlots[slotIndex];
            toolSlots[slotIndex] = equippedToolSlot;
            equippedToolSlot = toolToEquip;
        }
        UIManager.Instance.RenderInventory();
        */
    }
    public void HandToInventory(InventorySlot.InventoryType inventoryType)
    {
        /*注释这个方法
        if (inventoryType == InventorySlot.InventoryType.Item)
        {
            for (int i = 0; i < itemSlots.Length; i++)
            {
                if (itemSlots[i] == null)
                {
                    itemSlots[i] = equippedItemSlot;
                    equippedItemSlot = null; 
                    break;
                }
            }
            RenderHand();
        }
        else
        {
            for(int i = 0;i < toolSlots.Length; i++)
            {
                if(toolSlots[i] == null)
                {
                    toolSlots[i] = equippedToolSlot;
                    equippedToolSlot = null;
                    break;
                }
            }
        }
        UIManager.Instance.RenderInventory();*/
    }
    public void RenderHand()
    {
        if(handPoint.childCount>0)
        {
            Destroy(handPoint.GetChild(0).gameObject);
        }
        if(equippedItemSlot != null)
        {
            //更改调用的方法
            Instantiate(GetEquippedSlotItem(InventorySlot.InventoryType.Item).gameModel, handPoint);
        }
    }
    //
    public ItemData GetEquippedSlotItem(InventorySlot.InventoryType inventoryType)
    {
        if(inventoryType == InventorySlot.InventoryType.Item)
        {
            return equippedItemSlot.itemData;
        }
        return equippedToolSlot.itemData;
    }
    //
    public ItemSlotData GetEquippedSlot(InventorySlot.InventoryType inventoryType)
    {
        if(inventoryType == InventorySlot.InventoryType.Item)
        {
            return equippedItemSlot;
        }
        return equippedToolSlot;
    }
    //
    public ItemSlotData[] GetInventorySlots(InventorySlot.InventoryType inventoryType)
    {
        if (inventoryType == InventorySlot.InventoryType.Item)
        {
            return itemSlots;
        }
        return toolSlots;
    }
}

3、编辑InventorySlot.cs

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

public class InventorySlot : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler,IPointerClickHandler
{
    ItemData itemToDisplay;
    //显示数量
    int quantity;

    public Image itemDisplayImage;

    public enum InventoryType
    {
        Item, Tool
    }
    public InventoryType inventoryType;

    int slotIndex;
    //更改参数类型
    public void Display(ItemSlotData itemSlot)
    {
        //增加变量和数量
        itemToDisplay = itemSlot.itemData;
        quantity = itemSlot.quantity;

        if (itemToDisplay != null && itemToDisplay.thumbnail != null)
        {
            itemDisplayImage.sprite = itemToDisplay.thumbnail;
            //删除this.itemToDisplay = itemToDisplay;
            itemDisplayImage.gameObject.SetActive(true);
            return;
        }
        itemDisplayImage.gameObject.SetActive(false);
        this.itemToDisplay = null;
    }

    public void AssignIndex(int slotIndex)
    {
        this.slotIndex = slotIndex;
    }

    public void OnPointerEnter(PointerEventData eventData)
    {
        UIManager.Instance.DisplayItemInfo(itemToDisplay);
    }

    public void OnPointerExit(PointerEventData eventData)
    {
        UIManager.Instance.DisplayItemInfo(null);
    }

    public virtual void OnPointerClick(PointerEventData eventData)
    {
        InventoryManager.Instance.InventoryToHand(slotIndex,inventoryType);
    }
}

4、编辑UIManager.cs,

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

public class UIManager : MonoBehaviour, ITimeTracker
{
    public static UIManager Instance { get; private set; }
    private void Awake()
    {
        if (Instance != null && Instance != this) { Destroy(this); }
        else { Instance = this; }
    }

    [Header("Startas Bar")]
    public Image toolEquipSlotImage;
    public Text timeText;
    public Text dateText;

    [Header("Inventory System")]

    public GameObject inventoryPanel;
    public HandInventorySlot toolHandSlot;
    public InventorySlot[] toolSlots;
    public HandInventorySlot itemHandSlot;
    public InventorySlot[] itemSlots;

    public Text itemNameText;
    public Text itemDescriptionText;

    private void Start()
    {
        RenderInventory();
        AssignSlotIndex();
        TimeManager.Instance.RegisterTracker(this);
    }
    public void AssignSlotIndex()
    {
        for (int i = 0; i < toolSlots.Length; i++)
        {
            toolSlots[i].AssignIndex(i);
            itemSlots[i].AssignIndex(i);
        }
    }

    //更改参数
    public void RenderInventory(ItemSlotData[] inventoryToolSlot,ItemSlotData[] inventoryItemSlots)
    {
        
        //ItemSlotData[] inventoryToolSlots = InventoryManager.Instance.GetInventorySlots(InventorySlot.InventoryType.Tool);

        RenderInventoryPanel(inventoryToolSlot, toolSlots);

        RenderInventoryPanel(inventoryItemSlots, itemSlots);
        //
        toolHandSlot.Display(InventoryManager.Instance.GetEquippedSlot(InventorySlot.InventoryType.Tool));
        itemHandSlot.Display(InventoryManager.Instance.GetEquippedSlot(InventorySlot.InventoryType.Item));
        ItemData equippedTool = InventoryManager.Instance.GetEquippedSlotItem(InventorySlot.InventoryType.Tool);
        if (equippedTool != null)
        {
            toolEquipSlotImage.sprite = equippedTool.thumbnail;
            toolEquipSlotImage.gameObject.SetActive(true);
            return;
        }
        toolEquipSlotImage.gameObject.SetActive(false);
    }
    //更改参数类型
    void RenderInventoryPanel(ItemSlotData[] slots, InventorySlot[] uiSlots)
    {
        for (int i = 0; i < uiSlots.Length; i++)
        {
            uiSlots[i].Display(slots[i]);
        }
    }
    public void ToggleInventoryPanel()
    {
        inventoryPanel.SetActive(!inventoryPanel.activeSelf);
        RenderInventory();
    }

    public void DisplayItemInfo(ItemData data)
    {
        if (data == null)
        {
            itemNameText.text = "";
            itemDescriptionText.text = "";
            return;
        }
        itemNameText.text = data.name;
        itemDescriptionText.text = data.description;
    }
    public void ClockUpdate(GameTimestamp timestamp)
    {
        int hours = timestamp.hour;
        int minutes = timestamp.minute;

        string prefix = "AM ";
        if (hours > 12)
        {
            prefix = "PM ";
            hours -= 12;
        }
        timeText.text = prefix + hours + ":" + minutes.ToString("00");
        int day = timestamp.day;
        string season = timestamp.season.ToString();
        string dayOfTheWeek = timestamp.GetDayOfTheWeek().ToString();

        dateText.text = season + " " + day + " (" + dayOfTheWeek +")";
    }
}

5、编辑InventoryManager.cs,增加一个新的ItemSlotData对象组

    public ItemSlotData[] GetInventorySlots(InventorySlot.InventoryType inventoryType)
    {
        if (inventoryType == InventorySlot.InventoryType.Item)
        {
            return itemSlots;
        }
        return toolSlots;
    }

6、编辑UIManager.cs,

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

public class UIManager : MonoBehaviour, ITimeTracker
{
    public static UIManager Instance { get; private set; }
    private void Awake()
    {
        if (Instance != null && Instance != this) { Destroy(this); }
        else { Instance = this; }
    }

    [Header("Startas Bar")]
    public Image toolEquipSlotImage;
    public Text timeText;
    public Text dateText;

    [Header("Inventory System")]

    public GameObject inventoryPanel;
    public HandInventorySlot toolHandSlot;
    public InventorySlot[] toolSlots;
    public HandInventorySlot itemHandSlot;
    public InventorySlot[] itemSlots;

    public Text itemNameText;
    public Text itemDescriptionText;

    private void Start()
    {
        RenderInventory();
        AssignSlotIndex();
        TimeManager.Instance.RegisterTracker(this);
    }
    public void AssignSlotIndex()
    {
        for (int i = 0; i < toolSlots.Length; i++)
        {
            toolSlots[i].AssignIndex(i);
            itemSlots[i].AssignIndex(i);
        }
    }
    //删除参数
    public void RenderInventory()
    {
        //新增
        ItemSlotData[] inventoryToolSlots = InventoryManager.Instance.GetInventorySlots(InventorySlot.InventoryType.Tool);
        ItemSlotData[] inventoryItemSlots = InventoryManager.Instance.GetInventorySlots(InventorySlot.InventoryType.Item);

        RenderInventoryPanel(inventoryToolSlots, toolSlots);
        RenderInventoryPanel(inventoryItemSlots, itemSlots);
        toolHandSlot.Display(InventoryManager.Instance.GetEquippedSlot(InventorySlot.InventoryType.Tool));
        itemHandSlot.Display(InventoryManager.Instance.GetEquippedSlot(InventorySlot.InventoryType.Item));
        ItemData equippedTool = InventoryManager.Instance.GetEquippedSlotItem(InventorySlot.InventoryType.Tool);
        if (equippedTool != null)
        {
            toolEquipSlotImage.sprite = equippedTool.thumbnail;
            toolEquipSlotImage.gameObject.SetActive(true);
            return;
        }
        toolEquipSlotImage.gameObject.SetActive(false);
    }
    //更改参数类型
    void RenderInventoryPanel(ItemSlotData[] slots, InventorySlot[] uiSlots)
    {
        for (int i = 0; i < uiSlots.Length; i++)
        {
            uiSlots[i].Display(slots[i]);
        }
    }
    public void ToggleInventoryPanel()
    {
        inventoryPanel.SetActive(!inventoryPanel.activeSelf);
        RenderInventory();
    }

    public void DisplayItemInfo(ItemData data)
    {
        if (data == null)
        {
            itemNameText.text = "";
            itemDescriptionText.text = "";
            return;
        }
        itemNameText.text = data.name;
        itemDescriptionText.text = data.description;
    }
    public void ClockUpdate(GameTimestamp timestamp)
    {
        int hours = timestamp.hour;
        int minutes = timestamp.minute;

        string prefix = "AM ";
        if (hours > 12)
        {
            prefix = "PM ";
            hours -= 12;
        }
        timeText.text = prefix + hours + ":" + minutes.ToString("00");
        int day = timestamp.day;
        string season = timestamp.season.ToString();
        string dayOfTheWeek = timestamp.GetDayOfTheWeek().ToString();

        dateText.text = season + " " + day + " (" + dayOfTheWeek +")";
    }
}

7、编辑InventoryManager.cs

    public ItemSlotData[] GetInventorySlots(InventorySlot.InventoryType inventoryType)
    {
        if (inventoryType == InventorySlot.InventoryType.Item)
        {
            return itemSlots;
        }
        return toolSlots;
    }
    //新增方法
    public bool SlotEquipped(InventorySlot.InventoryType inventoryType)
    {
        if (inventoryType == InventorySlot.InventoryType.Item)
        {
            return equippedItemSlot != null;
        }
        return equippedToolSlot != null;
    }

8、编辑PlayerInteractor.cs

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

public class PlayerInteractor : MonoBehaviour
{
    PlayerController playerController;
    Land selectLand = null;
    InteractableObject selectedInteractable = null;
    void Start()
    {
        playerController = transform.parent.GetComponent<PlayerController>();
    }

    void Update()
    {
        RaycastHit hit;
        if (Physics.Raycast(transform.position, Vector3.down, out hit, 1))
        {
            OnInteractableHit(hit);
        }
    }
    void OnInteractableHit(RaycastHit hit)
    {
        Collider other = hit.collider;
        if (other != null && other.CompareTag("Land"))
        {
            Land land = other.GetComponent<Land>();
            if (land != null)
            {
                SelectLand(land);
                return;
            }
        }
        //
        if (other.CompareTag("Item"))
        {
            selectedInteractable = other.GetComponent<InteractableObject>();
            return;
        }

        if(selectedInteractable != null)
        {
            selectedInteractable = null;
        }

        if (selectLand != null)
        {
            selectLand.Select(false);
            selectLand = null;
        }
    }

    void SelectLand(Land land)
    {
        if (land == null)
        {
            Debug.Log("你没有选择田地!");
            return;
        }
        if (selectLand != null)
        {
            selectLand.Select(false);
        }
        selectLand = land;
        land.Select(true);
    }

    public void Interact()
    {
        //更改条件
        if(InventoryManager.Instance.SlotEquipped(InventorySlot.InventoryType.Item))
        {
            return;
        }

        if(selectLand != null)
        {
            selectLand.Interact();
            return;
        }
        Debug.Log("没站在田地里");
    }
    public void ItemInteract()
    {
        //更改条件
        if (InventoryManager.Instance.SlotEquipped(InventorySlot.InventoryType.Item))
        {
            InventoryManager.Instance.HandToInventory(InventorySlot.InventoryType.Item);
            return;
        }
        if(selectedInteractable != null)
        {
            selectedInteractable.Pickup();
        }
    }
}

9、编辑Land.cs

    public void Interact()
    {
        //更改
        ItemData toolSlot = InventoryManager.Instance.GetEquippedSlotItem(InventorySlot.InventoryType.Tool);

        if(toolSlot == null)
        {
            return;
        }
        EquipmentData equipmentTool = toolSlot as EquipmentData;
        if (equipmentTool != null)
        {
            EquipmentData.ToolType toolType = equipmentTool.toolType;

            switch (toolType)
            {
                case EquipmentData.ToolType.Hoe:
                    SwitchLandStatus(LandStatus.Farmland); break;
                case EquipmentData.ToolType.WateringCan:
                    SwitchLandStatus(LandStatus.Watered); break;
                //铲除作物
                case EquipmentData.ToolType.Shovel:
                    if(cropPlanted != null)
                    {
                        Destroy(cropPlanted.gameObject);
                    }
                    break;
            }
            return;
        }
        SeedData seedTool = toolSlot as SeedData;
        if (seedTool != null && landStatus !=LandStatus.Soil && cropPlanted==null)
        {
            GameObject cropObject =Instantiate(cropPrefab ,transform);
            cropObject.transform.position = new Vector3(transform.position.x,0f,transform.position.z);
            cropPlanted = cropObject.GetComponent<CropBehaviour>();
            cropPlanted.Plant(seedTool);
        }
    }

10、编辑InventoryManager.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using static InventorySlot;

public class InventoryManager : MonoBehaviour
{
    public static InventoryManager Instance { get; private set; }
    private void Awake()
    {
        if (Instance != null && Instance != this)
        {
            Destroy(this);
        }
        else
        {
            Instance = this;
        }
    }

    [Header("Tools")]
    //将ItemData类型更改为ItemSlots
    //重命名tools为toolSlots,重命名equippedTool为equippedToolSlot
    //将public更改为 private

    private ItemSlotData[] toolSlots = new ItemSlotData[8];
    private ItemSlotData equippedToolSlot = null;

    [Header("Items")]
    //将ItemData类型更改为ItemSlots
    //重命名items为itemSlots,equippedItem为equippedItemSlot
    private ItemSlotData[] itemSlots = new ItemSlotData[8];
    private ItemSlotData equippedItemSlot = null;

    public Transform handPoint;

    public void InventoryToHand(int slotIndex, InventorySlot.InventoryType inventoryType)
    {
        /*注释这个方法
        if (inventoryType == InventorySlot.InventoryType.Item)
        {
            ItemData itemToEquip = itemSlots[slotIndex];
            itemSlots[slotIndex] = equippedItemSlots;
            equippedItemSlots = itemToEquip;

            //调用收割作物的方法
            RenderHand();
        }
        else
        {
            ItemData toolToEquip = toolSlots[slotIndex];
            toolSlots[slotIndex] = equippedToolSlot;
            equippedToolSlot = toolToEquip;
        }
        UIManager.Instance.RenderInventory();
        */
    }
    public void HandToInventory(InventorySlot.InventoryType inventoryType)
    {
        /*注释这个方法
        if (inventoryType == InventorySlot.InventoryType.Item)
        {
            for (int i = 0; i < itemSlots.Length; i++)
            {
                if (itemSlots[i] == null)
                {
                    itemSlots[i] = equippedItemSlot;
                    equippedItemSlot = null; 
                    break;
                }
            }
            RenderHand();
        }
        else
        {
            for(int i = 0;i < toolSlots.Length; i++)
            {
                if(toolSlots[i] == null)
                {
                    toolSlots[i] = equippedToolSlot;
                    equippedToolSlot = null;
                    break;
                }
            }
        }
        UIManager.Instance.RenderInventory();*/
    }
    public void RenderHand()
    {
        if(handPoint.childCount>0)
        {
            Destroy(handPoint.GetChild(0).gameObject);
        }
        if(equippedItemSlot != null)
        {
            Instantiate(GetEquippedSlotItem(InventorySlot.InventoryType.Item).gameModel, handPoint);
        }
    }

    //新增判断
    public bool IsTool(ItemData item)
    {
        EquipmentData equipment = item as EquipmentData;
        if(equipment != null)
        {
            return true;
        }
        SeedData seed = item as SeedData;
        return seed != null;
    }

    //组织代码
    #region Gets and Checks

    //
    public ItemData GetEquippedSlotItem(InventorySlot.InventoryType inventoryType)
    {
        if(inventoryType == InventorySlot.InventoryType.Item)
        {
            return equippedItemSlot.itemData;
        }
        return equippedToolSlot.itemData;
    }
    //
    public ItemSlotData GetEquippedSlot(InventorySlot.InventoryType inventoryType)
    {
        if(inventoryType == InventorySlot.InventoryType.Item)
        {
            return equippedItemSlot;
        }
        return equippedToolSlot;
    }
    //新增
    public ItemSlotData[] GetInventorySlots(InventorySlot.InventoryType inventoryType)
    {
        if (inventoryType == InventorySlot.InventoryType.Item)
        {
            return itemSlots;
        }
        return toolSlots;
    }
    //新增方法
    public bool SlotEquipped(InventorySlot.InventoryType inventoryType)
    {
        if (inventoryType == InventorySlot.InventoryType.Item)
        {
            return equippedItemSlot != null;
        }
        return equippedToolSlot != null;
    }
    #endregion
    //新增方法
    public void EquipEmptySlot(ItemData item)
    {
        if(IsTool(item))
        {
            equippedToolSlot = new ItemSlotData(item);
        }
        else
        {
            equippedItemSlot = new ItemSlotData(item);
        }
    }
}

11、编辑InteractableObject.cs

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

public class InteractableObject : MonoBehaviour
{
    public ItemData item;

    //增加virtual以便重写
    public virtual void Pickup()
    {
        InventoryManager.Instance.EquipEmptySlot(item);
        InventoryManager.Instance.RenderHand();
        Destroy(gameObject);
    }
}

12、编辑RegrowableHarvestBehaviour.cs

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

public class RegrowableHarvestBehaviour : InteractableObject
{
    CropBehaviour parentCrop;
    public void SetParent(CropBehaviour parentCrop)
    {
        this.parentCrop = parentCrop;
    }
    public override void Pickup()
    {
        //更改
        InventoryManager.Instance.EquipHandSlot(item);
        InventoryManager.Instance.RenderHand();

        parentCrop.Regrow();
    }
}
二、设置物品数量

1、编辑InventoryManager.cs,序列化

[Header("Tools")]
//每一行增加[SerializeField]

[SerializeField] private ItemSlotData[] toolSlots = new ItemSlotData[8];
[SerializeField] private ItemSlotData equippedToolSlot = null;

[Header("Items")]
[SerializeField] private ItemSlotData[] itemSlots = new ItemSlotData[8];
[SerializeField] private ItemSlotData equippedItemSlot = null;

2、编辑InventoryManager.cs

    //新增方法
    public void OnValidate()
    {
        ValidateInventorySlots(equippedToolSlot);
        ValidateInventorySlots(equippedItemSlot);

        ValidateInventorySlots(itemSlots);
        ValidateInventorySlots(toolSlots);
    }
    //新增方法
    void ValidateInventorySlots(ItemSlotData slot)
    {
        if(slot.itemData != null &&slot.quantity == 0)
        {
            slot.quantity = 1;
        }
    }
    //新增方法
    void ValidateInventorySlots(ItemSlotData[] array)
    {
        foreach(ItemSlotData slot in array)
        {
            ValidateInventorySlots(slot);
        }
    }

3、赋值

选中Manager,找到Inspector上的InventoryManager.cs组件,赋值

4、添加物品数量文本

(1) 以HandSlot为父物体,UI-Text,重命名为QuantityText。

(2) 设置它的Rect Transform和Text

(3) 复制QuantityText,设置它的Rect Transform和Text

(4) 同样的方法,添加InventorySlot的子物体(文本)

(5) Apply预制体InventorySlot的更改

(6) 同样的方法,添加HandSlot的子物体(文本)

(7) 编辑InventorySlot.cs

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

public class InventorySlot : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler,IPointerClickHandler
{
    ItemData itemToDisplay;
    int quantity;
    //数量文本
    public Image itemDisplayImage;
    public Text quantityText;

    public enum InventoryType
    {
        Item, Tool
    }
    public InventoryType inventoryType;

    int slotIndex;
    public void Display(ItemSlotData itemSlot)
    {
        itemToDisplay = itemSlot.itemData;
        quantity = itemSlot.quantity;

        //显示数量文本
        quantityText.text = "";

        if (itemToDisplay != null && itemToDisplay.thumbnail != null)
        {
            itemDisplayImage.sprite = itemToDisplay.thumbnail;
            //显示数量文本
            if (quantity > 1)
            {
                quantityText.text = quantity.ToString();
            }
            itemDisplayImage.gameObject.SetActive(true);
            return;
        }
        itemDisplayImage.gameObject.SetActive(false);
        this.itemToDisplay = null;
    }

    public void AssignIndex(int slotIndex)
    {
        this.slotIndex = slotIndex;
    }

    public void OnPointerEnter(PointerEventData eventData)
    {
        UIManager.Instance.DisplayItemInfo(itemToDisplay);
    }

    public void OnPointerExit(PointerEventData eventData)
    {
        UIManager.Instance.DisplayItemInfo(null);
    }

    public virtual void OnPointerClick(PointerEventData eventData)
    {
        InventoryManager.Instance.InventoryToHand(slotIndex,inventoryType);
    }
}

(8) 赋值(预制体InventorySlot中)

(9) 赋值

三、

1、编辑ItemSlotData.cs

using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;

[System.Serializable]
public class ItemSlotData
{
    public ItemData itemData;
    public int quantity;
    public ItemSlotData(ItemData itemData, int quantity)
    {
        this.itemData = itemData;
        this.quantity = quantity;
        ValidateQuantity();
    }
    public ItemSlotData(ItemData itemData)
    {
        this.itemData = itemData;
        quantity = 1;
        ValidateQuantity();
    }
    //复制ItemSlotData对象
    public ItemSlotData(ItemSlotData slotToClone)
    {
        itemData = slotToClone.itemData;
        quantity = slotToClone.quantity;
    }

    public void AddQuantity()
    {
        AddQuantity(1);
    }
    public void AddQuantity(int amountToAdd)
    {
        quantity += amountToAdd;
    }
    public void Remove()
    {
        quantity--;
        ValidateQuantity();
    }
    //新增方法
    public bool Stackable(ItemSlotData slotToCompare)
    {
        return slotToCompare.itemData == itemData;
    }
    private void ValidateQuantity()
    {
        if (quantity <= 0 || itemData == null)
        {
            Empty();
        }
    }
    public void Empty()
    {
        itemData = null;
        quantity = 0;
    }
    //新增方法
    public bool IsEmpty()
    {
        return itemData == null;
    }
}

2、编辑InventoryManager.cs(这里有一个报错)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using static InventorySlot;

public class InventoryManager : MonoBehaviour
{
    public static InventoryManager Instance { get; private set; }
    private void Awake()
    {
        if (Instance != null && Instance != this)
        {
            Destroy(this);
        }
        else
        {
            Instance = this;
        }
    }

    [Header("Tools")]

    [SerializeField] private ItemSlotData[] toolSlots = new ItemSlotData[8];
    [SerializeField] private ItemSlotData equippedToolSlot = null;

    [Header("Items")]
    [SerializeField] private ItemSlotData[] itemSlots = new ItemSlotData[8];
    [SerializeField] private ItemSlotData equippedItemSlot = null;

    public Transform handPoint;

    public void InventoryToHand(int slotIndex, InventorySlot.InventoryType inventoryType)
    {
        //临时变量
        ItemSlotData handToEquip = equippedToolSlot;
        ItemSlotData[] inventoryToAlter = toolSlots;
        //装备物品槽
        if(inventoryType == InventorySlot.InventoryType.Item)
        {
            handToEquip = equippedItemSlot;
            inventoryToAlter = itemSlots;
        }
        //检查是否可以堆叠
        if (handToEquip.Stackable(inventoryToAlter[slotIndex]))
        {
            ItemSlotData slotToAlter = inventoryToAlter[slotIndex];
            handToEquip.AddQuantity(slotToAlter.quantity);
            slotToAlter.Empty();
        }
        else
        {
            ItemSlotData slotToEquip = new ItemSlotData(inventoryToAlter[slotIndex]);
            inventoryToAlter[slotIndex] = new ItemSlotData(handToEquip);
            EquipEmptySlot(slotToEquip);
            handToEquip.Empty();
        }
        if(inventoryType == InventorySlot.InventoryType.Item)
        {
            RenderHand();
        }
        //渲染
        UIManager.Instance.RenderInventory();
    }
    public void HandToInventory(InventorySlot.InventoryType inventoryType)
    {
        //临时变量
        ItemSlotData handSlot = equippedToolSlot;
        ItemSlotData[] inventoryToAlter = toolSlots;
        //装备
        if(inventoryType == InventorySlot.InventoryType.Item)
        {
            handSlot = equippedItemSlot;
            inventoryToAlter = itemSlots;
        }
        if(!StackItemToInventory(handSlot, inventoryToAlter))
        {
            for(int i =  0; i < inventoryToAlter.Length; i++)
            {
                if(inventoryToAlter[i] == null)
                {
                    inventoryToAlter[i] = new ItemSlotData(handSlot);
                    handSlot.Empty();
                    break;
                }
            }
        }
        if(inventoryType == InventorySlot.InventoryType.Item)
        {
            RenderHand();
        }
        UIManager.Instance.RenderInventory();
    }
    //新建方法
    public bool StackItemToInventory(ItemSlotData itemSlot, ItemSlotData[] inventoryArray)
    {
        for(int i = 0; i < inventoryArray.Length; i++)
        {
            if (inventoryArray[i].Stackable(itemSlot))
            {
                inventoryArray[i].AddQuantity(itemSlot.quantity);
                itemSlot.Empty();
                return true;
            }
        }
        return false;
    }
    public void RenderHand()
    {
        if(handPoint.childCount>0)
        {
            Destroy(handPoint.GetChild(0).gameObject);
        }
        //更改条件
        if(SlotEquipped(InventorySlot.InventoryType.Item))
        {
            Instantiate(GetEquippedSlotItem(InventorySlot.InventoryType.Item).gameModel, handPoint);
        }
    }


    #region Gets and Checks

    public ItemData GetEquippedSlotItem(InventorySlot.InventoryType inventoryType)
    {
        if(inventoryType == InventorySlot.InventoryType.Item)
        {
            return equippedItemSlot.itemData;
        }
        return equippedToolSlot.itemData;
    }
    //
    public ItemSlotData GetEquippedSlot(InventorySlot.InventoryType inventoryType)
    {
        if(inventoryType == InventorySlot.InventoryType.Item)
        {
            return equippedItemSlot;
        }
        return equippedToolSlot;
    }
    public ItemSlotData[] GetInventorySlots(InventorySlot.InventoryType inventoryType)
    {
        if (inventoryType == InventorySlot.InventoryType.Item)
        {
            return itemSlots;
        }
        return toolSlots;
    }
    public bool SlotEquipped(InventorySlot.InventoryType inventoryType)
    {
        if (inventoryType == InventorySlot.InventoryType.Item)
        {
            //更改
            return !equippedItemSlot.IsEmpty();
        }
        //更改
        return !equippedToolSlot.IsEmpty();
    }
    public bool IsTool(ItemData item)
    {
        EquipmentData equipment = item as EquipmentData;
        if (equipment != null)
        {
            return true;
        }
        SeedData seed = item as SeedData;
        return seed != null;
    }

    #endregion
    public void EquipEmptySlot(ItemData item)
    {
        if(IsTool(item))
        {
            equippedToolSlot = new ItemSlotData(item);
        }
        else
        {
            equippedItemSlot = new ItemSlotData(item);
        }
    }
    //组织
    #region Inventory Slot validation
    public void OnValidate()
    {
        ValidateInventorySlots(equippedToolSlot);
        ValidateInventorySlots(equippedItemSlot);

        ValidateInventorySlots(itemSlots);
        ValidateInventorySlots(toolSlots);
    }
    void ValidateInventorySlots(ItemSlotData slot)
    {
        if(slot.itemData != null &&slot.quantity == 0)
        {
            slot.quantity = 1;
        }
    }
    void ValidateInventorySlots(ItemSlotData[] array)
    {
        foreach(ItemSlotData slot in array)
        {
            ValidateInventorySlots(slot);
        }
    }
    #endregion 
}

 3、编辑InventoryManager.cs,处理报错

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using static InventorySlot;

public class InventoryManager : MonoBehaviour
{
    public static InventoryManager Instance { get; private set; }
    private void Awake()
    {
        if (Instance != null && Instance != this)
        {
            Destroy(this);
        }
        else
        {
            Instance = this;
        }
    }

    [Header("Tools")]

    [SerializeField] private ItemSlotData[] toolSlots = new ItemSlotData[8];
    [SerializeField] private ItemSlotData equippedToolSlot = null;

    [Header("Items")]
    [SerializeField] private ItemSlotData[] itemSlots = new ItemSlotData[8];
    [SerializeField] private ItemSlotData equippedItemSlot = null;

    public Transform handPoint;

    public void InventoryToHand(int slotIndex, InventorySlot.InventoryType inventoryType)
    {
        ItemSlotData handToEquip = equippedToolSlot;
        ItemSlotData[] inventoryToAlter = toolSlots;
        if (inventoryType == InventorySlot.InventoryType.Item)
        {
            handToEquip = equippedItemSlot;
            inventoryToAlter = itemSlots;
        }
        if (handToEquip.Stackable(inventoryToAlter[slotIndex]))
        {
            ItemSlotData slotToAlter = inventoryToAlter[slotIndex];
            handToEquip.AddQuantity(slotToAlter.quantity);
            slotToAlter.Empty();
        }
        else
        {
            ItemSlotData slotToEquip = new ItemSlotData(inventoryToAlter[slotIndex]);
            inventoryToAlter[slotIndex] = new ItemSlotData(handToEquip);
            EquipHandSlot(slotToEquip);
        }
        if (inventoryType == InventorySlot.InventoryType.Item)
        {
            RenderHand();
        }
        UIManager.Instance.RenderInventory();
    }
    public void HandToInventory(InventorySlot.InventoryType inventoryType)
    {
        ItemSlotData handSlot = equippedToolSlot;
        ItemSlotData[] inventoryToAlter = toolSlots;
        if (inventoryType == InventorySlot.InventoryType.Item)
        {
            handSlot = equippedItemSlot;
            inventoryToAlter = itemSlots;
        }
        if (!StackItemToInventory(handSlot, inventoryToAlter))
        {
            for (int i = 0; i < inventoryToAlter.Length; i++)
            {
                if (inventoryToAlter[i].IsEmpty())
                {
                    inventoryToAlter[i] = new ItemSlotData(handSlot);
                    handSlot.Empty();
                    break;
                }
            }
        }
        if (inventoryType == InventorySlot.InventoryType.Item)
        {
            RenderHand();
        }
        UIManager.Instance.RenderInventory();
    }
    public bool StackItemToInventory(ItemSlotData itemSlot, ItemSlotData[] inventoryArray)
    {
        for (int i = 0; i < inventoryArray.Length; i++)
        {
            if (inventoryArray[i].Stackable(itemSlot))
            {
                inventoryArray[i].AddQuantity(itemSlot.quantity);
                itemSlot.Empty();
                return true;
            }
        }
        return false;
    }
    public void RenderHand()
    {
        if (handPoint.childCount > 0)
        {
            Destroy(handPoint.GetChild(0).gameObject);
        }
        if (SlotEquipped(InventorySlot.InventoryType.Item))
        {
            Instantiate(GetEquippedSlotItem(InventorySlot.InventoryType.Item).gameModel, handPoint);
        }
    }


    #region Gets and Checks

    public ItemData GetEquippedSlotItem(InventorySlot.InventoryType inventoryType)
    {
        if (inventoryType == InventorySlot.InventoryType.Item)
        {
            return equippedItemSlot.itemData;
        }
        return equippedToolSlot.itemData;
    }
    public ItemSlotData GetEquippedSlot(InventorySlot.InventoryType inventoryType)
    {
        if (inventoryType == InventorySlot.InventoryType.Item)
        {
            return equippedItemSlot;
        }
        return equippedToolSlot;
    }
    public ItemSlotData[] GetInventorySlots(InventorySlot.InventoryType inventoryType)
    {
        if (inventoryType == InventorySlot.InventoryType.Item)
        {
            return itemSlots;
        }
        return toolSlots;
    }
    public bool SlotEquipped(InventorySlot.InventoryType inventoryType)
    {
        if (inventoryType == InventorySlot.InventoryType.Item)
        {
            return !equippedItemSlot.IsEmpty();
        }
        return !equippedToolSlot.IsEmpty();
    }
    public bool IsTool(ItemData item)
    {
        EquipmentData equipment = item as EquipmentData;
        if (equipment != null)
        {
            return true;
        }
        SeedData seed = item as SeedData;
        return seed != null;
    }

    #endregion
    public void EquipHandSlot(ItemData item)
    {
        if (IsTool(item))
        {
            equippedToolSlot = new ItemSlotData(item);
        }
        else
        {
            equippedItemSlot = new ItemSlotData(item);
        }
    }
    //新建方法,重载
    public void EquipHandSlot(ItemSlotData itemSlot)
    {
        ItemData item = itemSlot.itemData;
        if (IsTool(item))
        {
            equippedToolSlot = new ItemSlotData(itemSlot);
        }
        else
        {
            equippedItemSlot = new ItemSlotData(itemSlot);
        }
    }
    #region Inventory Slot validation
    public void OnValidate()
    {
        ValidateInventorySlots(equippedToolSlot);
        ValidateInventorySlots(equippedItemSlot);

        ValidateInventorySlots(itemSlots);
        ValidateInventorySlots(toolSlots);
    }
    void ValidateInventorySlots(ItemSlotData slot)
    {
        if (slot.itemData != null && slot.quantity == 0)
        {
            slot.quantity = 1;
        }
    }
    void ValidateInventorySlots(ItemSlotData[] array)
    {
        foreach (ItemSlotData slot in array)
        {
            ValidateInventorySlots(slot);
        }
    }
    #endregion 
}

4、编辑InventoryManager.cs,

    //新建方法
    public void ConsumeItem(ItemSlotData itemSlot)
    {
        if (itemSlot.IsEmpty())
        {
            Debug.LogError("没有种子了");
            return;
        }
        itemSlot.Remove();
        RenderHand();
        UIManager.Instance.RenderInventory();
    }

5、编辑Land.cs

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

public class Land : MonoBehaviour, ITimeTracker
{
    public enum LandStatus { Soil, Farmland, Watered }
    public LandStatus landStatus;
    public Material soilMat, farmlandMat, wateredMat;
    new Renderer renderer;

    public GameObject select;
    GameTimestamp timeWatered;

    [Header("Crops")]
    public GameObject cropPrefab;
    CropBehaviour cropPlanted = null;
    void Start()
    {
        renderer = GetComponent<Renderer>();
        SwitchLandStatus(LandStatus.Soil);
        //select.SetActive(false);
        Select(false);
        TimeManager.Instance.RegisterTracker(this);
    }

    public void SwitchLandStatus(LandStatus statusToSwitch)
    {
        landStatus = statusToSwitch;
        Material materialToSwitch = soilMat;
        switch (statusToSwitch)
        {
            case LandStatus.Soil: materialToSwitch = soilMat; break;
            case LandStatus.Farmland: materialToSwitch = farmlandMat; break;
            case LandStatus.Watered:
                materialToSwitch = wateredMat;
                timeWatered = TimeManager.Instance.GetGameTimestamp();
                break;
        }
        renderer.material = materialToSwitch;
    }
    public void Select(bool toggle)
    {
        select.SetActive(toggle);
    }

    public void Interact()
    {
        ItemData toolSlot = InventoryManager.Instance.GetEquippedSlotItem(InventorySlot.InventoryType.Tool);

        //更改条件
        if(!InventoryManager.Instance.SlotEquipped(InventorySlot.InventoryType.Tool))
        {
            return;
        }
        EquipmentData equipmentTool = toolSlot as EquipmentData;
        if (equipmentTool != null)
        {
            EquipmentData.ToolType toolType = equipmentTool.toolType;

            switch (toolType)
            {
                case EquipmentData.ToolType.Hoe:
                    SwitchLandStatus(LandStatus.Farmland); break;
                case EquipmentData.ToolType.WateringCan:
                    if (landStatus == LandStatus.Farmland||landStatus ==LandStatus.Watered)
                    {
                        SwitchLandStatus(LandStatus.Watered);
                    }
                    break;
                case EquipmentData.ToolType.Shovel:
                    if(cropPlanted != null)
                    {
                        Destroy(cropPlanted.gameObject);
                    }
                    break;
            }
            return;
        }
        SeedData seedTool = toolSlot as SeedData;
        if (seedTool != null && landStatus !=LandStatus.Soil && cropPlanted==null)
        {
            GameObject cropObject =Instantiate(cropPrefab ,transform);
            cropObject.transform.position = new Vector3(transform.position.x,0f,transform.position.z);
            cropPlanted = cropObject.GetComponent<CropBehaviour>();
            cropPlanted.Plant(seedTool);

            //被使用后消失
            InventoryManager.Instance.ConsumeItem(InventoryManager.Instance.GetEquippedSlot(InventorySlot.InventoryType.Tool));
        }
    }

    public void ClockUpdate(GameTimestamp timestamp)
    {
        if (landStatus == LandStatus.Watered)
        {
            int hoursElapsed = GameTimestamp.CompareTimestamp(timeWatered, timestamp);
            if(cropPlanted != null)
            {
                cropPlanted.Grow();
            }
            if (hoursElapsed > 24)
            {
                SwitchLandStatus(LandStatus.Farmland);
            }
        }
        if(landStatus != LandStatus.Watered && cropPlanted != null)
        {
            if(cropPlanted.cropState != CropBehaviour.CropState.Seed)
            {
                cropPlanted.Wilter();
            }
        }
    }
}

6、编辑UIManager.cs,添加StatusBar下显示数量的文本

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

public class UIManager : MonoBehaviour, ITimeTracker
{
    public static UIManager Instance { get; private set; }
    private void Awake()
    {
        if (Instance != null && Instance != this) { Destroy(this); }
        else { Instance = this; }
    }

    [Header("Startas Bar")]
    public Image toolEquipSlotImage;
    public Text toolQuantityText;
    public Text timeText;
    public Text dateText;

    [Header("Inventory System")]

    public GameObject inventoryPanel;
    public HandInventorySlot toolHandSlot;
    public InventorySlot[] toolSlots;
    public HandInventorySlot itemHandSlot;
    public InventorySlot[] itemSlots;

    public Text itemNameText;
    public Text itemDescriptionText;

    private void Start()
    {
        RenderInventory();
        AssignSlotIndex();
        TimeManager.Instance.RegisterTracker(this);
    }
    public void AssignSlotIndex()
    {
        for (int i = 0; i < toolSlots.Length; i++)
        {
            toolSlots[i].AssignIndex(i);
            itemSlots[i].AssignIndex(i);
        }
    }
    public void RenderInventory()
    {
        ItemSlotData[] inventoryToolSlots = InventoryManager.Instance.GetInventorySlots(InventorySlot.InventoryType.Tool);
        ItemSlotData[] inventoryItemSlots = InventoryManager.Instance.GetInventorySlots(InventorySlot.InventoryType.Item);

        RenderInventoryPanel(inventoryToolSlots, toolSlots);
        RenderInventoryPanel(inventoryItemSlots, itemSlots);
        toolHandSlot.Display(InventoryManager.Instance.GetEquippedSlot(InventorySlot.InventoryType.Tool));
        itemHandSlot.Display(InventoryManager.Instance.GetEquippedSlot(InventorySlot.InventoryType.Item));
        ItemData equippedTool = InventoryManager.Instance.GetEquippedSlotItem(InventorySlot.InventoryType.Tool);

        //数量文本
        toolQuantityText.text = "";

        if (equippedTool != null)
        {
            toolEquipSlotImage.sprite = equippedTool.thumbnail;
            toolEquipSlotImage.gameObject.SetActive(true);

            //数量文本
            int quantity = InventoryManager.Instance.GetEquippedSlot(InventorySlot.InventoryType.Tool).quantity;
            if (quantity > 1)
            {
                toolQuantityText.text = quantity.ToString();
            }
            return;
        }
        toolEquipSlotImage.gameObject.SetActive(false);
    }
    void RenderInventoryPanel(ItemSlotData[] slots, InventorySlot[] uiSlots)
    {
        for (int i = 0; i < uiSlots.Length; i++)
        {
            uiSlots[i].Display(slots[i]);
        }
    }
    public void ToggleInventoryPanel()
    {
        inventoryPanel.SetActive(!inventoryPanel.activeSelf);
        RenderInventory();
    }

    public void DisplayItemInfo(ItemData data)
    {
        if (data == null)
        {
            itemNameText.text = "";
            itemDescriptionText.text = "";
            return;
        }
        itemNameText.text = data.name;
        itemDescriptionText.text = data.description;
    }
    public void ClockUpdate(GameTimestamp timestamp)
    {
        int hours = timestamp.hour;
        int minutes = timestamp.minute;

        string prefix = "AM ";
        if (hours > 12)
        {
            prefix = "PM ";
            hours -= 12;
        }
        timeText.text = prefix + hours + ":" + minutes.ToString("00");
        int day = timestamp.day;
        string season = timestamp.season.ToString();
        string dayOfTheWeek = timestamp.GetDayOfTheWeek().ToString();

        dateText.text = season + " " + day + " (" + dayOfTheWeek + ")";
    }
}

7、赋值

【实例教程1】怎样编写一个插件? 1. 插件的注释与定义参数 2. 读取插件参数 3. 插件指令的实现 【实例教程2】制作一个启动画面 1. 从哪里开始? 2. 创建启动画面的场景类 【实例教程3】玩转菜单初级篇 1. 给各个菜单界面添加背景 2. 让背景滚动起来 3. 在主菜单界面增加自定义菜单:改名 4. 在主菜单界面移除菜单命令 5. 在主菜单界面增加一个自定义窗口 【实例教程4】玩转标题画面 1. 美化游戏标题 2. 让背景动起来 3. 自定义标题菜单 4. 美化菜单 【实例教程5】制作小游戏:坦克大战(上) 1. 游戏结构及流程介绍 2. 相关素材资源的下载和使用 3. 基础知识:音效的播放 4. 基础知识:精灵表的切帧 5. 基础知识:使用MV中的动画 6. Scene_TankWarTitle类解析 7. Sprite_Bullet类解析 8. Sprite_Explode类解析 9. Sprite_Tank类解析 10. Sprite_Enemy类解析 11. Scene_TankWar类解析 12. Scene_TankWarGameOver类解析 【实例教程6】存档的加密解密与保护 1. 找出MV存档和读档的方式 2. 制作MV存档的修改器 3. 如何保护存档? 4. 制作一个存档保护插件 【实例教程7】制作一个传送插件 1. 传送插件的主要功能 2. 将自定义数据保存到存档中 3. meta数据的使用 4. 使用地图备注登记传送点 5. 在插件中解析并记录传送点 6. 使用地图备注登记多个传送点并在插件中记录 7. 制作传送点选取窗口显示传送点数据 8. 将物品或技能标记为传送物品、传送技能 9. 显示传送动画实现传送功能 10. 禁止使用传送道具或传送技能 11. 实现插件命令
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值