Unity3D仿星露谷物语开发18之添加道具到库存栏
1、目标
当角色拾取道具时能够显示在库存栏中,同时可以显示拾取道具的数量。
2、TextMeshPro组件
TextMeshPro(TMP)是一个Unity文本组件,TMP为文本样式和纹理提供了强大的灵活性。
TMP与Text的差异:
- TMP文本样式比Text文本样式更加丰富和灵活
- TMP对应的Shader支持描边、阴影和颜色渐变等美术效果,而且不会额外增加网格的顶点数量。而Text需要添加Shadow组件、Outline组件等才能支持这些美术效果,且会增加网格的顶点数量。
- 性能方面,TMP比Text会占用更多的堆内存,消耗更多的渲染开销。
- TMP是以哦那个SDF技术来渲染字体,而Text使用FreeType库来渲染字体。
- TMP引用字体有限,如果没找到字体最终是CallBack不到系统字体,会显示一个方框。而Text能CallBack回系统字体。
3、创建插槽预制体
(1)创建UIInventorySlot
点击UIInventoryBar,然后按F键,Scene界面聚焦在UIInventoryBar物体上。
我们需要在里面创建一系列的库存槽,在插槽中操纵图像和文本类型的项目数。
在UIInventoryBar下创建空物体命名为UIInventorySlot。
重置它的位置为Middle Left。
然后给UIInventorySlot添加Image组件,设置属性如下:
Preserve Aspect:当勾选这个选项之后再对图片进行操作时,会保持图片的宽度和高度的比例不发生改变。
然后再添加Canvas Group组件。
(2)创建InventoryHighlight
在UIInventorySlot下创建InventoryHighlight对象,增加这个作用是:后续点击slot时,会有个红色方框突出一下,表明选中了当前slot。
增加Image组件,并设置属性如下:
目前不需要突出显示某个slot,所以需要设置color.alpha=0。
(3)创建TMP文本
在UIInventorySlot下Create -> UI -> Text - TextMeshPro。
接下来创建字体资源,Window -> TextMeshPro -> Font Asset Creator。
在Source Font File中选择Peepo,点击“Generate Font Atlas”,点击"Save"保存到默认文件夹下。
然后点击Text(TMP)对象,设置属性如下:
(4)创建预制体
在Assets -> Prefabs下创建UI目录,并将UIInventorySlot拖入其中。
(5)创建多个Slot
复制多个UIInventorySlot到UIInventoryBar中,通过调整Pos X值使得每个UIInventorySlot可以对号入座。
4、创建UIInventorySlot脚本
在Assets -> Scripts -> UI -> UIInventory下创建UIInventorySlot脚本。
using UnityEngine;
using TMPro;
using UnityEngine.UI;
public class UIInventorySlot : MonoBehaviour
{
public Image inventorySlotHighlight;
public Image inventorySlotImage;
public TextMeshProUGUI textMeshProUGUI;
[HideInInspector] public ItemDetails itemDetails;
[HideInInspector] public int itemQuantity;
}
双击UIInventorySlot预制体,添加UIInventorySlot组件,并设置对应的属性信息如下:
5、优化UIInventoryBar脚本
新增两个变量,一个是默认查抄的图案为空图案,另一个是插槽集合需要配置进来。
一般在OnEnable()和OnDisable()方法中监听事件。
新增部分代码如下:
[SerializeField] private Sprite blank16x16sprite = null; // 插槽默认图案
[SerializeField] private UIInventorySlot[] inventorySlot = null; // 所有插槽集合
private void OnDisable()
{
EventHandler.InventoryUpdatedEvent -= InventoryUpdated;
}
private void InventoryUpdated(InventoryLocation inventoryLocation, List<InventoryItem> inventoryList)
{
if (inventoryLocation == InventoryLocation.player)
{
ClearInventorySlots();
if (inventorySlot.Length > 0 && inventoryList.Count > 0)
{
for (int i = 0; i < inventorySlot.Length; i++)
{
if (i < inventoryList.Count)
{
int itemCode = inventoryList[i].itemCode;
ItemDetails itemDetails = InventoryManager.Instance.GetItemDetails(itemCode);
if (itemDetails != null)
{
// add images and details to inventory item slot
inventorySlot[i].inventorySlotImage.sprite = itemDetails.itemSprite;
inventorySlot[i].textMeshProUGUI.text = inventoryList[i].itemQuantity.ToString();
inventorySlot[i].itemDetails = itemDetails;
inventorySlot[i].itemQuantity = inventoryList[i].itemQuantity;
}
}
else
{
break;
}
}
}
}
}
private void ClearInventorySlots()
{
if(inventorySlot.Length > 0)
{
// loop through inventory slots and update with blank sprite
for(int i = 0; i < inventorySlot.Length; i++)
{
inventorySlot[i].inventorySlotImage.sprite = blank16x16sprite;
inventorySlot[i].textMeshProUGUI.text = "";
inventorySlot[i].itemDetails = null;
inventorySlot[i].itemQuantity = 0;
}
}
}
private void OnEnable()
{
EventHandler.InventoryUpdatedEvent += InventoryUpdated;
}
完整代码如下:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class UIInventoryBar : MonoBehaviour
{
[SerializeField] private Sprite blank16x16sprite = null; // 插槽默认图案
[SerializeField] private UIInventorySlot[] inventorySlot = null; // 所有插槽集合
private RectTransform rectTransform;
private bool _isInventoryBarPositionBottom = true;
public bool IsInventoryBarPositionBottom { get { return _isInventoryBarPositionBottom;} set { _isInventoryBarPositionBottom = value; } }
private void Awake()
{
rectTransform = GetComponent<RectTransform>();
}
private void OnDisable()
{
EventHandler.InventoryUpdatedEvent -= InventoryUpdated;
}
private void InventoryUpdated(InventoryLocation inventoryLocation, List<InventoryItem> inventoryList)
{
if (inventoryLocation == InventoryLocation.player)
{
ClearInventorySlots();
if (inventorySlot.Length > 0 && inventoryList.Count > 0)
{
for (int i = 0; i < inventorySlot.Length; i++)
{
if (i < inventoryList.Count)
{
int itemCode = inventoryList[i].itemCode;
ItemDetails itemDetails = InventoryManager.Instance.GetItemDetails(itemCode);
if (itemDetails != null)
{
// add images and details to inventory item slot
inventorySlot[i].inventorySlotImage.sprite = itemDetails.itemSprite;
inventorySlot[i].textMeshProUGUI.text = inventoryList[i].itemQuantity.ToString();
inventorySlot[i].itemDetails = itemDetails;
inventorySlot[i].itemQuantity = inventoryList[i].itemQuantity;
}
}
else
{
break;
}
}
}
}
}
private void ClearInventorySlots()
{
if(inventorySlot.Length > 0)
{
// loop through inventory slots and update with blank sprite
for(int i = 0; i < inventorySlot.Length; i++)
{
inventorySlot[i].inventorySlotImage.sprite = blank16x16sprite;
inventorySlot[i].textMeshProUGUI.text = "";
inventorySlot[i].itemDetails = null;
inventorySlot[i].itemQuantity = 0;
}
}
}
private void OnEnable()
{
EventHandler.InventoryUpdatedEvent += InventoryUpdated;
}
private void Update()
{
// Switch inventory bar position depending on player position
SwitchInventoryBarPosition();
}
private void SwitchInventoryBarPosition()
{
Vector3 playerViewportPosition = Player.Instance.GetPlayerViewportPosition();
if (playerViewportPosition.y > 0.3f && IsInventoryBarPositionBottom == false)
{
rectTransform.pivot = new Vector2(0.5f, 0f);
rectTransform.anchorMin = new Vector2(0.5f, 0f);
rectTransform.anchorMax = new Vector2(0.5f, 0f);
rectTransform.anchoredPosition = new Vector2(0f, 2.5f);
IsInventoryBarPositionBottom = true;
}
else if (playerViewportPosition.y <= 0.3f && IsInventoryBarPositionBottom == true)
{
rectTransform.pivot = new Vector2(0.5f, 1f);
rectTransform.anchorMin = new Vector2(0.5f, 1f);
rectTransform.anchorMax = new Vector2(0.5f, 1f);
rectTransform.anchoredPosition = new Vector2(0f, -2.5f);
IsInventoryBarPositionBottom = false;
}
}
}
点击UIInventoryBar对象,
1)配置Blank 16x16sprite对象如下。
2)点击右上角的锁按钮,然后把12个slot拖到Inventory Slot变量中。
6、优化InventoryManager脚本
注释所有调用DebugPrintInventoryList的地方(共2个)。
执行程序,效果如下: