少年乘勇气,百战过乌孙。这篇文章主要讲述开源移动小游戏项目《FlappyBird》学习心得相关的知识,希望能为你提供帮助。
文章图片
游戏设计思路: 场景关卡:
- 地图中会随机生成一个又一个的管道,每一个管道由上下管道组成,中间的空隙是固定的,每条管道的生成时间是随机的,所以它们之间的间距不一样
文章图片
- 点击屏幕,小鸟便会被施加一个向上的速度,该速度随重力会逐渐减少。
- 每当小鸟越过一个管道时,得分加1,当小鸟碰到地图上的管道或者掉入地面时,游戏结束。
- 游戏中的得分没有上限
文章图片
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,当游戏开始或结束重新开始时,会随机选择一个管道:
文章图片
- 【开源移动小游戏项目《FlappyBird》学习心得】管道物件是固定好的,每次生成只需调整它的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);
//使用死亡音效
}}
推荐阅读
- AndroidStudio右键new无activity
- 解决repo从codeaurora.org同步Android代码失败问题
- linux部署web App
- virtualenvwrapper.sh报错: There was a problem running the initialization hooks.解决
- unity与android交互相关资料整理(U2A)
- 安卓开发中的mave镜像设置
- AppleScript 实现短信自动转发
- Spring(MVC启动时的WebApplicationContext的关系)
- swapPairs