简介:

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


这是原本游戏效果图:

unity rpg小游戏开源代码 unity3d小游戏源码_游戏


这是本项目效果图:

unity rpg小游戏开源代码 unity3d小游戏源码_2d_02


资源下载:

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 initialization
	void 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 frame
	void 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 initialization
	void Start () {
		
	}
	
	// Update is called once per frame
	void 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 ();
	}
}