Unity 游戏实例开发集合 之 CompoundBigWatermelon (简单合成一个大西瓜) 休闲小游戏快速实现
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 (简单合成一个大西瓜) 休闲小游戏快速实现相关推荐
- Unity 游戏实例开发集合 之 Car Racing 2D (2D赛车) 休闲小游戏快速实现
Unity 游戏实例开发集合 之 Car Racing 2D (2D赛车) 休闲小游戏快速实现 目录 Unity 游戏实例开发集合 之 Car Racing 2D (2D赛车) 休闲小游戏快速实现 一 ...
- Unity 游戏实例开发集合 之 FlyPin (见缝插针) 休闲小游戏快速实现
Unity 游戏实例开发集合 之 FlyPin (见缝插针) 休闲小游戏快速实现 目录 Unity 游戏实例开发集合 之 FlyPin (见缝插针) 休闲小游戏快速实现 一.简单介绍 二.FlyPin ...
- Unity 游戏实例开发集合 之 CutFruit (切水果(水果忍者)) 休闲小游戏快速实现
Unity 游戏实例开发集合 之 CutFruit (切水果(水果忍者)) 休闲小游戏快速实现 目录 Unity 游戏实例开发集合 之 CutFruit (切水果(水果忍者)) 休闲小游戏快速实现 一 ...
- Unity 游戏实例开发集合 之 Circus (马戏团) 休闲小游戏快速实现
Unity 游戏实例开发集合 之 Circus (马戏团) 休闲小游戏快速实现 目录 Unity 游戏实例开发集合 之 Circus (马戏团) 休闲小游戏快速实现 一.简单介绍 二.Circus ( ...
- Unity 游戏实例开发集合 之 打砖块 休闲小游戏快速实现
Unity 游戏实例开发集合 之 打砖块 休闲小游戏快速实现 目录 Unity 游戏实例开发集合 之 打砖块 休闲小游戏快速实现 一.简单介绍 二.打砖块游戏内容与操作 三.游戏代码框架 四.知识点 ...
- python游戏后端开发_利用python如何实现猫捉老鼠小游戏
这篇文章我们来讲一下在网站建设中,利用python如何实现猫捉老鼠小游戏.本文对大家进行网站开发设计工作或者学习都有一定帮助,下面让我们进入正文. python实现猫捉老鼠小游戏 首界面 开始游戏界面 ...
- 【Python游戏】用Python 和 Pyglet 编写一个我的世界小游戏 | 附源码
相关文件 想学Python的小伙伴可以关注小编的公众号[Python日志] 有很多的资源可以白嫖的哈,不定时会更新一下Python的小知识的哈!! 需要源码的小伙伴可以在公众号回复我的世界 Pytho ...
- 【Pygame小游戏】一发超人:弓箭手佛系射鸟休闲小游戏,你能射中几只?(源码白嫖)
前言 嘿,有没有想我? 栗子驾着七彩祥云来给大家敲代码啦! 所有文章完整的素材+源码都在
- 游戏服务器开发丨采用skynet手撕万人同时在线游戏丨游戏客户端开发
用skynet手撕一个万人同时在线游戏 1. 多核并发编程 2. actor详解 3. 游戏实现原理 [技术分享篇]游戏服务器开发丨采用skynet手撕万人同时在线游戏丨游戏客户端开发 更多精彩内容包 ...
最新文章
- 适配iOS 13 tabbar 标题字体不显示以及返回变蓝色的为问题
- 基于JAVA+SpringMVC+MYSQL的火车票订票系统
- 新建word 无法切换输入法_WORD系列-1认识与保存
- linux清除log日志,linux清除log日志
- TKDE2022 | 最新深度学习推荐系统综述:从协同过滤到信息增强的推荐系统
- 错误摘要 HTTP 错误 403.14 - Forbidden Web 服务器被配置为不列出此目录的内容。
- 嵌入式linux实验一vim的使用,嵌入式Linux C语言开发工具—vi/vim实训操作
- Windows Azure 云服务角色架构
- VB 2010 (53)Command对象
- 金庸群侠传5 自动化脚本 绝情谷大厅开宝箱按键游戏
- error C2065: ‘_beginthread‘ : undeclared identifier
- 科隆国际游戏展:戴尔与ALIENWARE展示创新电竞产品
- ocx控件查看_控制HTML帮助查看器OCX控件
- 主板南北桥芯片都起什么作用
- 翠竹林 Opencv+C++之人脸识别
- Unity 粒子制作简单飞舞纸片特效
- 几个在线文档接口生成工具
- rdms系统_什么是关系数据库管理系统(RDMS)?
- 计算机工程怎么评,美国电气与计算机工程专业怎么样?评价如何
- 全球最易受黑客攻击的国家:中国排第五