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、等等