Unity2D:主要基于 SpriteRenderer 和 2D物理系统等组成。
UI:由 Canvas 以及 各种 UI 组件组成。
UI 的显示不基于 SpriteRenderer,且UI界面是完全贴合屏幕的,不会随相机的移动而移动。
UI 中除了文本,最多的就是图片、按钮。Image 组件主要复制图片的显示。
Image 游戏物体必须放在 Canvas 游戏物体下才能生效。
主要属性:
主要功能:
在项目管理器中点击一个图片资源,然后在检查器面板中可以看到资源的相关属性设置。
图片切片:实际开发中很多时候我们并不会一个按钮一个图片,而是选择打包在一起,所以需要在 Unity 中进行分割。
如果需要用脚本操作UI相关操作,必须引入UI的命名空间 System.UnityEngine.UI
。
Text 组件就是用来显示文本的,比如等级、属性值、角色名称等等。
Alignment:文本的对齐方式;
Horizontal Overflow:水平溢出
(1)Wrap:文本将自动换行,达到水平边界。
(2)Overflow:文本可以超出水平边界,继续显示。
Vertical Overflow:垂直溢出
(1)Truncate:文本不显示超出垂直边界的部分。
(2)Overflow:文本可以超出垂直边界,继续显示。
Best Fit:尽可能匹配边缘
(1)Min Size:字体的最小大小;
(2)Max Size:字体的最大大小。
Button:Image组件、Button组件
Text:Text组件
Interactable:可交互的,也就是按钮是否有效
Transition:过渡方式,按钮一般分为几种状态,比如鼠标悬浮、点击、不可用
在游戏中,我们经常使用 WASD 或 上下左右方向键等方式来选择按钮,Unity 中的UGUI 也具备这个功能,并且设置起来十分方便。
通过面板添加点击事件;
On Click()栏 -> 添加操作对象 -> 添加对象上绑定的方法
通过代码添加点击事件
private Button button;
private void Start()
{
button = GetComponent<Button>();
button.onClick.AddListener(ButtionClick2);
}
public void ButtionClick2()
{
Debug.Log("ButtonClick2");
}
InputField 中 ContentType 可以设置玩家输入的类型,比如邮箱、密码等。
与 Button 事件类似,虽然事件不同,但是操作方法基本一致。
需要注意的是,如果需要手动获取 InputField 中玩家输入的值,要直接使用 InputField.text
,而不要去查找子物体 Text 中的组件。
通过面板添加事件:
通过代码添加事件
private InputField inputField;
void Start()
{
inputField = GetComponent<InputField>();
// 修改InputField中的内容
/*inputField.text = "12345";
print(inputField.text);*/
// OnValueChanged + OnEndEdit
inputField.onValueChanged.AddListener(OnValueChanged);
inputField.onEndEdit.AddListener(onEndEdit);
}
public void OnValueChanged(string value)
{
Debug.Log(value);
}
public void onEndEdit(string value)
{
Debug.Log(value);
}
Toggle 结构:
private Toggle toggle;
void Start()
{
toggle = GetComponent<Toggle>();
toggle.onValueChanged.AddListener(OnValueChanged);
}
private void Update()
{
if(Input.GetMouseButtonDown(0))
print(toggle.isOn);
}
private void OnValueChanged(bool bl)
{
print("bool: " + bl);
}
注册:玩家输入账号、密码、重复密码、性别等来完成注册,其中需要对密码与重复密码进行一致性校验。
登录:玩家输入账号、密码后和之前输入的账号密码等信息进行匹配。
玩家输入有误时进行弹窗提示。
主面板:主面板上有两个按钮,注册、登录,点击后切换到对应面板。
注册面板:
玩家输入账号、密码、重复密码、性别后点击注册,对密码与重复密码进行匹配。
返回按钮:返回主面板
登录面板:
玩家输入账号、密码后点击登录:
返回按钮:返回主面板
// 主面板 MainPanel
public class MainPanelTest : MonoBehaviour
{
// 单例模式
public static MainPanelTest instance;
private Button registerButton;
private Button loginButton;
private void Awake()
{
instance = this;
}
void Start()
{
registerButton = transform.Find("RegisterButton").GetComponent<Button>();
loginButton = transform.Find("LoginButton").GetComponent<Button>();
registerButton.onClick.AddListener(RegisterButtonClick);
loginButton.onClick.AddListener(LoginButtonClick);
}
private void RegisterButtonClick()
{
// 打开注册面板
RegisterPanelTest.instance.Show();
gameObject.SetActive(false);
}
private void LoginButtonClick()
{
// 打开登录面板
LoginPanelTest.instance.Show();
gameObject.SetActive(false);
}
public void Show()
{
gameObject.SetActive(true);
}
}
// 注册面板 RegisterPanel
public class RegisterPanelTest : MonoBehaviour
{
// 单例模式
public static RegisterPanelTest instance;
private InputField UserName;
private InputField Password;
private InputField RePassword;
private Toggle IsMale;
private Button BackButton;
private Button OKButton;
private void Awake()
{
instance = this;
UserName = transform.Find("UserName/InputField").GetComponent<InputField>();
Password = transform.Find("Password/InputField").GetComponent<InputField>();
RePassword = transform.Find("RePassword/InputField").GetComponent<InputField>();
IsMale = transform.Find("GenderGroup/Male").GetComponent<Toggle>();
BackButton = transform.Find("BackButton").GetComponent<Button>();
OKButton = transform.Find("OKButton").GetComponent<Button>();
BackButton.onClick.AddListener(BackButtonClick);
OKButton.onClick.AddListener(OKButtonClick);
gameObject.SetActive(false);
}
private void BackButtonClick()
{
// 返回主面板
MainPanelTest.instance.Show();
gameObject.SetActive(false);
}
private void OKButtonClick()
{
// 确定注册
// 输入检测
if (string.IsNullOrEmpty(UserName.text) ||
string.IsNullOrEmpty(Password.text) ||
string.IsNullOrEmpty(RePassword.text))
{
FloatWindowTest.instance.ShowInfo("请输入账号或密码");
}
else if(Password.text != RePassword.text)
{
FloatWindowTest.instance.ShowInfo("密码和重复密码不一致");
}
else
{
// 当前用户已存在
if(GameManager.Instance.GetUserInfo(UserName.text) != null)
{
FloatWindowTest.instance.ShowInfo("请勿重复注册");
}
else
{
UserInfo userInfo = new UserInfo(UserName.text, Password.text, IsMale.isOn);
// 保存用户信息
GameManager.Instance.SaveUserInfo(userInfo);
FloatWindowTest.instance.ShowInfo("注册成功");
}
}
}
public void Show()
{
gameObject.SetActive(true);
UserName.text = "";
Password.text = "";
RePassword.text = "";
}
}
// 登录面板 LoginPanel
public class LoginPanelTest : MonoBehaviour
{
// 单例模式
public static LoginPanelTest instance;
private InputField UserName;
private InputField Password;
private Button BackButton;
private Button OKButton;
private void Awake()
{
instance = this;
UserName = transform.Find("UserName/InputField").GetComponent<InputField>();
Password = transform.Find("Password/InputField").GetComponent<InputField>();
BackButton = transform.Find("BackButton").GetComponent<Button>();
OKButton = transform.Find("OKButton").GetComponent<Button>();
BackButton.onClick.AddListener(BackButtonClick);
OKButton.onClick.AddListener(OKButtonClick);
gameObject.SetActive(false);
}
private void BackButtonClick()
{
// 返回主面板
MainPanelTest.instance.Show();
gameObject.SetActive(false);
}
public void OKButtonClick()
{
// 输入检测
if (string.IsNullOrEmpty(UserName.text) ||
string.IsNullOrEmpty(Password.text))
{
FloatWindowTest.instance.ShowInfo("请输入账号或密码");
}
else
{
// 登录用户不存在
UserInfo user = GameManager.Instance.GetUserInfo(UserName.text);
if (user == null)
{
FloatWindowTest.instance.ShowInfo("用户不存在");
}
else if (user.Password != Password.text)
{
FloatWindowTest.instance.ShowInfo("用户名或密码错误");
}
else if (user.Password == Password.text)
{
FloatWindowTest.instance.ShowInfo("登录成功");
}
}
}
public void Show()
{
gameObject.SetActive(true);
UserName.text = "";
Password.text = "";
}
}
// 弹窗 FloatWindow
public class FloatWindowTest : MonoBehaviour
{
// 单例模式
public static FloatWindowTest instance;
private Text infoText;
private Button okButton;
private void Awake()
{
instance = this;
infoText = transform.Find("Info").GetComponent<Text>();
okButton = transform.Find("OKButton").GetComponent<Button>();
// 确认按钮点击事件
okButton.onClick.AddListener(OKButtonClick);
gameObject.SetActive(false);
}
public void ShowInfo(string info)
{
gameObject.SetActive(true);
infoText.text = info;
}
public void OKButtonClick()
{
gameObject.SetActive(false);
}
}
// 存储用户信息(实际中不这么使用)
public class UserInfo
{
public string UserName;
public string Password;
public bool IsMale;
public UserInfo(string userName, string password, bool isMale)
{
UserName = userName;
Password = password;
IsMale = isMale;
}
}
public class GameManager
{
private static GameManager instance;
// 注册后的用户信息
public List<UserInfo> UserInfos = new List<UserInfo>();
public static GameManager Instance
{
get
{
if (instance == null)
instance = new GameManager();
return instance;
}
}
public UserInfo GetUserInfo(string userName)
{
for(int i = 0; i < UserInfos.Count; i++)
{
if(userName == UserInfos[i].UserName)
{
return UserInfos[i];
}
}
return null;
}
public void SaveUserInfo(UserInfo userInfo)
{
UserInfos.Add(userInfo);
}
}
组件结构
组件使用
private Slider slider;
void Start()
{
slider = GetComponent<Slider>();
slider.onValueChanged.AddListener(SliderOnValueChanged);
}
void SliderOnValueChanged(float value)
{
print(value);
}
与 Slider 组件的比较:
DropDown组件:
遮罩组件,是一种可以掩盖其他元素的控件。常用于修改其他元素的外观,或限制元素的形状,Scroll View 或是圆头像都有用到遮罩功能。
Mask 遮罩组件一般添加在父物体上,它将子物体限制为父物体的形状。
类似背包这种想要排列整齐的时候,一般就会使用 Grid Layout Group 表格布局组件。
Grid Layout Group 表格布局组件,会自动管理其下方所在其他 UI 元素的大小、位置等信息。
在层级面板中,点击右键并没有表格布局组件,想要创建表格布局,必须先创建一个空的游戏物体,然后再手动添加 Grid Layout Group.
这样只是创建了表格布局,要实现表格,需要在该游戏物体下方创建其他游戏物体来填充表格,形成类似背包的表格。
Grid Layout Group 表格布局组件
锚点用于固定子物体在父物体中的位置,无论父物体怎样改变,子物体相对于父物体的位置都不变。
UI 的根节点就是 Canvas,意味着 UI 游戏物体都要放在 Canvas 下,才可以得到正确的显示。
一个场景中 Canvas 是可以存在多个的,并且也可以同时生效。
Canvas 游戏物体是由三个组件组成的:
Render Mode:渲染模式
Pixel Perfect:完美像素,边缘更加清晰
Sort Order:画布排序,场景中具备多个 Canvas 时才有意义。
Canvas Scaler 也是屏幕适配的主要方式,一般通过该组件就可以完成适配。
UI Scale Mode 缩放模式:
在 Button 中,按钮的点击就是事件,但是在实际项目中,UI 并不是只有点击这一种事件,比如鼠标悬浮、鼠标按下、鼠标弹起、鼠标拖拽等等,而且 UI 本身可能也并不是一个按钮,这些事件我们通过给游戏物体创建脚本来实现。
脚本中添加 using UnityEngine.EventSystems
事件相关命名空间。
脚本需要继承以下事件接口,并实现对应方法即可。
鼠标事件接口:
IPointerClickHandler
:鼠标点击IPointerDownHandler
:鼠标按下IPointerUpHandler
:鼠标弹起IPointerEnterHandler
:鼠标进入IPointerExitHandler
:鼠标退出拖拽事件接口
IBeginDragHandler
:开始拖拽IDragHandler
:拖拽中IEndDragHandler
:停止拖拽