当前位置: 首页 > 最新文章 > 正文

Unity游戏教程初步(五):Resources与UI

当球体处于目的区域内时,其将变色。项目需求增加小球进入目的区域的音效。增加计分的UI界面。增加音效-本节相关内容请读者参考:-https://docs.unity.cn/cn/current/ScriptReference/Resources.html,《Resources》-https://docs.unity.cn/cn/current/Manual/class-AudioSource.htm

admin

当球体处于目的区域内时,其将变色。项目需求增加小球进入目的区域的音效。增加计分的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文件夹内。大多数游戏都会有UI,用于记录游戏的得分情况等信息。如果直接创建UI,unity会在此之前自动创建一个Canvas并将被创建的UI作为子项。Hierarchy->UI->Text,创建一个TextUI,我们命名为Bonus。设定初始分数为0,球体进入目的区域时分数加1。

前言

在上一节中我们给球体添加了纹理,并且为场景设置了一个目的区域。当球体处于目的区域内时,其将变色。在这一节里,我们将完善球体在到达目的区域时游戏的反馈,增加音乐和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);        }    }}

增加UI

-本节相关内容请读者参考:

-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。


上一篇: 玫瑰花开的句子唯美(玫瑰花绽放唯美句) 下一篇:英语单词Chart, Figure, Diagram, Illustration, Graph区别
返回顶部