前言:这一节论述制作控制道具使用的 UI 组件,并建立 UI 组件与程序后端联系的方法,以及一种游戏信息序列化与反序列化的方法。
改变道具数量
前一节我们定义了若干在游戏中出现的道具,关于道具的定义写在配置文件中,可以改动和增减道具的种类。而描述玩家持有何种道具,以及持有的数量,则需要额外的字段存放。在这个游戏中,使用道具会按照道具本身的价值将其兑换为游戏中的通货,这涉及到改变玩家持有的道具数量。
关于这部分功能的实现,分别从视觉展示和逻辑交互两部分入手。
弹出菜单
在物品栏窗口中控制道具消耗的实现方式有很多,这里采用右击物品标识弹出窗口的方式,它长这样:
鼠标在“黄油蛋糕”的图标上悬停并点击右键,出现弹窗提示当前锁定的物品名称,以及一系列按钮。弹窗的左下角点是鼠标点击时的位置。点击不同的按钮将触发不同的动作:使用物品,使用全部物品,关闭弹窗。
这个弹窗在编辑器中依然是一个挂在画布下的节点,内容包含底图、文字和一系列按钮。
UI (空节点,用来挂管理器脚本)
Canvas (UI 画布)
Column
Collection
ExitGame
Selector // 新增加的弹窗节点
Panel // 底图
Content // 这里挂了一个 Vertical Layout Group 组件
Current item name // 空节点,下面有一个 Text 组件
Use // “使用”按钮
Use all // “全部使用”按钮
Cancel // “取消”按钮
弹窗的图层在目前是最靠前的。弹窗节点 Selector 在整个 UI 中只有一个,要不要做成单例取决于个人偏好。个人倾向于将这个弹窗作为 UI 管理器脚本管辖的组件,弹窗的类中公开一些基本函数,在 UI 管理器中将这些基本函数集合入特定的事件函数,于是弹窗组件的内部实现就被隐藏了。
弹窗组件类 Selector 如下:
using UnityEngine;
using UnityEngine.UI;
[RequireComponent(typeof(RectTransform))]
public class Selector : MonoBehaviour
{
[HideInInspector] public Vector2 _defaultPos;
RectTransform rect;
float _width;
float _height;
float _halfWidth;
float _halfHeight;
public Text currentItemName;
private void Awake()
{
rect = GetComponent<RectTransform>();
_width = rect.sizeDelta.x;
_height = rect.sizeDelta.y;
_halfWidth = _width / 2;
_halfHeight = _height / 2;
_defaultPos = new Vector2(-_width, -_height);
}
// 设置自身位置,并保持自身不越过屏幕边缘
void Position(Vector2 pos)
{
pos.x = pos.x < _halfWidth ? _halfWidth :
(pos.x + _halfWidth > Screen.width ? Screen.width - _halfWidth : pos.x);
pos.y = pos.y < _halfHeight ? _halfHeight :
(pos.y + _halfHeight > Screen.height ? Screen.height - _halfHeight : pos.y);
rect.position = pos;
Debug.Log(pos+ ", "+ Input.mousePosition); // 调试信息,可以删
}