【unity实战】Unity中基于瓦片的网格库存系统——类似《逃离塔科夫》的库存系统

最终效果

在这里插入图片描述

文章目录

  • 最终效果
  • 前言
  • 素材下载
  • 图片配置
  • 获取格子坐标
  • 动态控制背包大小
  • 添加物品
  • 移动物品
  • 物品跟随鼠标
  • 创建物品的容器,定义不同物品
  • 修改物品尺寸
  • 修复物品放置位置问题
  • 按物品尺寸占用对应大小的格子
  • 判断物品是否超出边界范围
  • 物品放置重叠,交换物品
  • 放置加入点偏移量
  • 突出显示我们选中的物品
  • 优化
  • 多个背包
  • 自动入库物品
  • 旋转物品
  • 修改旋转高亮背景和占位也跟着旋转
  • 选中拖拽物品排序问题
  • 最终效果
  • 源码
  • 完结

前言

在这一集中我将使用Unity制作基于瓦片的网格库存系统。 就像在《逃离塔科夫》、《暗黑破坏神》或《流放之路》等游戏中一样。

素材下载

https://assetstore.unity.com/packages/2d/gui/icons/gui-parts-159068

图片配置

配置图片为重复
在这里插入图片描述

不懂UI画布适配查看:【Unity小技巧】最简单的UI设置适配方案

修改UI画布适配
在这里插入图片描述

新增UI图片,类型改为平铺,默认图片是256的,太大了,所以我们选择缩小4倍,每单位像素为4,同时注意修改轴心在左上角
在这里插入图片描述

获取格子坐标

新增ItemGrid代码

public class ItemGrid : MonoBehaviour
{
    // 定义每个格子的宽度和高度
    const float tileSizeWidth = 256 / 4;
    const float tileSizeHeight = 256 / 4;

    // 计算在格子中的位置
    Vector2 positionOnTheGrid = new Vector2();
    Vector2Int tileGridPosition = new Vector2Int();

    RectTransform rectTransform;
    Canvas canvas;
    private void Start()
    {
        rectTransform = GetComponent<RectTransform>();
        canvas = FindObjectOfType<Canvas>();
    }

    private void Update()
    {

        if (Input.GetMouseButtonDown(0))
        {
            // 获取当前鼠标位置在网格中的格子坐标,并打印到控制台
            Debug.Log(GetTileGridPosition(Input.mousePosition));
        }

    }
    
    // 根据鼠标位置计算在格子中的位置
    public Vector2Int GetTileGridPosition(Vector2 mousePosition)
    {
        // 计算鼠标位置相对于 RectTransform 的偏移量
        positionOnTheGrid.x = mousePosition.x - rectTransform.position.x;
        positionOnTheGrid.y = rectTransform.position.y - mousePosition.y;

        // 将偏移量转换为网格位置
        // 这里假设 tileSizeWidth 和 tileSizeHeight 是单个瓦片的宽度和高度
        // canvas.scaleFactor 是 Canvas 的缩放因子(通常用于 UI 适配不同分辨率)
        tileGridPosition.x = (int)(positionOnTheGrid.x / tileSizeWidth / canvas.scaleFactor);
        tileGridPosition.y = (int)(positionOnTheGrid.y / tileSizeHeight / canvas.scaleFactor);

        // 返回计算出的网格位置
        return tileGridPosition;
    }
}

挂载脚本
在这里插入图片描述
效果,点击格子打印位置
在这里插入图片描述

动态控制背包大小

修改ItemGrid

[SerializeField] int gridSizeWidth = 10;
[SerializeField] int gridSizeHeight = 10;

private void Start()
{
    rectTransform = GetComponent<RectTransform>();
    canvas = FindObjectOfType<Canvas>();

    Init(gridSizeWidth, gridSizeHeight);
}

void Init(int width, int height){
    Vector2 size = new Vector2(width * tileSizeWidth, height * tileSizeHeight);
    rectTransform.sizeDelta = size;
}

配置
在这里插入图片描述
效果
在这里插入图片描述

添加物品

配置物品预制体。修改尺寸和去掉光线投射目标
在这里插入图片描述
新增Item脚本,挂载在物品上

public class Item : MonoBehaviour {
    
}

在这里插入图片描述

动态添加测试物品,修改ItemGrid

Item[,] itemSlot;//存储物品位置信息

private void Start()
{
	itemSlot= new Item[gridSizeWidth, gridSizeHeight];

    rectTransform = GetComponent<RectTransform>();
    canvas = FindObjectOfType<Canvas>();

    Init(gridSizeWidth, gridSizeHeight);

    //动态添加测试物品
    Item item = Instantiate(itemPrefab).GetComponent<Item>();
    PlaceItem(item, 0, 0);

    item = Instantiate(itemPrefab).GetComponent<Item>();
    PlaceItem(item, 3, 2);

    item = Instantiate(itemPrefab).GetComponent<Item>();
    PlaceItem(item, 2, 4);
}
    
//按格子坐标添加物品
public void PlaceItem(Item item, int posX, int posY){
    itemSlot[posX, posY] = item;
    item.transform.SetParent(transform, false);
    Vector2 positon = new Vector2();
    positon.x = posX * tileSizeWidth + tileSizeWidth / 2;
    positon.y = -(posY * tileSizeHeight + tileSizeHeight / 2);
    item.transform.localPosition = positon;
}

配置
在这里插入图片描述

运行效果
在这里插入图片描述

移动物品

修改ItemGrid,按格子坐标获取物品

//按格子坐标获取物品
public Item PickUpItem(int x, int y){
    Item toReturn = itemSlot[x, y];
    itemSlot[x, y] = null;
    return toReturn;
}

新增InventoryController,实现物品交互功能

public class InventoryController : MonoBehaviour
{
    public ItemGrid selectedItemGrid;//操作的背包
    Item selectedItem;//选中物品

    private void Update()
    {
        if (selectedItemGrid == null) return;

        if (Input.GetMouseButtonDown(0))
        {
            // 获取当前鼠标位置在网格中的格子坐标,并打印到控制台
            Debug.Log(selectedItemGrid.GetTileGridPosition(Input.mousePosition));

            //获取物品
            Vector2Int tileGridPosition = selectedItemGrid.GetTileGridPosition(Input.mousePosition);
            if(selectedItem == null){
                selectedItem = selectedItemGrid.PickUpItem(tileGridPosition.x, tileGridPosition.y);
            }else{
                selectedItemGrid.PlaceItem(selectedItem, tileGridPosition.x, tileGridPosition.y);
                selectedItem = null;
            }
        }
    }
}

新增GridInteract,动态赋值背包数据

[RequireComponent(typeof(ItemGrid))]
public class GridInteract : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler
{
    private InventoryController inventoryController;
    private ItemGrid itemGrid;

    private void Awake()
    {
        inventoryController = FindObjectOfType<InventoryController>();
        itemGrid = GetComponent<ItemGrid>();
    }

    // 鼠标进入触发
    public void OnPointerEnter(PointerEventData eventData)
    {
        inventoryController.selectedItemGrid = itemGrid;
    }

    // 鼠标退出触发
    public void OnPointerExit(PointerEventData eventData)
    {
        inventoryController.selectedItemGrid = null;
    }
}

挂载
在这里插入图片描述
在这里插入图片描述
效果
在这里插入图片描述

物品跟随鼠标

修改InventoryController

private void Update()
{
    //物品跟随鼠标
    if(selectedItem) selectedItem.transform.position = Input.mousePosition;
	
	//...
}

效果
在这里插入图片描述

创建物品的容器,定义不同物品

新增ItemData

[CreateAssetMenu]
public class ItemData : ScriptableObject
{
    public int width = 1;
    public int height = 1;
    public Sprite itemIcon;
}

配置物品
在这里插入图片描述

修改Item

public class Item : MonoBehaviour
{
    public ItemData itemData;
    
    public void Set(ItemData itemData){
        this.itemData = itemData;
        GetComponent<Image>().sprite = itemData.itemIcon;
    }
}

修改InventoryController

[SerializeField] List<ItemData> items;
[SerializeField] GameObject itemPrefab;
Canvas canvas;

private void Start() {
    canvas = FindObjectOfType<Canvas>();
}

private void Update()
{
    //TODO: 方便测试,动态随机添加物品
    if (Input.GetKeyDown(KeyCode.Q))
    {
        CreateRandomItem();
    }

    //...
}

//随机添加物品
private void CreateRandomItem()
{
	if (selectedItem) return;
    Item item = Instantiate(itemPrefab).GetComponent<Item>();
    selectedItem = item;
    selectedItem.transform.SetParent(canvas.transform, false);
    int index = UnityEngine.Random.Range(0, items.Count);
    item.Set(items[index]);
}

配置
在这里插入图片描述

效果,按Q生成不同物品
在这里插入图片描述

修改物品尺寸

修改Item

public void Set(ItemData itemData){
    this.itemData = itemData;
    GetComponent<Image>().sprite = itemData.itemIcon;

    //修改物品尺寸
    Vector2 size = new Vector2();
    size.x = itemData.width * ItemGrid.tileSizeWidth;
    size.y = itemData.height * ItemGrid.tileSizeHeight;
    GetComponent<RectTransform>().sizeDelta = size;
}

效果
在这里插入图片描述

修复物品放置位置问题

修改ItemGrid

//按格子坐标添加物品
public void PlaceItem(Item item, int posX, int posY){
    itemSlot[posX, posY] = item;
    item.transform.SetParent(transform, false);
    Vector2 positon = new Vector2();
    positon.x = posX * tileSizeWidth + tileSizeWidth * item.itemData.width / 2;
    positon.y = -(posY * tileSizeHeight + tileSizeHeight * item.itemData.height / 2);
    item.transform.localPosition = positon;
}

效果
在这里插入图片描述

按物品尺寸占用对应大小的格子

修改ItemGrid

//按格子坐标添加物品
public void PlaceItem(Item item, int posX, int posY)
{
    item.transform.SetParent(transform, false);

    // 按物品尺寸占用对应大小的格子
    for (int ix = 0; ix < item.itemData.width; ix++){
        for (int iy = 0; iy < item.itemData.height; iy++){
            itemSlot[posX + ix, posY + iy] = item;
        }
    }
    item.onGridPositionX = posX;
    item.onGridPositionY = posY;

    Vector2 positon = new Vector2();
    positon.x = posX * tileSizeWidth + tileSizeWidth * item.itemData.width / 2;
    positon.y = -(posY * tileSizeHeight + tileSizeHeight * item.itemData.height / 2);
    item.transform.localPosition = positon;
}

//按格子坐标获取物品
public Item PickUpItem(int x, int y)
{
    Item toReturn = itemSlot[x, y];
    
	if(toReturn == null) return null;
	
    CleanGridReference(toReturn);
    
    return toReturn;
}

//按物品尺寸取消对应大小的格子的占用
void CleanGridReference(Item item){
    for (int ix = 0; ix < item.itemData.width; ix++)
    {
        for (int iy = 0; iy < item.itemData.height; iy++)
        {
            itemSlot[item.onGridPositionX + ix, item.onGridPositionY + iy] = null;
        }
    }
}

运行看是否正常
在这里插入图片描述

判断物品是否超出边界范围

修改ItemGrid

//按格子坐标添加物品
public bool PlaceItem(Item item, int posX, int posY)
{
    //判断物品是否超出边界
    if (BoundryCheck(posX, posY, item.itemData.width, item.itemData.height) == false) return false;
    
    //...
	
	return true;
}

//判断物品是否超出边界
bool BoundryCheck(int posX, int posY, int width, int height)
{
    if (PositionCheck(posX, posY) == false) return false;

    posX += width - 1;
    posY += height - 1;
    if (PositionCheck(posX, posY) == false) return false;
    return true;
}

//判断格子坐标是否超出
bool PositionCheck(int posX, int posY)
{
    if (posX < 0 || posY < 0) return false;

    if (posX >= gridSizeWidth || posY >= gridSizeHeight) return false;

    return true;
}

修改InventoryController

private void Update()
{
   //...

   if (Input.GetMouseButtonDown(0))
   {
       Vector2Int tileGridPosition = selectedItemGrid.GetTileGridPosition(Input.mousePosition);
       if (selectedItem == null)
       {
           //选中物品
           selectedItem = selectedItemGrid.PickUpItem(tileGridPosition.x, tileGridPosition.y);
       }
       else
       {
           // 移动物品
           PlaceItem(tileGridPosition);
       } 
   }
}
    
//移动物品
void PlaceItem(Vector2Int tileGridPosition){
    bool complete = selectedItemGrid.PlaceItem(selectedItem, tileGridPosition.x, tileGridPosition.y);
    if(complete) selectedItem = null;
}

效果

在这里插入图片描述

物品放置重叠,交换物品

修改InventoryController

Item overlapItem;//重叠物品

//移动物品
void PlaceItem(Vector2Int tileGridPosition){
    bool complete = selectedItemGrid.PlaceItem(selectedItem, tileGridPosition.x, tileGridPosition.y, ref overlapItem);
    if(complete) {
        selectedItem = null;

        //如果存在重叠物品
        if(overlapItem != null) {
            selectedItem = overlapItem;
            overlapItem = null;
        }
    }
}

修改ItemGrid

//按格子坐标添加物品
public bool PlaceItem(Item item, int posX, int posY, ref Item overlapItem)
{
    //判断物品是否超出边界
    if (BoundryCheck(posX, posY, item.itemData.width, item.itemData.height) == false) return false;

    //检查指定位置和范围内是否存在重叠物品,有多个重叠物品退出
    if (OverlapCheck(posX, posY, item.itemData.width, item.itemData.height, ref overlapItem) == false) return false;

    if(overlapItem) CleanGridReference(overlapItem);

	//...
}

//检查指定位置和范围内是否存在重叠物品,并overlapItem返回重叠物品,,有多个重叠物品返回false
private bool OverlapCheck(int posX, int posY, int width, int height, ref Item overlapItem)
{
    for (int x = 0; x < width; x++)
    {
        for (int y = 0; y < height; y++)
        {
            // 如果当前位置有物品
            if (itemSlot[posX + x, posY + y] != null)
            {
                // 如果 overlapItem 还未被赋值(第一次找到重叠物品)
                if (overlapItem == null)
                {
                    overlapItem = itemSlot[posX + x, posY + y];
                }
                else
                {
                    // 如果发现范围有多个重叠物品
                    if (overlapItem != itemSlot[posX + x, posY + y]){
                        overlapItem = null;
                        return false;
                    }
                }
            }
        }
    }
    // 如果所有被检查的位置都有相同的重叠物品,则返回 true
    return true;
}

效果
在这里插入图片描述

放置加入点偏移量

修改InventoryController放置时加入点偏移量,让放置效果更好

private void Update()
{
    //TODO: 方便测试,动态随机添加物品
    if (Input.GetKeyDown(KeyCode.Q))
    {
        CreateRandomItem();
    }

    //物品跟随鼠标
    if (selectedItem) selectedItem.transform.position = Input.mousePosition;

    if (selectedItemGrid == null) return;

    if (Input.GetMouseButtonDown(0))
    {
        LeftMouseButtonPress();
    }
}

//点击操作
private void LeftMouseButtonPress()
{
    Vector2 position = Input.mousePosition;
    if (selectedItem != null)
    {
        position.x -= (selectedItem.itemData.width - 1) * ItemGrid.tileSizeWidth / 2;
        position.y += (selectedItem.itemData.height - 1) * ItemGrid.tileSizeHeight / 2;
    }

    Vector2Int tileGridPosition = selectedItemGrid.GetTileGridPosition(position);
    if (selectedItem == null)
    {
        //选中物品
        selectedItem = selectedItemGrid.PickUpItem(tileGridPosition.x, tileGridPosition.y);
    }
    else
    {
        // 移动物品
        PlaceItem(tileGridPosition);
    }
}

效果
在这里插入图片描述

突出显示我们选中的物品

修改ItemGrid

//按格子坐标转化为UI坐标位置
public Vector2 CalculatePositionOnGrid(Item item, int posX, int posY)
{
    Vector2 position = new Vector2();
    position.x = posX * tileSizeWidth + tileSizeWidth * item.itemData.width / 2;
    position.y = -(posY * tileSizeHeight + tileSizeHeight * item.itemData.height / 2);
    return position;
}

//按格子坐标获取物品
internal Item GetItem(int x, int y)
{
    return itemSlot[x, y];
}

新增InventoryHighlight,控制高亮背景显示

//控制高亮背景显示
public class InventoryHighlight : MonoBehaviour
{
    [SerializeField] RectTransform highlighter;

    // 设置高亮框大小
    public void SetSize(Item targetItem)
    {
        Vector2 size = new Vector2();
        size.x = targetItem.itemData.width * ItemGrid.tileSizeWidth;
        size.y = targetItem.itemData.height * ItemGrid.tileSizeHeight;
        highlighter.sizeDelta = size;
    }

    // 设置高亮框位置
    public void SetPosition(ItemGrid targetGrid, Item targetItem)
    {
        Vector2 pos = targetGrid.CalculatePositionOnGrid(targetItem, targetItem.onGridPositionX, targetItem.onGridPositionY);
        highlighter.localPosition = pos;
    }

    //显示隐藏
    public void Show(bool b){
        highlighter.gameObject.SetActive(b);        
    }

    //设置高亮背景父级
    public void SetParent(ItemGrid targetGrid){
        highlighter.SetParent(targetGrid.GetComponent<RectTransform>());
    }

    //设置高亮框位置
    public void SetPosition(ItemGrid targetGrid, Item targetItem, int posX, int posY)
    {
        Vector2 pos = targetGrid.CalculatePositionOnGrid(targetItem, posX, posY);
        highlighter.localPosition = pos;
    }

}

修改InventoryController

InventoryHighlight inventoryHighlight;
Item itemToHighlight;//高亮显示物品

private void Start()
{
    canvas = FindObjectOfType<Canvas>();
    inventoryHighlight = GetComponent<InventoryHighlight>();
}

private void Update()
{
    //TODO: 方便测试,动态随机添加物品
    if (Input.GetKeyDown(KeyCode.Q))
    {
        CreateRandomItem();
    }

    //物品跟随鼠标
    if (selectedItem) selectedItem.transform.position = Input.mousePosition;

    if (selectedItemGrid == null)
    {
        inventoryHighlight.Show(false);
        return;
    }

    if (Input.GetMouseButtonDown(0))
    {
        // 获取当前鼠标位置在网格中的格子坐标,并打印到控制台
        Debug.Log(selectedItemGrid.GetTileGridPosition(Input.mousePosition));

        LeftMouseButtonPress();
    }

    //高亮显示
    HandleHighlight();
}

//点击操作,选中物品
private void LeftMouseButtonPress()
{
    Vector2Int tileGridPosition = GetTileGridPosition();
    if (selectedItem == null)
    {
        //选中物品
        selectedItem = selectedItemGrid.PickUpItem(tileGridPosition.x, tileGridPosition.y);
    }
    else
    {
        // 移动物品
        PlaceItem(tileGridPosition);
    }
}

//鼠标坐标转化为格子坐标
private Vector2Int GetTileGridPosition()
{
    Vector2 position = Input.mousePosition;
    if (selectedItem != null)
    {
        position.x -= (selectedItem.itemData.width - 1) * ItemGrid.tileSizeWidth / 2;
        position.y += (selectedItem.itemData.height - 1) * ItemGrid.tileSizeHeight / 2;
    }
    Vector2Int tileGridPosition = selectedItemGrid.GetTileGridPosition(position);
    return tileGridPosition;
}

//高亮显示
private void HandleHighlight()
{
    Vector2Int positionOnGrid = GetTileGridPosition();
    if (selectedItem == null)
    {
        itemToHighlight = selectedItemGrid.GetItem(positionOnGrid.x, positionOnGrid.y);
        if (itemToHighlight != null)
        {
            inventoryHighlight.Show(true);
            inventoryHighlight.SetSize(itemToHighlight);
            inventoryHighlight.SetParent(selectedItemGrid);
            inventoryHighlight.SetPosition(selectedItemGrid, itemToHighlight);
        }else{
            inventoryHighlight.Show(false);
        }
    }
    else
    {
        inventoryHighlight.Show(selectedItemGrid.BoundryCheck(
                positionOnGrid.x,
                positionOnGrid.y,
                selectedItem.itemData.width,
                selectedItem.itemData.height)
        );//防止显示跨界
        inventoryHighlight.SetSize(selectedItem);
        inventoryHighlight.SetParent(selectedItemGrid);
        inventoryHighlight.SetPosition(selectedItemGrid, selectedItem, positionOnGrid.x, positionOnGrid.y);
    }
}

新增高亮背景
在这里插入图片描述
挂载配置
在这里插入图片描述
效果
在这里插入图片描述

优化

修改InventoryController,节约不必要的计算

Vector2Int oldPosition;

//高亮显示
private void HandleHighlight()
{
    Vector2Int positionOnGrid = GetTileGridPosition();

    //节约没必要的计算
    if(oldPosition == positionOnGrid) return;
    oldPosition = positionOnGrid;
    //...
}

最好为光线投射添加一些填充,Raycast Padding区域
参考:Unity 显示Raycast Padding区域
在这里插入图片描述

多个背包

只要复制背包,修改尺寸即可
在这里插入图片描述
效果
在这里插入图片描述

自动入库物品

修改ItemGrid

//按格子坐标添加物品
public bool PlaceItem(Item item, int posX, int posY, ref Item overlapItem)
{
    //判断物品是否超出边界
    if (BoundryCheck(posX, posY, item.itemData.width, item.itemData.height) == false) return false;

    //检查指定位置和范围内是否存在重叠物品,有多个重叠物品退出
    if (OverlapCheck(posX, posY, item.itemData.width, item.itemData.height, ref overlapItem) == false) return false;

    if (overlapItem) CleanGridReference(overlapItem);

    PlaceItem(item, posX, posY);

    return true;
}

//按格子坐标添加物品
public void PlaceItem(Item item, int posX, int posY)
{
    item.transform.SetParent(transform, false);

    // 按物品尺寸占用对应大小的格子
    for (int ix = 0; ix < item.itemData.width; ix++)
    {
        for (int iy = 0; iy < item.itemData.height; iy++)
        {
            itemSlot[posX + ix, posY + iy] = item;
        }
    }
    item.onGridPositionX = posX;
    item.onGridPositionY = posY;

    Vector2 position = CalculatePositionOnGrid(item, posX, posY);

    item.transform.localPosition = position;
}

// 检查指定位置是否有足够的空间来放置物品
private bool CheckAvailableSpace(int posX, int posY, int width, int height)
{
    for (int x = 0; x < width; x++)
    {
        for (int y = 0; y < height; y++)
        {
            if (itemSlot[posX + x, posY + y] != null)
            {
                return false; // 如果当前位置已经有物品,则返回false
            }
        }
    }
    return true; // 如果所有位置都空闲,则返回true
}

// 在网格中找到适合放置物品的位置Data
public Vector2Int? FindSpaceForObject(ItemData itemData)
{
    int height = gridSizeHeight - itemData.height + 1;
    int width = gridSizeWidth - itemData.width + 1;

    for (int y = 0; y < height; y++)
    {
        for (int x = 0; x < width; x++)
        {
            if (CheckAvailableSpace(x, y, itemData.width, itemData.height) == true)
            {
                return new Vector2Int(x, y); // 返回找到的空闲位置
            }
        }
    }
    return null; // 如果没有找到合适的位置,则返回null
}

修改InventoryController

//TODO:方便测试,随机入库物品
if (Input.GetKeyDown(KeyCode.W))
{
    InsertRandomItem();
}

//随机入库物品
private void InsertRandomItem()
{
    if(selectedItemGrid == null) return;

    int index = UnityEngine.Random.Range(0, items.Count);
    // 在网格中找到适合放置物品的位置
    Vector2Int? posOnGrid = selectedItemGrid.FindSpaceForObject(items[index]);
    if (posOnGrid == null) return;
    
    Item item = Instantiate(itemPrefab).GetComponent<Item>();
    item.transform.SetParent(canvas.transform, false);
    item.Set(items[index]);
    
    // 将物品放置到网格中的指定位置
    selectedItemGrid.PlaceItem(item, posOnGrid.Value.x, posOnGrid.Value.y);
}

效果
在这里插入图片描述

旋转物品

修改Item

public bool rotated = false;

//旋转物品
public void Rotate()
{
    rotated = !rotated;
    transform.rotation = Quaternion.Euler(0, 0, rotated == true ? 90f : 0f);
}

修改InventoryController

//旋转物品
if (Input.GetKeyDown(KeyCode.R))
{
    RotateItem();
}

//旋转物品
void RotateItem(){
    if (selectedItem == null) return;
    selectedItem.Rotate();
}

效果
在这里插入图片描述

修改旋转高亮背景和占位也跟着旋转

修改Item

public int WIDTH{
    get{
        if(rotated == false){
            return itemData.width;
        }
        return itemData.height;
    }
}

public int HEIGHT{
    get{
        if(rotated == false){
            return itemData.height;
        }
        return itemData.width;
    }
}

然后修改InventoryController、ItemGrid和InventoryHighlight把
item.itemData.width改为 item.WIDTH
item.itemData.height改为item.HEIGHT

给大家提供一个技巧,可以先修改ItemData宽高注释,这时代码会报错,对应修改位置即可,然后再还原回去
在这里插入图片描述
效果
在这里插入图片描述

选中拖拽物品排序问题

修改InventoryController,大概就是添加selectedItem.transform.SetAsLastSibling();保证选中对象排最后,及排序最靠前

//点击操作,选中物品
private void LeftMouseButtonPress()
{
    Vector2Int tileGridPosition = GetTileGridPosition();
    if (selectedItem == null)
    {
        //选中物品
        selectedItem = selectedItemGrid.PickUpItem(tileGridPosition.x, tileGridPosition.y);
        selectedItem.transform.SetAsLastSibling();
    }
    else
    {
        // 移动物品
        PlaceItem(tileGridPosition);
    }
}
    
//移动物品
void PlaceItem(Vector2Int tileGridPosition)
{
    bool complete = selectedItemGrid.PlaceItem(selectedItem, tileGridPosition.x, tileGridPosition.y, ref overlapItem);
    if (complete)
    {
        selectedItem = null;

        //如果存在重叠物品
        if (overlapItem != null)
        {
            selectedItem = overlapItem;
            overlapItem = null;
            selectedItem.transform.SetAsLastSibling();
        }
    }
}

//随机添加物品
private void CreateRandomItem()
{
     if (selectedItem) return; 
    Item item = Instantiate(itemPrefab).GetComponent<Item>();
    selectedItem = item;
    selectedItem.transform.SetParent(canvas.transform, false);
    selectedItem.transform.SetAsLastSibling();
    int index = UnityEngine.Random.Range(0, items.Count);
    item.Set(items[index]);
}

效果

在这里插入图片描述

最终效果

在这里插入图片描述

源码

整理好了我会放上来

完结

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

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

一位在小公司默默奋斗的开发者,出于兴趣爱好,最近开始自学unity,闲暇之余,边学习边记录分享,站在巨人的肩膀上,通过学习前辈们的经验总是会给我很多帮助和启发!php是工作,unity是生活!如果你遇到任何问题,也欢迎你评论私信找我, 虽然有些问题我也不一定会,但是我会查阅各方资料,争取给出最好的建议,希望可以帮助更多想学编程的人,共勉~
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Oracle优化案例-教你在线搞定top cpu的sql(十二)

监控告警阈值load 大于10 SQL如下&#xff0c;太好用了 SELECT A.SQL_ID, A.SESS_COUNT, A.CPU_LOAD, B.SQL_TEXTFROM (SELECT SQL_ID,COUNT(*) SESS_COUNT,ROUND(COUNT(*) / SUM(COUNT(*)) OVER(), 2) CPU_LOADFROM V$ACTIVE_SESSION_HISTORYWHERE SAMPLE_TIME > SYSDATE…

[深度学习] 门控循环单元GRU

门控循环单元&#xff08;Gated Recurrent Unit, GRU&#xff09;是一种用于处理序列数据的递归神经网络&#xff08;Recurrent Neural Network, RNN&#xff09;变体&#xff0c;它通过引入门控机制来解决传统RNN在处理长序列时的梯度消失问题。GRU与长短期记忆网络&#xff0…

反射及动态代理

反射 定义&#xff1a; 反射允许对封装类的字段&#xff0c;方法和构造 函数的信息进行编程访问 图来自黑马程序员 获取class对象的三种方式&#xff1a; 1&#xff09;Class.forName("全类名") 2&#xff09;类名.class 3) 对象.getClass() 图来自黑马程序员 pac…

前端JS必用工具【js-tool-big-box】学习,数值型数组的正向排序和倒向排序

这一小节&#xff0c;我们说一下前端 js-tool-big-box 这个工具库&#xff0c;添加的数值型数组的正向排序和倒向排序。 以前呢&#xff0c;我们的数组需要排序的时候&#xff0c;都是在项目的utils目录里&#xff0c;写一段公共方法&#xff0c;弄个冒泡排序啦&#xff0c;弄…

JNI详解

JNI简介 Java是跨平台的语言&#xff0c;但在有的时候仍需要调用本地代码&#xff08;这些代码通常由C/C编写的&#xff09;。 Sun公司提供的JNI是Java平台的一个功能强大的接口&#xff0c;JNI接口提供了Java与操作系统本地代码互相调用的功能。 Java调C 1&#xff09;使用…

Spring Boot 学习第八天:AOP代理机制对性能的影响

1 概述 在讨论动态代理机制时&#xff0c;一个不可避免的话题是性能。无论采用JDK动态代理还是CGLIB动态代理&#xff0c;本质上都是在原有目标对象上进行了封装和转换&#xff0c;这个过程需要消耗资源和性能。而JDK和CGLIB动态代理的内部实现过程本身也存在很大差异。下面将讨…

VMware vSphere 8.0 Update 3 发布下载 - 企业级工作负载平台

VMware vSphere 8.0 Update 3 发布下载 - 企业级工作负载平台 vSphere 8.0U3 | ESXi 8.0U3 & vCenter Server 8.0U3 请访问原文链接&#xff1a;https://sysin.org/blog/vmware-vsphere-8-u3/&#xff0c;查看最新版。原创作品&#xff0c;转载请保留出处。 作者主页&am…

Java面试八股之JVM内存溢出的原因及解决方案

JVM内存溢出的原因及解决方案 JVM内存溢出&#xff08;Out Of Memory&#xff0c;OOM&#xff09;通常是由于程序运行过程中内存使用不当造成的&#xff0c;常见原因及相应的解决方案如下&#xff1a; 原因及解决方案 内存中加载的数据量过大 原因&#xff1a;一次性从数据…

运维入门技术——监控的三个维度(非常详细)零基础收藏这一篇就够了_监控维度怎么区分

一个好的监控系统最后要做到的形态:实现Metrics、Tracing、Logging的融合。监控的三个维度也就是Metrics、Tracing、Logging。 Metrics Metrics也就是我们常说的指标。 首先它的典型特征就是可聚合(aggregatable).什么是可聚合的呢,简单讲可聚合就是一种基本单位可以在一种维…

Verilog刷题笔记48——FSM1型异步复位

题目: 解题&#xff1a; module top_module(input clk,input areset, // Asynchronous reset to state Binput in,output out);// parameter A0, B1; reg state, next_state;always (*) begin // This is a combinational always block// State transition logiccase(…

加拿大魁北克IT人士的就业分析

魁北克省作为加拿大东部的一个重要省份&#xff0c;近年来在IT行业的就业市场上展现出了强劲的增长势头。随着数字化转型的加速&#xff0c;魁北克对IT专业人士的需求日益增加&#xff0c;特别是在软件开发、网络安全、数据分析和人工智能等领域。 热门职位方面&#xff0c;软…

禹晶、肖创柏、廖庆敏《数字图像处理(面向新工科的电工电子信息基础课程系列教材)》Chapter 9插图

禹晶、肖创柏、廖庆敏《数字图像处理&#xff08;面向新工科的电工电子信息基础课程系列教材&#xff09;》 Chapter 9插图

201.回溯算法:全排列(力扣)

class Solution { public:vector<int> res; // 用于存储当前排列组合vector<vector<int>> result; // 用于存储所有的排列组合void backtracing(vector<int>& nums, vector<bool>& used) {// 如果当前排列组合的长度等于 nums 的长度&am…

用 Rust 实现一个替代 WebSocket 的协议

很久之前我就对websocket颇有微词&#xff0c;它的确满足了很多情境下的需求&#xff0c;但是仍然有不少问题。对我来说&#xff0c;最大的一个问题是websocket的数据是明文传输的&#xff0c;这使得websocket的数据很容易遭到劫持和攻击。同时&#xff0c;WebSocket继承自HTTP…

【操作系统】操作系统发展简史

目录 1.前言 2.第一代&#xff08;1945~1955&#xff09;&#xff1a;真空管和穿孔卡片 3.第二代&#xff08;1955~1965&#xff09;&#xff1a;晶体管和批处理系统 4.第三代&#xff08;1965~1980&#xff09;&#xff1a;集成电路和多道程序设计 5.第四代&#xff08;1…

关于VMware遇到的一些问题

问题一&#xff1a;打不开磁盘…或它所依赖的某个快照磁盘&#xff0c;开启模块DiskEarly的操作失败&#xff0c;未能启动虚拟机 解决方法&#xff1a; 首先将centos 7关机&#xff0c;然后把快照1删掉 然后打开虚拟机所在目录&#xff0c;把提示的000001.vmdk全部删除&…

本地读取classNames txt文件

通过本地读取classNames,来减少程序修改代码,提高了程序的拓展性和自定义化。 步骤: 1、输入本地路径,分割字符串。 2、将className按顺序放入vector容器中。 3、将vector赋值给classNmaes;获取classNames.size(),赋值给CLASSES;这样,类别个数和类别都已经赋值完成。…

大厂面试官问我:Redis内存淘汰,LRU维护整个队列吗?【后端八股文四:Redis内存淘汰策略八股文合集】

往期内容&#xff1a; 大厂面试官问我&#xff1a;Redis处理点赞&#xff0c;如果瞬时涌入大量用户点赞&#xff08;千万级&#xff09;&#xff0c;应当如何进行处理&#xff1f;【后端八股文一&#xff1a;Redis点赞八股文合集】-CSDN博客 大厂面试官问我&#xff1a;布隆过滤…

vue3 Cesium 离线地图

1、vite-plugin-cesium 是一个专门为 Vite 构建工具定制的插件&#xff0c;用于在 Vite 项目中轻松使用 Cesium 库。它简化了在 Vite 项目中集成 Cesium 的过程。 npm i cesium vite-plugin-cesium vite -D 2、配置vite.config.js import cesium from vite-plugin-cesiumexp…

监测与管理:钢筋计在工程项目中的应用

在现代工程建设中&#xff0c;特别是大型长期工程项目&#xff0c;对结构安全性的监测与管理至关重要。钢筋计作为一种重要的监测工具&#xff0c;在工程项目中发挥着不可替代的作用。本文将探讨钢筋计在长期工程项目中的应用&#xff0c;包括安装方法、数据监测与分析以及实际…