用Unity3D开发2D小游戏 Flappy Bird

来源:互联网 发布:福建广电网络宽带 编辑:程序博客网 时间:2024/05/22 13:15

简介:

最近在学习Unity3D,用了两天时间做了个小游戏打算放上了和大家分享一下,项目名定义为Flapping,是参考Flappy Bird做的,高手勿喷。


这是原本游戏效果图:



这是本项目效果图:



资源下载:

1. 完整源代码下载

2. PC发布版下载

3. Android发布版APK下载


源代码:

源代码里已经打好了注释,主要分为3个C#脚本。第一个是Player.cs,是本游戏最核心脚本,用来初始化场景和控制小鸟;第二个是Pillar.cs,处理柱子被小鸟撞后的特效;第三个是Menu.cs,这是菜单。


Player.cs

using System.Collections;using System.Collections.Generic;using UnityEngine;using UnityEngine.UI;using UnityEngine.SceneManagement;public class Player : MonoBehaviour {// Use this for initializationvoid Start () {// 获取各个对象或组件goBird = transform.Find ("Bird").gameObject;srBird = goBird.GetComponent<SpriteRenderer>();goCamera = GameObject.Find ("Main Camera");goScores = GameObject.Find ("Scores");if (canPlay) {InitBackground ();InitBlocks ();// 重设分数PlayerPrefs.SetInt ("scores", 0);} else {// 显示分数if (goScores) {goScores.transform.GetComponent <Text>().text = "SCORES: "+PlayerPrefs.GetInt("scores");}}}public bool canPlay = true;// 判断是否能开始public float screenHeight = 10;  // 屏幕高度public float moveSpeed = 5;// 小鸟移动速度public float upSpeed = 19;// 往上爬速度public float upHeight = 0.9f;// 往上爬高度private float curUpHeight = 0;// 当前高度private bool upping = false;// 判断是否正在攀爬public float flapInterval = 0.1f;// 多长时间需要改变小鸟的样子private float curInterval = 0;// 当前经过的时间public Sprite srUnflap;// 小鸟正常样子public Sprite srFlapped;// 小鸟正在攀爬的样子private GameObject goBird;// 小鸟对象private SpriteRenderer srBird;// 存放小鸟样子private GameObject goCamera;   // 摄像头private bool isDead = false;// 判断是否死亡private GameObject goScores;// 分数对象private int scores = 0;// 分数public AudioClip collisionAduio;// 碰撞音效// Update is called once per framevoid Update () {// 判断是否死亡if (!isDead) {UpdateFlap ();// 如果没死就继续更新下一帧if (canPlay) {// 更新动作UpdateMovement ();// 更新分数UpdateScores ();// 更新会动的柱子UpdateMovingBlocks ();}} else {UpdateDieCompleted ();}}private void UpdateMovement() {float s = Time.deltaTime * moveSpeed;transform.Translate (new Vector3 (s, 0, 0));// 重设摄像头位置goCamera.transform.position = new Vector3(transform.position.x,goCamera.transform.position.y,goCamera.transform.position.z);if ((Input.GetKeyUp (KeyCode.Space) || Input.GetButtonUp("Fire1"))) {curUpHeight = 0;upping = true;// 旋转小鸟的角度为45度goBird.transform.eulerAngles = new Vector3 (0,0,45);}// 往上爬if (upping) {float us = upSpeed * Time.deltaTime;if (us + curUpHeight >= upHeight) {us = upHeight - curUpHeight;}transform.Translate (new Vector3(0,us,0));curUpHeight += us;if (curUpHeight >= upHeight) {upping = false;curUpHeight = 0;// 旋转小鸟的角度为正常goBird.transform.eulerAngles = new Vector3 (0,0,0);}}// 如果撞到天花板就往下坠float top = transform.localScale.y / 2 + transform.position.y;if (top >= screenHeight / 2) {upping = false;curUpHeight = 0;// 旋转小鸟的角度为正常goBird.transform.eulerAngles = new Vector3 (0,0,0);}// 如果碰到地板就死亡float bottom = -transform.localScale.y / 2 + transform.position.y;if (bottom <= -screenHeight / 2) {// 小鸟死亡BirdDie ();}}private void BirdDie() {isDead = true;goBird.transform.eulerAngles = new Vector3 (0,0,90);}private void UpdateDieCompleted() {// 如果碰到地板就死亡float bottom = transform.localScale.y / 2 + transform.position.y;if (bottom <= -screenHeight / 2) {DieCompleted ();}}private void DieCompleted() {Destroy (gameObject);// 载入Gameover场景SceneManager.LoadScene ("GameOver");SceneManager.UnloadSceneAsync ("Game_1");}// 改变小鸟样子private void UpdateFlap() {curInterval += Time.deltaTime;if (curInterval >= flapInterval && !upping) {if (srBird.sprite == srUnflap) {srBird.sprite = srFlapped;} else {srBird.sprite = srUnflap;}curInterval = 0;}}// 更新分数private void UpdateScores() {float tail = transform.position.x - transform.localScale.x / 2 - blockWidth;tail = (tail < 0) ? 0 : tail;int killBlocks = (int)(tail / (blockOffset) + ((tail > blockWidth) ? 1 : 0));scores = killBlocks * 10;goScores.transform.GetComponent <Text>().text = "SCORES: "+scores;// 保存分数PlayerPrefs.SetInt ("scores",scores);// 判断游戏是否已经结束if (scores >= (totalBlock * 10)) {DieCompleted ();}}// 柱子public GameObject block;public float blockWidth = 1;//柱子宽度public float blockMinHeight = 1;    // 柱子最小高度public float blockOffset = 8;// 柱子距离public float blockExitHeight = 4;// 两柱之间给小鸟通过的缝的距离public float blockNarrow = 0.2f;// 两柱之间给小鸟通过的缝的距离的递减数,越后的柱子的缝越小public int totalBlock = 40;// 柱子数量public int blockClass = 5;// 将所有柱子分为多少组private List<GameObject> movingBlocks = new List<GameObject>(); // 会移动的柱子private float curBlockMoveHeight = 0;    // 柱子移动高度public float blockMoveSpeed = 1;      // 柱子移动速度private bool isBlockMovingUp= true;// 判断是否正在移动private GameObject CreateBlock(Vector3 pos, Vector3 scale, Vector3 rotation) {GameObject go = GameObject.Instantiate (block).gameObject;go.transform.position = pos;go.transform.localScale = scale;go.transform.Rotate(rotation);return go;}// 初始化柱子private void InitBlocks() {int perClassBlock = totalBlock / blockClass;float x = 0.0f;System.Random rm = new System.Random (); // 随机数for (int i = 0; i < blockClass; ++i) {// 越后的柱子的缝越窄,这就表示游戏越难float narrow = blockExitHeight - i*blockNarrow;float avaliableHeight = screenHeight - narrow;for (int j = 0; j < perClassBlock; ++j, x+=blockOffset) {float height1,height2,y1,y2;height1 = (float)rm.NextDouble() * avaliableHeight;float blockMinHeight2 = blockMinHeight * 2;height1 = (height1 > (avaliableHeight - blockMinHeight2)) ? (avaliableHeight - blockMinHeight2) : height1;height1 = (height1 < blockMinHeight2) ? (blockMinHeight2) : height1; height2 = avaliableHeight - height1;y1 = (screenHeight - height1) / 2;y2 = (screenHeight - height2) / 2;GameObject go1 = CreateBlock (new Vector3(x,y1), new Vector3(1,height1/2,1), new Vector3(0,0,0));GameObject go2 = CreateBlock (new Vector3(x,-y2), new Vector3(1,height2/2,1), new Vector3(0,0,180));// 保存会动的柱子if (j >= perClassBlock - 2) {movingBlocks.Add (go1);movingBlocks.Add (go2);}}}}// 移动会动的柱子private void UpdateMovingBlocks() {float speed = blockMoveSpeed*Time.deltaTime;if (speed + curBlockMoveHeight >= blockMinHeight) {speed = blockMinHeight - curBlockMoveHeight;}curBlockMoveHeight += speed;speed = isBlockMovingUp ? speed : -speed;for (int i = 0; i < movingBlocks.Count; i += 2) {int j = i + 1;Vector3 pos1 = movingBlocks[i].transform.position;Vector3 pos2 = movingBlocks[j].transform.position;Vector3 scale1 = movingBlocks [i].transform.localScale;Vector3 scale2 = movingBlocks [j].transform.localScale;scale1.y -= speed;scale2.y += speed;pos1.y = (screenHeight - scale1.y*2)/2;pos2.y = -(screenHeight - scale2.y*2)/2;movingBlocks [i].transform.position = pos1;movingBlocks [j].transform.position = pos2;movingBlocks [i].transform.localScale = scale1;movingBlocks [j].transform.localScale = scale2;}isBlockMovingUp = curBlockMoveHeight >= blockMinHeight ? !isBlockMovingUp : isBlockMovingUp;curBlockMoveHeight = curBlockMoveHeight >= blockMinHeight ? 0 : curBlockMoveHeight;}// 背景public GameObject background;public float bgWidth = 20;public float bgStartPos = -10;public int bgCount = 50;// 创建背景private void CreateBackground(Vector3 pos, Vector3 scale) {GameObject go = GameObject.Instantiate (background).gameObject;go.transform.position = pos;go.transform.localScale = scale;}// 初始化背景private void InitBackground() {int n = bgCount;for (int i=0; i<n; ++i) {CreateBackground(new Vector3(bgStartPos+i*bgWidth,0,2),new Vector3(1,1,1));}}// 小鸟的碰撞处理void OnCollisionEnter2D(Collision2D col) {if (col.gameObject.tag == "Block") {AudioSource a = GetComponent<AudioSource>();if (!isDead) {BirdDie ();// 发出碰撞声音a.clip = collisionAduio;a.Stop ();}a.Play ();}}}


Pillar.cs

using System.Collections;using System.Collections.Generic;using UnityEngine;public class Pillar : MonoBehaviour {// Use this for initializationvoid Start () {}// Update is called once per framevoid Update () {}public int crushPiece = 5;// 碎片数量public float pieceWidth = 0.8f;// 碎片宽高public GameObject piece;// 碎片对象// 碰撞后弹出碎片private void Crush(Collision2D col) {System.Random rm = new System.Random ();for (int i = 0; i < crushPiece; ++i) {Vector3 pos = new Vector3(col.contacts [0].point.x, col.contacts [0].point.y, 0);Vector3 scale = new Vector3 (pieceWidth,pieceWidth, 1);float fr = (float)rm.NextDouble ();float angle = (float)fr * -180;Vector3 rotation = new Vector3 (0,0,angle);GameObject go = CreatePiece (pos,scale,rotation);go.transform.GetComponent<Rigidbody2D>().AddForce(new Vector2(-fr*2,3) * 100);Destroy (go, 3.0f);}}private GameObject CreatePiece(Vector3 pos, Vector3 scale, Vector3 rotate) {GameObject go = GameObject.Instantiate (piece);go.transform.position = pos;go.transform.localScale = scale;go.transform.eulerAngles = rotate;return go;}void OnCollisionEnter2D(Collision2D col) {if (col.gameObject.tag == "Player") {Crush (col);}}}


Menu.cs

using System.Collections;using System.Collections.Generic;using UnityEngine;using UnityEngine.SceneManagement;public class Menu : MonoBehaviour {public void StartGame() {// 载入游戏SceneManager.LoadScene ("Game_1");SceneManager.UnloadSceneAsync ("Menu");SceneManager.UnloadSceneAsync ("GameOver");}public void QuitGame() {// 退出游戏Application.Quit ();}}



原创粉丝点击