开源移动小游戏项目《FlappyBird》学习心得
Posted rickcode
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了开源移动小游戏项目《FlappyBird》学习心得相关的知识,希望对你有一定的参考价值。
游戏设计思路:
场景关卡:
- 地图中会随机生成一个又一个的管道,每一个管道由上下管道组成,中间的空隙是固定的,每条管道的生成时间是随机的,所以它们之间的间距不一样
玩法:
- 点击屏幕,小鸟便会被施加一个向上的速度,该速度随重力会逐渐减少。
- 每当小鸟越过一个管道时,得分加1,当小鸟碰到地图上的管道或者掉入地面时,游戏结束。
- 游戏中的得分没有上限
技术实现:
GameState:
用脚本写一个枚举类GmaeState,表明游戏的三个场景状态
public enum GameState
{
Intro,
Playing,
Dead
}
public static class GameStateManager
{
public static GameState GameState { get; set; }
static GameStateManager ()
{
GameState = GameState.Intro;
}
}
摄像机和场景:
摄像机作为父物体,他的子物体如下:
分别是:background背景,Spawnerobject管道物体,Floor地板,Pipedestroy管道销毁模板,ceiling天花板,IntroGUI开始界面UI,Score得分计数,DeathGUI死亡时UI图标
摄像机:
非常简单,只需要每帧向右移动0.5即可,
void Start () {
cameraZ = transform.position.z;
}
float cameraZ;
void Update () {
transform.position = new Vector3(Player.position.x + 0.5f, 0, cameraZ);
}
public Transform Player;
}
Spawnerobject管道物体:
-
定义了一个数组:里面有两个管道prefab,当游戏开始或结束重新开始时,会随机选择一个管道:
-
管道物件是固定好的,每次生成只需调整它的y轴即可,y轴数值随机生成
-
每隔一段随机的时间,在小鸟前面生成管道
void Start()
{
SpawnObject = SpawnObjects[Random.Range(0, SpawnObjects.Length)];
Spawn();
}
void Spawn()
{
if (GameStateManager.GameState == GameState.Playing)
{
//random y position
float y = Random.Range(-0.5f, 1f);
GameObject go = Instantiate(SpawnObject, this.transform.position + new Vector3(0, y, 0), Quaternion.identity) as GameObject;
}
Invoke("Spawn", Random.Range(timeMin, timeMax));
}
private GameObject SpawnObject;
public GameObject[] SpawnObjects;
public float timeMin = 0.7f;
public float timeMax = 2f;
}
Floor地板:
游戏开始时,小鸟和相机绑定在一起,不断先前移动,为了实现一个小鸟一直往前飞的效果,此时地板只需不动就好
但地板的长度有限,所以要让它不断的向前刷新位置。
void Update()
{
if (transform.localPosition.x < -3.9f)
{
transform.localPosition = new Vector3(0, transform.localPosition.y, transform.localPosition.z);
}
transform.Translate(-Time.deltaTime, 0, 0);
}
}
Pipedestroy管道销毁模板:
每当管道触碰到它时,就销毁
ceiling天花板:
小鸟的飞行高度上限,防止飞出屏幕外
IntroGUI开始界面UI:
几张spite的简单UI
DeathGUI死亡时UI图标:
同上;
Score得分计数:
使用Sprite[] numberSprites数组来根据得分情况调用相应的spite图片;
void Start () {
(Tens.gameObject as GameObject).SetActive(false);
(Hundreds.gameObject as GameObject).SetActive(false);
}
// Update is called once per frame
void Update () {
if (previousScore != Score) //save perf from non needed calculations
{
if(Score < 10)
{
//just draw units
Units.sprite = numberSprites[Score];
}
else if(Score >= 10 && Score < 100)
{
(Tens.gameObject as GameObject).SetActive(true);
Tens.sprite = numberSprites[Score / 10];
Units.sprite = numberSprites[Score % 10];
}
else if(Score >= 100)
{
(Hundreds.gameObject as GameObject).SetActive(true);
Hundreds.sprite = numberSprites[Score / 100];
int rest = Score % 100;
Tens.sprite = numberSprites[rest / 10];
Units.sprite = numberSprites[rest % 10];
}
}
}
int previousScore = -1;
public Sprite[] numberSprites;
public SpriteRenderer Units, Tens, Hundreds;
}
主角小鸟:
- 屏幕点击,开始游戏。游戏中点击屏幕,小鸟向上飞跃,并触发音效
- 小鸟越过管道,加分并触发加分音效
- 小鸟碰到地板和管道,触发死亡和死亡音效
- 小鸟恒定移动速度、向上飞跃速度、坠落速度的设置,飞跃时的角度修正
public class FlappyScript : MonoBehaviour
{
public AudioClip FlyAudioClip, DeathAudioClip, ScoredAudioClip;
public Sprite GetReadySprite;
public float RotateUpSpeed = 1, RotateDownSpeed = 1;
public GameObject IntroGUI, DeathGUI;
public Collider2D restartButtonGameCollider;
public float VelocityPerJump = 3;
public float XSpeed = 1;
// Use this for initialization
void Start()
{
}
FlappyYAxisTravelState flappyYAxisTravelState;
enum FlappyYAxisTravelState
{
GoingUp, GoingDown
}
Vector3 birdRotation = Vector3.zero;
// Update is called once per frame
void Update() //每帧侦测屏幕的点击状态
{
//handle back key in Windows Phone
if (Input.GetKeyDown(KeyCode.Escape))
Application.Quit();
if (GameStateManager.GameState == GameState.Intro)
{
MoveBirdOnXAxis();
if (WasTouchedOrClicked())
{
BoostOnYAxis();
GameStateManager.GameState = GameState.Playing;
IntroGUI.SetActive(false);
ScoreManagerScript.Score = 0;
}
}
else if (GameStateManager.GameState == GameState.Playing)
{
MoveBirdOnXAxis();
if (WasTouchedOrClicked())
{
BoostOnYAxis();
}
}
else if (GameStateManager.GameState == GameState.Dead)
{
Vector2 contactPoint = Vector2.zero;
if (Input.touchCount > 0)
contactPoint = Input.touches[0].position;
if (Input.GetMouseButtonDown(0))
contactPoint = Input.mousePosition;
//check if user wants to restart the game
if (restartButtonGameCollider == Physics2D.OverlapPoint
(Camera.main.ScreenToWorldPoint(contactPoint)))
{
GameStateManager.GameState = GameState.Intro;
Application.LoadLevel(Application.loadedLevelName);
}
}
}
void FixedUpdate()
{
//just jump up and down on intro screen
if (GameStateManager.GameState == GameState.Intro)
{
if (GetComponent<Rigidbody2D>().velocity.y < -1) //when the speed drops, give a boost
GetComponent<Rigidbody2D>().AddForce(new Vector2(0, GetComponent<Rigidbody2D>().mass * 5500 * Time.deltaTime)); //调整开始界面小鸟的飞行状态
}
else if (GameStateManager.GameState == GameState.Playing || GameStateManager.GameState == GameState.Dead)
{
FixFlappyRotation(); // 角度修正
}
}
bool WasTouchedOrClicked()
{
if (Input.GetButtonUp("Jump") || Input.GetMouseButtonDown(0) ||
(Input.touchCount > 0 && Input.touches[0].phase == TouchPhase.Ended))
return true;
else
return false;
}
void MoveBirdOnXAxis()
{
transform.position += new Vector3(Time.deltaTime * XSpeed, 0, 0);
}
void BoostOnYAxis()
{
GetComponent<Rigidbody2D>().velocity = new Vector2(0, VelocityPerJump);
GetComponent<Audiosource>().PlayOneShot(FlyAudioClip);
}
/// <summary>
/// when the flappy goes up, it‘ll rotate up to 45 degrees. when it falls, rotation will be -90 degrees min
/// </summary>
private void FixFlappyRotation()
{
if (GetComponent<Rigidbody2D>().velocity.y > 0) flappyYAxisTravelState = FlappyYAxisTravelState.GoingUp;
else flappyYAxisTravelState = FlappyYAxisTravelState.GoingDown;
float degreesToAdd = 0;
switch (flappyYAxisTravelState) //根据小鸟的状态,来选择相应的角度计算数值
{
case FlappyYAxisTravelState.GoingUp:
degreesToAdd = 6 * RotateUpSpeed;
break;
case FlappyYAxisTravelState.GoingDown:
degreesToAdd = -3 * RotateDownSpeed;
break;
default:
break;
}
//solution with negative eulerAngles found here: http://answers.unity3d.com/questions/445191/negative-eular-angles.html
//clamp the values so that -90<rotation<45 *always*
birdRotation = new Vector3(0, 0, Mathf.Clamp(birdRotation.z + degreesToAdd, -90, 45)); //生成新的方向
transform.eulerAngles = birdRotation; //根据方向生成新的角度
}
/// <summary>
/// check for collision with pipes
/// </summary>
/// <param name="col"></param>
void OnTriggerEnter2D(Collider2D col)
{
if (GameStateManager.GameState == GameState.Playing) //如果游戏开始
{
if (col.gameObject.tag == "Pipeblank") //pipeblank is an empty gameobject with a collider between the two pipes 如果
{
GetComponent<AudioSource>().PlayOneShot(ScoredAudioClip);
ScoreManagerScript.Score++;
}
else if (col.gameObject.tag == "Pipe") //col的
{
FlappyDies();
}
}
}
void OnCollisionEnter2D(Collision2D col)
{
if (GameStateManager.GameState == GameState.Playing)
{
if (col.gameObject.tag == "Floor") //小鸟触发到了地板
{
FlappyDies();
}
}
}
void FlappyDies() //小鸟死亡
{
GameStateManager.GameState = GameState.Dead;
DeathGUI.SetActive(true); //使用死亡UI
GetComponent<AudioSource>().PlayOneShot(DeathAudioClip); //使用死亡音效
}
}
以上是关于开源移动小游戏项目《FlappyBird》学习心得的主要内容,如果未能解决你的问题,请参考以下文章
#跟着小白一起学鸿蒙# [番外]一起学做FlappyBird