unity的ui怎么用(Unity游戏教程初步五)
在上一节中我们给球体添加了纹理,并且为场景设置了一个目的区域当球体处于目的区域内时,其将变色在这一节里,我们将完善球体在到达目的区域时游戏的反馈,增加音乐和UI显示,下面我们就来说一说关于unity的ui怎么用?我们一起去了解并探讨一下这个问题吧!
unity的ui怎么用
前言在上一节中我们给球体添加了纹理,并且为场景设置了一个目的区域。当球体处于目的区域内时,其将变色。在这一节里,我们将完善球体在到达目的区域时游戏的反馈,增加音乐和UI显示。
项目需求增加小球进入目的区域的音效。
增加计分的UI界面。
增加音效-本节相关内容请读者参考:
-https://docs.unity.cn/cn/current/ScriptReference/Resources.html,《Resources》
-https://docs.unity.cn/cn/current/Manual/class-AudioSource.html,《音频源》
我们可以用两个方法将音效素材导入到游戏。第一个就是按照上一节绑定变量的方法,将音效素材作为JudgeController的属性绑定到类中;第二个是使用Resources文件夹。同时,为了让JudgeController可以播放音乐,我们需要为其添加一个Audio Source组件。
Resources文件夹是一类文件夹,其文件夹名为Resources,位于工程目录下的Assets文件夹内(不需要位于根目录下,比如Assets\a\Resources也有效)。我们可以在脚本中使用Resources.Load来访问Resources文件夹下的文件。
第一种方法因为已经在前面使用过了,所以在这里我们不多赘述,来看第二种方法。由于unity预设建立的项目中没有Resources文件夹,我们先在Assets文件夹下建立一个Resources文件夹,然后将音效文件放进去。
然后码代码:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class JudgeController : MonoBehaviour
{
public GameObject sphere; //球体的引用
//近点和远点分别是目的区域离原点最近和最远的点
public Vector3 nearP=new Vector3(2.5f,0,2.5f); //近点
public Vector3 farP= new Vector3(5,0,5); //远点
private AudioClip m;
bool hasClip=false; //标志,球体在一次进出是否播放过音效
// Start is called before the first frame update
void Start()
{
m=Resources.Load<AudioClip>("001"); //加载Assets/.../Resources/001.*
}
// Update is called once per frame
void Update()
{
Vector3 p=sphere.GetComponent<Transform>().position; //位置
if(p.x>nearP.x && p.x<farP.x && p.z>nearP.z &&p.z<farP.z){
//小球中心点在目的区域内
GetComponent<AudioSource>().clip=m;
if(!hasClip){
GetComponent<AudioSource>().Play(); //播放
hasClip=true;
}
sphere.GetComponent<Sphere>().changeMaterial(true); //调用Sphere的函数
}else{
//不在区域内,变回来
hasClip=false;
sphere.GetComponent<Sphere>().changeMaterial(false);
}
}
}
-本节相关内容请读者参考:
-https://docs.unity.cn/cn/current/Manual/UISystem.html,《UI》
-https://docs.unity.cn/cn/current/Manual/UICanvas.html,《画布》
UI是User Interface(用户界面)的缩写。大多数游戏都会有UI,用于记录游戏的得分情况等信息。在unity中,UI必须作为Canvas(画布)的子项存在。如果直接创建UI,unity会在此之前自动创建一个Canvas并将被创建的UI作为子项。
Hierarchy->UI->Text,创建一个TextUI,我们命名为Bonus。设定初始分数为0,球体进入目的区域时分数加1。改写JudgeController的代码:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class JudgeController : MonoBehaviour
{
public GameObject sphere; //球体的引用
public GameObject bonusUI; //显示分数的UI
//近点和远点分别是目的区域离原点最近和最远的点
public Vector3 nearP=new Vector3(2.5f,0,2.5f); //近点
public Vector3 farP= new Vector3(5,0,5); //远点
private AudioClip m; //音效文件
private int bonus; //分数
bool hasClip=false; //标志,球体在一次进出是否播放过音效
// Start is called before the first frame update
void Start()
{
bonus=0;
m=Resources.Load<AudioClip>("001"); //加载Assets/.../Resources/001.*
}
// Update is called once per frame
void Update()
{
Vector3 p=sphere.GetComponent<Transform>().position; //位置
if(p.x>nearP.x && p.x<farP.x && p.z>nearP.z &&p.z<farP.z){
//小球中心点在目的区域内
GetComponent<AudioSource>().clip=m;
if(!hasClip){
bonus ;
bonusUI.GetComponent<Text>().text=bonus.ToString(); //更新分数
GetComponent<AudioSource>().Play(); //播放
hasClip=true;
}
sphere.GetComponent<Sphere>().changeMaterial(true); //调用Sphere的函数
}else{
//不在区域内,变回来
hasClip=false;
sphere.GetComponent<Sphere>().changeMaterial(false);
}
}
}
可以看到我们增加了一个引用bonusUI,将这个变量与Bonus绑定。然后调整Bonus的大小和其Text的内容(由于后续内容由JudgeController控制,这里只需要将Text置为0即可)。
# TextMeshPro-Text同样是UI,TextMeshPro可以被看做是Text的升级版。因为文档里没有与其相关的资料,所以在这里笔者会简单描述一下与它有关的信息。
TextMeshPro又称为TMP,一开始是一个外部插件,在最近的版本中才被包含进unity本体中。TMP采用了SDF文字渲染技术,相比原生的Text组件它能保证文字在缩放数倍后仍然保持平滑(其实就是矢量绘图)。
但是保持文字的平滑自然需要代价,TMP会为字体创建一个纹理集,而此纹理集在字体所属语言为中文的情况下会占用较大的空间。
而TMP也不只有这一个长处,TMP还可以设置文字的描边颜色渐变等,并且可以图文混用。
增加得分点-本节相关内容请读者参考:
-https://docs.unity.cn/cn/current/ScriptReference/Random.html,《Random》
既然已经有了一套基础的得分系统,不妨在之前的基础上增加一个得分点,比如说,让平面上的正方体在进入得分区域时重置位置并且得分。
按照之前的思路,修改JudgeController,并给Cube添加脚本:
JudgeController.cs(注:前文中对于近点/远点的定义有误,在这里更正)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class JudgeController : MonoBehaviour
{
public GameObject sphere; //球体的引用
public GameObject bonusUI; //显示分数的UI
public GameObject cube; //正方体的引用
//近点和远点分别是目的区域离xy最大的点和xy最小的点
public Vector3 nearP=new Vector3(2.5f,0,2.5f); //近点
public Vector3 farP= new Vector3(5,0,5); //远点
private AudioClip m; //音效文件
private int bonus; //分数
bool hasClip=false; //标志,球体在一次进出是否播放过音效
// Start is called before the first frame update
void Start()
{
bonus=0;
m=Resources.Load<AudioClip>("001"); //加载Assets/.../Resources/001.*
}
bool comPosition(Vector3 p)
{ //比较传入点与近点/远点的相对位置,内部函数
if(p.x>nearP.x && p.x<farP.x && p.z>nearP.z &&p.z<farP.z){
return true;
}else{
return false;
}
}
// Update is called once per frame
void Update()
{
Vector3 p=sphere.GetComponent<Transform>().position; //位置
if(this.comPosition(p)){
//小球中心点在目的区域内
GetComponent<AudioSource>().clip=m;
if(!hasClip){
bonus ;
bonusUI.GetComponent<Text>().text=bonus.ToString(); //更新分数
GetComponent<AudioSource>().Play(); //播放
hasClip=true;
}
sphere.GetComponent<Sphere>().changeMaterial(true); //调用Sphere的函数
}
else{
//不在区域内,变回来
hasClip=false;
sphere.GetComponent<Sphere>().changeMaterial(false);
}
Vector3 c=cube.GetComponent<Transform>().position;
if(this.comPosition(c)){
//一旦抵达目标地点,就开始传送,所以不需要额外标志,也没有else
cube.GetComponent<Cube>().transmit(nearP,farP);
bonus =2;
bonusUI.GetComponent<Text>().text=bonus.ToString(); //更新分数
}
}
}
Cube.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Random=UnityEngine.Random;
public class Cube : MonoBehaviour
{
public GameObject plane; //平台,用于计算区域长度
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
}
float comVxy(float far,float near,float width){ //封装内部函数
if(far<width){ //换成near>-width也是一样的,因为目的区域必然不大于整个区域,所以只要比较一个
if(Random.value>0.5){
return Random.Range(far,width);
}
else{
return Random.Range(-1*width,near);
}
}
else{
return Random.Range(-1*width,near);
}
}
public void transmit(Vector3 near,Vector3 far){
//以0,0,0为中心的情况下,给出:整个区域长度、目的区域近点和远点 将正方体传送到整个区域之内,目的区域之外
//设定平面长宽相等,生成在与目的区域相对的区域内
Vector3 v2=new Vector3(0,-4.5f,0);
float myWidth=GetComponent<Transform>().localScale.x*0.5f; //由于算的是物体中心的位置,要减去到中心的距离
float width=plane.GetComponent<Transform>().localScale.x*5-myWidth;
v2.x=this.comVxy(far.x,near.x,width);
v2.z=this.comVxy(far.z,near.z,width); //笔者的实例里y轴朝上
transform.localPosition=v2; //这里是相对坐标
print(v2);
}
}
可以看到在Cube.cs中,我们传送物体使用的是transform.localPosition(GetComponent<Transform>().localPosition),而非position。这是因为笔者在之前建立了一个空游戏对象作为Cube的父对象,而这里需要对正方体的父对象定位(如果没有父对象localPosition就与position相同)。我们把position称为世界位置,而localPosition则是相对位置。position是游戏对象在绝对坐标系下(世界坐标系,也就是无父对象时Transform面板显示的坐标)的位置,而localPosition则是position对游戏对象的所有父对象的位置进行变换之后的位置。例如在场景下有一个根游戏对象A(1,1,1),其子游戏对象B在Transform面板里的坐标为(0,1,-1),则B在世界坐标系的坐标为A B(1,2,0)。
由于需要判断两个物体的位置,为了节省代码量我们把判断位置部分的代码封装为一个函数comPosition(其实也就是节省了一行不到,但是也省得写了)。同时,建议读者尽量使用unity的Random来生成随机数,而不使用C#自带的Random。
,免责声明:本文仅代表文章作者的个人观点,与本站无关。其原创性、真实性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容文字的真实性、完整性和原创性本站不作任何保证或承诺,请读者仅作参考,并自行核实相关内容。文章投诉邮箱:anhduc.ph@yahoo.com