百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程字典 > 正文

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

toyiye 2024-06-21 11:55 8 浏览 0 评论

前言

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

相关推荐

为何越来越多的编程语言使用JSON(为什么编程)

JSON是JavascriptObjectNotation的缩写,意思是Javascript对象表示法,是一种易于人类阅读和对编程友好的文本数据传递方法,是JavaScript语言规范定义的一个子...

何时在数据库中使用 JSON(数据库用json格式存储)

在本文中,您将了解何时应考虑将JSON数据类型添加到表中以及何时应避免使用它们。每天?分享?最新?软件?开发?,Devops,敏捷?,测试?以及?项目?管理?最新?,最热门?的?文章?,每天?花?...

MySQL 从零开始:05 数据类型(mysql数据类型有哪些,并举例)

前面的讲解中已经接触到了表的创建,表的创建是对字段的声明,比如:上述语句声明了字段的名称、类型、所占空间、默认值和是否可以为空等信息。其中的int、varchar、char和decimal都...

JSON对象花样进阶(json格式对象)

一、引言在现代Web开发中,JSON(JavaScriptObjectNotation)已经成为数据交换的标准格式。无论是从前端向后端发送数据,还是从后端接收数据,JSON都是不可或缺的一部分。...

深入理解 JSON 和 Form-data(json和formdata提交区别)

在讨论现代网络开发与API设计的语境下,理解客户端和服务器间如何有效且可靠地交换数据变得尤为关键。这里,特别值得关注的是两种主流数据格式:...

JSON 语法(json 语法 priority)

JSON语法是JavaScript语法的子集。JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔花括号保存对象方括号保存数组JS...

JSON语法详解(json的语法规则)

JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔大括号保存对象中括号保存数组注意:json的key是字符串,且必须是双引号,不能是单引号...

MySQL JSON数据类型操作(mysql的json)

概述mysql自5.7.8版本开始,就支持了json结构的数据存储和查询,这表明了mysql也在不断的学习和增加nosql数据库的有点。但mysql毕竟是关系型数据库,在处理json这种非结构化的数据...

JSON的数据模式(json数据格式示例)

像XML模式一样,JSON数据格式也有Schema,这是一个基于JSON格式的规范。JSON模式也以JSON格式编写。它用于验证JSON数据。JSON模式示例以下代码显示了基本的JSON模式。{"...

前端学习——JSON格式详解(后端json格式)

JSON(JavaScriptObjectNotation)是一种轻量级的数据交换格式。易于人阅读和编写。同时也易于机器解析和生成。它基于JavaScriptProgrammingLa...

什么是 JSON:详解 JSON 及其优势(什么叫json)

现在程序员还有谁不知道JSON吗?无论对于前端还是后端,JSON都是一种常见的数据格式。那么JSON到底是什么呢?JSON的定义...

PostgreSQL JSON 类型:处理结构化数据

PostgreSQL提供JSON类型,以存储结构化数据。JSON是一种开放的数据格式,可用于存储各种类型的值。什么是JSON类型?JSON类型表示JSON(JavaScriptO...

JavaScript:JSON、三种包装类(javascript 包)

JOSN:我们希望可以将一个对象在不同的语言中进行传递,以达到通信的目的,最佳方式就是将一个对象转换为字符串的形式JSON(JavaScriptObjectNotation)-JS的对象表示法...

Python数据分析 只要1分钟 教你玩转JSON 全程干货

Json简介:Json,全名JavaScriptObjectNotation,JSON(JavaScriptObjectNotation(记号、标记))是一种轻量级的数据交换格式。它基于J...

比较一下JSON与XML两种数据格式?(json和xml哪个好)

JSON(JavaScriptObjectNotation)和XML(eXtensibleMarkupLanguage)是在日常开发中比较常用的两种数据格式,它们主要的作用就是用来进行数据的传...

取消回复欢迎 发表评论:

请填写验证码