Unity 游戏实例开发集合 之 FlappyBird (像素鸟) 休闲小游戏快速实现 您所在的位置:网站首页 所有休闲小游戏 Unity 游戏实例开发集合 之 FlappyBird (像素鸟) 休闲小游戏快速实现

Unity 游戏实例开发集合 之 FlappyBird (像素鸟) 休闲小游戏快速实现

2023-06-04 04:09| 来源: 网络整理| 查看: 265

Unity 游戏实例开发集合 之 FlappyBird (像素鸟) 休闲小游戏快速实现

目录

Unity 游戏实例开发集合 之 FlappyBird (像素鸟) 休闲小游戏快速实现

一、简单介绍

二、FlappyBird (像素鸟) 游戏内容与操作

三、相关说明

四、游戏代码框架

五、知识点

六、游戏效果预览

七、实现步骤

八、工程源码地址

九、延伸扩展

一、简单介绍

Unity 游戏实例开发集合,使用简单易懂的方式,讲解常见游戏的开发实现过程,方便后期类似游戏开发的借鉴和复用。

本节介绍,FlappyBird (像素鸟) 休闲小游戏快速实现的方法,希望能帮到你,若有不对,请留言。

这是一个 2D 游戏,主要是使用精灵图、2D 重力、2D 碰撞体,实现,游戏实现原理:

1、鸟 x 方向位置保持不变,背景天空草地,管道等在从右向左不动移动,从而实现鸟向前飞行效果

2、鸟有重力效果,通过 GetComponent().Velocity 的 y 方向添加速度,从而实现鸟向上飞的效果

3、背景天空草地,管道 也有Rigidbody2D,但是 Body Type 是 Kinematic ,没有重力向下的效果,但是可以 设置 GetComponent().Velocity 向左的速度,实现匀速向左运动的效果

4、游戏暂停实现原理是:1)暂停效果:把背景天空草地,管道 也有Rigidbody2D的Velocity 设置为0 ,暂停时记录鸟的Rigidbody2D的Velocity ,把 Rigidbody2D的 Body Type 是 Static,从而实现停止效果;2)继续游戏效果:重新设置背景天空草地,管道 也有Rigidbody2D的Velocity 设置为0之前的原值,把鸟Rigidbody2D的 Body Type 是 Dynamics,Rigidbody2D的Velocity设置为之前记录的值即可,这样就恢复现场,继续游戏了

5、无限背景实现:把背景天空草地设置两份(可以根据需要设置多份),1) 两份左右拼接

2)先是左边的背景显示,背景一起向左边运动到左边看不见,左边的看不到的背景,重新移动到右边背景的右边,这样,就实现无限循环背景了

二、FlappyBird (像素鸟) 游戏内容与操作

1、游戏开始,背景背景开始向左移动,鸟会受重力向下坠落

2、点击鼠标左键,鸟就会添加一个向上的力,避免坠落地面

3、鸟每过一个管子,就会有对应的分数增加

4、鸟撞到水管或者碰到地面,游戏则结束

三、相关说明

1、音频的枚举命名对应实际音频的名字,方便加载和指定播放音频

2、由于2D 游戏(元素都在同一平面),设置 SpriteRenderer 的 Order in Layer 来控制显示先后,Order in Layer 越大,显示就在前面,所以各个 Order in Layer 定义显示规则为 :天空预制体为 -5,草地 为 5,Bird 为 0,Pipe 下的上下管子为 2

3、Pipe 、GrassTile、SkyTile 的 Rigidbody2D, Body Type 是 Kinematic ,没有重力向下的效果

4、脚本复刻这块建议:先复刻 Common 和 Tools 文件夹的脚本,然后 各个实体 文件夹的脚本,接着 Manager 的各个脚本(顺序可按实现步骤的顺序来),最后 GameManager 和 GameStart 即可

四、游戏代码框架

(其实可以把Manager 拆分 Server 和 Data,或者更好)

 

五、知识点

1、MonoBehaviour 生命周期函数:Awake,Start,Update,Destroy

2、Input 按键的监控鼠标按键的状态

3、GameObject.Instantiate 物体的生成,GameObject.Destroy 物体的销毁

4、简单的对象池管理

5、Rigidbody 重力效果,添加 EdgeCollider2D ,进行 碰撞检测(Trigger)

6、简单UGUI的使用

7、简单屏幕适配(主要是UI和 Pipe生成位置)

8、一些数据,路径等的统一常量管理

9、Animation、Animator 的简单使用

10、游戏中 Tag 的使用

11、IManager 简单的接口规范 Manager 类函数

12、Action OnChangeValue 属性变化中委托的使用

13、Resources.Load() 代码加载预制体的使用

14、简单的屏幕坐标转为世界坐标的工具类

15、 SceneManager.LoadScene 加载,和 SceneManager.GetActiveScene() 当前场景的获取

16、游戏开发的资源脚本文件夹分类管理

17、等等

六、游戏效果预览

 

七、实现步骤

1、打开 Unity,导入相关资源

2、因为是 2D 游戏,场景中设置MainCamera 的Clear Flags 为 Solid Color,Projection 为 Orthographic ,Pos(0,0,-10),大家根据需要设置即可

 

3、把导入的图片设置为 Sprite 精灵图

 

4、把两张天空图拖入场景,左右拼接两张图,一个pos(0,0,0),另一个pos(20.25,0,0),20.25很关键,将作为循环背景移动的关键参考数据

 

 5、把屏幕设置为 1920x1080 作为参考大小,天空显示如图

 6、同理,拖入草地的背景图,左右拼接,一个为pos(0,-2.5,0),另一个为pos(20.25,-2.5,0),效果如下

 

 7、把天空和草地作为预制体,其中图片显示层级做修改,SkyTile 的 Order in Layer 为 -5(显示在后面),GrassTile 的 Order in Layer 为 5(显示在前面面),两个添加 Rigidbody2D ,其中 Rigidbody2D 的 Body Type 设置为 Kinematic(不会有向下的重力,但是可以施加 Rigidbody2D.velocity 的速度效果),然后 拖到 Resources 作为预制体

 

8、把两张飞行的鸟图拖入场景中,然后系统会自动生成一个动画和对应动画机挂载在图片上,运行场景,鸟动画大致如下

 

9、把BirdHero_01 改名为 Bird,选中 Bird,在菜单栏 Window - Animation - Animation,打开动画编辑,添加 BirdDie 鸟死亡动画,选择 Add Property ,添加SpriteRenderer 的 Sprite ,然后在 0.00 和 0.01 添加死亡图片,完成BirdDie 动画

 

 

 10、选中Bird ,在Windows菜单中,选择 Animation - Animator,进入动画机,添加 Parameters参数来控制动画播放,这里添加Bool 的 IsDie 和 IsFly

 

 

 11、在空白处右键,添加一个空动画,作为Idle 动画,选中 Idle ,右键 设置为默认动画,选中Idle 右键,点击 Make Transition ,拖到 BirdFly,形成一个动画过渡条件,同理,添加各个动画过渡条件线如图

 

 

 

12、其中 Idle 到 BirdFly 的过渡线的条件,选择为 IsFly 为true,BirdFly 到 Idle 的过渡线为 IsFly 为 flase 

 

 

13、其中 BirdFly 到 BirdDie 的过渡线的条件,选择为 IsDie 为true,BirdDie 到 BirdFly 的过渡线为 IsDie 为 flase (或者可以不要这根过渡线也可以),Idle 到 BirdDie 的过渡线的条件,选择为 IsDie 为true

 

 

 

14、这样 Bird 的动画机完成了,整理一下相关资源,在 Bird 上,添加 Rigidbody ,和 BoxCollider2D,并整理BoxCollider2D大小适配鸟实际大小,然后把 Bird 拖入 Resources 作为预制体资源

 

15、把管子拖入场景,把 Bird 拖入场景中,为了适配鸟过去,添加一个空物体GameObject,改名为 Pipe(添加 Rigidbody2D,BodyType 设置为 Kinematic),把管子图片置于其下,上下一个,位置如下,DownColumnSprite 的 Pos(0,-6,0),BoxCollider2D 适配精灵图实际大小,UpColumnSprite的 Pos(0,6,0),BoxCollider2D 适配精灵图实际大小,ScoreEdgeCollider2D 位置和方向如图,刚好鸟在中间触发加分,并勾选 IsTrigger (可以碰撞触发,但没有实际碰撞效果)

 

 

16、把设置好的Pipe 作为预制体,拖入 Resources 文件夹下

 

17、在场景中添加一个空物体GameObject,改名为 World (pos(0,0,0)),然后把 Main Camera 等拖到其下,新建多个 空物体GameObject,依次命名为 SpawnSkyTilePos(天空背景的生成位置和父物体),SpawnGrassTilePos(草地背景的生成位置和父物体),SpawnBirdPos(Bird的生成位置和父物体),SpawnPipePos(管子的生成位置和父物体),AudioSourceTrans(音频播放源的挂载体),位置 都为 Pos(0,0,0)

18、  在 World 下添加一个 GameObject ,添加 EdgeCollider2D ,改名为 GroundEdgeCollider2D ,位置搞好放置到草地上(拖入草地预制体作为参考),如图,最后记得把参考的参照物删除就好

 

19、  在 World 下添加一个 GameObject ,添加 EdgeCollider2D ,改名为 SkyEdgeCollider2D ,添加一个Cube 作为可视化参考,位置搞好放置到天空上(拖入天空预制体作为参考),如图

 

 20、新建一个 GameObject,改名为UI,用来当作 UI相关部分的父物体,pos 为 (0,0,0)

21、在UI下面,添加一个Canvas (自动添加EventSystem),设置 Canvas Scaler 的 UI Scale Mode 为 Scale with Screen Size ,Reference Resolution 为  1920 x 1080  ,Match 滑动到 Width

 

22、PauseGameButton 放置在左边上,改变锚点,文字加粗居中显示,可以根据实际情况自行调整

 

23、ScoreText 放置在右边上,改变锚点,文字加粗居中显示,可以根据实际情况自行调整

 

24、ResumeGameImage 图片铺满屏幕,设置为黑色,增加透明度,ResumeGameText 文字加粗居中显示,ResumeGameButton 放大,文字调大,可以根据实际情况自行调整,最终如图

 

25、GameOverImage 图片铺满屏幕,设置为黑色,增加透明度,GameOverText 文字加粗居中显示,RestartGameButton 放大,文字调大,可以根据实际情况自行调整,最终如图

 

26、在工程中添加 Common (一般可以游戏开发最后写,脚本中抽出来,整理统一管理),管理游戏中的一些常量,AnimatorParametersDefine 动画机的参数定义类,Enum 管理所有枚举,GameConfig 一些游戏配置,GameObjectPathInSceneDefine 场景中的游戏物体路径定义,ResPathDefine 预制体路径定义类,TagDefine Tag 定义类

 

27、 TagDefine Tag 定义类,其中 Tag 定义方式如下,选择一个游戏物体,选择 Tag 下拉菜单,点击 Add Tag ... 添加 Tag ,然后选择 + ,命名一个名称,save 即可,这里,我们把预制体的 Pipe的  Tag 设置为 Pipe (后面碰撞体触发用到)

 

 

28、在工程中添加 IManager 脚本,主要功能是定义管理类的一些基本接口

public interface IManager { // 初始化 void Init(Transform rootTrans, params object[] managers); // 帧更新 void Update(); // 销毁时调用(主要是释放数据等使用) void Destroy(); // 游戏结束 void GameOver(); }

29、在工程中添加 ResLoadManager 脚本,主要功能是,加载 Resources 文件加载的预制体,这里主要涉及加载 GameObject 和 AudioClip

/// /// 加载预制体 GameObject /// /// /// public GameObject LoadPrefab(string path) { if (m_PrefabsDict.ContainsKey(path) == true) { return m_PrefabsDict[path]; } else { GameObject prefab = Load(path); if (prefab!=null) { m_PrefabsDict.Add(path, prefab); } return prefab; } } /// /// 加载预制体 AudioClip /// /// /// public AudioClip LoadAudioClip(string path) { if (m_AudioClipsDict.ContainsKey(path) == true) { return m_AudioClipsDict[path]; } else { AudioClip prefab = Load(path); if (prefab != null) { m_AudioClipsDict.Add(path, prefab); } return prefab; } } /// /// 泛型加载预制体 /// /// /// /// private T Load(string path) where T:Object{ T prefab = Resources.Load(path); if (prefab == null) { Debug.LogError(GetType() + "/Load()/prefab is null,path = " + path); } return prefab; }

 

30、在工程中添加 Model 脚本,主要功能是定义了一个基本的数据模型,包含数值,和数值变化触发的事件

/// /// 数据模型 /// public class Model { private int m_Value; public int Value { get { return m_Value; } set { if (m_Value != value) { m_Value = value; if (OnValueChanged != null) { OnValueChanged.Invoke(value); } } } } /// /// 数值变化事件 /// public Action OnValueChanged;

 

31、在工程中添加 DataModelManager 脚本,主要功能是定义游戏中涉及到的数据,这里定义了 Score (既是 Model 类类型参数)的数据

private Model m_Scroe; public Model Score => m_Scroe; public void Init(Transform rootTrans, params object[] manager) { m_Scroe = new Model(); m_Scroe.Value = 0; } public void Destroy() { m_Scroe.OnValueChanged = null; m_Scroe.Value = 0; m_Scroe = null; }

32、在工程中添加 SkyTile脚本,主要功能是 利用 Rigidbody2D.velocity,更新天空背景位置,当位置到达指定位置,进行位置左移,从而实现无限循环

/// /// 初始化 /// /// 第几块天空,从 0 开始 public void Init(int index) { m_TargetPosX = -1 * GameConfig.BACKGROUND_SPRITE_INTERVAL_X; m_Velocity = Vector2.left * GameConfig.BACKGROUND_MOVE_LEFT_X; Vector3 curPos = transform.position; transform.position = new Vector3(curPos.x+(index)* GameConfig.BACKGROUND_SPRITE_INTERVAL_X, curPos.y, curPos.z); m_IsPause = false; Move(); } public void Resume() { m_IsPause = false; Move(); } public void Pause() { m_IsPause = true; Rigidbody2D.velocity = Vector2.zero; } public void GaomeOver() { Rigidbody2D.velocity = Vector2.zero; } private void Move() { Rigidbody2D.velocity = m_Velocity; } /// /// 更新天空背景位置 /// 当位置到达指定位置,进行位置左移,从而实现无限循环 /// private void UpdatePosOperation() { Vector3 curPos = transform.position; if (curPos.x 0) { GameObject.Destroy(m_TQueue.Dequeue().gameObject); } } m_TQueue = null; } /// /// 生成实例 /// /// /// /// private T InstantiateT(GameObject prefab,Transform parent) { GameObject go = GameObject.Instantiate(prefab, parent); return go.AddComponent(); } }

37、在工程中添加 Bird 脚本,主要功能是 Rigidbody2D.velocity 实现鸟飞行,鸟的动画切换,以及触发碰撞体相关事件(死亡和得分事件)

/// /// 初始化 /// public void Init(Action onGroundCollisionEnter2D, Action onScoreCollisionEnter2D) { m_OnGroundCollisionEnter2D = onGroundCollisionEnter2D; m_OnScoreCollisionEnter2D = onScoreCollisionEnter2D; m_UpVelocity = Vector2.up * GameConfig.BIRD_MOVE_UP_Y; PlayFlyAnimation(); } public void Fly() { Rigidbody2D.velocity = m_UpVelocity; } public void Resume() { Rigidbody2D.bodyType = RigidbodyType2D.Dynamic; Move(m_CurVelocity); PlayFlyAnimation(); } public void Pause() { m_CurVelocity = Rigidbody2D.velocity; Rigidbody2D.bodyType = RigidbodyType2D.Static; PlayIdleAnimation(); } public void GameOver() { //Rigidbody2D.bodyType = RigidbodyType2D.Static; PlayDieAnimation(); } private void Move(Vector2 velocity) { Rigidbody2D.velocity = velocity; } private void PlayIdleAnimation() { Animator.SetBool(AnimatorParametersDefine.IS_FLY, false); Animator.SetBool(AnimatorParametersDefine.IS_DIE, false); } private void PlayFlyAnimation() { Animator.SetBool(AnimatorParametersDefine.IS_FLY, true); Animator.SetBool(AnimatorParametersDefine.IS_DIE, false); } private void PlayDieAnimation() { Animator.SetBool(AnimatorParametersDefine.IS_FLY, false); Animator.SetBool(AnimatorParametersDefine.IS_DIE, true); } /// /// 触发死亡碰撞 /// /// private void OnCollisionEnter2D(Collision2D collision) { if (collision.collider.name.StartsWith(GameConfig.GROUND_EDGE_COLLIDER2D_NAME) || collision.collider.CompareTag(TagDefine.PIPE)) { if (m_OnGroundCollisionEnter2D!=null) { m_OnGroundCollisionEnter2D.Invoke(); } } } /// /// 触发加分碰撞 /// /// private void OnTriggerEnter2D(Collider2D collision) { if (collision.name.StartsWith(GameConfig.SCORE_EDGE_COLLIDER2D_NAME)) { if (m_OnScoreCollisionEnter2D != null) { m_OnScoreCollisionEnter2D.Invoke(); } } }

38、在工程中添加 BirdManager脚本,主要功能是加载 BIrd预制体,生成到指定位置,然后在游戏暂停、继续、结束控制 Bird 是否可出发飞行等事件和动画,以及游戏结束和游戏得分事件

/// /// 初始化 /// /// /// public void Init(Transform rootTrans, params object[] managers) { m_SpawnBirdPosTrans = rootTrans.Find(GameObjectPathInSceneDefine.SPAWN_BIRD_POS_PATH); m_ResLoadManager = managers[0] as ResLoadManager; m_DataModelManager = managers[1] as DataModelManager; m_AudioManager = managers[2] as AudioManager; m_IsPause = false; m_IsGameOver = false; LoadPrefab(); } public void Update() { if (m_IsPause == true || m_IsGameOver == true) { return; } UpdatePosOperation(); } public void Destroy() { m_SpawnBirdPosTrans = null; m_ResLoadManager = null; m_Bird = null; } public void GameResume() { m_IsPause = false; m_Bird.Resume(); } public void GamePause() { m_IsPause = true; m_Bird.Pause(); } public void GameOver() { m_IsGameOver = true; m_Bird.GameOver(); } /// /// 加载实例化鸟 /// private void LoadPrefab() { GameObject prefab = m_ResLoadManager.LoadPrefab(ResPathDefine.PREFAB_BIRD_PATH); GameObject bird = GameObject.Instantiate(prefab, m_SpawnBirdPosTrans); m_Bird = bird.AddComponent(); m_Bird.Init(OnBirdGroundCollisionEnter, OnBirdScoreCollisionEnter); } /// /// 监听是否鼠标按下,向上飞 /// private void UpdatePosOperation() { if (Input.GetMouseButtonDown(0) == true && EventSystem.current.IsPointerOverGameObject() ==false) // 鼠标点击在 UI 上不触发 { m_AudioManager.PlayAudio(AudioClipSet.Fly); m_Bird.Fly(); } } /// /// 游戏结束事件 /// private void OnBirdGroundCollisionEnter() { m_AudioManager.PlayAudio(AudioClipSet.Collider); m_IsGameOver = true; } /// /// 游戏加分事件 /// private void OnBirdScoreCollisionEnter() { m_AudioManager.PlayAudio(AudioClipSet.Tip); m_DataModelManager.Score.Value += GameConfig.PASS_PIPE_GET_SCORE; }

39、在工程中添加 Tools 脚本,主要功能是 把屏幕坐标转为世界坐标

/// /// 把屏幕坐标转为世界坐标 /// /// 对应参照对象 /// 对应参照相机 /// 屏幕位置 /// 屏幕位置的世界位置 public static Vector3 ScreenPosToWorldPos(Transform refTran, Camera refCamera, Vector2 screenPos) { //将对象坐标换成屏幕坐标 Vector3 pos = refCamera.WorldToScreenPoint(refTran.position); //让鼠标的屏幕坐标与对象坐标一致 Vector3 mousePos = new Vector3(screenPos.x, screenPos.y, pos.z); //将正确的鼠标屏幕坐标换成世界坐标交给物体 return refCamera.ScreenToWorldPoint(mousePos); }

 

40、在工程中添加 Pipe 脚本,主要功能是 Rigidbody2D.velocity 实现 管子移动,和到达指定位置,进行对象回收

/// /// 初始化 /// /// /// /// /// public void Init(float spawnPosX, float spawnPosY, float movePosTargetPosX, Action onRecycleSelfAction) { m_TargetPosX = movePosTargetPosX; m_Velocity = Vector2.left * GameConfig.BACKGROUND_MOVE_LEFT_X; Vector3 curPos = transform.position; transform.position = new Vector3(spawnPosX, spawnPosY, curPos.z); m_OnRecycleSelfAction = onRecycleSelfAction; m_IsPause = false; Move(); } private void Move() { Rigidbody2D.velocity = m_Velocity; } /// /// 位置更新 /// 判断位置是否到达指定位置,进行对象回收 /// private void UpdatePosOperation() { Vector3 curPos = transform.position; if (curPos.x 0) { foreach (var item in m_PipeList) { item.Pause(); } } } public void GameResume() { m_IsPause = false; if (m_PipeList != null && m_PipeList.Count > 0) { foreach (var item in m_PipeList) { item.Resume(); } } } public void GameOver() { m_IsGameOver = true; if (m_PipeList!=null && m_PipeList.Count>0) { foreach (var item in m_PipeList) { item.GaomeOver(); } } } /// /// 预载实例化对象 /// /// /// private void LoadPrefab(GameObject prefab,Transform parent) { PreloadT(prefab, parent); } /// /// 计时生成管子,以及初始化管子和设置回收管子事件 /// void UpdateSpawnPipe() { m_SpawnTimer += Time.deltaTime; if (m_SpawnTimer>=GameConfig.PIPE_SPAWN_TIME_INTERVAL) { m_SpawnTimer -= GameConfig.PIPE_SPAWN_TIME_INTERVAL; Pipe pipe = Get(m_PipePrefab, m_SpawnPipePosTrans); float spawnPosY = Random.Range(GameConfig.PIPE_SPAWN_POS_Y_LIMIT_MIN,GameConfig.PIPE_SPAWN_POS_Y_LIMIT_MAX); pipe.Init(m_SpawnPosX, spawnPosY,m_TargetMovePosX, (p)=> { m_PipeList.Remove(p); Recycle(p); }); m_PipeList.Add(pipe); } }

 42、在工程中添加 AudioManager 脚本,主要功能是加载指定音频,以及添加AudioSource ,播放指定音频(Sound 拖到 Resources 文件夹下,枚举命名上注意与音频文件对应)

/// /// 初始化 /// /// /// public void Init(Transform rootTrans, params object[] managers) { m_AudioSourceTrans = rootTrans.Find(GameObjectPathInSceneDefine.AUDIO_SOURCE_TRANS_PATH); m_ResLoadManager = managers[0] as ResLoadManager; m_AudioClipDict = new Dictionary(); m_AudioSource = m_AudioSourceTrans.gameObject.AddComponent(); Load(); } /// /// 播放指定音频 /// /// public void PlayAudio(AudioClipSet audioName) { if (m_AudioClipDict.ContainsKey(audioName) == true) { m_AudioSource.PlayOneShot(m_AudioClipDict[audioName]); } else { Debug.LogError(GetType()+ "/PlayAudio()/ audio clip is null,audioName = "+ audioName); } } /// /// 加载音频 /// private void Load() { for (AudioClipSet clipPath = AudioClipSet.Collider; clipPath < AudioClipSet.SUM_COUNT; clipPath++) { AudioClip audioClip = m_ResLoadManager.LoadAudioClip(ResPathDefine.AUDIO_CLIP_BASE_PATH+ clipPath.ToString()); m_AudioClipDict.Add(clipPath, audioClip); } }

 43、在工程中添加 UIManager 脚本,主要功能是获取 UI 元素,对应和 Score 添加对应事件,以及 游戏暂停,继续、结束按钮的事件添加

public void Init(Transform rootTrans, params object[] managers) { m_ScoreText = rootTrans.Find(GameObjectPathInSceneDefine.UI_SCORE_TEXT_PATH).GetComponent(); m_ResumeGameImageGo = rootTrans.Find(GameObjectPathInSceneDefine.UI_RESUME_GAME_IMAGE_PATH).gameObject; m_GameOverImageGo = rootTrans.Find(GameObjectPathInSceneDefine.UI_GAME_OVER_IMAGE_PATH).gameObject; m_ResumeGameButton = rootTrans.Find(GameObjectPathInSceneDefine.UI_RESUME_GAME_BUTTON_PATH).GetComponent(); m_PauseGameButton = rootTrans.Find(GameObjectPathInSceneDefine.UI_PAUSE_GAME_BUTTON_PATH).GetComponent(); m_RestartGameButton = rootTrans.Find(GameObjectPathInSceneDefine.UI_RESTART_GAME_BUTTON_PATH).GetComponent(); m_DataModelManager = managers[0] as DataModelManager; m_GameOverImageGo.SetActive(false); m_ScoreText.text = m_DataModelManager.Score.Value.ToString(); m_DataModelManager.Score.OnValueChanged += OnScroeValueChanged; m_ResumeGameButton.onClick.AddListener(OnResumeGameButton); m_PauseGameButton.onClick.AddListener(OnPauseGameButton); m_RestartGameButton.onClick.AddListener(OnRestartButton); m_ResumeGameImageGo.SetActive(true); m_IsPause = true; } public void Update() { } public void Destroy() { m_RestartGameButton.onClick.RemoveAllListeners(); m_ScoreText = null; m_GameOverImageGo = null; m_RestartGameButton = null; m_DataModelManager = null; } public void GameOver() { m_GameOverImageGo.SetActive(true); } private void OnScroeValueChanged(int score) { m_ScoreText.text = score.ToString(); } private void OnPauseGameButton() { m_IsPause = true; m_ResumeGameImageGo.SetActive(true); } private void OnResumeGameButton() { m_IsPause = false; m_ResumeGameImageGo.SetActive(false); } private void OnRestartButton() { SceneManager.LoadScene(SceneManager.GetActiveScene().name); }

44、在工程中添加 GameManager 脚本(单例),主要功能:1)获取场景中相关游戏物体或者 UI根物体,2)new 相关的 Manager 管理类,初始化Init,Update 、和Destroy,3)判断游戏状态,是否暂停、继续、结束

public void Awake() { m_ResLoadManager = new ResLoadManager(); m_AduioManager = new AudioManager(); m_SkyTileManager = new SkyTileManager(); m_GrassTileManager = new GrassTileManager(); m_BirdManager = new BirdManager(); m_PipeManager = new PipeManager(); m_DataModelManager = new DataModelManager(); m_UIManager = new UIManager(); } public void Start() { m_WorldTrans = GameObject.Find(GameObjectPathInSceneDefine.WORLD_PATH).transform; m_UITrans = GameObject.Find(GameObjectPathInSceneDefine.UI_PATH).transform; Init(null); m_IsGameOver = false; } public void Init(Transform rootTrans, params object[] managers) { m_DataModelManager.Init(null); m_ResLoadManager.Init(null); m_AduioManager.Init(m_WorldTrans, m_ResLoadManager); m_SkyTileManager.Init(m_WorldTrans, m_ResLoadManager); m_GrassTileManager.Init(m_WorldTrans, m_ResLoadManager); m_BirdManager.Init(m_WorldTrans, m_ResLoadManager, m_DataModelManager, m_AduioManager); m_PipeManager.Init(m_WorldTrans, m_ResLoadManager); m_UIManager.Init(m_UITrans, m_DataModelManager); } public void Update() { JudgeGamePauseOrResume(); JudgeGameOver(); m_DataModelManager.Update(); m_ResLoadManager.Update(); m_SkyTileManager.Update(); m_GrassTileManager.Update(); m_BirdManager.Update(); m_PipeManager.Update(); m_UIManager.Update(); m_AduioManager.Update(); } public void Destroy() { m_DataModelManager.Destroy(); m_ResLoadManager.Destroy(); m_SkyTileManager.Destroy(); m_GrassTileManager.Destroy(); m_BirdManager.Destroy(); m_PipeManager.Destroy(); m_UIManager.Destroy(); m_AduioManager.Destroy(); }

 

45、GameStart 脚本,整个游戏的入口,管理对应 GameManager 的 Awake(),Start(),Update(),OnDestroy() ,OnGUI() 对应函数功能

public class GameStart : MonoBehaviour { private void Awake() { GameManager.Instance.Awake(); } // Start is called before the first frame update void Start() { GameManager.Instance.Start(); } // Update is called once per frame void Update() { GameManager.Instance.Update(); } private void OnDestroy() { GameManager.Instance.Destroy(); } }

46、在场景中添加 GameObject 空物体,改名为 GameStart,并且挂载 GameStart 脚本

47、运行场景,就会自动生成场景,点击 Game ,开始游戏,Pause 暂停游戏,Bird 撞地面和管子都会游戏结束,每过一个管子都会增加分数

 

八、工程源码地址

github 地址:https://github.com/XANkui/UnityMiniGameParadise

的 MGP_006FlappyBird 工程

九、延伸扩展

游戏的好不好玩,趣味性,视觉化等诸多因素影响,下面简单介绍几个方面拓展游戏的方向,仅做参考

1、可以根据自己需要修改游戏资源,换肤什么的等

2、可以根据需要添加加分特效,音效,背景更多的细节变化等等

3、添加 UI 面板等,美化游戏

4、Bird 得分特效添加

5、Bird 不同分数下的不同状态或者皮肤,抑或速度;

6、添加最高分数保留,和游戏排行榜等;

7、管子可以出来一些什么东西,或者也有上下动的管子;

8、天空和草地的不同组别,比如春夏秋冬,中国日本埃及不同风格,以增加新奇性

9、等等  



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有