[原创]Unity2D 开发 + UGUI 中文教程三

news/2024/7/8 6:40:59

不知道上一篇里,大家是不是都做出了跳跃的效果。从这一节开始,我提交了代码到Github,大家如果有什么不明白的地方,可以去看源码。另外我的Github里还有两个以前写的spritekit游戏,大家也可以围观一下。传送门

添加障碍物

首先我们测试一下上一节提到的跳跃的数值,我测试出了一组比较合理的数据,大家可以试用一下。

private float jumpForce = 15;
private float gravity = 1;

接着我们添加一个障碍物的素材到游戏中,然后将素材拖拽到关系树面板,会自动生成一个以该精灵为外观的游戏对象。我们在属性面板中,添加一个Box Collider2D组件,和一个Rigidbody2D组件。点击AddComponent之后,直接输入组件的名字,下面会列出搜索结果,直接点击就可以。

我来解释下这两个组件的作用,大家不明白可以百度一下,网上相应的介绍特别多。collider是设置一个碰撞盒,用来检测碰撞的组件。Rigidbody是刚体盒,表示这个游戏对象的物理属性,比如重量、密度等。据我所知,两个物体如果想检测碰撞,必须至少有一者是刚体,如果两个都只设定了collider没有设定刚体,那么检测不到碰撞。创建collider组件之后,会自动按照当前Sprite Renderer组件中的精灵尺寸,创建一个对应尺寸的碰撞盒,也就是collider组件中的Size属性。刚体组件中,默认使用的是动态的刚体,会受到重力影响,勾选Is Kinematic之后,就变成了静态的刚体,大家可以自己尝试一下选和不选的区别,这里我们使用的是静态刚体。如下图:

图片描述

之后我要向大家介绍一个Unity里很好用的玩具:Prefab。这个单词的意思,是预制体,通俗的来说,就是比如我要造一辆车子,那么Prefab就是一些做好的部件模具,在需要的时候,我可以直接用模具立即创建一个现成的零件来使用。当需要在游戏运行过程中,创建大量相同的物体时,这个东西真的很好用,只需要做一次设置,以后直接拿过来初始化就可以了。

这里我们设置好了一个障碍物,然后拖拽关系面板里的障碍物对象到Assets面板中,一个预制体就做好了~!然后我们删掉关系树中的这个预制体,如果后续需要修改它,直接在Assets目录中选中,就可以在属性面板修改了。

在脚本里挂载预制体Prefab

下面我们需要在游戏过程中,动态创建障碍物对象了。

首先我们在关系面板中,添加一个空对象GameObject,设置其坐标到原点。然后点AddComponet添加一个脚本组件,名字叫CreateObstacle,也就是创建障碍物的意思。在Assets面板中打开这个脚本,下面我们来说一下,如何在代码中链接到上面提到的预制体。

CreateObstacle类中,添加一行代码,然后保存一下
public GameObject obstaclePrefab;
还记得我之前说过吧,public属性的内容,可以在Unity引擎的编辑器的属性面板直接访问到,这里也是同理。预制体的默认类型是GameObject,我们在这里创建了一个预制体对象,但是没有赋值,因为我们会在Unity编辑器中拖拽赋值,告诉脚本我们将使用哪一个预制体。(变量名是我个人习惯,加一个Prefab后缀方便我们自己辨认哪一个是预制体)

回到Unity编辑器,选中这个刚创建的GameObject,会发现脚本组件下面多出了一个属性框(如果没有一般是脚本没有保存或者代码有错误)。如图:
图片描述

然后我们将预制体,也就是右边这个拖拽到这个属性栏里,预制体就链接到脚本中了。注意:精灵和预制体从icon上看起来差不多,不要选错了,如果区分不开,仔细对比这两个对象的属性面板就知道了。同时,如果你拖拽的目标不是GameObject类型,那么是无法拖拽上去的。

之后我们回到Mono,现在可以用预制体创建实例了。

使用计时器

计时器在任何游戏中都非常的常用,下面我们做一个简单的计时器。

首先在obstaclePrefab下面,定义两个变量currentTime和interval,分别表示累计时间和时间间隔。

private float currentTime = 0;
private float interval = 1;

然后在Update函数中添加如下代码:

currentTime += Time.deltaTime;//每一帧计算一下累计时间
if(currentTime > interval){//时间超过时间间隔 触发事件
    currentTime = 0;//重置计数器
    Debug.Log("something happen");//Unity中用来打印日志到控制台的函数
}

这样我们就制作了一个间隔时间为1秒的触发器。在Unity中执行一下,会看到控制台每隔一秒会输出字符串something happen。
图片描述

在我的布局里,Project面板和Console都在下面,Assets文件夹就显示在Project面板中。

动态创建障碍物

下面我们用计时器来做一些事。

删掉打印日志的代码,添加以下代码:
Instantiate(obstaclePrefab, Vector3.zero, Quaternion.identity);
这个你从未见过的函数,是以后会大量使用的一个函数,专门用来将预制体实例化为一个可以用的零件,并添加到场景里。第一个参数是预制体链接的变量,第二个参数是一个初始坐标,第三个参数是初始角度。Vector3.zero表示的是坐标原点,Quaternion那个神马的相当于是角度的原点,也就是不旋转任何角度。

然后我们执行游戏,发现场景里只能看到一个对象,但是关系树面板中却不断生成新的对象,这些对象都叠加到了原点上。因为主角只会原地跑,而障碍物需要随着地面一起运动,那么我们下面就让障碍物自己动起来。

在Assets文件夹里选中预制体,添加一个脚本组件:Moving,双击Moving脚本就会在Mono中打开。因为障碍物是随着地面运动,所以我们将ScrollGround脚本中的这一行拷贝到Moving中的Update函数里:
transform.position -= new Vector3(Time.deltaTime, 0, 0);

当障碍物移动到屏幕外的时候,这个障碍物没有用了,只会白白占用内存,那我们在下面来清理掉屏幕外的障碍物。最终Moving脚本的Update函数如下:

void Update () {
    transform.position -= new Vector3(Time.deltaTime, 0, 0);

    if(transform.position.x < -11.36f){//这个数值可以是任何超过屏幕左边界的一个X坐标 我这里直接使用了一个比较大的值
        Destroy(gameObject);//这个函数用来销毁游戏对象
    }
}

Destroy函数中的参数,如果写gameObject(注意小写首字母),那么指代的就是当前游戏对象的本体,这个函数也可以用来销毁当前游戏对象的某个组件,比如Destroy(gameObject.GetComponent<Rigidbody2D>());,GetComponent函数用来获取一个特定组件,这个我们后面再说。

现在执行一下游戏,可以看到障碍物已经“跑”起来了~!

设定角色的碰撞检测

但是好像哪里不对劲!障碍物应该选一个更合适的位置来创建~我们可以拖拽一个预制体到场景中,来回拖动,看它的坐标值变化,找到一个合适的生成障碍物的初始位置。我这里测出的坐标是:
图片描述
不要忘记测试完坐标值,删掉这个临时放进去的障碍物。

我们把这个坐标值填入CreateObstacle脚本中,替换掉Vector3.zero,变成:
Instantiate(obstaclePrefab, new Vector3(7, -0.24f, 0), Quaternion.identity);

回到Unity编辑器,选中主角,添加一个Box Collider2D组件,用来检测主角和障碍物的碰撞,这里collider的尺寸也自动帮我们设定好了。进入Player脚本,添加一个函数:

void OnTriggerExit2D(Collider2D other) {
    Debug.Log("game over");
}

这里我们使用的是一个触发器函数,当碰撞触发时,这个函数里的代码会被执行。但是执行游戏时,发现这个函数没有被触发,这是为什么呢?因为我们还需要设置碰撞盒为trigger类型。分别编辑主角和障碍物的预制体的Box Collider2D组件,勾选Is Trigger选项。这样这两个对象,就会检测到碰撞事件的触发了。

Is Trigger选项,三言两语不太好说明白。如果你需要做不可穿越的碰撞效果,比如人撞到了墙,那么就可以不用Is Trigger。如果你需要做可穿越的碰撞,比如人碰到了毒雾,那么就需要用触发器的形式来做。这里我都用代码来控制了,所以使用了触发器模式,只是为了检测到碰撞。如果不用触发器模式,那么两个collider都要取消Is Trigger选项,然后使用OnCollisionEnter2D函数来检测,具体的用法大家百度一下即可。



http://www.niftyadmin.cn/n/4138407.html

相关文章

测试、文件的读写、SharedPreferences

冒烟测试: adb shell monkey -p <程序的包名> -v <事件的数量>android下单元测试: 在AndroidManifest.xml文件中配置一下信息:在manifest节点下: <!-- 指定测试信息和要测试的包 --><instrumentationandroid:name"android.test.Instrumentat…

Java从入门到精通——基础篇之Java基础概念

5月份就要开始软考了&#xff0c;年后我就开始看软考视频了&#xff0c;根据一个软考复习的计划文档我开始看马士兵的Java基础。 上图是Java基础第一章的总结 Java开始讲的是大部分语言都讲的一些基础语法。其实和以前学的面向对象的语言特别相似&#xff0c;跟C#的语法差不多。…

【转】ubuntu打包压缩命令总结

原文网址&#xff1a;http://blog.csdn.net/renero/article/details/6428523 .tar解包&#xff1a;tar xvf FileName.tar打包&#xff1a;tar cvf FileName.tar DirName&#xff08;注&#xff1a;tar是打包&#xff0c;不是压缩&#xff01;&#xff09;---------------------…

pull生成、解析xml

public class TestCase extends AndroidTestCase {public void test() { // writeXmlToLocal();/*** 获取 xml 中的数据*/List<Person> personList parserXmlFromLocal();for (Person person : personList) {Log.i("TestCase", person.toString());}}/**…

完美版js金钱正则表达式校验

前言 &#xff1a; 同事在实现发布商品中填写单价时&#xff0c;需要js校验价格是否符合金钱的格式&#xff0c;在网上找了一些&#xff0c;没有一个能解决问题的&#xff0c;都是简单的校验&#xff0c;漏洞百出。 我说这还不简单&#xff0c;不就一个正小数吗&#xff1f;他说…

openoffice安装手记

安装目的&#xff1a;通过JAVA实现OFFICE在线预览 操作系统版本&#xff1a;Red Hat Enterprise Linux Server release 5.4 (Tikanga) OPENOFFICE版本&#xff1a;OOo_3.3.0_Linux_x86_install-rpm_en-US.tar.gz 安装&#xff1a; 1.解压 tar -xzvf OOo_3.3.0_Linux_x86_instal…

一个三次函数求参数b的最大值

设$f(x)ax^3bxc$ (a,b,c是实数),当$0\le x\le1$时&#xff0c;$0\le f(x)\le 1$求$b$的可能的最大值。转载于:https://www.cnblogs.com/zjyyhs/archive/2013/03/09/2951438.html

OC 类别(分类)Categroy

Categroy类别&#xff0c;又称为扩展类&#xff0c;在类的原基础上扩展方法&#xff0c;且不可添加变量&#xff0c;如果扩展的方法与原始类中的方法相同&#xff0c;则会隐藏原始方法&#xff0c;且不可在扩展方法中通过super调用原始方法&#xff0c;这里与继承不同。 定义: …