IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 游戏开发 -> Unity 游戏实例开发集合 之 Circus (马戏团) 休闲小游戏快速实现 -> 正文阅读

[游戏开发]Unity 游戏实例开发集合 之 Circus (马戏团) 休闲小游戏快速实现

Unity 游戏实例开发集合 之 Circus (马戏团) 休闲小游戏快速实现

目录

Unity 游戏实例开发集合 之 Circus (马戏团) 休闲小游戏快速实现

一、简单介绍

二、Circus (马戏团) 游戏内容与操作

三、相关说明

四、游戏代码框架

五、知识点

?六、游戏效果预览

七、实现步骤

八、工程源码地址

九、延伸扩展


一、简单介绍

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

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

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

0、这是2D 游戏基于 横屏 1920x1080 开发的,并实现屏幕适配;

1、玩家 Joker x 方向位置保持不变,背景和火圈从左往右移动,从而实现 Joke 向前跑动的效果

2、Joker 有重力效果,挂载Rigidbody2D, 通过 GetComponent<Rigidbody2D>().Velocity 的 方向添加速度,来实现向上跳动的效果

3、无限背景实现:使用 shader 中的 MainTex 的 Offset 属性中的 x 实时变化,实现无限

二、Circus (马戏团) 游戏内容与操作

1、游戏开始,背景、火圈自动向左移动,Joker 开始跑动

2、点击鼠标右键 Joker 跳跃

3、没跳过一个 火圈对应加分

4、Joker 碰到火圈,游戏结束

三、相关说明

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

2、由于2D 游戏(元素都在同一平面),设置 SpriteRenderer 的 Order in Layer 来控制显示先后,Order in Layer 越大,显示就在前面,所以各个 Order in Layer 定义显示规则为 :Background 预制体为 -5,Joker 为 0,FireCircle 为 -2 ,FireHalfCircle 为 2

3、Background 无限移动是通过 shader ,一张图实现的,原理是:1)获取Sprite 的材质,2)材质上获取 shader 的 _MainTex,对 Offset 进行动态修改,从而实现无限循环

m_BgMat = bg.GetComponent<SpriteRenderer>().material;
m_BgMainTexVect = m_BgMat.GetTextureOffset(MAIN_TEX);
m_BgMat.SetTextureOffset(MAIN_TEX, new Vector2(m_BgMainTexVect.x += m_MainTexRunSpeed * Time.deltaTime, m_BgMainTexVect.y));

4、火圈是两层 Sprite 组成,Sprite 中的 layer 不同,且一个大于 Joker 的 layer ,一个小于 Joker 的 Layer ,从而实现跳跃火圈的效果

5、火圈生成的位置,是根据屏幕宽的上的 百分(1+?%)多少设置的,所以,可以保证,生成前保证是看不见火圈的;火圈的回收的位置,也是根据屏幕的宽左边的百分(-?%)多少设置的,可以保证回收火圈,也是看不见火圈的

?

四、游戏代码框架

(仅做参考,可以根据需要重新架构,添加消息中心,管理一些事件,或者更好)

?

?

五、知识点

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

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

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

4、简单的对象池管理

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

6、简单UGUI的使用

7、2D 游戏屏幕适配(主要是UI 、 NPC 生成位置,屏幕适配 Camera orthographicSize)

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

9、Animation、Animator 的简单使用

10、游戏中 Tag 的使用

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

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

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

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

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

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

17、Audio 简单管理播放

18、等等


?
六、游戏效果预览

七、实现步骤

1、打开 Unity,导入相关资源,并把图片都转为精灵图

?

2、把 Main Camera 的位置设置为(0,0,-10),Clear Flags 设置为 Solid Color , Projection 设置为 Orthofraphic,调整 Size 为0.95,是在Screen (1920x1080)屏幕下 ,根据背景图 调整的,如图

?

3、把背景图改名为 Background ,调整 Scale? X 比例为 1.35(根据需要调整合适值) 使之铺满 Game 窗口,创建 Material ,shader 设置为 Unlit-Texture ,赋给 Background ,并把 Background? 拖到 Resources ,设置为 预制体

?

4、在场景中,添加一个 GameObject ,改名为 World ,pos(0,0,0),删除 Directional Light ,把 Main Camera 拖到其下,并把屏幕设置为 1080x1920 作为游戏开发宽高(后面屏幕适配都是基于1080x1920做适配)

?

5、把小丑2-3图片拖到场景中,创建小丑的 Joker_Run 动画,和 Joker 动画机,改名为 Joker ,选中 Joker,然后 Window-Aniamtion-Animation ,在 Animation 窗口添加 Joker_Jump(小丑2图) 和 Joker_Collider(小丑4图) 动画

?

6、如果 Joker_Run 默认动画速度过快,可以调整 Samples 12 改为 6(可以根据需要适当修改)

?

7、选中 Joker,然后 Window-Aniamtion-Animator,动画过渡线如图,添加 Collider(Trigger) 和 IsJump(Bool) 参数,Any State 过渡线到 Joker_Collider 是 Collider ,Joker_Run 过渡线到 Joker_Jump 是 IsJump 为 true ,Joker_Jump? 过渡线到 Joker_Run? 是 IsJump 为 false,最后拖到 Resources 文件夹下作为预制体

?

7-1、给 Joker 添加 Rigidbody2D ,BoxCollider2D ,size 设置如图(根据需要设置即可)

8、同理,把 火图a1-2 拖到场景,构建动画,改名为 FireCircle ;把 火图a1f-2f 拖到场景,构建动画,改名为 FireHalfCircle 并把它置于 FireCircle 其下

8-1、给 FireCircle 添加 BoxCollider2D ,size 和位置设置如下,作为碰撞火圈结束的碰撞体,添加 EdgeCollider2D,设置大小方向如下,勾选 IsTrigger 作为触发得分使用

?9、由于2D 游戏(元素都在同一平面),设置 SpriteRenderer 的 Order in Layer 来控制显示先后,Order in Layer 越大,显示就在前面,所以各个 Order in Layer 定义显示规则为 :Background 预制体为 -5,Joker 为 0,FireCircle 为 -2 ,FireHalfCircle 为 2,层级效果如下

?

10、在 World 下面添加多个 GameObject,位置都为(0,0,0),改名为 SpawnBackgroundPos,AudioSourceTrans,SpawnJokerPos,SpawnFireCirclePos,功能如其名,用于生成 Background 父物体,音频源挂载,生成 Joker 的父物体,生成 FireCircle 的父物体

?

11、在 World 下面添加 GameObject,改名为 Ground ,添加 BoxCollider2D,位置为(-1.2,-0.62,0),x 作为后面 Joker 生成的位置(根据需调整BoxCollider2D ,位置)

?

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

13、在Canvas 下,添加 ScoreText ,参数设置如图

?

14、在Canvas 下,添加 GameOverImage ,参数设置如图

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

?

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

?

?

?

17、在 Interface,添加各种基础的接口,便于具体类的功能指定添加

?

18、Tools 工具类 ,目前添加两个功能函数,把屏幕坐标转为世界坐标函数,2D游戏 屏幕适配 函数

	public class Tools 
	{
		/// <summary>
		/// 把屏幕坐标转为世界坐标
		/// </summary>
		/// <param name="refTran">对应参照对象</param>
		/// <param name="refCamera">对应参照相机</param>
		/// <param name="screenPos">屏幕位置</param>
		/// <returns>屏幕位置的世界位置</returns>
		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);

		}


		/// <summary>
		/// 2D游戏 屏幕适配 
		/// vaildWidth =(Screen.width/Screen.height*2*orthographicSize)
		/// </summary>
		/// <param name="BaseScreenWitdh">开发时的参考屏幕宽</param>
		/// <param name="BaseScreenHeight">开发时的参考屏幕高</param>
		/// <param name="orthographicCamera2D">正交的相加</param>
		public static void AdaptationFor2DGame(int BaseScreenWitdh,int BaseScreenHeight,Camera orthographicCamera2D)
        {
            if (orthographicCamera2D.orthographic ==false)
            {
				Debug.LogError("AdaptationFor2DGame()/ Camera is not orthographic , Please Check !! ");
				return;
            }
			// 获取开发设置的 正交相机的 size  
			float BaseOrSize = orthographicCamera2D.orthographicSize;
			 // 获得有效的可视宽度
            float vaildWidth = (BaseScreenWitdh * 1.0f / BaseScreenHeight) * 2 * BaseOrSize;
			// 实际屏幕的 宽高比
            float aspectRatio = Screen.width * 1f / Screen.height;
			// 根据实际屏幕和有效的可视宽度得到,适配的 size ,并赋值到相机
            float adapterOrthoSize = vaildWidth / aspectRatio / 2;
			orthographicCamera2D.orthographicSize = adapterOrthoSize;
        }
    }

?

?19、在工程中添加 IServer 脚本,主要功能是定义服务类的一些基本功能接口

?

20、在工程中添加 ResLoadServer 脚本,继承 IServer,主要功能是 加载预制体和音频文件

        /// <summary>
        /// 加载预制体 GameObject 
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        public GameObject LoadPrefab(string path)
        {
            if (m_PrefabsDict.ContainsKey(path) == true)
            {
                return m_PrefabsDict[path];
            }
            else
            {
                GameObject prefab = Load<GameObject>(path);
                if (prefab != null)
                {
                    m_PrefabsDict.Add(path, prefab);
                }

                return prefab;
            }
        }

        /// <summary>
        /// 加载预制体 AudioClip 
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        public AudioClip LoadAudioClip(string path)
        {
            if (m_AudioClipsDict.ContainsKey(path) == true)
            {
                return m_AudioClipsDict[path];
            }
            else
            {
                AudioClip prefab = Load<AudioClip>(path);
                if (prefab != null)
                {
                    m_AudioClipsDict.Add(path, prefab);
                }

                return prefab;
            }
        }

?

21、在工程中添加 AudioServer 脚本,继承 IServer,主要功能是加载指定音频,添加音频源,以及播放背景音乐和指定音频文件

        /// <summary>
        /// 播放指定背景音乐
        /// </summary>
        /// <param name="audioName"></param>
        public void PlayBG(AudioClipSet audioName,bool isLoop=true)
        {
            if (m_AudioClipDict.ContainsKey(audioName) == true)
            { 
                m_AudioSource.Stop();
                m_AudioSource.clip = m_AudioClipDict[audioName];
                m_AudioSource.loop = isLoop;
                m_AudioSource.Play();
            }
            else
            {
                Debug.LogError(GetType() + "/PlayAudio()/ audio clip is null,audioName = " + audioName);
            }
        }

        /// <summary>
        /// 停止背景音乐
        /// </summary>
        public void StopBG() {
            m_AudioSource.Stop();
        }

        /// <summary>
        /// 播放指定音频
        /// </summary>
        /// <param name="audioName"></param>
        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);
            }
        }

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

23、在工程中添加 BackgroundManager 脚本,主要功能是加载 Background ,实例化 ? Background? ,获取 Sprite 材质的 Shader ,更新? shader 中 MainTex 的 Offset 使之运动,,实现循环 Background?

        /// <summary>
        /// 加载预制体
        /// </summary>
        private void LoadPrefab()
        {
            GameObject prefab = m_ResLoadServer.LoadPrefab(ResPathDefine.PREFAB_BACKGROUND_PATH);
            GameObject bg = GameObject.Instantiate(prefab, m_SpawnBackgroundPosTrans);
            m_BgMat = bg.GetComponent<SpriteRenderer>().material;
            m_BgMainTexVect = m_BgMat.GetTextureOffset(MAIN_TEX);
        }

        /// <summary>
		/// 更新 Sprite Shader 图片的 Offset 位置
		/// 从而实现无限循环
		/// </summary>
		private void UpdatePosOperation()
        {
            m_BgMat.SetTextureOffset(MAIN_TEX, new Vector2(m_BgMainTexVect.x += m_MainTexRunSpeed * Time.deltaTime, m_BgMainTexVect.y));

        }

?

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

	/// <summary>
	/// 数据模型
	/// </summary>
	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);

					}
				}
			}
		}

		/// <summary>
		/// 数值变化事件
		/// </summary>
		public Action<int> OnValueChanged;
	}

?

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

?

26、在工程中添加 Joker 脚本,主要功能是实现 Joker 的 Jump 、Run 动作,以及动画,并且监听 碰撞事件

		public void Jump()
		{
			Rigidbody2D.velocity = m_UpVelocity;
			PlayJumpAnimation();
		}

		public void Run()
		{
			PlayRunAnimation();
		}

		public void GameOver()
		{
			PlayCollderAnimation();
			Rigidbody2D.bodyType = RigidbodyType2D.Static;
		}

		private void PlayCollderAnimation()
		{
			Animator.SetTrigger(AnimatorParametersDefine.JOKER_TRIGGER_COLLIDER);
		}

		private void PlayJumpAnimation()
		{
			Animator.SetBool(AnimatorParametersDefine.JOKER_IS_JUMP,true);
		}

		private void PlayRunAnimation()
		{
			Animator.SetBool(AnimatorParametersDefine.JOKER_IS_JUMP,false);
		}

		/// <summary>
		/// 触发碰撞
		/// </summary>
		/// <param name="collision"></param>
		private void OnCollisionEnter2D(Collision2D collision)
		{
			if (m_OnColliderCollisionEnter2D != null)
			{
				m_OnColliderCollisionEnter2D.Invoke(collision);
			}
		}

		/// <summary>
		/// 触发加分碰撞
		/// </summary>
		/// <param name="collision"></param>
		private void OnTriggerEnter2D(Collider2D collision)
		{
			if (m_OnScoreCollisionEnter2D != null)
			{
				m_OnScoreCollisionEnter2D.Invoke();
			}
		}

26、在工程中添加 JokerManager 脚本,主要功能是 Joker 的加载,实例化,以及控制Jump动作,并且设置相关碰撞事件

        /// <summary>
        /// 加载实例化 Joker 
        /// </summary>
        private void LoadPrefab()
        {
            GameObject prefab = m_ResLoadServer.LoadPrefab(ResPathDefine.PREFAB_JOKER_PATH);
            GameObject joker = GameObject.Instantiate(prefab, m_SpawnJokerPosTrans);
            joker.transform.position = m_SpawnJokerPos;
            m_Joker = joker.AddComponent<Joker>();
            m_Joker.Init(OnJokerColliderCollisionEnter, OnBirdScoreCollisionEnter);
            m_Joker.Run();
        }

        /// <summary>
        /// 监听是否鼠标按下,向上飞
        /// </summary>
        private void UpdatePosOperation()
        {

            if (Input.GetMouseButtonDown(0) == true
                && EventSystem.current.IsPointerOverGameObject() == false) // 鼠标点击在 UI 上不触发(注意场景中要有 EventSystem组件)
            {
                if (m_IsJump==false)
                {
                    m_AudioServer.PlayAudio(AudioClipSet.Circus_Jump);
                    m_Joker.Jump();
                    m_IsJump = true;
                }
                
            }
        }

        /// <summary>
        /// 游戏碰撞火圈和地面事件
        /// </summary>
        private void OnJokerColliderCollisionEnter(Collision2D collision)
        {

            if (collision.collider.CompareTag(Tag.FIRE_CIRCLE))
            {
                GameManager.Instance.GameOver();

                m_AudioServer.PlayAudio(AudioClipSet.Circus_GameOver);
            }

            if (collision.collider.CompareTag(Tag.GROUND))
            {
                m_IsJump = false;
                m_Joker.Run();
            }
            

        }

        /// <summary>
        /// 游戏加分事件
        /// </summary>
        private void OnBirdScoreCollisionEnter()
        {
            m_DataModelManager.Score.Value += GameConfig.JOKER_PASS_FIRECIRCLE_GET_SCORE;

        }

27、在工程中添加 ObjectPool 和 ObjectPoolContainer 脚本,主要功能是建立对象池(对象的预载,获取,释放、清空),和对象池对象使用状态(使用和未使用)管理

?

28、在工程中添加 ObjectPoolManager 脚本,主要功能是管理各个对象池,预载、获取、释放、各个对象池的对象

29、在工程中添加 FireCircleManager脚本,主要功能是加载预制体 FireCircle,定时实例化 FireCircle ,并且更新位置是,判断是否可回收

        /// <summary>
        /// 加载预制体
        /// </summary>
        private void LoadPrefab()
        {
            m_FireCirclePrefab = m_ResLoadServer.LoadPrefab(ResPathDefine.PREFAB_FIRECIRCLE_PATH);
        }

        /// <summary>
        /// 计时生成火圈,以及初始化管子和设置回收管子事件
        /// </summary>
        void UpdateSpawnFireCircle()
        {
            m_SpawnTimer += Time.deltaTime;
            if (m_SpawnTimer >= GameConfig.FIRECIRLE_SPAWN_TIME_INTERVAL)
            {
                m_SpawnTimer -= GameConfig.FIRECIRLE_SPAWN_TIME_INTERVAL;

                GameObject npc = m_ObjectPoolManager.SpawnObject(m_FireCirclePrefab, m_SpawnFireCirclePosTrans);
                npc.transform.position = m_SpawnPos;
                m_ShowFireCircleTransformList.Add(npc.transform);
            }

            foreach (Transform trans in m_ShowFireCircleTransformList)
            {
                trans.Translate(Vector3.left * m_MoveSpeed * Time.deltaTime,Space.World);
            }
        }

        /// <summary>
        /// 判断位置,回收对象
        /// </summary>
        void UpdateFireClePosRecycle()
        {
            if (m_ShowFireCircleTransformList != null)
            {
                foreach (Transform fireTrans in m_ShowFireCircleTransformList)
                {
                    if (fireTrans.position.x <= m_TargetMovePosX)
                    {
                        m_RemoveFireCircleTrQue.Enqueue(fireTrans);
                        m_ObjectPoolManager.ReleaseObject(fireTrans.gameObject);
                        fireTrans.position = m_SpawnPos;
                    }
                }
                
                // 移除
                while (m_RemoveFireCircleTrQue.Count > 0)
                {
                    m_ShowFireCircleTransformList.Remove(m_RemoveFireCircleTrQue.Dequeue());
                }
            }
        }

30、在工程中添加 UIManager脚本,主要功能是更新 分数显示,添加重新开始按钮事件、游戏结束显示界面

        /// <summary>
        /// 游戏结束
        /// </summary>
        public void GameOver()
        {
            m_GameOverImageGo.SetActive(true);

        }

        /// <summary>
        /// 更新分数显示
        /// </summary>
        /// <param name="score"></param>
        private void OnScroeValueChanged(int score)
        {
            m_ScoreText.text = score.ToString();
        }

        /// <summary>
        /// 重新开始按钮事件
        /// </summary>
        private void OnRestartButton()
        {
            SceneManager.LoadScene(SceneManager.GetActiveScene().name);
        }

31、在工程中添加 BaseGameManager 脚本,主要功能是 定义注册个接口,和 Update Destroy 的统一处理函数,并实现继承单例功能

        // 单例
        private static T m_Instance;
        public static T Instance
        {
            get
            {
                if (m_Instance == null)
                {
                    m_Instance = new T();
                }

                return m_Instance;
            }
        }

        /// <summary>
        ///  Manager 初始化
        /// </summary>
        /// <param name="rootTrans"></param>
        /// <param name="objs"></param>
        protected abstract void InitManager(Transform rootTrans);

        /// <summary>
        ///  Server 初始化
        /// </summary>
        /// <param name="rootTrans"></param>
        /// <param name="objs"></param>
        protected abstract void InitServer(Transform rootTrans);


        /// <summary>
        /// 注册 Manager
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="manager"></param>
        protected void RegisterManager<T>(T manager) where T : IManager
        {
            Type t = typeof(T);
            if (m_ManagerDict.ContainsKey(t) == true)
            {
                m_ManagerDict[t] = manager;
            }
            else
            {
                m_ManagerDict.Add(t, manager);
            }
        }

        /// <summary>
        /// 注册 Server
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="server"></param>
        protected void RegisterServer<T>(T server) where T : IServer
        {
            Type t = typeof(T);
            if (m_ServerDict.ContainsKey(t) == true)
            {
                m_ServerDict[t] = server;
            }
            else
            {
                m_ServerDict.Add(t, server);
            }
        }

        /// <summary>
        /// 获取指定 Manger 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public T GetManager<T>() where T : class
        {
            Type t = typeof(T);
            if (m_ManagerDict.ContainsKey(t) == true)
            {
                return m_ManagerDict[t] as T;
            }
            else
            {
                Debug.LogError("GetManager()/ not exist ,t = " + t.ToString());
                return null;
            }
        }

        /// <summary>
        /// 获取指定 Server 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public T GetServer<T>() where T : class
        {
            Type t = typeof(T);
            if (m_ServerDict.ContainsKey(t) == true)
            {
                return m_ServerDict[t] as T;
            }
            else
            {
                Debug.LogError("GetServer()/ not exist ,t = " + t.ToString());
                return null;
            }
        }

32、在工程中添加 GameManager 脚本(单例),继承BaseGameManager ,主要功能:1)获取场景中相关游戏物体或者 UI根物体,简单游戏适配;2)new 相关的 Manager 管理类,初始化Init;3)背景音乐开启与关闭的功能;4)判断游戏状态,是否游戏结束

        public override void Start()
        {
            base.Start();

            m_AudioServer.PlayBG(AudioClipSet.Circus_BG);
        }

        protected override void InitManager(Transform rootTrans)
        {
            m_DataModelManager.Init(null);
            m_ObjectPoolManager.Init(null);
            m_BackgroundManager.Init(m_WorldTrans);
            m_FireCircleManager.Init(m_WorldTrans);
            m_JokerManager.Init(m_WorldTrans);
            m_UIManager.Init(m_UITrans);
        }

        protected override void InitServer(Transform rootTrans)
        {
            m_ResLoadServer.Init(null);
            m_AudioServer.Init(m_WorldTrans);
        }

        public void GameOver()
        {
            m_AudioServer.StopBG();

            m_BackgroundManager.GameOver();
            m_FireCircleManager.GameOver();
            m_JokerManager.GameOver();
            m_UIManager.GameOver();

        }

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

	public class GameStart : MonoBehaviour
	{
        private void Awake()
        {
            GameManager.Instance.Awake(this);
        }

        // 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();
        }
    }

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

?

35、运行场景,就会自动生成场景,跳过火圈,加分,撞到火圈,游戏结束

八、工程源码地址

github 地址:GitHub - XANkui/UnityMiniGameParadise: Unity 游戏开发集合代码集

的 MGP_008Circus 工程

九、延伸扩展

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

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

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

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

4、越过火圈 得分特效添加

5、设置成关卡类型的游戏;

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

7、Joker 向前向后停止的新操作方式等

8、等等
?

  游戏开发 最新文章
6、英飞凌-AURIX-TC3XX: PWM实验之使用 GT
泛型自动装箱
CubeMax添加Rtthread操作系统 组件STM32F10
python多线程编程:如何优雅地关闭线程
数据类型隐式转换导致的阻塞
WebAPi实现多文件上传,并附带参数
from origin ‘null‘ has been blocked by
UE4 蓝图调用C++函数(附带项目工程)
Unity学习笔记(一)结构体的简单理解与应用
【Memory As a Programming Concept in C a
上一篇文章      下一篇文章      查看所有文章
加:2022-02-01 20:55:16  更:2022-02-01 20:55:50 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/27 18:41:36-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码