不知道上一篇里,你们是否是都作出了跳跃的效果。从这一节开始,我提交了代码到Github,你们若是有什么不明白的地方,能够去看源码。另外个人Github里还有两个之前写的spritekit游戏,你们也能够围观一下。传送门git
首先咱们测试一下上一节提到的跳跃的数值,我测试出了一组比较合理的数据,你们能够试用一下。github
private float jumpForce = 15; private float gravity = 1;
接着咱们添加一个障碍物的素材到游戏中,而后将素材拖拽到关系树面板,会自动生成一个以该精灵为外观的游戏对象。咱们在属性面板中,添加一个Box Collider2D组件,和一个Rigidbody2D组件。点击AddComponent以后,直接输入组件的名字,下面会列出搜索结果,直接点击就能够。app
我来解释下这两个组件的做用,你们不明白能够百度一下,网上相应的介绍特别多。collider是设置一个碰撞盒,用来检测碰撞的组件。Rigidbody是刚体盒,表示这个游戏对象的物理属性,好比重量、密度等。据我所知,两个物体若是想检测碰撞,必须至少有一者是刚体,若是两个都只设定了collider没有设定刚体,那么检测不到碰撞。建立collider组件以后,会自动按照当前Sprite Renderer组件中的精灵尺寸,建立一个对应尺寸的碰撞盒,也就是collider组件中的Size属性。刚体组件中,默认使用的是动态的刚体,会受到重力影响,勾选Is Kinematic以后,就变成了静态的刚体,你们能够本身尝试一下选和不选的区别,这里咱们使用的是静态刚体。以下图:编辑器
以后我要向你们介绍一个Unity里很好用的玩具:Prefab。这个单词的意思,是预制体,通俗的来讲,就是好比我要造一辆车子,那么Prefab就是一些作好的部件模具,在须要的时候,我能够直接用模具当即建立一个现成的零件来使用。当须要在游戏运行过程当中,建立大量相同的物体时,这个东西真的很好用,只须要作一次设置,之后直接拿过来初始化就能够了。ide
这里咱们设置好了一个障碍物,而后拖拽关系面板里的障碍物对象到Assets面板中,一个预制体就作好了~!而后咱们删掉关系树中的这个预制体,若是后续须要修改它,直接在Assets目录中选中,就能够在属性面板修改了。函数
下面咱们须要在游戏过程当中,动态建立障碍物对象了。布局
首先咱们在关系面板中,添加一个空对象GameObject,设置其坐标到原点。而后点AddComponet添加一个脚本组件,名字叫CreateObstacle,也就是建立障碍物的意思。在Assets面板中打开这个脚本,下面咱们来讲一下,如何在代码中连接到上面提到的预制体。测试
CreateObstacle类中,添加一行代码,而后保存一下。public GameObject obstaclePrefab;
还记得我以前说过吧,public属性的内容,能够在Unity引擎的编辑器的属性面板直接访问到,这里也是同理。预制体的默认类型是GameObject,咱们在这里建立了一个预制体对象,可是没有赋值,由于咱们会在Unity编辑器中拖拽赋值,告诉脚本咱们将使用哪个预制体。(变量名是我我的习惯,加一个Prefab后缀方便咱们本身辨认哪个是预制体)spa
回到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函数来检测,具体的用法你们百度一下便可。