Unity 游戏实例开发集合 之 CompoundBigWatermelon (简单合成一个大西瓜) 休闲小游戏快速实现

目录

Unity 游戏实例开发集合 之 CompoundBigWatermelon (简单合成一个大西瓜) 休闲小游戏快速实现

一、简单介绍

二、CompoundBigWatermelon (简单合成一个大西瓜) 游戏内容与操作

三、注意事项

四、游戏代码框架

五、知识点

六、游戏效果预览

七、实现步骤

八、工程源码地址

九、延伸扩展


一、简单介绍

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

本节介绍,CompoundBigWatermelon (简单合成一个大西瓜)休闲小游戏快速实现的方法,希望能帮到你,若有不对,请留言。

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

水果的合成线路如下:

山竹 -> 苹果 -> 橙子-> 柠檬-> 猕猴桃-> 番茄-> 水蜜桃-> 菠萝-> 椰子-> 西瓜-> 大西瓜

二、CompoundBigWatermelon (简单合成一个大西瓜) 游戏内容与操作

1、游戏开始,鼠标按下,移动水果,会有瞄准线对准落下方向

2、鼠标松开,水果落下

3、相同2个水果相碰,会触发合成新水果,并增加对应分数

4、水果等级一定高度会触发,警告线

5、水果接近或者超过警告线持续若干秒,则游戏结束

三、注意事项

1、水果的图片的大小直接影响游戏精灵图大小,同一屏幕尺寸下,图片越大,其实合成一个大西瓜的难度越大,可以在游戏配置统一改生成的水果精灵图大小

2、随机生成水果的规则是,随机数是(0,水果路线总数的一半),需要更改,可以在游戏配置中修改

3、两个相碰撞的水果合成规则是:1)相碰撞的水果,在下面的(Y值较小的)触发合成事件;2)如果相碰撞的两个水果同一水平线(Y值相等),则左边的(X值较小的)触发合成事件;3)合成的水果在碰撞点合成,且带有两相撞水果中某个水果的角速度

4、水果的碰撞体大小是默认的,如果觉得碰撞不是很好,可以手动调整一下水果的碰撞体尺寸

5、水果的重力是默认设置,如果想修改不同重力效果,可以手动调整水果的下落重力

6、由于2D 游戏(元素都在同一平面),设置 SpriteRenderer 的 Order in Layer 来控制显示先后,Order in Layer 越大,显示就在前面,所以各个 Order in Layer 定义显示规则为 :水果预制体为 0,BorderLine 边界为 2,WarningLine 为 5,Effect 为 8,AimLine 为 -2

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

四、游戏代码框架

五、知识点

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

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

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

4、简单的对象池管理

5、Rigidbody2D 重力效果,添加 CirecleCollider2D ,进行 碰撞检测

6、简单UGUI的使用

7、Vector3.Lerp 位移向量插值使用,Vector3.Distance 位置距离函数的使用

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

9、Transform.Rotate 旋转使用

10、IEnumerator 协程 , StartCoroutine 开始协程 和 StopAllCoroutines 停止所有协程的使用

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

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

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

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

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

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

17、等等

六、游戏效果预览

七、实现步骤

1、打开 Unity,导入水果、音频的资源

2、因为是 2D 游戏,修改MainCamera 位置为(0,0,-10),Camera 中的 Clear Flag 为 Solid Color ,设置 Background 做为游戏背景颜色,Projection 设置为 Orthographic 正交模式,然后设置屏幕为竖屏 1080x1920 作为游戏基础屏,效果如下

3、把导入进来的图片,全部设置为 Sprite 精灵图

4、把转换为精灵图的水果拖入场景中(系统会自动添加SpriteRenderer 精灵图渲染),然后添加 Rigidbody2D(2D重力) 和 CircleCollider2D(2D圆形碰撞体)

5、给水果的 Rigidbody 2D 添加 FruitPhysicsMaterial2D (2D 物理材质),以增加水果落地的稍稍的回弹效果,如图

6、FruitPhysicsMaterial2D (2D 物理材质) 创建如图,Bounciness 设置为 0.25

 

7、根据上面的方法,把所有水果都做成预制体

8、effect 拖入场景,然后拖回工程文件夹中,也作为预制体

9、把 BorderLine 拖到场景中,并添加一个 2D 碰撞体 (BoxCollider2D),拷贝两份,作为边界,如图 ,BorderLine_Down 的 pos(0,-5,0),BorderLine_Left 的 pos(-2.8,0,0) Rotation(0,0,90),BorderLine_Right 的 pos(2.8,0,0) Rotation(0,0,90)

10、把 WarningLine 拖到场景中,设置 Position(0,3,0)

11、把 WarningLine 拖到场景中,设置 Position(0,0,0)

12、创建一个GameObject 空物体,改名为 SpawnFruitPos ,设置 Position(0,4,0) 刚好在 AimLine 上端点

13、由于2D 游戏(元素都在同一平面),设置SpriteRenderer 的 Order in Layer 来控制显示先后,Order in Layer 越大,显示就在前面,所以各个 Order in Layer 定义显示为 :水果预制体为 0,BorderLine 边界为 2,WarningLine 为 5,Effect 为 8,AimLine 为 -2

14、创建一个 GameObject 空物体,改名为 World,把场景中的所有物体,都作为其子物体

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

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

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

 

18、创建Game Object空物体,改名为 UI ,把 Canvas 相关的都拖到 其下, UI Canvas 效果如图

19、在工程中添加 Fruit 脚本,主要功能是,进行水果类型的标记,以及水果碰撞的监测

20、Fruit 脚本主要函数:Init() 定义水果类型,和统一水果碰撞合成的事件,EnableFruit()/DisableFruit() 是设置该水果是否有重力和碰撞效果,OnCollisionEnter2D() 该水果的碰撞检测,相同水果且不是大西瓜,则触发水果合成委托

       public void Init(FruitSeriesType fruitSeriesType, Action<Collision2D, Fruit> onCompoundAction){DisableFruit();m_FruitSeriesType = fruitSeriesType;m_OnCompoundAction = onCompoundAction;}public void EnableFruit(){Rigidbody2D.bodyType = RigidbodyType2D.Dynamic;CircleCollider2D.enabled = true;}public void DisableFruit(){Rigidbody2D.bodyType = RigidbodyType2D.Static;CircleCollider2D.enabled = false;}public void Fall(){EnableFruit();}public float GetRadius(){return CircleCollider2D.radius;}#region Unity Function/// <summary>/// 碰撞检测函数/// </summary>/// <param name="collision"></param>private void OnCollisionEnter2D(Collision2D collision){// 不是大西瓜,则合成if (this.FruitType != FruitSeriesType.BigWatermelon){// 判断与之相碰的也是水果Fruit otherRuit = collision.gameObject.GetComponent<Fruit>();if (otherRuit != null){// 水果类型相同,才触发合成新瓜if (otherRuit.FruitType == this.FruitType){if (m_OnCompoundAction != null){m_OnCompoundAction.Invoke(collision, this);}}}}}#endregion

21、在工程中添加 FruitManager 脚本,主要功能是:1)水果的预制体加载;2)水果的生成;3)水果未释放前的位置移动;4)相同合成水果时新水果的生成事件;

22、FruitManager 脚本主要函数:LoadFruitsPrefab() 加载水果预制体,UpdateFruitOperation()监控鼠标情况,进行水果移动和释放

     /// <summary>/// /// </summary>void LoadFruitsPrefab() {m_FuritPrefabList.Clear();// FruitSeriesType 枚举的名字和预制体名字一致for (FruitSeriesType i = 0; i < FruitSeriesType.SUM_COUNT; i++){Debug.Log(GetType() + "/LoadFruitsPrefab()/ " + i);string path = ResPathDefine.FRUITS_PREFAB_BASE_PATH + i;GameObject fruit = Resources.Load<GameObject>(path);if (fruit == null){Debug.LogError(GetType()+ "/LoadFruitsPrefab()/fruit is null, path =  "+ path);}else {m_FuritPrefabList.Add(fruit);}}}/// <summary>/// 监控鼠标情况,进行水果移动和释放/// </summary>void UpdateFruitOperation(){if (Input.GetMouseButtonDown(0)){}else if (Input.GetMouseButton(0)){UpdateCurFuritPos();}else if (Input.GetMouseButtonUp(0)){m_IsFalled = true;if (m_CurFruit != null){m_CurFruit.Fall();}if (m_IsCanSpawn == true){m_Mono.StartCoroutine(SpawnRandomFruit(m_SpawnFruitPosTrans.position, m_SpawnFruitPosTrans));}}}

23、FruitManager 脚本主要函数:IEnumerator SpawnRandomFruit(Vector2 pos, Transform parent) 协程释放水果后,随机生成水果(规则时:随机的上限是水果系列的总数的一半Random.Range(0, (int)((int)FruitSeriesType.SUM_COUNT / 2));),SpawnFruit() 真正生成水果的函数,这里没有做对象池的处理,大家其实可以根据需要进行生成水果和释放水果的对象池处理,可以作为性能优化

     /// <summary>/// 写成生成水果/// </summary>/// <param name="pos"></param>/// <param name="parent"></param>/// <returns></returns>IEnumerator SpawnRandomFruit(Vector2 pos, Transform parent){m_IsCanSpawn = false;yield return new WaitForSeconds(GameConfig.FRUIT_SPAWN_INTERVAL_TIME);if (GameManager.Instance.GameOver == false){int random = Random.Range(0, (int)((int)FruitSeriesType.SUM_COUNT / 2));m_CurFruit = SpawnFruit((FruitSeriesType)random, pos, parent);m_IsFalled = false;m_IsCanSpawn = true;}}/// <summary>/// 生成水果(非合成水果)/// </summary>/// <param name="fruitSeriesType"></param>/// <param name="pos"></param>/// <param name="parent"></param>/// <returns></returns>Fruit SpawnFruit(FruitSeriesType fruitSeriesType, Vector2 pos, Transform parent){m_AudioManager.PlaySpawnSound();return SpawnFruit(fruitSeriesType, pos, parent, false);}/// <summary>/// 生成水果(可合成水果)/// </summary>/// <param name="fruitSeriesType"></param>/// <param name="pos"></param>/// <param name="parent"></param>/// <param name="isCompound"></param>/// <returns></returns>Fruit SpawnFruit(FruitSeriesType fruitSeriesType, Vector2 pos, Transform parent, bool isCompound){GameObject go = GameObject.Instantiate(m_FuritPrefabList[(int)fruitSeriesType], parent);Fruit fruit = go.AddComponent<Fruit>();fruit.Init(fruitSeriesType, OnCompoundAction);if (isCompound == true){fruit.EnableFruit();}fruit.transform.position = pos;fruit.transform.localScale *= GameConfig.FRUIT_SCALE;return fruit;}

24、FruitManager 脚本主要函数:UpdateCurFuritPos()鼠标操作时,实时更新对应的当前的水果位置,ClampFruitPos(Vector3 pos)移动水果的时候,水平位置的限制

     /// <summary>/// 鼠标操作时,实时更新对应的当前的水果位置/// </summary>private void UpdateCurFuritPos(){if (m_CurFruit != null && m_IsFalled == false){Vector3 pos = Tools.ScreenPosToWorldPos(m_CurFruit.transform, m_MainCamera, Input.mousePosition);m_CurFruit.transform.position = ClampFruitPos(pos);}}/// <summary>/// 释放水果的时候,水平位置的限制/// </summary>/// <param name="pos"></param>/// <returns>限制后的水果位置</returns>private Vector3 ClampFruitPos(Vector3 pos){if (m_CurFruit != null){if (pos.x - m_CurFruit.GetRadius() < m_FruitXLeftLimitValue){pos.x = m_FruitXLeftLimitValue + m_CurFruit.GetRadius();}if (pos.x + m_CurFruit.GetRadius() > m_FruitXRightLimitValue){pos.x = m_FruitXRightLimitValue - m_CurFruit.GetRadius();}pos.y = m_CurFruit.transform.position.y;}return pos;}

25、FruitManager 脚本主要函数:OnCompoundAction(Collision2D col, Fruit toColFruit)判断合成水果的时候条件进行哪个水果作为事件触发,CompoundHandle(Collision2D col, Fruit toColFruit) 销毁水果(这里可以和生成水果一起做一个对象池处理),合成新水果,,并进行特效、声音和分数的相关处理

     /// <summary>/// 可合成水果的委托/// </summary>/// <param name="col"></param>/// <param name="toColFruit"></param>void OnCompoundAction(Collision2D col, Fruit toColFruit){if (col.transform.position.y < toColFruit.transform.position.y)  // 同一水平位置Y比较难判断,分开判断{CompoundHandle(col, toColFruit);}else if (col.transform.position.y == toColFruit.transform.position.y){if (col.transform.position.x < toColFruit.transform.position.x){CompoundHandle(col, toColFruit);}}}/// <summary>/// 满足合成条件的处理/// </summary>/// <param name="col"></param>/// <param name="toColFruit"></param>void CompoundHandle(Collision2D col, Fruit toColFruit){Debug.Log($"融合 {toColFruit.FruitType.ToString()} ============");int colFruitId = (int)toColFruit.FruitType;FruitSeriesType compoundFruitType = (FruitSeriesType)(colFruitId + 1);SpawnFruit(compoundFruitType,col.contacts[0].point, // 碰撞点m_SpawnFruitPosTrans,true).Rigidbody2D.angularVelocity = toColFruit.Rigidbody2D.angularVelocity; // 附上角速度// 当前是直接销毁,好一点的方式的建立对象池,循环利用GameObject.Destroy(col.gameObject);GameObject.Destroy(toColFruit.gameObject);m_EffectManager.ShowEffect(new Color(Random.Range(0, 1.0f), Random.Range(0, 1.0f), Random.Range(0, 1.0f), 1),col.contacts[0].point);// 碰撞点m_AudioManager.PlayBombSound();m_ScoreManager.Score += colFruitId * GameConfig.COMPOUND_FRUIT_BASE_SCORE;}

26、在工程中添加脚本 Effect ,主要功能是:水果合成的特效动画(这里只做了特效颜色透明度的处理,大家可以根据需要设置大小等的动画变化)

27、Effect脚本主要函数: Show(Color32 color, Action<Effect> showAnimationEndAction)设置特效颜色和特效结束事件委托,EffectAnimation(Color color, Action<Effect> showAnimationEndAction) 协程实现特效动画,并且触发特效结束委托事件

     public void Show(Color32 color, Action<Effect> showAnimationEndAction){StartCoroutine(EffectAnimation(color, showAnimationEndAction));}IEnumerator EffectAnimation(Color color, Action<Effect> showAnimationEndAction){m_ColorValue = 0;color.a = 0;SpriteRenderer.color = color;while (true){// lerp 匀速插值处理m_ColorValue += 1.0f / GameConfig.EFFECT_ANIMATION_SPEED * Time.deltaTime;color.a = Mathf.Lerp(color.a, 1, m_ColorValue);SpriteRenderer.color = color;if ((1 - color.a <= 0.05f)){color.a = 1;SpriteRenderer.color = color;break;}yield return new WaitForEndOfFrame();}m_ColorValue = 0;while (true){// lerp 匀速插值处理m_ColorValue += 1.0f / GameConfig.EFFECT_ANIMATION_SPEED * Time.deltaTime;color.a = Mathf.Lerp(color.a, 0, m_ColorValue);SpriteRenderer.color = color;if ((color.a - 0) <= 0.05f){color.a =0;SpriteRenderer.color = color;break;}yield return new WaitForEndOfFrame();}if (showAnimationEndAction!=null){showAnimationEndAction.Invoke(this);}}

28、在工程中添加 EffectManager 脚本,主要功能是:特效预制体的获取,和特效的显示,这里特效的生成使用了简单的对象池作为处理

29、EffectManager 脚本主要函数:Init() 初始化获取Effect预制体,ShowEffect(Color32 color, Vector3 pos) 设置位置和颜色,显示特效,GetEffect() 使用简单对象池获取特效,OnEffectShowEndAction(Effect effect)特效动画结束回收对象到对象池

       public void Init(Transform worldTrans, Transform uiTrans, params object[] manager){m_EffectPrefab = Resources.Load<GameObject>(ResPathDefine.EFFECT_PREFAB_PATH);if (m_EffectPrefab==null){Debug.LogError(GetType()+ "/Init()/m_EffectPrefab Loaded is null, path = " + ResPathDefine.EFFECT_PREFAB_PATH);}m_IdleEffectQueue = new Queue<Effect>();}public void ShowEffect(Color32 color, Vector3 pos){Effect effect = GetEffect();effect.transform.position = pos;effect.transform.rotation = Quaternion.Euler(Vector3.forward * Random.Range(-180, 180));effect.Show(color, OnEffectShowEndAction);}/// <summary>/// 简单对象池获取特效/// </summary>/// <returns></returns>private Effect GetEffect() {if (m_IdleEffectQueue.Count > 0){Effect effect = m_IdleEffectQueue.Dequeue();effect.gameObject.SetActive(true);return effect;}else {GameObject go = GameObject.Instantiate(m_EffectPrefab);return go.AddComponent<Effect>();}}/// <summary>/// 特效动画结束,回收特效到对象池/// </summary>/// <param name="effect"></param>private void OnEffectShowEndAction(Effect effect) {effect.gameObject.SetActive(false);m_IdleEffectQueue.Enqueue(effect);}

30、这里简单说一下 IManager 接口类,是为了统一各个管理类中函数的定义规范

public interface IManager {// 初始化void Init(Transform worldTrans, Transform uiTrans, params object[] manager);// 帧更新void Update();// 销毁时调用(主要是释放数据等使用)void Destroy();}

31、在工程中添加 AudioManager 脚本,主要功能是:加载音频,添加AudioSource(播放声音必须的),和播放对应音效

32、AudioManager 脚本主要函数:Init() 加载需要的音频,添加AudioSource ,PlaySpawnSound()/PlayBombSound() 播放水果生成/合成音效

        public void Init(Transform worldTrans, Transform uiTrans, params object[] manager){m_SpawnSound = Resources.Load<AudioClip>(ResPathDefine.AUDIO_SPAWN_PATH);m_BombSound = Resources.Load<AudioClip>(ResPathDefine.AUDIO_BOMB_PATH);GameObject audiosSourceGO = worldTrans.Find(GameObjectPathInSceneDefine.AUDIO_SOURCE_PATH).gameObject;if (audiosSourceGO == null){Debug.LogError(GetType() + "/AudioSource()/ audiosSourceGO is null , path = " + GameObjectPathInSceneDefine.AUDIO_SOURCE_PATH);}else{m_AudioSource = audiosSourceGO.AddComponent<AudioSource>();}}public void PlaySpawnSound(){m_AudioSource.PlayOneShot(m_SpawnSound);}public void PlayBombSound(){m_AudioSource.PlayOneShot(m_BombSound);}

33、在工程中添加 LineManager脚本,主要功能是,进行边界的左右适应屏幕,瞄准线的显示隐藏、位置更新,和游戏结束线的显示和隐藏

34、LineManager脚本主要函数:BorderLineSimpleAdaptScreen()简单边界适配屏幕,UpdateWarninglineHandle()警告线的显示隐藏处理,UpdateAimlineHandle()瞄准线的显示隐藏,移动位置处理

        /// <summary>/// 简单边界适配屏幕/// </summary>void BorderLineSimpleAdaptScreen(){// 左边缘屏幕适配float left_X = Tools.ScreenPosToWorldPos(m_BorderLine_Left, m_MainCamera, Vector2.zero).x; m_BorderLine_Left.position = new Vector3(left_X, m_BorderLine_Left.position.y, m_BorderLine_Left.position.z);// 右边缘屏幕适配float Right_X = Tools.ScreenPosToWorldPos(m_BorderLine_Right, m_MainCamera, Vector2.right * Screen.width).x;m_BorderLine_Right.position = new Vector3(Right_X, m_BorderLine_Right.position.y, m_BorderLine_Right.position.z);}/// <summary>/// 警告线的显示隐藏处理/// </summary>void UpdateWarninglineHandle() {m_Warningline.gameObject.SetActive(GameManager.Instance.GameOverWarning);}/// <summary>/// 瞄准线的显示隐藏,移动处理/// </summary>void UpdateAimlineHandle() {if (Input.GetMouseButtonDown(0)){if (m_FruitManager != null && m_FruitManager.CurFruit != null){m_Aimline.gameObject.SetActive(true);}}else if (Input.GetMouseButton(0)){UpdateAimlinePos();}else if (Input.GetMouseButtonUp(0)){m_Aimline.gameObject.SetActive(false);}}/// <summary>/// 瞄准线的移动处理/// </summary>void UpdateAimlinePos() {if (m_FruitManager!=null && m_FruitManager.CurFruit!=null){m_Aimline.transform.position = new Vector3(m_FruitManager.CurFruit.transform.position.x,m_Aimline.transform.position.y,m_Aimline.transform.position.z);}}

35、在工程中添加 ScoreManager 脚本,主要功能是分数的增加统计,和分数变化的事件处理

36、在工程中添加 UIManager 脚本,主要的功能是:实时显示分数,游戏结束的时候显示结束面板,并且添加重新开始游戏的按钮事件,重新加载场景,重新开始游戏

37、UIManager 脚本主要函数:OnGameOver() 游戏结束时,显示结束面板,OnScroeValueChanged(int score) 更新游戏得分,OnRestartButton()游戏重新开始

        public void OnGameOver() {m_GameOverImageGo.SetActive(true);}private void OnScroeValueChanged(int score) {m_ScoreText.text = score.ToString();}private void OnRestartButton() {SceneManager.LoadScene(SceneManager.GetActiveScene().name);}

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

39、GameManager 脚本主要函数:Awake(MonoBehaviour mono)/Start()/Init()/Update()/Destroy() 对应各个Manager 的 new 对象,以及初始化Init,Update 、和Destroy,FindGameObjectInScene()获取场景中相关游戏物体或者 UI

        public void Awake(MonoBehaviour mono) {m_Mono = mono;m_FruitManager = new FruitManager();m_LineManager = new LineManager();m_EffectManager = new EffectManager();m_AudioManager = new AudioManager();m_ScoreManager = new ScoreManager();m_UIManager = new UIManager();}public void Start(){FindGameObjectInScene();Init(m_WorldTrans, m_UITrans,this);}public void Init(Transform worldTrans, Transform uiTrans, params object[] manager){m_IsGameOverWarning = false;m_IsGameOVer = false;m_ScoreManager.Init(worldTrans, uiTrans);m_EffectManager.Init(worldTrans, uiTrans);m_AudioManager.Init(worldTrans, uiTrans);m_FruitManager.Init(worldTrans, uiTrans, m_Mono, m_EffectManager,m_AudioManager, m_ScoreManager);m_LineManager.Init(worldTrans, uiTrans, m_FruitManager);            m_UIManager.Init(worldTrans, uiTrans, m_ScoreManager);}public void Update(){if (m_IsGameOVer==true){return;}m_FruitManager.Update();m_LineManager.Update();m_EffectManager.Update();m_AudioManager.Update();m_ScoreManager.Update();m_UIManager.Update();UpdateJudgeGaveOverAndWarning();}public void Destroy(){m_FruitManager.Destroy();m_LineManager.Destroy();m_EffectManager.Destroy();m_AudioManager.Destroy();m_ScoreManager.Destroy();m_UIManager.Destroy();m_WorldTrans = null;m_UITrans = null;m_Warningline = null;m_SpawnFruitPosTrans = null;m_IsGameOverWarning = false;m_IsGameOVer = false;}void FindGameObjectInScene() {m_WorldTrans = GameObject.Find(GameObjectPathInSceneDefine.WORLD_PATH).transform;m_UITrans = GameObject.Find(GameObjectPathInSceneDefine.UI_PATH).transform;m_Warningline = m_WorldTrans.Find(GameObjectPathInSceneDefine.WARNING_LINE_PATH);m_SpawnFruitPosTrans = m_WorldTrans.Find(GameObjectPathInSceneDefine.SPAWN_FRUIT_POS_TRANS_PATH);}

40、GameManager 脚本主要函数:UpdateJudgeGaveOverAndWarning()/IsGameOverWarning()/IsJudgeGameOver() 判断游戏是否发出警告,或者游戏结束,OnGameOver() 游戏结束事件

        void UpdateJudgeGaveOverAndWarning() {if (IsGameOverWarning() == true){m_WarningTimer += Time.deltaTime;if (m_WarningTimer >= GameConfig.JUDGE_GAME_OVER_WARNING_TIME_LENGHT){m_Warningline.gameObject.SetActive(true);}if (IsJudgeGameOver() == true){m_OverTimer += Time.deltaTime;if (m_OverTimer >= GameConfig.JUDGE_GAME_OVER_TIME_LENGHT){m_IsGameOVer = true;if (m_FruitManager.CurFruit != null){m_FruitManager.CurFruit.DisableFruit();}OnGameOver();}}else{m_OverTimer = 0;}}else{m_Warningline.gameObject.SetActive(false);m_OverTimer = 0;m_WarningTimer = 0;}}bool IsGameOverWarning(){Fruit fruit;foreach (Transform item in m_SpawnFruitPosTrans){if (item.gameObject.activeSelf == true){fruit = item.GetComponent<Fruit>();if (fruit != null){if (fruit.CircleCollider2D.enabled == true && fruit != m_FruitManager.CurFruit){if (m_Warningline.transform.position.y - (fruit.transform.position.y + fruit.CircleCollider2D.radius) < GameConfig.GAME_OVER_WARNING_LINE_DISTANCE){return true;}}}}}return false;}bool IsJudgeGameOver(){Fruit fruit;foreach (Transform item in m_SpawnFruitPosTrans){if (item.gameObject.activeSelf == true){fruit = item.GetComponent<Fruit>();if (fruit != null){if (fruit.CircleCollider2D.enabled == true){if (m_Warningline.transform.position.y - (fruit.transform.position.y + fruit.CircleCollider2D.radius) <= 0){return true;}}}}}return false;}void OnGameOver() {m_FruitManager.OnGameOver();m_UIManager.OnGameOver();}

41、Tools 工具类,把屏幕坐标转为世界坐标

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

42、Enum 管理各种枚举,这里主要时水果类型的枚举

 /// <summary>/// 水果类型/// 注意:其中顺序是合成的顺序/// </summary>public enum FruitSeriesType{Mangosteen = 0,     // 山竹Apple = 1,            // 苹果Orange = 2,           // 桔子Lemon = 3,            // 柠檬Kiwi = 4,           // 猕猴桃Tomato = 5,            // 西红柿Peach = 6,           // 桃子Pineapple = 7,        // 菠萝Coco = 8,           // 椰子Watermelon = 9,     // 西瓜BigWatermelon = 10,   // 大西瓜SUM_COUNT = 11,      //总数(计数使用)}

43、GameConfig游戏配置类,游戏不同配置,直接影响游戏的不同体验

 public class GameConfig {// 生成水果的比例(用来控制游戏中生成水果的整体比例)public const float FRUIT_SCALE = 0.80f;// 每次生成水果的间隔时间public const float FRUIT_SPAWN_INTERVAL_TIME = 0.5f;// 水果触及警告线持续多少秒,算游戏结束public const float JUDGE_GAME_OVER_TIME_LENGHT = 3;// 水果满足条件差不多到警告线前,持续多少秒,发出警告信息public const float JUDGE_GAME_OVER_WARNING_TIME_LENGHT = 0.5f;// 某个水果距离警告线多远,触发警告条件public const float GAME_OVER_WARNING_LINE_DISTANCE = 1.5f;// 特效的动画速度public const float EFFECT_ANIMATION_SPEED = 5f;// 水果合成的基础分 (实际计算规则是 : 水果的类型 * 该 base score)public const int COMPOUND_FRUIT_BASE_SCORE = 10;}

44、GameObjectPathInSceneDefine 场景中游戏物体路径定义类,统一管理景中游戏物体路径

 /// <summary>/// 场景中游戏物体路径定义类,统一管理景中游戏物体路径/// </summary>public class GameObjectPathInSceneDefine {public const string WORLD_PATH = "World";public const string UI_PATH = "UI";public const string UI_SCORE_TEXT_PATH = "Canvas/ScoreText";public const string UI_GAME_OVER_IMAGE_PATH = "Canvas/GameOverImage";public const string UI_RESTART_GAME_BUTTON_PATH = "Canvas/GameOverImage/RestartGameButton";public const string BORDERLINE_DOWN_PATH = "BorderLine_Down";public const string BORDERLINE_LEFT_PATH = "BorderLine_Left";public const string BORDERLINE_RIGHT_PATH = "BorderLine_Right";public const string AIM_LINE_PATH = "AimLine";public const string WARNING_LINE_PATH = "Warningline";public const string SPAWN_FRUIT_POS_TRANS_PATH = "SpawnFruitPos";public const string Main_Camera_TRANS_PATH = "Main Camera";public const string AUDIO_SOURCE_PATH = "AudioSource";}

45、ResPathDefine 预制体路径定义类,统一管理预制体路径

 /// <summary>/// 预制体路径定义类,统一管理预制体路径/// </summary>public class ResPathDefine {// 水果预制体文件夹路径public const string FRUITS_PREFAB_BASE_PATH = "Prefabs/Fruits/";public const string EFFECT_PREFAB_PATH = "Prefabs/Effect";public const string AUDIO_BOMB_PATH = "Audios/bomb";public const string AUDIO_SPAWN_PATH = "Audios/spawn";}

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

    /// <summary>/// 整个游戏入口/// </summary>public class GameStart : MonoBehaviour{private void Awake(){GameManager.Instance.Awake(this);}// Start is called before the first frame updatevoid Start(){GameManager.Instance.Start();}// Update is called once per framevoid Update(){GameManager.Instance.Update();}private void OnDestroy(){GameManager.Instance.Destroy();}

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

48、运行场景,就会自动随机生成水果,并更新分数

八、工程源码地址

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

的 MGP_004CompoundBigWatermelon 工程

九、延伸扩展

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

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

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

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

4、Effect 可以设置一个World 游戏父物体,便于管理,游戏场景显得不是那么乱

5、可以重构水果生成,水果生成和销毁没有进行对象池管理,这里可以做性能优化;

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

7、这里的特效Effect 颜色是随机的,可以对应添加合成水果颜色更新Effect 颜色和大小,或者设置不同特效Effect;

8、游戏判断结束的条件,可能游戏存在bug,大家实际使用中,可以优化一下有些结束条件的判断

9、等等

Unity 游戏实例开发集合 之 CompoundBigWatermelon (简单合成一个大西瓜) 休闲小游戏快速实现相关推荐

  1. Unity 游戏实例开发集合 之 Car Racing 2D (2D赛车) 休闲小游戏快速实现

    Unity 游戏实例开发集合 之 Car Racing 2D (2D赛车) 休闲小游戏快速实现 目录 Unity 游戏实例开发集合 之 Car Racing 2D (2D赛车) 休闲小游戏快速实现 一 ...

  2. Unity 游戏实例开发集合 之 FlyPin (见缝插针) 休闲小游戏快速实现

    Unity 游戏实例开发集合 之 FlyPin (见缝插针) 休闲小游戏快速实现 目录 Unity 游戏实例开发集合 之 FlyPin (见缝插针) 休闲小游戏快速实现 一.简单介绍 二.FlyPin ...

  3. Unity 游戏实例开发集合 之 CutFruit (切水果(水果忍者)) 休闲小游戏快速实现

    Unity 游戏实例开发集合 之 CutFruit (切水果(水果忍者)) 休闲小游戏快速实现 目录 Unity 游戏实例开发集合 之 CutFruit (切水果(水果忍者)) 休闲小游戏快速实现 一 ...

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

    Unity 游戏实例开发集合 之 Circus (马戏团) 休闲小游戏快速实现 目录 Unity 游戏实例开发集合 之 Circus (马戏团) 休闲小游戏快速实现 一.简单介绍 二.Circus ( ...

  5. Unity 游戏实例开发集合 之 打砖块 休闲小游戏快速实现

    Unity 游戏实例开发集合 之 打砖块 休闲小游戏快速实现 目录 Unity 游戏实例开发集合 之 打砖块 休闲小游戏快速实现 一.简单介绍 二.打砖块游戏内容与操作 三.游戏代码框架 四.知识点 ...

  6. python游戏后端开发_利用python如何实现猫捉老鼠小游戏

    这篇文章我们来讲一下在网站建设中,利用python如何实现猫捉老鼠小游戏.本文对大家进行网站开发设计工作或者学习都有一定帮助,下面让我们进入正文. python实现猫捉老鼠小游戏 首界面 开始游戏界面 ...

  7. 【Python游戏】用Python 和 Pyglet 编写一个我的世界小游戏 | 附源码

    相关文件 想学Python的小伙伴可以关注小编的公众号[Python日志] 有很多的资源可以白嫖的哈,不定时会更新一下Python的小知识的哈!! 需要源码的小伙伴可以在公众号回复我的世界 Pytho ...

  8. 【Pygame小游戏】一发超人:弓箭手佛系射鸟休闲小游戏,你能射中几只?(源码白嫖)

    前言 嘿,有没有想我? 栗子驾着七彩祥云来给大家敲代码啦! 所有文章完整的素材+源码都在

  9. 游戏服务器开发丨采用skynet手撕万人同时在线游戏丨游戏客户端开发

    用skynet手撕一个万人同时在线游戏 1. 多核并发编程 2. actor详解 3. 游戏实现原理 [技术分享篇]游戏服务器开发丨采用skynet手撕万人同时在线游戏丨游戏客户端开发 更多精彩内容包 ...

最新文章

  1. 适配iOS 13 tabbar 标题字体不显示以及返回变蓝色的为问题
  2. 基于JAVA+SpringMVC+MYSQL的火车票订票系统
  3. 新建word 无法切换输入法_WORD系列-1认识与保存
  4. linux清除log日志,linux清除log日志
  5. TKDE2022 | 最新深度学习推荐系统综述:从协同过滤到信息增强的推荐系统
  6. 错误摘要 HTTP 错误 403.14 - Forbidden Web 服务器被配置为不列出此目录的内容。
  7. 嵌入式linux实验一vim的使用,嵌入式Linux C语言开发工具—vi/vim实训操作
  8. Windows Azure 云服务角色架构
  9. VB 2010 (53)Command对象
  10. 金庸群侠传5 自动化脚本 绝情谷大厅开宝箱按键游戏
  11. error C2065: ‘_beginthread‘ : undeclared identifier
  12. 科隆国际游戏展:戴尔与ALIENWARE展示创新电竞产品
  13. ocx控件查看_控制HTML帮助查看器OCX控件
  14. 主板南北桥芯片都起什么作用
  15. 翠竹林 Opencv+C++之人脸识别
  16. Unity 粒子制作简单飞舞纸片特效
  17. 几个在线文档接口生成工具
  18. rdms系统_什么是关系数据库管理系统(RDMS)?
  19. 计算机工程怎么评,美国电气与计算机工程专业怎么样?评价如何
  20. 全球最易受黑客攻击的国家:中国排第五

热门文章

  1. windows下nslookup命令
  2. 华为p10关闭更新_华为P10怎么取消系统更新提醒
  3. SQLSERVER 2000 以及SQL Server 2005的版本号
  4. 使用PyMOL绘制蛋白与配体分子结合模式图
  5. 彻底理解——指针常量和常量指针、指向常量的常指针
  6. 某人写的openCV学习笔记_拔剑-浆糊的传说_新浪博客
  7. 数字图像处理(1)-采样,量化,空间分辨率,灰度级分辨率
  8. 下拉列表(select标签)
  9. 树莓派摄像头检测运动物体
  10. saltstack配置管理和数据系统