怎样使用Unity3D开发Flappy Bird游戏
这是一个教你怎样使用Unity3D制作Tappy Plane(Flappy Bird克隆版)的教程。如果你是有一些C#编程经验的Unity 2D游戏开发者,这个教程正适合你。现在让我们开始吧。
原文网址:http://anwell.me/articles/unity3d-flappy-bird/
完整工程代码在这里下载(https://github.com/anwell/TappyPlane)
安装Unity
Unity3D是个免费的游戏开发引擎。虽然Unity3D的名字中有个“3D”,但它最近发布的版本已经支持2D游戏的开发。使用Unity创建出来的游戏,可以运行在iOS,Android,Windows Phone,网页和其它许多平台上。
创建新的工程
在“Create New Project”窗口,修改窗口底部的默认设置为“2D”,工程名称为“TappyPlane”,然后点击“Create”按钮。
组织你的工程
创建工程后,应该能看到这样一个空窗口。
在“Project”面板下创建文件夹来存放你需要的文件,增加的4个文件夹名称分别为“Prefabs”,“Scenes”,“Scripts”,以及“Textures”。以下是每种文件夹的作用说明。
Prefabs
在Unity中,Prefab是一个可以重新创建和使用的对象,例如:子弹,敌人,或者墙。
Scenes
一个Scene等同于游戏的一个关卡。
Scripts
这个目录下存放所有代码。
Textures
所有游戏中使用的图片。在2D游戏中,这些图片被称为“Sprites”。
设置背景
保存这张图片到刚才创建的Textures文件夹中。
拖放这张图片到Scene视图的中心位置。在Inspector面板,设置Scale的x和y值都为2.5。
增加主角
保存这张图片到Textures文件夹下。和设置背景一样,拖放这张图片到Scene视图。
在Inspector面板,点击“Add Component”,找到“Rigidbody 2D”,点击确定。使用Rigidbody组件来给这架飞机增加重力和其它物理特性。
点击屏幕上方的三角形“Play”按钮,你将看到飞机随着重力而向下坠落。
控制主角
现在我们创建一个脚本让主角移动起来。在Scripts文件夹,创建一个名为Player.cs的C#文件,代码如下:
using UnityEngine;
public class Player : MonoBehaviour
{
// The force which is added when the player jumps
// This can be changed in the Inspector window
public Vector2 jumpForce = new Vector2(0, 300);
// Update is called once per frame
void Update ()
{
// Jump
if (Input.GetKeyUp("space"))
{
rigidbody2D.velocity = Vector2.zero;
rigidbody2D.AddForce(jumpForce);
}
}
}
代码中需要关注的两点是:jumpForce变量和update方法。
jumpForce:用来存储跳起时作用在主角身上的力。用Vector2类型,意味着它只有2个值:x和y。这个变量是public类型,你可以在Inspector面板中修改它的值。
Update方法:在游戏中的每一帧都被调用。如果按下空格键,会有一个力作用到rigidbody对象。
和前面增加RigidBody 2D组件的方法一样,使用“Add Component”把这个脚本挂载到主角对象上。现在点击“Play”,可以跳跃和下落了。
创建障碍物
保存这2张图片到Textures文件夹,拖拉它们到Scene视图,在Inspector面板,修改Scale的X和Y值为2.5。
移动这些对象,使它们位于背景之上,并且上下缝隙足够宽使得主角能越过它们。
在File菜单,GameObject -> Create Empty,这将会增加一个对象到场景,它是不可见的,作为整合我们的岩石障碍物的一个目录。改变名字为“RockPair”。拖拉这2个岩石对象到“RockPair”下。
移动障碍物
增加一个“RigidBody 2D”组件给RockPair父对象。在Inspector面板,勾选上Is Kinematic,这将使障碍物不会受到重力影响。
创建另一个名为Obstacle.cs的脚本,放在Scripts目录下。这个脚本用来把岩石从屏幕右边移动到左边。代码如下:
using UnityEngine;
public class Obstacle : MonoBehaviour
{
public Vector2 velocity = new Vector2(-4, 0);
// Use this for initialization
void Start()
{
rigidbody2D.velocity = velocity;
}
}
当对象创建时,Start方法只运行一次。因此,我们设置这个对象的速率在x方向的值为-4.
把这个脚本挂载到RockPair对象,点击Play按钮,会看到障碍物慢慢横穿过屏幕。
动态生成障碍物
我们需要每隔几秒创建出新的岩石障碍。首先,把RockPair对象拖到Prefabs文件夹下,这会把RockPair对象变成一个可以创建和销毁许多次的Prefab。接着在Scene场景窗口中删除RockPair。
创建一个空对象,修改名字为“Scripts”。再创建一个名为Generate.cs的脚本,输入以下代码,并且把Generate脚本挂载到刚创建出来的Scripts对象。
using UnityEngine;
public class Generate : MonoBehaviour
{
public GameObject rocks;
// Use this for initialization
void Start()
{
InvokeRepeating("CreateObstacle", 1f, 1.5f);
}
void CreateObstacle()
{
Instantiate(rocks);
}
}
在这个脚本中,我们使用了InvokeRepeating方法,这个方法的功能是每隔若干秒调用一次指定函数。第一个参数是字符串,代表着要调用的函数名称。第二个参数代表延迟几秒后调用这个函数。第三个参数是每一次调用之间的间隔秒数。
在CreateObstacle方法中,我们使用了Instantiate,这个方法的功能是生成一个新的Prefab到场景中,这里我们增加到场景中的新Prefab是个叫rocks的变量。但这个变量还没有和我们的RockPair关联起来,所以,现在把RockPair prefab从它的目录中拖放到Inspector的rocks值中,就像下面这样。
试着运行代码,你能看到每隔1.5秒会生成新的障碍。
销毁主角
你可能已经注意到那个障碍物什么作用也没有,让我们给这个碰撞加点什么吧。
单击player对象,增加一个叫“Box Collider 2D”的组件。
现在选定RockPair预制件,单击小箭头。给第一个对象增加一个叫“Polygon Collider 2D”的组件,对另外一个障碍同样这样做。
一个碰撞器组件是一个触发碰撞的形状,运行游戏看看发生了什么,看起来有点乐趣了。
当主角和障碍物碰撞时,需要让游戏重新启动。我们继续编辑Player.cs文件,代码如下:
using UnityEngine;
public class Player : MonoBehaviour
{
// The force which is added when the player jumps
// This can be changed in the Inspector window
public Vector2 jumpForce = new Vector2(0, 300);
// Update is called once per frame
void Update ()
{
// Jump
if (Input.GetKeyUp("space"))
{
rigidbody2D.velocity = Vector2.zero;
rigidbody2D.AddForce(jumpForce);
}
// Die by being off screen
Vector2 screenPosition = Camera.main.WorldToScreenPoint(transform.position);
if (screenPosition.y > Screen.height || screenPosition.y < 0)
{
Die();
}
}
// Die by collision
void OnCollisionEnter2D(Collision2D other)
{
Die();
}
void Die()
{
Application.LoadLevel(Application.loadedLevel);
}
}
在Update方法中,我们增加了一些代码用来检测主角的位置是否在屏幕里面。如果不是,主角将会死掉。
无论这个脚本附加在哪个游戏对象身上,transform都用来处理位置、旋转和比例。
Die方法将使关卡重置。
无论何时,两个有Collider 2D组件的游戏对象产生碰撞,都会调用OnCollisionEnter2D方法。
运行游戏,每次主角死亡或飞出屏幕,游戏都会重新开始。
增加一点随机性
如果你现在玩这个游戏,会感觉到一点。。。无聊。我们需要让障碍物的高度有变化,使得它更有挑战性。Obstacle.cs的代码更新如下:
using UnityEngine;
public class Obstacle : MonoBehaviour
{
public Vector2 velocity = new Vector2(-4, 0);
public float range = 4;
// Use this for initialization
void Start()
{
rigidbody2D.velocity = velocity;
transform.position = new Vector3(transform.position.x, transform.position.y - range * Random.value, transform.position.z);
}
}
range是表示随机范围的变量,这个数字越大,岩石位置的变化幅度也越大。你可以调整这个参数以便适合自己的游戏。
当岩石对象第一次创建时,我们移动它的位置到一个随机量。
计分
最后,让我们计分吧。更新Generate.cs文件的代码如下:
using UnityEngine;
public class Generate : MonoBehaviour
{
public GameObject rocks;
int score = 0;
// Use this for initialization
void Start()
{
InvokeRepeating("CreateObstacle", 1f, 1.5f);
}
// Update is called once per frame
void OnGUI ()
{
GUI.color = Color.black;
GUILayout.Label(" Score: " + score.ToString());
}
void CreateObstacle()
{
Instantiate(rocks);
score++;
}
}
我们用一个整数来计分。
OnGUI方法每一帧被调用若干次,用来显示文本和按钮。这里我们用黑色文本来把分数放在屏幕左上角。
每创建一个新岩石,加一分。
保存你的工作
点击菜单File -> Save,保存这个关卡到Scenes文件夹,命名为Play.unity,恩,大功告成了。
就这些了
恭喜,你用Unity完成了一个Flappy Bird克隆版,你可以用自己的想法和美术来任意改变这个游戏,这里还有几项需要优化:
目前,我们创建了新的障碍物,但从来没有销毁它。运行一段时间后,这个游戏会变慢很多。
没有提示菜单或开始画面。