Unity 2D入门基础教程之僵尸先生

摘要:
创建游戏后切换到2D(默认为3D)有什么区别?上述对话框是Unity中遇到的第一个二维特征设置。您可以随时更改此2D设置,稍后我们将解释Sprite资源导入设置的详细信息。2D模式下场景视图的一个2D功能是场景视图中有一个按钮来控制2D切换。该按钮将在透视视图和正交投影视图之间切换场景摄影机。它们之间的区别是什么

注:这是根据网上教程完成的。

翻译:http://blog.1vr.cn/?p=1422

原文:http://www.raywenderlich.com/61532/unity-2d-tutorial-getting-started

如果用以前版本的Unity做2D游戏,虽然能做,但是要费很多周折.
比如你可以将一张纹理赋予一个”面片”网格,然后用脚本控制它的动画调整它的位移.如果你要使用物理引擎,那么还要将这个Obeject处理3D的,所以 你还要确保你的Object要有足够的深度以确保他们在其它轴向上不起冲突.或者你选用一个第三方插件,如2D Toolkit或者Orthello 2D Framework,他们有着强大的功能,但同样需要你去做一些约束工作.
当上面这些你仍然可以选用上面这些方法的时候,Unity4.3增加了原生的2D开发环境,让我们一探究竟吧.

创建项目

Unity 2D入门基础教程之僵尸先生第1张

从上图标记中可以看出:首先是游戏保存位置,然后是选择游戏需要的资源文件也就是包,其次是游戏类型选择2D,当然也可以创建游戏后,在导入需要的包和切换到2D游戏,稍后会说明,创建游戏后在切换到2D有什么区别(默认是3D)

上面这个对话框是Unity中遇到的第一个含有2D特性的设置.你可以随时改变这个2D设置,如果你想更改这个设置,可以选择”EditProject SettingsEditor”打开编辑器设置,在”Default Behavior Mode”中改模式为2D,如下图:

Unity 2D入门基础教程之僵尸先生第2张

“Default Behavior Mode”(默认行为模式)定义你项目在导入Assets时的默认导入设置,当设置为3D模式时,Unity假设你将导入的文件创建为纹理类型 (如:PNG文件);当设置为2D时,Unity假定你想要的导入的资源为Sprite类型,稍后会对关于Sprite资源导入设置具体的解释.

场景视图的2D模式

下一个2D特征就是在场景视图里有个控制二维切换的按钮,点击2D按钮可以激活2D模式,像下面这样:

Unity 2D入门基础教程之僵尸先生第3张

这个按钮会将场景相机在透视视图和正交投影视图之间进行切换.它们有什么差别呢?当观察透视视图时,远离相机的物体看起来更小,就像在现实世界中眼睛看物 体一样,然而当正交投影视图的时候,物体的大小并不受与相机的距离影响.因此,在二维模式时,一个对象不管位置离相机远近,只要尺寸不变,它看起来将没有 变化的.

Unity 2D入门基础教程之僵尸先生第4张

轻松制造精灵(Sprites)

直接把图片拖到project窗口中,当然你可以在project 右键 选择 Import New Asset 

注:不管那种方式,资源都不能放在中文目录下面

Unity 2D入门基础教程之僵尸先生第5张

因为之前默认设置了游戏类型是2D。所以。图片会生成精灵,图片都有一个小三角形,单击展开

Unity 2D入门基础教程之僵尸先生第6张

说明此时创建精灵成功,如果不成功,你可以手动改变图片的类型:

Unity 2D入门基础教程之僵尸先生第7张

然后单击 Apply 则把图片转换为精灵

Unity 2D入门基础教程之僵尸先生第8张

你会发现。为什么生成精灵后。会有两个一样的 cat 那有什么区别呢?

父级的cat是纹理资源.它将关联到你导入的原始美术资源文件cat.png,以及控制着如何从这个纹理资源创建Sprites,你可以看到它有个文件内容的缩略图.

子集的cat是Unity导入cat.png时创建的Sprite资源.现在只有一个子项,因为Unity只从文件里创建了一个Sprite,教程后面将教你创建”slicing sprite”,即从一个图片创建出多个Sprites.

注:Unity渲染Sprite对象实际上是由一个Texture2D生成的,图像信息实际是存储于图片文件中,你也可以动态的创建自己需要的Texture2D对象来运行时生成Sprite,这个进阶的知识本教程就先不讲了.

比如cat.png,你可以从Finder中拽一个图片到Scene视图(或者Hierarchy视图,随你自己)中创建Sprites.但是更常见的是先添加资源到Project里在添加它到场景中.

将下载到的文件添加到项目里:background.png, enemy.png, 和 zombie.png.Unity提供了五种方法让你将资源导入项目中:


从Finder窗口拖拽文件到Project视图.到”AssetsImport New Asset…”菜单,选择文件并点击Import.


在Project视图中右键选择”AssetsImport New Asset…”菜单,选择文件并点击Import.


在你的系统中直接添加文件或者创建子目录到项目的Assets目录,Unity会自动刷新显示最新的资源内容.不过要注意,一定不要直接从文件系统里删除 不用的资源,要总是从Unity编辑器内部删除资源,因为Unity会存储有关项目的资源metadate,直接从文件系统修改删除可能损坏项目结构.

从Project视图里拖拽enemy到Hierachy视图.和cat一样,同样会有两个名字为enemy项出现在Project视图中,当现在这样只有一个子精灵的时候(后面会提到精灵表)你选择拖拽哪个enemy到Hierarchy视图都是一样的

精灵创建成功后。你就可以把精灵直接拖到Scene或者Hierarchy中使用,此时,Unity自动附加了一个Sprite Renderer组件,用来显示精灵图片

Unity 2D入门基础教程之僵尸先生第9张

可以看到Sprite的名称.上图里你可以看到”cat”对象在精灵渲染器里被分配的名字是”cat”

现在分别把cat,enemy,background,然后把zombie拖到Sceen中,如上图结构

把backgrond设置位置为(0,0,0),cat设置它的位置为(0,2,0)

但你会发现,Scene中cat,enemy都不显示,

Unity 2D入门基础教程之僵尸先生第10张

现在看不到cat和enemy没关系,它们只是被背景暂时挡住了.可以很容易的调整出来,在调整他们层次之前,我们需要弄一个僵尸 zombie

切片精灵表(Slicing Sprite Sheets)

已经导入zombie.png到项目了,你会发现这个文件和其它文件不同,它包含了好多个图像,如下图:

Unity 2D入门基础教程之僵尸先生第11张

这种文件通常被称为精灵表(sprite sheet),我们将为表里的每个图像创建单独的Sprite.在Project视图里展开zombie,能看到像下面截图这样,Unity创建了一个包含所有图像的Sprite.这不是我们想要的.

Unity 2D入门基础教程之僵尸先生第12张

Unity提供了一个非常简单的解决方案,可以来处理这个需求,在Porject视图选择zombie的顶层级后会看到Inspector中显示了它的Import Settings,设置Sprite模式到Multiple并点击Apply:

Unity 2D入门基础教程之僵尸先生第13张

unity默认切片,生成了4个小僵尸

Unity 2D入门基础教程之僵尸先生第14张

当然你也可以手动切片,单击 Sprite Editor打开精灵编辑器

Unity 2D入门基础教程之僵尸先生第15张

打开精灵编辑器

 Unity 2D入门基础教程之僵尸先生第16张

Unity是基于贴图的透明度来确定精灵切分范围的.你可以看到它找到的精灵都会有一个线框表示.现在,我们看到Unity找到了4个精灵:

精灵编辑器的slice按钮 Unity能根据图片自动找到精灵,同样你也可以调整它自动处理的结果.这里我们用它默认设置,点击Slice按钮.

Unity 2D入门基础教程之僵尸先生第17张

我们可以改变这里的值,也可以直接在图像中调整范围和中心点位置.
通常,做了更改后,要点击应用(Appley)或者还原(Revert)按钮来保存或者放弃做的修改.

Unity 2D入门基础教程之僵尸先生第18张

Unity 2D入门基础教程之僵尸先生第19张

现在你可以拖动一个僵尸到scene中,并并设置位置为(-2,0,0)

 

配置游戏视图

我们要将游戏视图尺寸设定为1136 x 640大小. 用Game视图左上角的下拉菜单来改变纵横比或固定分辨率,如下图:

Unity 2D入门基础教程之僵尸先生第20张

Unity 2D入门基础教程之僵尸先生第21张

此时的Sceen场景是这个样子的

Unity 2D入门基础教程之僵尸先生第22张

但你做到这里的时候,已经 遇到两个问题了:

1:场景视图的Camera设置不正确,背景不能完全填充到视图中.
2:场景中游戏对象的渲染顺序不正确,所以cat和enemy都埋在了沙土里.

首先我们来修正Camera.

修正相机Projection

在2D游戏中,通常希望相机使用正交视图而不是透视图.本教程的前面我们已经提到Unity默认是使用透视视图的相机.我们在Hierarchy视 图中选择”Main Camera”,在相机组件中,将投影设置为正交投影.并调整调整它Transform组件里的Position为(0,0,-10).如下图:

Unity 2D入门基础教程之僵尸先生第23张

现在效果看上去与透视投影没什么区别,精灵不受距离相机的远近影响,那怎么放大背景使其充满屏幕呢?我们推荐改变Camera的Size属性.

Camera的Size定义了视图的尺寸.它的值是从视图中心到视图顶部的距离.换句话说这个值等于视图一半高度.视图的宽度基于视图的长宽比计算,如下图:

 Unity 2D入门基础教程之僵尸先生第24张

 在本例中,我们需要将背景图片从上到下完全占满整个屏幕,并允许其水平滚动.背景图像的高度是640px,我们取一半,即320px.不过这并不是完全正确的.
在Project视图里选择background的父级查看Import Settings.
在精灵渲染器(Sprite Renderer)的”像素到单位(Pixels to Units)”默认值是100,如下图:

Unity 2D入门基础教程之僵尸先生第25张

在Unity中,”单位(Units)”并不一定对应到屏幕上的像素.通常物体的大小都是相对于彼此的,可以假设单位为任何计量单位,如1 unit=1米.对于精灵,Unity以像素为单位来确定大小.

例如,准备将一个500px宽度的图像导成精灵.下表显示了将它用不同的”Pixels to Units”时所呈现出的精灵在X轴向上的差别.

Pixels to UnitsX ScaleWidth CalculationWidth
1001.0500/100*1.05units
1000.5500/100*0.52.5units
1002.0500/100*2.010units
501.0500/50*1.010units
500.5500/50*0.55units
502.0500/50*2.020units

 

不同”像素到单位(Pixels to Units)”的对比图. background.png为640高,background精灵的”像素到单位(Pixels to Units)”比例为100,所以在Hierarchy视图中它将呈现为6.4个units高.正交相机的Size属性值是屏幕高度的一半,所以我们要设 置相机尺寸(Size)为3.2个单位,如下图:

Unity 2D入门基础教程之僵尸先生第26张

现在背景已经正确的充满了Game视图中,如下图:

Unity 2D入门基础教程之僵尸先生第27张

正确的相机设置下的Game视图 现在背景图像显示正常了,你就可以看到图像质量的问题了.下面两张图片是图片对比:

Unity 2D入门基础教程之僵尸先生第28张

当前设置的海滩

Unity 2D入门基础教程之僵尸先生第29张

改变纹理设置后的海滩

上面这个问题是由于背景纹理在导入时压缩导致.我们可以通过改变导入设置修正它.

纠正导入设置

在Project视图选择background的父级再次显示导入设置(Import Settings),这次我们看底部的预览图.
这个预览窗口将显示纹理的尺寸,颜色信息和内存使用情况.正如下面截图中所看到的当前纹理大小为1024×320像素,但background.png实际为2048×640像素,这就意味着Unity缩小了50%以适应1024×1024纹理尺寸.

为了解决这个质量问题,在导入设置的底部选择如图所示的最大尺寸和格式设置:

Unity 2D入门基础教程之僵尸先生第30张

最大尺寸(Max Size)定义生成纹理所允许的最大尺寸,它是一个正方形,默认为1024px.同时图像深度默认为压缩的(Compressed).

我们可以为不同目标平台设置不同的值(例如iOS,网上及Android上),但本例中我们只处理默认(Default)选项卡.

在默认(Default)选项卡中,改最大尺寸(Max Size)到2040和点击应用(Apply)按钮.导入设置现在应该是这样的:

Unity 2D入门基础教程之僵尸先生第31张

马上你就会看到无论是场景视图还是游戏视图,画质都很好.这是因为背景图像用了较少的压缩.

用了正确设置的游戏视图 在Inspector预览图中我们能看到背景纹理现在占用5.0MB内存,远高于之前的大小

Unity 2D入门基础教程之僵尸先生第32张

控制绘图顺序(Controlling Draw Order)

因为cat和enemy被绘制在了背景后面,所以我们看不到它们.可以调整游戏对象Z轴的位置,使对象靠近相机,我觉得这是一个非常好的方式,然而Unity现在支持图层排序(Sorting Layers),更适合处理这个问题.

在Hierarchy视图选择cat,把精灵渲染器的层排序(Sorting Layer)设置为Default,如下图:

Unity 2D入门基础教程之僵尸先生第33张

同一个层后面绘制的会把前面的绘制的覆盖掉,可以通过order in Layer 改变排序,但我这里不必要放在同一个层。因为他们不属于一类

现在创建新层

点击Sorting Layer下拉框,你项目所有层都将呈现在这里,现在只有默认定义的Default层.选择Add Sorting Layer

Unity 2D入门基础教程之僵尸先生第34张

可以看到有”Add Sorting Layer…. “选项,点击+号,我们创建一个新的排序图层,命名为cat,同样的再创建两个层,分别是Enemies和Zombie.现在看起来如下图:

Unity 2D入门基础教程之僵尸先生第35张

这些层将定义绘制顺序,Layer 0,名字是Default,是在最远最后面的,Layer 1,名字是Cats,在它的前面.
现在,已经添加的每个游戏物体都是被设定为Default层.背景图像在这层是没问题的,因为它在最后面,所以我们要更改其它精灵的层.
在Hierarchy视图选择cat的Sorting Layer为Cats.你会在场景视图和游戏视图里立刻看到cat出现了.

Unity 2D入门基础教程之僵尸先生第36张

最后,将zombie的层设定为Zombie,确保所有精灵都在背景之上渲染,现在视图看起来像这样:

Unity 2D入门基础教程之僵尸先生第37张

正确绘制顺序的游戏视图

注:精灵渲染器同样有个名为Order的属性,使用它可以调整相同排序层中精灵间顺序.

在本例中我们不需要调整Order属性,因为我们没有在同一个层里放不同的精灵.从我的测试结果来看,Unity在添加添加一个精灵到一个层的时候,将总会把最新的精灵画在层内旧精灵的前面.

给精灵编程

现在沙滩上散落着一些精灵,它们没有任何动作.教程这部分我们将完成它们的控制,我们会编写两段脚本,一个是僵尸的动画,另外一个是允许玩家控制僵尸的移动

精灵动画(Animating Sprites)

首先我们添加一个脚本来制作僵尸的动画.在Hierarchy视图选择zombie并给它新建个脚本,命名为”ZombieAnimator”

我们要让僵尸进行简单的行走动画,需要精灵动作表和一个循环速度.我们定义两个公共变量到脚本中:

public Sprite[] sprites;
public float framesPerSecond;

公共变量将在Unity的编辑器中暴露出来,所以你可以直接修改它们的值而不用改变代码,哪怕是运行的时候!这个特性在实际使用中异常方便.

通过分配不同的精灵给SpriteRenderer组件来渲染动画.而不是在Update中调用动画,我们要在脚本开始运行时给它缓存个实例变量.

我们添加一个私有变量到ZombieAnimator:
private SpriteRenderer spriteRenderer;

私有变量是不会暴露在Unity编辑器中的,我们在Start中初始这个变量:

spriteRenderer = renderer as SpriteRenderer;

脚本子类MonoBehaviour可以获得变量同名的渲染器.对于显示精灵的游戏对象,渲染器将是SpriteRenderer.

注:可以在脚本里直接引用常见的对象,比较常见的如游戏对象的Transform,场景的main Camera.

我们添加如下代码在Update中:
int index = (int)(Time.timeSinceLevelLoad * framesPerSecond);
index = index % sprites.Length;
spriteRenderer.sprite = sprites[ index ];

关卡载入到当前的时间秒数 (更多信息请查阅文档的Time类)和每秒渲染的帧数相乘.如果动画帧是存储在一个无限长的数组里,得出的数就是数组中成员的索引数.

但是你知道数组成员不会是无限数量的,当动画帧数组播放一遍后你需要循环回到开始,通过执行模数(%)操作,即做两个数字之间的整除取余.换句话说 你将得到0~数组总成员数之间的索引来控制动画帧的播放.写完上面脚本后保存,然后切换回Unity.在Hierarchy视图选择zombie会看到 Zombie Animator脚本组件将显示刚才写的两个公共变量.

Unity 2D入门基础教程之僵尸先生第38张

精灵数组字段里面没有内容,我们需要按照如下顺序添加精灵库到数组里:zombie_0, zombie_1, zombie_2, zombie_3, zombie_2, zombie_1,

我最喜欢的做法是在Hierarchy视图里选择zombie,在Inspector视图右上角点击锁头图标,这样zombie的 Inspector面板将会一直保持显示状态,即使你选择其它对象,它依旧会显示.

Unity 2D入门基础教程之僵尸先生第39张

在Project视图中展开zombie纹理,单击zombie_0以选中它,然后按住shift键再点击zombie_3来选择4个僵尸精灵.

拽到精灵数组那里,这时可以看到所选项都加到了精灵数组里.现在Zombie Animator脚本组件看起来应该是这样的:

Unity 2D入门基础教程之僵尸先生第40张

然后只选择zombie_2以同样的方式追加到数组里,再追加个zombie_1,这时精灵数组将包含正确顺序的六个元素,就像这样:

最后,设置Frames Per Second到10,像下面这样:

Unity 2D入门基础教程之僵尸先生第41张

运行一下游戏,你会看到可怕的僵尸…

注:你可以在运行时根据自己心情调整 Frames Per Second来找到一个合适的速度,但Unity停止播放后会重置这个调整的值,因此你要停下时一定要记录一下这个值在赋到 Frames Per Second上.

现在僵尸已经复活了,下一节我们要创建一个简单的控制器脚本让它行走起来.

Unity 2D入门基础教程之僵尸先生第42张

ZombieAnimator.cs完整代码

 1 using UnityEngine;
 2 using System.Collections;
 3 
 4 public class ani : MonoBehaviour
 5 {
 6 
 7     public Sprite[] sprites; //精灵数组
 8     public float framesPerSecond; //每秒渲染的帧数
 9 
10     private SpriteRenderer spriteRenderer;
11 
12 
13     // Use this for initialization
14     void Start()
15     {
16         //私有变量是不会暴露在Unity编辑器中的,我们在Start中初始这个变量:
17         spriteRenderer = renderer as SpriteRenderer;
18     }
19 
20     // Update is called once per frame
21     void Update()
22     {
23         /*
24          * 关卡载入到当前的时间秒数 (更多信息请查阅文档的Time类)和每秒渲染的帧数相乘.
25          * 如果动画帧是存储在一个无限长的数组里,得出的数就是数组中成员的索引数.
26          * 但是你知道数组成员不会是无限数量的,当动画帧数组播放一遍后你需要循环回到开始,
27          * 通过执行模数(%)操作,即做两个数字之间的整除取余.换句话说你将得到0~数组总成员数之间的索引来控制动画帧的播放.
28          */
29         int index = (int)(Time.time * framesPerSecond);
30         index = index % sprites.Length;
31         spriteRenderer.sprite = sprites[index];
32     }
33 }

控制精灵运动

在Hierarchy视图中选择zombie并添加一个新C#脚本,命名为”ZombieController”,你可能要一个年老的迈着沉重步伐的僵尸,也或者要一个比较年轻有活力的僵尸,可以通过移动速度来调整它们的姿态,便于我们微调,我们将它写为公共变量.

打开ZombieController.cs脚本并添加如下代码:

public float moveSpeed;

moveSpeed将存储一个units数,这个单位不是像素,而是僵尸每秒移动的速度.因为现在精灵是一个单位为100个像素,所以这个值可能需要相当小.

正如下面的动画,要做当用户点击鼠标后,僵尸沿着直线走到鼠标的那个点(或这用户是按住鼠标同时拖拽鼠标来改变僵尸新的位置).

Unity 2D入门基础教程之僵尸先生第43张

Unity 2D入门基础教程之僵尸先生第44张

平时很可能不会在每一帧都得到输入事件,所以当僵尸目的方向改变时我们需要存储僵尸的目的地方向.要做到这一点,我们要计算出指向僵尸行走方向的normalized向量(长度为1的向量).

添加如下变量到ZombieController中:

private Vector3 moveDirection;

虽然我们现在在做一个2D游戏,但是Unity仍旧使用的是3D坐标系,因此要改变对象位置的Vector3.虽然这里僵尸不会改变z轴的位置,我 们可以用Vector2类型,但是我避免后面要在Vector2和Vector3两种类型转换的麻烦,我还是用Vector3了.

添加以下代码以便有输入时间时更新moveDirection:

// 1
Vector3 currentPosition = transform.position;
// 2
if( Input.GetButton("Fire1") ) {
// 3
Vector3 moveToward = Camera.main.ScreenToWorldPoint( Input.mousePosition );
// 4
moveDirection = moveToward - currentPosition;
moveDirection.z = 0;
moveDirection.Normalize();
}

下面说明一下刚才这段代码的用途:
我们要获得僵尸当前位置,所以将位置付给局部变量,然后判断鼠标左键(Fire1)是否被按下,用场景的main Camera,转换鼠标目前位置为世界坐标系,因为ScreenToWorldPoint不会影响到Z轴的值,所以这里我们直接用鼠标的位置来取得 moveToward,计算移动的方向是用目标位置减去僵尸目前的位置,,因为你不想改变僵尸Z轴的位置,所以我们设置moveDirection的z值 为0,并用Normalize将moveDirection变为长度为1的”单位长度(unit length)”.Unit length的向量用起来是很方便的,可以通过一个标量值,如moveSpeed乘以这个向量来让向量指向一个方向,而保持长度.后面会用到这个.

注:用Input来访问输入数据是比较通用的方法,一个项目默认定义了各种输入名称,比如Horizontal, Vertical, 和 Jump, Horizontal是检测操纵杆x轴的位置以及键盘左右箭头按钮状态.如果你需要获得水平方向的输入数据,可以直接用Horizontal来获取,而不 用关心具体是怎么获取来的.

Fire1默认定义的是虚拟键之一,它注册的是一个操纵杆或鼠标的按钮0,而左control键是用Input.GetButton返回的布尔值获 得的.代码将在鼠标按下的每一帧时更新moveDirection(不只是当初按下的那一阵).没错,这也意味着你可以通过键盘的左CTRL键来控制僵尸 方向,只是还要用鼠标来掌舵.
在EditProject SettingsInput能看到关于InputManager设置.

下面我们添加下面的代码来做僵尸跟随鼠标走路的效果:

Vector3 target = moveDirection * moveSpeed + currentPosition;
transform.position = Vector3.Lerp( currentPosition, target, Time.deltaTime );

第一行是用来计算以moveSpeed速度单位让僵尸从当前位置移动到目标位置,也就是僵尸将按照当前位置朝向鼠标目标位置方向移动过去.
第二行使用Vector3.Lerp来计算当前位置与目标位置之前路径上僵尸的新位置,线性插值(Lerp)是为取两个值之间内插值的最便利方法.Lerp第 三个参数取值范围是0~1,这意味着0时将返回你现在的位置点,值为1时将返回目标点,0.5时将返回它们的中点.我们这里用 Time.deltaTime来作为第三个参数值,因为它是一秒钟的一小部分,很可能会小于1,会让你得到沿着起点到终点路径上的一些点,正因为 Time.deltaTime任何时候都将接近于1,因此你可以得到一个不错的平滑运动.

保存这个脚本并切换回Unity.

运行游戏,点击某个地方让僵尸走过去,因为没有设定ZombieController的moveSpeed,所以它还不会走动,不用停止游戏,我们 在Inspector面板中选择zombie找到Zombie Controller脚本组件改变移动速度为2,再次在沙滩上点击鼠标,你会看到僵尸走过去了.

Unity 2D入门基础教程之僵尸先生第45张

在Inspector更改移动速度知道你觉得满意.根据你调整的移动速度,你可能还需要调整Zombie Animator脚本中的Frames Per Second来让僵尸动画与行走速度相匹配.
当你觉得满意的时候你记住现在设定的数值,然后停止游戏的运行,重新设定这些值好让下次运行时移动速度和动画是正确的.

这个时候,你有可能发现下面这些问题:
1.当游戏开始运行时,你会发现僵尸的腿在动,可它确实静止在那里的.
2.僵尸愉快的向右走出了屏幕.
3.他走路的时候并不看路.

在看完这个教程时你会解决它跑出屏幕的问题,所以现在暂时忽略这个问题.此外,如果它跑到了屏幕外面,只需再次点击沙滩,他有可能就会回来的.

再次回到MonoDevelop打开ZombieController.cs.
这个脚本用moveDirection来移动僵尸,但是只有当有输入事件的时候它才开始移动,为了让场景开始的时候它就前进,我们需要初始moveDirection指向它的右方.
在Start中添加下面这行:

moveDirection = Vector3.right;

这个点是在x轴的正方向上,换句话说它指向朝右的方向.

保存ZombieController.cs并回到Unity中再次播放游戏.
现在僵尸自己就跑了,接下来我们要让他看路走.
回到ZombieController.cs,添加一个公共变量在ZombieController中做为僵尸的扭率:

public float turnSpeed;

我们将用turnSpeed来控制僵尸定位自己方向的响应速度.
Unity内部是使用四元数表示旋转.如果你想了解四元数,可以看此链接:http://en.wikipedia.org/wiki/Quaternion,不过也许你看了后会觉得头脑发昏,但值得宽慰的是在Unity做2D游戏不用完全了解四元数是什么.
因为用 Quaternion.Euler 方法可以从一个欧拉角获得四元数.大多数人都习惯欧拉角,它包含单独的x,y,z的旋转角度.虽然它们因为如万向轴死锁(gimbal lock)等问题在3D创作中使用不太理想,但对于2D游戏来说,欧拉角是蛮好用的,我们可能只需要绕z轴旋转.

注:欲了解更多关于四元数,可以看我们这个教程OpenGL ES Transformations with Gestures(http://www.raywenderlich.com/50398/opengl-es-transformations-gestures)”.

最后我们在Update脚本里添加下面的代码:

float targetAngle = Mathf.Atan2(moveDirection.y, moveDirection.x) * Mathf.Rad2Deg;
transform.rotation =
Quaternion.Slerp( transform.rotation,
Quaternion.Euler( 0, 0, targetAngle ),
turnSpeed * Time.deltaTime );

我们来看一下这个代码,首先我们用Mathf.Atan2来找到x轴与moveDirection之间的角度.Mathf.Atan2将返回角度的弧度,所以要乘以Mathf.Rad2Deg来转换为角度.
然后用Quaternion.Slerp来转向您所计算的目标角度.
Quaternion.Slerp执行的是指定两个角度的球面线性插值.类似于前面我们用到的Vector3.Lerp,只是它是计算新的旋转,而不是计算新的位置.

此前,调用Vector3.Lerp,并用moveSpeed调整僵尸移动的距离,同时用turnSpeed做僵尸的面向角度处理.

以上就是ZombieController.cs脚本,保存它并回到Unity.
在Hierarchy视图选择zombie.设定Turn Speed到5,如下图:

Unity 2D入门基础教程之僵尸先生第46张

运行游戏并点击周围的海滩,僵尸将始终朝向你鼠标点击的位置.

Unity 2D入门基础教程之僵尸先生第47张

ZombieController.cs完整代码

 1 using UnityEngine;
 2 using System.Collections;
 3 
 4 public class ZombieController : MonoBehaviour
 5 {
 6 
 7     /*
 8      * moveSpeed将存储一个units数,这个单位不是像素,
 9      * 而是僵尸每秒移动的速度.因为现在精灵是一个单位为100个像素,所以这个值可能需要相当小.
10      */
11     public float moveSpeed;
12     private Vector3 moveDirection;
13     public float turnSpeed;
14     // Use this for initialization
15     void Start()
16     {
17         moveDirection = Vector3.right;
18     }
19 
20     // Update is called once per frame
21     void Update()
22     {
23         Vector3 currentPosition = transform.position;
24         if (Input.GetButton("Fire1"))
25         {
26             /*
27              * 用场景的main Camera,转换鼠标目前位置为世界坐标系,因为ScreenToWorldPoint不会影响到Z轴的值,
28             */
29             Vector3 moveToward = Camera.main.ScreenToWorldPoint(Input.mousePosition);
30             moveDirection = moveToward - currentPosition;
31             moveDirection.z = 0;
32             moveDirection.Normalize();//使向量的长度为1.当规范化时,一个向量保持相同的方向,但它的长度为1.0。
33         }
34         //计算以moveSpeed速度单位让僵尸从当前位置移动到目标位置,也就是僵尸将按照当前位置朝向鼠标目标位置方向移动过去.
35         Vector3 target = moveDirection * moveSpeed + currentPosition;
36         /*
37          * 使用Vector3.Lerp来计算当前位置与目标位置之前路径上僵尸的新位置,
38          * 线性插值(Lerp)是为取两个值之间内插值的最便利方法.Lerp第三个参数取值范围是0~1,
39          * 这意味着0时将返回你现在的位置点,值为1时将返回目标点,0.5时将返回它们的中点.
40          * 我们这里用Time.deltaTime来作为第三个参数值,因为它是一秒钟的一小部分,很可能会小于1,
41          * 会让你得到沿着起点到终点路径上的一些点,正因为Time.deltaTime任何时候都将接近于1,因此你可以得到一个不错的平滑运动.
42          */
43         transform.position = Vector3.Lerp(currentPosition, target, Time.deltaTime);
44 
45         float targetAngle = Mathf.Atan2(moveDirection.y, moveDirection.x) * Mathf.Rad2Deg;
46         transform.rotation = Quaternion.Slerp(
47             transform.rotation,
48             Quaternion.Euler(0, 0, targetAngle),
49             turnSpeed * Time.deltaTime
50             );
51     }
52 }

精灵封装(Sprite Packing).

注:本节介绍的功能,只适用于Unity Pro中.你仍然可以在Unity free版本中直接使用一个纹理图集,可它需要你用不同的工具来创建生成纹理图集的图片文件.你同样可以在运行时将一些精灵压缩为图集切片,但是它会令你 组织和使用资源变成很不直观的,因此我们这里不介绍这种方法.

播放游戏,并点击游戏视图顶部控制栏的Stats按钮查看渲染状态信息,如下图:

Unity 2D入门基础教程之僵尸先生第48张

请注意,现在场景中因为没有进行配料(batching)优化,所以Draw calls看起来很多.

当然,Draw calls现在是正常的,因为现在场景里渲染了四个精灵,每一个精灵都用了一个独自的材质球.虽然现在只有五个draw calls,但真正的游戏中随着场景中对象和效果的增加,这个draw calls数也会增加,太多的draw calls会降低游戏性能,所以我们要仔细的组织精灵纹理,幸运的是有个基本的方法来帮助我们优化draw calls,就是将零散的精灵图片转换成精灵纹理图集.纹理图集(texture atlases)是由若干个小纹理组成的大纹理贴图,用于优化渲染时GPU的调用,这不是新技术,以前要我们用第三方工具或者手工创建它,而现在 Unity可以帮我们自动创建它.

为了将精灵合并到图集里,首先需要修改其导入设置.
在Project视图中找到cat.png并打开Import Settings,这里注意名为Packing的标签属性. Packing标签用来定义精灵加入到纹理图集后的名称,可以是任何你想要的字符串.
在Packing标签中输入它的名字”toons”:

Unity 2D入门基础教程之僵尸先生第49张

然后点击应用按钮保存设置,用同样的方法将enemy和zombie也命名一下.
然后从”WindowSprite Packer”菜单中打开”Sprite Packer”

Unity 2D入门基础教程之僵尸先生第50张

如果提示这个错误:

Unity 2D入门基础教程之僵尸先生第51张

我们到”EditProject SettingsEditor”中把Sprite Packer的模式选为”Always Enabled”,像下图这样:

Unity 2D入门基础教程之僵尸先生第52张

当选择”Always Enabled”后,你可以在build时候看到一个”only packing your Sprites for builds”选项.

在这个窗口的左上方点击Pack按钮,你会看到精灵都排列在窗口里了,如下图:

Unity 2D入门基础教程之僵尸先生第53张

再次运行游戏到游戏视图查看运行状态信息,你将看到现在只用了3个draw calls,比原来省了两个.

Unity 2D入门基础教程之僵尸先生第54张

这样做的好处是显而易见的,精灵共享使用了材质球,优化了性能,同时做这个优化如此简单,何乐不为.

Sprite Packer窗口顶部包含一个控制栏,如下图:

Unity 2D入门基础教程之僵尸先生第55张

标记1:视图中看到的是目前的图集.第一个下拉菜单是你使用过的Packing标签名称.可以选择它查看它的内容.
标记2:如果Sprite Packer帮你整合图集超过一张图,你需要通过第二个下拉菜单切换其它图集.
标记3:默认精灵在图集中的分配方法是按照DefaultPackerPolicy进行的,可以通过调整DefaultPackerPolicy来自定义分配方法,不过这个高级功能本教程就不介绍了.

有时候Unity会将我们本来要整合到一个图集拆分创建成多个地图集,并把名字加了序号.造成这个问题的原因是精灵纹理压缩格式不同.

例如:zombie.png我们设置的是16位颜色(16 bits),而enemy.png和cat.png是用的压缩格式(Compressed),那么Unity整合图集时,将会创建出两个图集,名称分别 是”toons (Group 1)”和”toons (Group 2)”:

Unity 2D入门基础教程之僵尸先生第56张

尽管这三个精灵有相同的Packing标签,但Unity仍旧创建了多个图集.为了确保图集最优化,我们要确保准备整合到同一个图集中的精灵的压缩格式相同.

正常情况下,将尽可能的减少精灵图集的总数,除非精灵太多,一张图集存不下,Unity会再次自动拆分图集,我们要用Packing标签合理安排精灵归属,尽可能做到精灵图集的最优化.

源码下载:http://pan.baidu.com/s/1uFK7c

免责声明:文章转载自《Unity 2D入门基础教程之僵尸先生》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇FastReport.Net使用:[21]表格(Table)控件Yii2基本概念之——配置(Configurations)下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

python+opencv笔记(2)——边缘填充

python+opencv之边缘填充 一、边缘填充 相信很多喜欢玩电脑的小伙伴,遇到过这种情况:有时候换电脑壁纸的时候,原本一张很好看完整的图片,换成电脑壁纸就是一个不完整或者由很多重复的图片组成的壁纸。其实这里就有填充的出现。 边缘填充:因为对于图像的卷积操作,最边缘的像素一般无法处理,所以卷积核中心到不了最边缘像素。这就需要先将图像的边界填充,再根据不...

SQL Server:创建索引视图

视图也称为虚拟表,这是因为由视图返回的结果集其一般格式与由列和行组成的表相似,并且,在 SQL 语句中引用视图的方式也与引用表的方式相同。标准视图的结果集不是永久地存储在数据库中。查询每次引用视图时,Microsoft® SQL Server™ 2000 会动态地将生成视图结果集所需的逻辑合并到从基表数据生成完整查询结果集所需的逻辑中。生成视图结果的过程称...

SurfaceView 与view区别详解

SurfaceView 与view区别详解 https://blog.csdn.net/u011339364/article/details/83347109 2018年10月24日 17:20:08 可爱的you 阅读数:2077   在Android系统中,有一种特殊的视图,称为SurfaceView,它拥有独立的绘图表面,即它不与其宿主...

【Amba系列】之安霸新推出的计算机视觉芯片CV22简介

DATE: 2019-2-18 1、参考 https://www.ambarella.com/uploads/docs/CV22-product-brief-consumer.pdf http://www.ambarella.com/about/news-events/press-images/CV22-press-image https://www.m...

61 相机投影原理、相机模型中的坐标系统以及标定方法

0 引言   世界坐标系下的点如何投影到CCD镜头上,通过成像的方式得到点在二维图像上的像素坐标值,这是摄影测量中的一个基础而核心的问题。这个问题中核心的东西有两个:1、坐标系的定义及其空间转换矩阵  2、成像中的误差 下面将从这两个角度对这个问题进行详细探讨。文章参考了 # 陈建平: 《相机成像原理》PPThttps://blog.csdn.net/...

unity sprite怎么获取切割后的图

学习了一段时间的unity,对里面的组件有一个大致的了解,但是具体操作来说还不是很熟悉,今天看了一片关于unity sprite怎么获取切割后的图的文章,感觉还不错。 假设有一张png/tga图集,导入到Unity,放置目录"Assets/Resources/UI"(UI文件夹可替换成其他的,重要的是要在"Assets/Resources/"路径下),默认...