【用unity实现100个游戏之13】复刻类泰瑞利亚生存建造游戏——包括建造系统和库存系统

news2025/5/12 4:54:06

文章目录

  • 前言
  • 素材
    • 人物
    • 瓦片
    • 其他
  • 一、建造系统
    • 1. 定义物品类
    • 2. 绘制地图
    • 3. 实现瓦片选中效果
    • 4. 限制瓦片选择
    • 5. 放置物品功能
    • 6. 清除物品
    • 7. 生成和拾取物品功能
  • 二、库存系统
    • 1. 简单绘制UI
    • 2. 零代码控制背包的开启关闭
    • 3. 实现物品的拖拽
      • 拖拽功能
      • 拖拽恢复问题
    • 4. 拖拽放置物品
    • 5. 定义物品属性
    • 6. 在库存中寻找空闲位置
    • 7. 满库存判断
    • 8. 物品数量显示
    • 9. 物品堆叠
    • 10. 快捷栏物品选择
    • 11. 选中工具功能
    • 12. 使用物品 删除物品
  • 三、建造系统和库存系统结合
  • 最终效果
  • 源码
  • 完结

前言

本文来实现一个类泰瑞利亚游戏的demo,其中主要包括经典的库存系统和建造系统

注意:文章主要分为建造系统、库存系统和建造系统和库存系统结合三大部分,其中建造系统和库存系统相互独立实现,都可以单独提取出来使用

先来看看最终效果
在这里插入图片描述

素材

人物

https://assetstore.unity.com/packages/2d/characters/warrior-free-asset-195707
在这里插入图片描述

瓦片

https://assetstore.unity.com/packages/2d/environments/platform-tile-pack-204101
在这里插入图片描述

其他

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

一、建造系统

1. 定义物品类

游戏物品基类

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:RuleTileWithData 的意义在于扩展了 Unity 自带的 RuleTile 类,允许我们在规则瓦片中关联额外的物品数据(Item)。这样做的好处是,我们可以在使用规则瓦片的地图中,直接获取与特定瓦片关联的物品信息,而不需要额外的查找或维护数据结构。

添加游戏物品和RuleTileWithData
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
Mining同理

2. 绘制地图

简单绘制一个地图
在这里插入图片描述

3. 实现瓦片选中效果

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绘制地图,Temp Tilemap用于显示选中框
在这里插入图片描述

挂载脚本,配置参数
在这里插入图片描述

效果
在这里插入图片描述

4. 限制瓦片选择

按Item里的range,控制瓦片只能在人物一定区域可选中

修改BuildingSystem

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;
}

效果
在这里插入图片描述

5. 放置物品功能

BuildingSystem新增功能

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 上放置方块
}

为了测试,先修改item类型为BuildingBlock
在这里插入图片描述

效果
在这里插入图片描述

6. 清除物品

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 上移除方块
}

为了测试,先修改item类型为Tool
在这里插入图片描述

效果
在这里插入图片描述

7. 生成和拾取物品功能

新增Loot预制体,用于显示物品
在这里插入图片描述
在这里插入图片描述

新增脚本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); // 拾取完成后销毁物品对象
    }
}

挂载脚本,并配置参数
在这里插入图片描述

修改BuildingSystem生成物品

[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);// 初始化拾取物品数据
}

记得挂载预制体,修改Player标签
在这里插入图片描述
运行效果
在这里插入图片描述
为了效果更好,可以去除物品直接的碰撞,并减小生成物的大小
在这里插入图片描述
效果
在这里插入图片描述

二、库存系统

1. 简单绘制UI

UI绘制这里就不多说了,节省大家时间,之前文章已经说了很多次了,不懂得可以去看我往期的文章

层级
在这里插入图片描述

效果
在这里插入图片描述

2. 零代码控制背包的开启关闭

点击背包显示背包,隐藏按钮
在这里插入图片描述
点击背景隐藏背包,开启按钮
在这里插入图片描述
效果

在这里插入图片描述

3. 实现物品的拖拽

拖拽功能

在物品插槽子集新增一个物品预制体,并挂载新增脚本InventoryItem
在这里插入图片描述

InventoryItem 脚本

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); // 恢复拖拽结束后物品的父级位置
    }
}

效果
在这里插入图片描述

拖拽恢复问题

你会发现,拖拽结束物品并没有回到原来的位置,即使我们已经恢复了拖拽结束后物品的父级位置

这是因为物品的位置我们并没有恢复,这里我们可以给在物品父级,也就是物品插槽中新增Grid Layout Group组件,强制定义子物体的布局位置
在这里插入图片描述
运行效果
在这里插入图片描述

4. 拖拽放置物品

新增InventorySlot 脚本,挂载在物品插槽

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;
        }
    }
}

效果
在这里插入图片描述

5. 定义物品属性

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   // 开采动作类型
}

创建几种不同的物品
在这里插入图片描述
修改InventoryItem,初始化不同的道具

public Item item;

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

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

为了测试,我们配置几种不同的物品
在这里插入图片描述
效果
在这里插入图片描述

6. 在库存中寻找空闲位置

实际使用,我们肯定不可能通过挂载配置不同物品,所以进行修改,等待后续使用,隐藏item

[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;
}

新增InventoryManager代码,在库存中寻找空闲位置,添加物品

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); // 初始化物品信息
    }
}

新增InventoryManager空节点,挂载脚本,绑定挂载所有的物品插槽
在这里插入图片描述

新增Test测试脚本,用于测试添加物品功能

using UnityEngine;

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

新增测试面板挂载test脚本,并新增几个按钮测试
在这里插入图片描述
效果
在这里插入图片描述

7. 满库存判断

前面有点问题,如果我们库存已经满了,拾取的物品就消失了,这时候就需要修改InventoryManager的AddItem方法,返回添加物品的状态

// 添加物品到背包
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;
}

同步修改Test代码,根据返回值判断物品是否添加成功

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

效果
在这里插入图片描述

8. 物品数量显示

在物品的子集新增一个Text文本,用于显示物品数量,并添加Canvas Group组件,将这个组件的blocksRaycasts属性设置为false,表示在我们刚开始拖拽的整个过程当中,鼠标不会再去把这个UI物品当作一个阻挡物来看待,包括他的子物体的所有的UI对象
在这里插入图片描述

并修改InventoryItem物品脚本

[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();

}

效果
在这里插入图片描述
如果计算是1我们可以选择隐藏数量显示,这样效果会更好

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

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

效果
在这里插入图片描述
随机添加数量,测试

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

效果
在这里插入图片描述

9. 物品堆叠

修改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;
}

效果
在这里插入图片描述

10. 快捷栏物品选择

我们通过修改选中物品的背景颜色,提供选中的视觉效果
修改InventorySlot代码

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;
}

修改InventoryManager

int selectedSlot = -1;

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

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

效果
在这里插入图片描述
1-6键盘数字实现切换

修改InventoryManager代码

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

优化代码

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

效果
在这里插入图片描述

11. 选中工具功能

InventoryManager新增选中物品方法

// 获取当前选中物品
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脚本中测试打印

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

新增按钮测试
在这里插入图片描述

12. 使用物品 删除物品

修改InventoryManagerGetselectedItem方法

// 获取当前选中物品
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新增方法测试

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

效果
在这里插入图片描述

三、建造系统和库存系统结合

把库存系统的UI全部到建造系统里,并重新物品插槽信息
在这里插入图片描述

修改InventoryManager,配置开始时,默认显示物品的物品信息

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

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

这里我默认配置两个工具
在这里插入图片描述

修改InventoryManager为单例,方便其他地方调用

public static InventoryManager instance;

void Awake(){
   instance = this;
}

修改BuildingSystem,获取当前选中物品

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

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

收集物品,修改Loot代码

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

使用减少物品,修改BuildingSystem代码

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

最终效果

在这里插入图片描述

源码

整理好后我会放上来

完结

赠人玫瑰,手有余香!如果文章内容对你有所帮助,请不要吝啬你的点赞评论和关注,以便我第一时间收到反馈,你的每一次支持都是我不断创作的最大动力。点赞越多,更新越快哦!当然,如果你发现了文章中存在错误或者有更好的解决方法,也欢迎评论私信告诉我哦!

好了,我是向宇,https://xiangyu.blog.csdn.net

一位在小公司默默奋斗的开发者,出于兴趣爱好,于是最近才开始自习unity。如果你遇到任何问题,也欢迎你评论私信找我, 虽然有些问题我可能也不一定会,但是我会查阅各方资料,争取给出最好的建议,希望可以帮助更多想学编程的人,共勉~
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1036755.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【C语言精髓 之 指针】指针*、取地址、解引用*、引用

/*** file * author jUicE_g2R(qq:3406291309)————彬(bin-必应)* 一个某双流一大学通信与信息专业大二在读 * copyright 2023.9* COPYRIGHT 原创技术笔记&#xff1a;转载需获得博主本人同意&#xff0c;且需标明转载源* language …

人工智能驱动的自然语言处理:解锁文本数据的价值

文章目录 什么是自然语言处理&#xff1f;NLP的应用领域1. 情感分析2. 机器翻译3. 智能助手4. 医疗保健5. 舆情分析 使用Python进行NLP避免NLP中的陷阱结论 &#x1f389;欢迎来到AIGC人工智能专栏~人工智能驱动的自然语言处理&#xff1a;解锁文本数据的价值 ☆* o(≧▽≦)o *…

flutter web 优化和flutter_admin_template

文章目录 Flutter Admin TemplateLive demo: https://githubityu.github.io/live_flutter_adminWeb 优化 Setup登录注册英文 亮色主题 中文 暗黑主题管理员登录权限 根据权限动态添加路由 第三方依赖License最后参考学习 Flutter Admin Template Responsive web with light/da…

C++ 学习系列 -- std::vector (未完待续)

一 std::vector 是什么&#xff1f; vector 是c 中一种序列式容器&#xff0c;与前面说的 array 类似&#xff0c;其内存分配是连续的&#xff0c;但是与 array 不同的地方在于&#xff0c;vector 在运行时是可以动态扩容的&#xff0c;此外 vector 提供了许多方便的操作&…

世界前沿技术发展报告2023《世界信息技术发展报告》(四)电子信息技术

&#xff08;四&#xff09;电子信息技术 1. 概述2. 微电子技术2.1 精细制程芯片2.1.1 中国台积电发布2纳米制程工艺细节2.1.2 美国英特尔公司称2030年芯片晶体管密度将达到目前的10倍2.1.3 韩国三星电子率先实现3纳米制程芯片量产2.1.4 日本丰田、索尼等8家公司合资成立高端芯…

【李沐深度学习笔记】矩阵计算(1)

课程地址和说明 线性代数实现p4 本系列文章是我学习李沐老师深度学习系列课程的学习笔记&#xff0c;可能会对李沐老师上课没讲到的进行补充。 本节是第一篇 矩阵计算 标量导数 导数刻画的是函数在某点的瞬时变化率 这东西都是考研学过的&#xff0c;快速略过&#xff0c;如…

网站接入公网并配置域名访问【详细教程】

网站接入公网并配置域名访问【详细教程】 安装Nginx上传网页文件配置Nginx腾讯云配置域名映射接入公网备案流程 本教程将以腾讯云服务器和腾讯云域名为例&#xff0c;介绍如何快速将网站接入公网并配置域名访问。我们将使用xshell工具进行操作&#xff0c;并涵盖安装nginx、上传…

Unity之VR如何实现跟随视角的UI

前言 我们在制作VR项目的时候,大部分时候,是把UI固定到一个位置,比如桌子或者空中,这么做固然稳定,但是当我们有以下需求的时候,固定位置的UI可能会不适用: 1.场景较小,操作物体占用了很大体积,没有固定的可以清晰显示完整UI的位置。 2.需要频繁的前后左右,更换姿势…

Unity3D 使用LineRenderer自由画线

原理 一个LineRenderer是一次画线&#xff0c;需要使用对象池一帧记录一个鼠标位置 代码 这是线绘制器的代码&#xff0c;依赖于笔者写过的一个简易对象池 传送门&#xff1a;>>对象池 using EasyAVG; using System; using System.Collections.Generic; using UnityEn…

指针和数组笔试题的透析

指针---进阶篇&#xff08;三&#xff09; 一、前言二、一维数组例题透析&#xff1a;三、指针笔试题1.例一&#xff1a;2.例二&#xff1a;3.例三&#xff1a;4.例四&#xff1a;5.例五&#xff1a;6.例六&#xff1a; 一、前言 那么好了好了&#xff0c;宝子们&#xff0c;从…

王道408计组汇编语言部分学习总结

x86汇编语言指令基础 x86处理器中程序计数器PC 通常被称为IP 高级语言—>汇编语言—>机器语言 x86架构CPU&#xff0c;有哪些寄存器 EAX通用寄存器EBXECXEDXESI 变址寄存器 变址寄存器可用于线性表、字符串的处理EDIEBP堆栈基指针堆栈寄存器用于实现函数调用 ESP堆栈…

LESS的叶绿素荧光模拟实现与操作

LESS的叶绿素荧光模拟实现与操作 前情提要FLUSPECT模型荧光的三维面元冠层辐射传输过程日光诱导叶绿素荧光模拟 前情提要 本文默认您对LESS (LargE-Scale remote sensing data and image Simulation framework) 模型和叶绿素荧光(Sun-Induced chlorophyll Fluorescence, SIF)有…

2023华为杯研究生数学建模研赛E题出血脑卒中完整论文(含28个详细预处理数据及结果表格)

大家好呀&#xff0c;从发布赛题一直到现在&#xff0c;总算完成了全国研究生数学建模竞赛&#xff08;数模研赛&#xff09;E题完整的成品论文。 本论文可以保证原创&#xff0c;保证高质量。绝不是随便引用一大堆模型和代码复制粘贴进来完全没有应用糊弄人的垃圾半成品论文。…

高级运维学习(十)系统安全

kali 实际上它就是一个预安装了很多安全工具的Debian Linux [rootmyhost ~]# kali reset kali reset OK. 该虚拟机系统用户名为:kali,密码为:kali 基础配置 $ ip a s # 查看网络IP地址&#xff0c;本例中查看到的是192.168.88.40 $ sudo systemctl start ssh # 启s…

java面试题-并发编程基础

1.线程的基础知识 1.1 线程和进程的区别&#xff1f; 难易程度&#xff1a;☆☆ 出现频率&#xff1a;☆☆☆ 程序由指令和数据组成&#xff0c;但这些指令要运行&#xff0c;数据要读写&#xff0c;就必须将指令加载至 CPU&#xff0c;数据加载至内存。在指令运行过程中还需要…

驱动开发,基于gpio子系统编写LED灯的驱动,亮灭控制

1.gpio子系统介绍 一个芯片厂商生产出芯片后会给linux提供一个当前芯片中gpio外设的驱动&#xff0c;我们当前只需要调用对应的厂商驱动即可完成硬件的控制。而linux内核源码中的gpio厂商驱动有很多&#xff0c;这里linux内核对厂商驱动做了一些封装&#xff0c;提供了一系列的…

中秋国庆内卷之我爱学习C++

文章目录 前言Ⅰ. 内联函数0x00 内联函数和宏的比较0x01 内联函数的概念0x02 内联函数的特性 Ⅱ. auto&#xff08;C 11)0x00 auto的概念0x01 auto的用途 Ⅲ. 范围for循环(C11)0x00 基本用法0x01 范围for循环(C11)的使用条件 Ⅳ. 指针空值nullptr(C11)0x00 概念 前言 亲爱的夏…

leetcode Top100(17)矩阵置零

给定一个 m x n 的矩阵&#xff0c;如果一个元素为 0 &#xff0c;则将其所在行和列的所有元素都设为 0 。请使用 原地 算法。 示例 1&#xff1a; 输入&#xff1a;matrix [[1,1,1],[1,0,1],[1,1,1]] 输出&#xff1a;[[1,0,1],[0,0,0],[1,0,1]]示例 2&#xff1a; 输入&…

C++ -- 类型转换

目录 C语言中的类型转换 为什么C需要四种类型转换 C 类型转换 static_cast reinterpret_cast const_cast 添加关键字 volatile dynamic_cast 补充 RTTI 总结 C语言中的类型转换 在C语言中&#xff0c;如果赋值运算符左右两侧类型不同&#xff0c;或者形参与实参类型…

如何搜索浏览器添加印象笔记中搜藏的结果

在印象笔记记录的东西多了&#xff0c;就放在哪里不动&#xff0c;失去记录的意义了 1、如何将浏览器中添加印象笔记一块的搜索结果 2、需要两个步骤 第一&#xff1a;将浏览器中添加印象笔记的插件 第二&#xff1a;将印象笔记中的搜索方法勾上&#xff0c;如下 结果如下&…