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

news/2024/7/7 23:24:25

文章目录

  • 前言
  • 素材
    • 人物
    • 瓦片
    • 其他
  • 一、建造系统
    • 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://lihuaxi.xjx100.cn/news/1569808.html

相关文章

【Clickhouse2022.02 查询优化】

一、现场场景概述 现场每天每张表入库数据量大约2-4亿条,页面涉及到自定义时间段查询(白天08:00-15:00,夜晚23:00-06:00)与不同时间段(最近一天、一周、一个月和全部)的统计指标查询。 二、主要问题 时间跨度大无查询或查询条件命中数据过多的分页查询场景速度慢 (主要是数据…

记账APP:小哈记账5——记账首页页面的制作(2)

项目介绍&#xff1a; 小哈记账是一款用于记账APP&#xff0c;基于Android Studio开发工具&#xff0c;采用Java语言进行开发&#xff0c;同时使用litepal和阿里云数据库进行数据的增删查改&#xff0c;以图标的形式在App的界面上显示。App可以清晰显示收支情况&#xff0c;并以…

软件面试笔试复习之C语言

本篇为软件开发工程师打造&#xff0c;从入门到复习&#xff0c;巩固知识点&#xff0c;从而提高自己笔试或面试的知识水平。C/C编程技能是嵌入式软件开发最常用的编程语言&#xff0c;因此熟练掌握是非常有必要的。 开篇 C语言的学习永远绕不开的程序“Hello world&#xff…

Docker文档阅读笔记-How to Commit Changes to a Docker Image with Examples

介绍 在工作中使用Docker镜像和容器&#xff0c;用得最多的就是如何提交修改过的Docker镜像。当提交修改后&#xff0c;就会在原有的镜像上创建一个新的镜像。 本博文说明如何提交一个新的Docker镜像。 前提 ①有一个可以直接访问服务器的运行终端&#xff1b; ②帐号需要r…

更新、修改

MySQL从小白到总裁完整教程目录:https://blog.csdn.net/weixin_67859959/article/details/129334507?spm1001.2014.3001.5502 语法: update 表名 列名该列新值, 列名该列新值, ... where 记录匹配条件; 说明&#xff1a;update 更新、修改 set 设置 …

F对象和Q对象

F对象和Q对象 F对象 一个F对象代表数据库中某条记录的字段的信息 作用: 通常是对数据库中的字段值在不获取的情况下进行操作 用于类属性(字段)之间的比较 语法 from django.db.models import F F(列名)解决一种极端事件的产生&#xff0c;比如用户对一条微博的点赞&#xf…

LeetCode(力扣)509. 斐波那契数Python

LeetCode509. 斐波那契数 题目链接代码 题目链接 https://leetcode.cn/problems/fibonacci-number/ 代码 class Solution:def fib(self, n: int) -> int:if n 0:return 0dp [0] * (n 1)dp[0] 0dp[1] 1for i in range(2, n 1):dp[i] dp[i - 1] dp[i - 2]return d…

剑指YOLOv7改进最新重参数化结构RepVB 顶会2023 二次改进升级版,最新开源移动端网络架构,速度贼快

💡本篇内容:剑指YOLOv7改进最新重参数化结构RepVB 顶会2023 二次改进升级版,最新开源移动端网络架构,速度贼快 💡🚀🚀🚀本博客 改进源代码改进 适用于 YOLOv7 按步骤操作运行改进后的代码即可 💡:重点:该专栏《剑指YOLOv7原创改进》只更新改进 YOLOv7 模型的…