详细的来为大家剖析一下unity flappy bird,附带源码内容详解。FlappyBird不用详细的废话了,它大家应该都玩过的,是一款极其简单,但是又很活宝的游戏。当我知道这款游戏的时候,就有一种把它重现的冲动,然后花了我4个多小时,写出来了一个可以玩的版本,分享给大家。
下面简单介绍游戏的开发过程(本文的例子需要使用unity4.3.0以上的版本打开)。
目录介绍
项目的目录结构如下图,anims中存放动画资源,prefab中存放预置对象,scprits存放脚本,sprites用来存放贴图。
准备资源
获取FlappyBird的贴图资源和音效资源。把资源导入到sprites文件夹下,选中atlas,在Inspector中进行编辑,如下图:
设置为sprite,模式为Multiple,点击按钮Sprite Editor进行相应的图片分隔。在弹出的对话框中,可以使用自动切图方式,如下图:
设置场景
并填写如下信息:
移动的道路和障碍
下面是道路移动的部分代码road.cs
- public class road : MonoBehaviour {
- ....
- // Update is called once per frame
- void Update () {
- Vector3 pos = trans.position;
- pos.x -= speed * Time.deltaTime;
- trans.position = pos;
- if(pos.x <= -1.6f - 3.35f*idx) { //当道路移出屏幕后,从小调整其位置
- Vector3 pp = roads[idx%2].transform.position;
- pp.x += 3.35f;
- idx++;
- roads[idx%2].transform.position = pp;
- if(isBegin){
- roads[idx%2].GetComponent<roadGen>().gen();
- }
- }
- }
道路障碍的显示与否(在欢迎页面,路面不需要障碍),以及障碍的生成都在文件roadGen.cs中,我把上下柱子合并成一个对象,在生成障碍时,只要使其在一定范围内上下移动就可以了。代码片段如下:
- public class roadGen : MonoBehaviour {
- public GameObject[] zhuzi;
- public float down=3.8f, upper = 6.0f; ...
- public void gen() { // 一格道路有两个柱子
- zhuzi[0].SetActive(true);
- zhuzi[1].SetActive(true);
- Vector3 p = zhuzi[0].transform.localPosition;
- float vv = Random.value;
- p.y = Mathf.Lerp(down, upper, vv);
- zhuzi[0].transform.localPosition = p; //设置第一个柱子的位置
- p = zhuzi[1].transform.localPosition;
- vv = Random.value;
- p.y = Mathf.Lerp(down, upper, vv);
- zhuzi[1].transform.localPosition = p; //设置第二个柱子的位置
- }
- public void hidden() {
- zhuzi[0].SetActive(false);
- zhuzi[1].SetActive(false);
- }
- }
大嘴唇的小鸟
同样要给小鸟一个BoxCollider2D的Component,使其能够响应碰撞,还要添加Rigibody2D。具体请参考例子。这里会涉及到两个脚本(时间匆忙,没怎么考虑设计):bird.cs和clider.cs;前者用来向小鸟施加力的作用,后者处理碰撞。
这个游戏的最主要部分就是 clider .cs,这个文件处理得分和是否碰撞到障碍物。代码如下:
- using UnityEngine;
- using System.Collections;
- public class clider : MonoBehaviour {
- public score s;
- public int clideNum;
- public string tag;
- public bool isSuccess = false, isFail = false;
- // Use this for initialization
- void Start () {
- s = GameObject.Find("score").GetComponent<score>();
- clideNum = 0;
- tag = "";
- isSuccess = false;
- isFail = false;
- }
- // Update is called once per frame
- void Update () {
- }
- void OnTriggerEnter2D(Collider2D other) {
- if(other.gameObject.tag.Equals("success")) {
- if(!isSuccess) {
- print("===trigger enter==");
- isSuccess = true;
- s.success();
- print ("success");
- }
- } else if(!isFail) {
- print("===trigger enter==");
- isFail = true;
- s.fail();
- print ("fail");
- }
- }
- void OnTriggerExit2D(Collider2D other) {
- print("===trigger exit==");
- isSuccess = false;
- }
- void OnCollisionEnter2D(Collision2D other) {
- if(other.gameObject.tag.Equals("success")) {
- if(!isSuccess) {
- print("===collision enter==");
- isSuccess = true;
- s.success();
- }
- } else if(!isFail) {
- print("===collision enter==");
- isFail = true;
- s.fail();
- }
- }
- void OnCollisionExit2D(Collision2D coll) {
- print("===collision exit==");
- isSuccess = false;
- }
- public void reset() {
- isSuccess = false;
- isFail = false;
- }
- }
欢迎页面
isReady.cs的代码如下:
- public class isReady : MonoBehaviour {
- public GameObject road, bird;
- // Use this for initialization
- void Start () {
- }
- // Update is called once per frame
- void Update () {
- if(Input.GetButtonDown("Fire1")){ //用户触摸屏幕之后,就开始游戏了
- gameObject.SetActive(false);
- road.GetComponent<road>().isBegin = true;
- bird.GetComponent<Rigidbody2D>().isKinematic = false;//欢迎页面,这里设置为true,使小鸟不响应重力,开始后要设置为false
- bird.GetComponent<Animator>().enabled = false;
- }
- }
- }
结算页面
- public class restart : MonoBehaviour {
- public Camera cam2d;
- public GameObject ready;
- void Update () {
- if(Input.GetButtonDown("Fire1")){
- Collider2D h = Physics2D.OverlapPoint(cam2d.ScreenToWorldPoint(Input.mousePosition), (1<<LayerMask.NameToLayer("btn")));
- if(h) { // 如果点击play按钮
- gameObject.SetActive(false);
- Time.timeScale = 1;
- ready.SetActive(true);
- GameObject[] resets = GameObject.FindGameObjectsWithTag("needReset"); //查找所有tag为needReset的对象
- foreach(GameObject r in resets) {
- r.BroadcastMessage("reset"); //调用其自身以及子对象中的代码中的reset函数来进行游戏的重置
- }
- }
- }
- }