AutoCAD 3DMAX C语言 Pro/E UG JAVA编程 PHP编程 Maya动画 Matlab应用 Android
Photoshop Word Excel flash VB编程 VC编程 Coreldraw SolidWorks A Designer Unity3D
 首页 > Unity3D

Unity4.3 2D教程:入门实战(六)

51自学网 2014-05-24 http://www.51zixue.net

给精灵编程

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

注:我们用C#(发音为”see-sharp”)写脚本,它很容易,如果你喜欢,也可以用JavaScript来写.

精灵动画(Animating Sprites)

首先我们添加一个脚本来制作僵尸的动画.在Hierarchy视图选择zombie并给它新建个脚本,命名为”ZombieAnimator”.下面动画演示了具体步骤:

add_script_steps

在MonoDevelop中打开ZombieAnimator.cs,一般情况下在Unity双击ZombieAnimator文件就可以打开了.如下图:

spriteanimator_in_inspector
Inspector视图中的SpriteAnimator脚本

spriteanimator_in_project
Project视图中的SpriteAnimator

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

1
2
public Sprite[] sprites;
public float framesPerSecond;

注:在C#中变量定义在所有大括号之外,标志着它是定义在类之内,所有函数之外.这不用特别理解明白,通常将它放在类的顶部,即任何函数定义之前.

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

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

我们添加一个私有变量到ZombieAnimator:

1
private SpriteRenderer spriteRenderer;

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

1
spriteRenderer = renderer as SpriteRenderer;

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

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

我们添加如下代码在Update中:

1
2
3
int index = (int)(Time.timeSinceLevelLoad * framesPerSecond);
index = index % sprites.Length;
spriteRenderer.sprite = sprites[ index ];


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

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

public_variables

精灵数组字段里面没有内容,我们需要按照如下顺序添加精灵库到数组里:zombie_0, zombie_1, zombie_2, zombie_3, zombie_2, zombie_1,我最喜欢的做法是在Hierarchy视图里选择zombie,在Inspector视图右上角点击锁头图标,这样zombie的Inspector面板将会一直保持显示状态,即使你选择其它对象,它依旧会显示.

inspector_locked

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

sprites_array_plus_icon

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

sprites_array_partial

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

sprites_array_full
精灵数组与六个元素

再次点击锁按钮解锁,如图:

inspector_unlocked

Inspector视图解锁

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

zombie_frames_per_second

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

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

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

控制精灵运动

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

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

1
public float moveSpeed;

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

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

Zombie walking toward and then past where you click.

Zombie following the cursor as it is dragged.

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

添加如下变量到ZombieController中:

1
private Vector3 moveDirection;

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

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

1
2
3
4
5
6
7
8
9
10
11
// 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设置.

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

1
2
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,再次在沙滩上点击鼠标,你会看到僵尸走过去了.

zombie_brains

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

这个时候,你有可能发现下面这些问题:

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

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

再次回到MonoDevelop打开ZombieController.cs.

这个脚本用moveDirection来移动僵尸,但是只有当有输入事件的时候它才开始移动,为了让场景开始的时候它就前进,我们需要初始moveDirection指向它的右方.

在Start中添加下面这行:

1
moveDirection = Vector3.right;

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

保存ZombieController.cs并回到Unity中再次播放游戏.

现在僵尸自己就跑了,接下来我们要让他看路走.

回到ZombieController.cs,添加一个公共变量在ZombieController中做为僵尸的扭率:

1
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脚本里添加下面的代码:

1
2
3
4
5
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,如下图:

turn_speed_set

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

dizzy_zombie

上面这些就是这个教程教你做Zombie Conga游戏的所有内容.通过”FileSave Scene as…. ”并命名为”CongaScene”保存场景.

下一节我们要讲一些只在Unity专业版(付费版本)才提供的功能,这些对于Zombie Conga游戏不是必要的,但你可能想了解更复杂项目的制作,就需要用到它-Sprite Packing.

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

本部分文字翻译来源:http://blog.1vr.cn/?p=1422


建议使用电驴(eMule)下载分享的资源。

说明
:本教程来源互联网或网友分享或出版商宣传分享,仅为学习研究或媒体推广,51zixue.net不保证资料的完整性。
 
上一篇:Unity4.3 2D教程:入门实战(六)  下一篇:Unity4.3 2D教程:入门实战(五)