[No. 13 of 100 Games Realized with Unity] A replica of the Tyrilia-like survival and construction game—including the construction system and inventory system

Preface

This article implements a demo of a Tyrelia-like game, which mainly includes the classic inventory system and construction system.

Note: The article is mainly divided into three parts: construction system, inventory system and combination of construction system and inventory system. The construction system and inventory system are implemented independently of each other and can be extracted and used separately.

Let’s take a look at the final effect first
Insert image description here

material

figure

https://assetstore.unity.com/packages/2d/characters/warrior-free-asset-195707
Insert image description here

tiles

https://assetstore.unity.com/packages/2d/environments/platform-tile-pack-204101
Insert image description here

other

Insert image description here
Insert image description here
Insert image description here
Insert image description here

1. Construction system

1. Define item categories

Game item base class

using UnityEngine;
using UnityEngine.Tilemaps;

// 创建一个 ScriptableObject,用于表示游戏物品
[CreateAssetMenu(menuName = "GameObject/Item")]
public class Item : ScriptableObject
{
    
    
    public TileBase tile;   // 物品对应的瓦片
    public Sprite image;    // 物品的图像
    public ItemType type;   // 物品的类型
    public ActionType actionType;   // 物品的动作类型

    public Vector2Int range = new Vector2Int(5, 4);   // 物品的范围,默认为 5x4
}

// 定义枚举类型 ItemType,表示物品的类型
public enum ItemType
{
    
    
    BuildingBlock,   // 建筑块物品类型
    Tool   // 工具物品类型
}

// 定义枚举类型 ActionType,表示动作的类型
public enum ActionType
{
    
    
    Dig,   // 挖掘动作类型
    Mine   // 开采动作类型
}
using UnityEngine;

// 创建一个继承自 RuleTile 的自定义规则瓦片
[CreateAssetMenu(menuName = "Tiles/Custom Rule Tile")]
public class RuleTileWithData : RuleTile
{
    
    
    public Item item;   // 规则瓦片对应的物品数据
}

ps: The significance of RuleTileWithData is to extend Unity's own RuleTile class, allowing us to associate additional item data (Item) in rule tiles. The advantage of this is that we can directly obtain the item information associated with a specific tile in a map using regular tiles, without the need for additional lookups or maintenance of data structures.

Add game items and RuleTileWithData
Insert image description here

Insert image description here

Insert image description here
Mining is the same

2. Draw a map

Simply draw a map
Insert image description here

3. Implement tile selection effect

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

public class BuildingSystem : MonoBehaviour
{
    
    
    [SerializeField] private Item item;             // 当前选中的物品
    [SerializeField] private TileBase highlightTile; // 高亮显示瓦片所使用的 TileBase
    [SerializeField] private Tilemap mainTilemap;   // 主要的地图瓦片对象
    [SerializeField] private Tilemap tempTilemap;   // 临时地图瓦片对象,用于显示高亮瓦片
    private Vector3Int highlightedTilePos;          // 高亮显示的瓦片在网格中的位置
    private bool highlighted;                       // 是否在高亮显示

    private void Update()
    {
    
    
        // 如果当前有选中的物品,则在 Update 方法中更新高亮显示
        if (item != null)
        {
    
    
            HighlightTile(item);
        }
    }

    private Vector3Int GetMouseOnGridPos()
    {
    
    
        // 获取鼠标在当前网格中的位置
        Vector3 mousePos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
        Vector3Int mouseCellPos = mainTilemap.WorldToCell(mousePos);
        mouseCellPos.z = 0;
        return mouseCellPos;
    }

    private void HighlightTile(Item currentItem)
    {
    
    
        // 获取鼠标在当前网格中的位置
        Vector3Int mouseGridPos = GetMouseOnGridPos();

        // 如果当前高亮显示的瓦片位置不等于鼠标位置,则更新高亮显示
        if (highlightedTilePos != mouseGridPos)
        {
    
    
            // 清除之前高亮显示的瓦片
            tempTilemap.SetTile(highlightedTilePos, null);

            // 获取当前位置的瓦片,并在临时地图瓦片对象上高亮显示
            TileBase tile = mainTilemap.GetTile(mouseGridPos);
            if (tile)
            {
    
    
                tempTilemap.SetTile(mouseGridPos, highlightTile);
                highlightedTilePos = mouseGridPos;
                highlighted = true;
            }
            else
            {
    
    
                highlighted = false;
            }
        }
    }
}

Main Tilemap draws the map, Temp Tilemap is used to display the check box
Insert image description here

Mount script, configuration parameters
Insert image description here

Effect
Insert image description here

4. Limit tile selection

According to the range in the Item, the control tile can only be selected in a certain area of ​​the character.

ModifyBuildingSystem

private Vector3Int playerPos;   //玩家位置

//。。。

private void Update()
{
    
    
    playerPos = mainTilemap.WorldToCell(transform.position);
    // 如果当前有选中的物品,则在 Update 方法中更新高亮显示
    if (item != null)
    {
    
    
        HighlightTile(item);
    }
}
private void HighlightTile(Item currentItem)
{
    
    
    // 获取鼠标在当前网格中的位置
    Vector3Int mouseGridPos = GetMouseOnGridPos();

    // 如果当前高亮显示的瓦片位置不等于鼠标位置,则更新高亮显示
    if (highlightedTilePos != mouseGridPos)
    {
    
    
        // 清除之前高亮显示的瓦片
        tempTilemap.SetTile(highlightedTilePos, null);

        // 检查鼠标位置与玩家位置是否在范围内
        if (InRange(playerPos, mouseGridPos, (Vector3Int)currentItem.range))
        {
    
    
            // 获取鼠标位置上的瓦片,并检查条件 GetTile获取指定坐标格子瓦片
            if (CheckCondition(mainTilemap.GetTile<RuleTileWithData>(mouseGridPos), currentItem))
            {
    
    
                // 在临时地图瓦片对象上高亮显示瓦片
                tempTilemap.SetTile(mouseGridPos, highlightTile);
                highlightedTilePos = mouseGridPos;
                highlighted = true;
            }
            else
            {
    
    
                highlighted = false;
            }
        }
        else
        {
    
    
            highlighted = false;
        }
    }
}
//判断鼠标位置与玩家位置是否在范围内
private bool InRange(Vector3Int positionA, Vector3Int positionB, Vector3Int range)
{
    
    
    // 判断两个位置之间的距离是否在范围内
    Vector3Int distance = positionA - positionB;
    if (Math.Abs(distance.x) >= range.x || Math.Abs(distance.y) >= range.y)
    {
    
    
        return false;
    }
    return true;
}

//检查瓦片与当前物品的条件是否匹配
private bool CheckCondition(RuleTileWithData tile, Item currentItem)
{
    
    
    // 检查瓦片与当前物品的条件是否匹配
    if (currentItem.type == ItemType.BuildingBlock)
    {
    
    
        if (!tile)
        {
    
    
            return true;
        }
    }
    else if (currentItem.type == ItemType.Tool)
    {
    
    
        if (tile)
        {
    
    
            if (tile.item.actionType == currentItem.actionType)
            {
    
    
                return true;
            }
        }
    }
    return false;
}

Effect
Insert image description here

5. Place items function

BuildingSystem new features

private void Update()
{
    
    
     if (Input.GetMouseButtonDown(0))// 当玩家按下左键时
     {
    
    
         if (highlighted)
         {
    
    
             if (item.type == ItemType.BuildingBlock)// 如果当前选中的物品是建筑方块
             {
    
    
                 Build(highlightedTilePos, item);// 放置方块
             }
         }
     }
 }
// 放置方块
private void Build(Vector3Int position, Item itemToBuild)
{
    
    
    tempTilemap.SetTile(position, null);// 清除临时 Tilemap 上的方块
    highlighted = false;// 取消高亮状态
    mainTilemap.SetTile(position, itemToBuild.tile);// 在主 Tilemap 上放置方块
}

For testing, first change the item type to BuildingBlock
Insert image description here

Effect
Insert image description here

6. Clear items

private void Update()
{
    
    
   if (Input.GetMouseButtonDown(0))// 当玩家按下左键时
   {
    
    
       if (highlighted)
       {
    
    
           if (item.type == ItemType.BuildingBlock)// 如果当前选中的物品是建筑方块
           {
    
    
               Build(highlightedTilePos, item);// 放置方块
           }
           else if (item.type == ItemType.Tool)// 如果当前选中的物品是工具
           {
    
    
               Destroy(highlightedTilePos);// 移除方块
           }
       }
   }
}
// 移除方块以及生成相应物品
private void Destroy(Vector3Int position)
{
    
    
    tempTilemap.SetTile(position, null);// 清除临时 Tilemap 上的方块
    highlighted = false;// 取消高亮状态
    RuleTileWithData tile = mainTilemap.GetTile<RuleTileWithData>(position);// 获取当前位置上的方块数据
    mainTilemap.SetTile(position, null);// 在主 Tilemap 上移除方块
}

For testing, first change the item type to Tool
Insert image description here

Effect
Insert image description here

7. Generate and pick up items function

Added Loot prefab for displaying items
Insert image description here
Insert image description here

Added script Loot

using System.Collections;
using UnityEngine;

public class Loot : MonoBehaviour
{
    
    
    [SerializeField] private SpriteRenderer sr; // 用于显示物品图像的组件
    [SerializeField] private new BoxCollider2D collider; // 触发器组件
    [SerializeField] private float moveSpeed; // 拾取时的移动速度
    private Item item; // 表示此物品的数据模型

    // 初始化物品
    public void Initialize(Item item)
    {
    
    
        this.item = item;
        sr.sprite = item.image; // 显示物品图像
    }

    // 当进入触发器时执行的逻辑
    private void OnTriggerEnter2D(Collider2D other)
    {
    
    
        if (other.CompareTag("Player"))
        {
    
    
            StartCoroutine(MoveAndCollect(other.transform)); // 开始移动并拾取物品
        }
    }

    // 移动并拾取物品的逻辑
    private IEnumerator MoveAndCollect(Transform target)
    {
    
    
        Destroy(collider); // 拾取后销毁触发器
        while (transform.position != target.position)
        {
    
    
            transform.position = Vector3.MoveTowards(transform.position, target.position, moveSpeed * Time.deltaTime); // 向目标移动
            yield return 0;
        }

        Destroy(gameObject); // 拾取完成后销毁物品对象
    }
}

Mount the script and configure parameters
Insert image description here

Modify BuildingSystem to generate items

[SerializeField] private GameObject lootPrefab;// 拾取物品时生成的对象

// 移除方块以及生成相应物品
private void Destroy(Vector3Int position)
{
    
    
    //。。。
    
    Vector3 pos = mainTilemap.GetCellCenterWorld(position);// 获取方块中心的世界坐标
    GameObject loot = Instantiate(lootPrefab, pos, Quaternion.identity);// 创建拾取物品
    loot.GetComponent<Loot>().Initialize(tile.item);// 初始化拾取物品数据
}

Remember to mount the prefabricated body and modify the Player tag to
Insert image description here
run the effect
Insert image description here
. For better effects, you can remove the direct collision of items and reduce the size of the generated object
Insert image description here
.
Insert image description here

2. Inventory system

1. Simple drawing UI

I won’t go into detail about UI drawing here to save everyone’s time. I’ve talked about it many times in previous articles. If you don’t understand, you can read my previous articles.

Hierarchy
Insert image description here

Effect
Insert image description here

2. Zero code to control the opening and closing of the backpack

Click on the backpack to display the backpack and hide the button.
Insert image description here
Click on the background to hide the backpack and turn on the button.
Insert image description here
Effect

Insert image description here

3. Implement dragging of items

Drag and drop function

Add an item prefab to the item slot subset and mount the new script InventoryItem
Insert image description here

InventoryItem script

using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;

public class InventoryItem : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler
{
    
    
    [Header("UI")]
    [HideInInspector] public Image image; // 物品的图像组件
    [HideInInspector] public Transform parentAfterDrag; // 记录拖拽前的父级位置

    //开始拖拽时调用
    public void OnBeginDrag(PointerEventData eventData)
    {
    
    
        image = transform.GetComponent<Image>();
        image.raycastTarget = false; // 禁用射线检测,防止拖拽物体遮挡其他UI元素的交互
        parentAfterDrag = transform.parent; // 记录拖拽前的父级位置
        //transform.root 是用来获取当前对象的根物体,这里及是Canvas
        transform.SetParent(transform.root); // 设置拖拽物体的父级为Canvas,以保证拖拽物体在最上层显示
    }

    //拖拽过程中调用
    public void OnDrag(PointerEventData eventData)
    {
    
    
        transform.position = Input.mousePosition; // 将拖拽物体的位置设置为鼠标的当前位置
    }

    //拖拽结束时调用
    public void OnEndDrag(PointerEventData eventData)
    {
    
    
        image.raycastTarget = true; // 启用射线检测
        transform.SetParent(parentAfterDrag); // 恢复拖拽结束后物品的父级位置
    }
}

Effect
Insert image description here

Drag and drop recovery problem

You will find that the item does not return to its original position after dragging, even if we have restored the parent position of the item after dragging.

This is because we have not restored the position of the item. Here we can add a Grid Layout Group component to the parent of the item, that is, the item slot, to forcefully define the layout position of the child object. Running
Insert image description here
effect
Insert image description here

4. Drag and drop items

Added InventorySlot script, mounted in the item slot

using UnityEngine;
using UnityEngine.EventSystems;

public class InventorySlot : MonoBehaviour, IDropHandler
{
    
    
    // 在拖拽物体放置在目标对象上时被调用
    public void OnDrop(PointerEventData eventData)
    {
    
    
    	//检查背包槽是否没有子物体(即没有物品),只有背包槽为空才能放置物品。
        if (transform.childCount == 0)
        {
    
    
        	//从拖拽事件的 pointerDrag 对象中获取拖拽的物品
            InventoryItem inventoryItem = eventData.pointerDrag.GetComponent<InventoryItem>();
            inventoryItem.parentAfterDrag = transform;
        }
    }
}

Effect
Insert image description here

5. Define item attributes

using UnityEngine;
using UnityEngine.Tilemaps;

// 创建一个 ScriptableObject,用于表示游戏物品
[CreateAssetMenu(menuName = "GameObject/Item")]
public class Item : ScriptableObject
{
    
    
    [Header("游戏内")]
    public TileBase tile;   // 物品对应的瓦片
    public ItemType type;   // 物品的类型
    public ActionType actionType;   // 物品的动作类型
    public Vector2Int range = new Vector2Int(5, 4);   // 物品的范围,默认为 5x4

    [Header("UI内")]
    public bool stackable = true;//是否可叠起堆放的,默认是

    [Header("两者")]
    public Sprite image;    // 物品的图像
}

// 定义枚举类型 ItemType,表示物品的类型
public enum ItemType
{
    
    
    BuildingBlock,   // 建筑块物品类型
    Tool   // 工具物品类型
}

// 定义枚举类型 ActionType,表示动作的类型
public enum ActionType
{
    
    
    Dig,   // 挖掘动作类型
    Mine   // 开采动作类型
}

Create several different items,
Insert image description here
modify InventoryItem, and initialize different props

public Item item;

private void Start()
{
    
    
   image = transform.GetComponent<Image>();
   InitialiseItem(item);
}

public void InitialiseItem(Item newItem)
{
    
    
   image.sprite = newItem.image;
}

For testing purposes, we configure several different item
Insert image description here
effects
Insert image description here

6. Find an empty spot in the inventory

In actual use, we definitely cannot configure different items through mounting, so we make modifications, wait for subsequent use, and hide the items.

[HideInInspector] public Image image; // 物品的图像组件
[HideInInspector] public Item item;
[HideInInspector] public Transform parentAfterDrag; // 记录拖拽前的父级位置

private void Start()
{
    
    
    image = transform.GetComponent<Image>();
}

public void InitialiseItem(Item newItem)
{
    
       
    item = newItem;
    image.sprite = newItem.image;
}

Added InventoryManager code to find free locations in the inventory and add items

using UnityEngine;

public class InventoryManager : MonoBehaviour
{
    
    
    public InventorySlot[] inventorySlots; // 背包槽数组
    public GameObject inventoryItemPrefab; // 物品预制体

	private void Start()
    {
    
    
        //判断inventorySlots是否为空
        if (inventorySlots.Length <= 0)
        {
    
    
            Debug.Log("背包槽数组没有配置,请先配置好!");
            return;
        }
    }
    
    // 添加物品到背包
    public void AddItem(Item item)
    {
    
    
        for (int i = 0; i < inventorySlots.Length; i++)
        {
    
    
            InventorySlot slot = inventorySlots[i]; // 获取当前遍历的背包槽
            InventoryItem itemInSlot = slot.GetComponentInChildren<InventoryItem>(); // 在背包槽中查找是否已经存在物品

            if (itemInSlot == null) // 如果背包槽内没有物品
            {
    
    
                SpawnNewItem(item, slot); // 生成新的物品到这个背包槽中
                return;
            }
        }
    }

    // 生成新的物品到背包槽中
    void SpawnNewItem(Item item, InventorySlot slot)
    {
    
    
        GameObject newItemGo = Instantiate(inventoryItemPrefab, slot.transform); // 实例化物品预制体并设置父级为当前的背包槽
        InventoryItem inventoryItem = newItemGo.GetComponent<InventoryItem>(); // 获取生成物品的 InventoryItem 组件
        inventoryItem.InitialiseItem(item); // 初始化物品信息
    }
}

Added InventoryManager empty node, mounting script, binding and mounting all item slots
Insert image description here

Added Test test script for testing the function of adding items

using UnityEngine;

public class Test : MonoBehaviour
{
    
    
    public InventoryManager inventoryManager;
    public Item[] itemsToPickup;
    public void PickupItem(int id)
    {
    
    
        inventoryManager.AddItem(itemsToPickup[id]);
    }
}

Add a new test panel to mount the test script, and add several new buttons to test
Insert image description here
the effect
Insert image description here

7. Determination of full inventory

There is a problem before. If our inventory is full, the picked items will disappear. At this time, we need to modify the AddItem method of InventoryManager to return to the state of adding items.

// 添加物品到背包
public bool AddItem(Item item)
{
    
    
    for (int i = 0; i < inventorySlots.Length; i++)
    {
    
    
        InventorySlot slot = inventorySlots[i]; // 获取当前遍历的背包槽
        InventoryItem itemInSlot = slot.GetComponentInChildren<InventoryItem>(); // 在背包槽中查找是否已经存在物品

        if (itemInSlot == null) // 如果背包槽内没有物品
        {
    
    
            SpawnNewItem(item, slot); // 生成新的物品到这个背包槽中
            return true;
        }
    }
    return false;
}

Modify the Test code synchronously and determine whether the item is added successfully based on the return value.

public void PickupItem(int id)
{
    
    
    bool result = inventoryManager.AddItem(itemsToPickup[id]);
    if (result == true)
    {
    
    
        Debug.Log("添加物品");
    }
    else
    {
    
    
        Debug.Log("添加物品失败,库存已满");
    }
}

Effect
Insert image description here

8. Item quantity display

Add a Text text to the subset of items to display the number of items, and add the Canvas Group component. Set the blocksRaycasts property of this component to false, which means that during the entire process when we first start dragging, the mouse will not move again. Treat this UI item as a blocker, including all UI objects of its sub-objects
Insert image description here

And modify the InventoryItem item script

[HideInInspector] public GameObject countText; // 数量文本
[HideInInspector] public int count = 1; //默认数量


public void InitialiseItem(Item newItem)
{
    
    
	countText = transform.GetChild(0).gameObject;
    item = newItem;
    image.sprite = newItem.image;
    RefreshCount();
}

public void RefreshCount()
{
    
    
    countText.GetComponent<TextMeshProUGUI>().text = count.ToString();

}

Effect
Insert image description here
If the calculation is 1, we can choose to hide the quantity display, so the effect will be better

public void RefreshCount()
{
    
    
     countText.GetComponent<TextMeshProUGUI>().text = count.ToString();

     //控制数量显示隐藏 大于1才显示
     bool textActive  = count > 1;
     countText.gameObject.SetActive(textActive);
 }

Effect
Insert image description here
Randomly add quantity, test

public void InitialiseItem(Item newItem)
{
    
    
     countText = transform.GetChild(0).gameObject;
     item = newItem;
     image.sprite = newItem.image;
     count = Random.Range(1, 4);//随机添加物品数量测试
     RefreshCount();
 }

Effect
Insert image description here

9. Item stacking

Modify InventoryManager

public int maxStackedItems = 4; //最大堆叠数量,默认4

// 添加物品到背包
public bool AddItem(Item item)
{
    
    
    for (int i = 0; i < inventorySlots.Length; i++)
    {
    
    
        InventorySlot slot = inventorySlots[i]; // 获取当前遍历的背包槽
        InventoryItem itemInSlot = slot.GetComponentInChildren<InventoryItem>(); // 在背包槽中查找是否已经存在物品

        if (itemInSlot == null) // 如果背包槽内没有物品
        {
    
    
            SpawnNewItem(item, slot); // 生成新的物品到这个背包槽中
            return true;
        }
        else if (itemInSlot.item == item && itemInSlot.count < maxStackedItems && itemInSlot.item.stackable == true)
        {
    
    
            itemInSlot.count++;//添加数量
            itemInSlot.RefreshCount();
            return true;
        }
    }
    return false;
}

Effect
Insert image description here

10. Shortcut bar item selection

We provide selected visual effects by modifying the background color of the selected items.
Modify the InventorySlot code.

private Image image;
public Color selectedColor, notSelectedColor;

private void Awake()
{
    
    
    image = GetComponent<Image>();
    Deselect();// 初始化时取消选中
}
//选择该槽位颜色修改
public void Select()
{
    
    
    image.color = selectedColor;
}
//取消选择该槽位颜色修改
public void Deselect()
{
    
    
    image.color = notSelectedColor;
}

Modify InventoryManager

int selectedSlot = -1;

private void Start()
{
    
    
    ChangeSelectedSlot(0);//默认选中第一个槽
}

void ChangeSelectedSlot(int newValue)
{
    
    
    if (selectedSlot >= 0)
    {
    
    
        inventorySlots[selectedSlot].Deselect();// 取消之前选中的槽位
    }
    inventorySlots[newValue].Select();// 选择新的槽位
    selectedSlot = newValue;// 更新选中的槽位索引
}

Effect
Insert image description here
1-6 keyboard numbers to achieve switching

Modify InventoryManager code

private void Update(){
    
    
  	if (Input.GetKeyDown (KeyCode.Alpha1))
        ChangeSelectedSlot(0);
    else if (Input.GetKeyDown(KeyCode.Alpha2))
        ChangeSelectedSlot(1);
    else if (Input.GetKeyDown(KeyCode.Alpha3))
        ChangeSelectedSlot(2);
    else if (Input.GetKeyDown(KeyCode.Alpha4))
        ChangeSelectedSlot(3);
    else if (Input.GetKeyDown(KeyCode.Alpha5))
        ChangeSelectedSlot(4);
    else if (Input.GetKeyDown(KeyCode.Alpha6))
        ChangeSelectedSlot(5);
    else if (Input.GetKeyDown(KeyCode.Alpha7))
        ChangeSelectedSlot(6);
}

Optimize code

private void Update()
{
    
    
    if (Input.inputString != null)
    {
    
    
        bool isNumber = int.TryParse(Input.inputString, out int number);
        if (isNumber & number > 0 & number < 8) ChangeSelectedSlot(number - 1);
    }
}

Effect
Insert image description here

11. Select tool functions

InventoryManager adds a new method for selecting items

// 获取当前选中物品
public Item GetSelectedItem(){
    
    
	if (inventorySlots.Length > 0)
    {
    
    
	    InventorySlot slot = inventorySlots[selectedSlot];// 获取当前选中槽位
	    InventoryItem itemInSlot = slot.GetComponentInChildren<InventoryItem>();// 获取槽位上的物品
	    if (itemInSlot != null) return itemInSlot.item;// 如果有物品,则返回物品
	}
    return null;//如果没有选中物品则返回null
}

Test printing in Test script

//获取当前选中物品并打印输出
public void GetSelectedItem()
{
    
    
    Item receivedItem = inventoryManager.GetSelectedItem();//获取当前选中物品
    if (receivedItem != null)
    {
    
    
        Debug.Log("选中物品:" + receivedItem);
    }
    else
    {
    
    
        Debug.Log("没有选中物品!");
    }
}

Add button test
Insert image description here

12. Delete items using items

Modify the InventoryManagerGetselectedItem method

// 获取当前选中物品
public Item GetSelectedItem(bool use)
{
    
    
	if (inventorySlots.Length > 0){
    
    
	    InventorySlot slot = inventorySlots[selectedSlot];// 获取当前选中槽位
	    InventoryItem itemInSlot = slot.GetComponentInChildren<InventoryItem>();// 获取槽位上的物品
	    if (itemInSlot != null)
	    {
    
    
	        Item item = itemInSlot.item;
	        //是否使用物品
	        if (use == true)
	        {
    
    
	            itemInSlot.count--;//减少库存
	            if (itemInSlot.count <= 0)
	            {
    
    
	                Destroy(itemInSlot.gameObject);//删除物品
	            }
	            else
	            {
    
    
	                itemInSlot.RefreshCount();//更新数量文本显示
	            }
	        }
	        return item;
	    }
	}
    return null;//如果没有选中物品则返回null
}

Test new method test

//使用物品测试
public void UseSelectedItem()
{
    
    
    Item receivedItem = inventoryManager.GetSelectedItem(true);//获取当前使用的物品
    if (receivedItem != null)
    {
    
    
        Debug.Log("使用物品:" + receivedItem);
    }
    else
    {
    
    
        Debug.Log("没有可使用的物品!");
    }
}

Effect
Insert image description here

3. Integration of construction system and inventory system

Move all the UI of the inventory system into the construction system and reset the item slot information
Insert image description here

Modify the InventoryManager so that when the configuration starts, the item information of the item is displayed by default.

public Item[] startItems; //默认物品列表

private void Start()
{
    
    
     ChangeSelectedSlot(0);//默认选中第一个槽
     foreach (var item in startItems){
    
    
         AddItem(item);
     }
 }

Here I configure two tools by default
Insert image description here

Modify InventoryManager to be a singleton to facilitate calling from other places

public static InventoryManager instance;

void Awake(){
    
    
   instance = this;
}

Modify the BuildingSystem to obtain the currently selected items

// [SerializeField] private Item item;             // 当前选中的物品

private void Update()
{
    
    
    Item item = InventoryManager.instance.GetSelectedItem(false);
}

Collect items and modify Loot code

// 当进入触发器时执行的逻辑
private void OnTriggerEnter2D(Collider2D other)
{
    
    
    if (other.CompareTag("Player"))
    {
    
    
        bool canAdd = InventoryManager.instance.AddItem(item);
        if (canAdd)
        {
    
    
            StartCoroutine(MoveAndCollect(other.transform));// 开始移动并拾取物品
        }
    }
}

Use reduced items and modify the BuildingSystem code

// 放置方块
private void Build(Vector3Int position, Item itemToBuild)
{
    
    
    InventoryManager.instance.GetSelectedItem(true);
    
    tempTilemap.SetTile(position, null);// 清除临时 Tilemap 上的方块
    highlighted = false;// 取消高亮状态
    mainTilemap.SetTile(position, itemToBuild.tile);// 在主 Tilemap 上放置方块
}

final effect

Insert image description here

Source code

I'll put it up after I've sorted it out.

end

Gifts of roses, hand a fragrance! If the content of the article is helpful to you, please don't be stingy with your 点赞评论和关注feedback so that I can receive feedback as soon as possible. Your every feedback 支持is the biggest motivation for me to continue creating. The more likes, the faster the updates will be! Of course, if you find 存在错误something in the article 更好的解决方法, please feel free to comment and send me a private message!

Okay, I am 向宇, https://xiangyu.blog.csdn.net

A developer who has been working quietly in a small company recently started studying Unity by himself out of interest. If you encounter any problems, you are also welcome to comment and send me a private message. Although I may not necessarily know some of the problems, I will check the information from all parties and try to give the best suggestions. I hope to help more people who want to learn programming. People, encourage each other~
Insert image description here

Guess you like

Origin blog.csdn.net/qq_36303853/article/details/133104080