从零开始制作基于Unity引擎的宝石消消乐(三)
前言
前兩篇把消消樂的設計以及基本操作的方法都講了,這章開始講消消樂最核心的部分。
生成
首先,先在Hierarchy中制作好600600像素的游戲面板作為容器存放Jewel(每個Jewel大小為100100像素),這樣就的到得到一個6*6可以存放36個Jewel的面板
 接著是游戲生成的制作方法。
 在GameManager中有一個Sprite數組用于保存Jewel的Sprite(通過獲取Jewel的形狀通過Sprite改變)。
然后在Start中通過動態(tài)加載來獲取所有的JewelSprite,以及找到在Hierarchy中的游戲面板gamePlayPanel(因為Jewel要放在里邊)
jewelSprites = Resources.LoadAll<Sprite>("Graphics/Jewels"); gamePlayPanel = GameObject.Find("/UICanvas/GamePlay/GamePlayPanel");得到了JewelSprites之后,可以開始寫生成的方法InitializedGame()。
 其實很容易就能想到根據游戲面板的rowSize和colSize可以直接生成36個Jewel,但是要有一個二維數組來保存這些Jewel,這樣就容易得到每個Jewel在游戲面板的位置(可以用**GetJewelPosition()**得到)。
 那么具體怎么生成的呢?
 首先,每一個Jewel的Sprite都要是隨機的,可以通過JewelSprites[Random.Range()]來得到隨機的Sprite并賦值給Jewel中的JewelPicture。游戲本身的設計是開局生成一個沒有三連以及三連以上的Jewel,所以在生成里需要做一些操作來保證生成的是一個沒有以上這種情況的開局。這樣的話每生成一個Jewel就需要向四周圍延申去尋找是否有相同的Jewel了。
 
 以下是具體的方法
具體的思路就是找以前生成過Jewel進行匹配,看看該位置的四周是否有相同的Jewel,如果有相同的情況,就把該Sprite從數組中刪除(這里聲明了一個局部變量remainIndex的數組來保存JewelSprites的內容)。這樣實例化Jewel的時候就不會遇到三連重復的Jewel了。
 
如上圖所示,在游戲面板GamePlayPanel外生成Jewel,由于有mask組件的遮罩,所以生成的時候是看不見的,再把生成的Jewel通過DOTween的DOLocalMove移動到合適的位置,填充整個GamePlayPanel。
jewelPrefab.transform.Find("JewelPicture").GetComponent<Image>().sprite = jewelSprites[remainIndex[UnityEngine.Random.Range(0, remainIndex.Count)] - 1]; GameObject itemObject = Instantiate<GameObject>(jewelPrefab, gamePlayPanel.transform, false); itemObject.GetComponent<RectTransform>().localPosition = new Vector2(-250f + j * xOffset, 250f + (i-6) * yOffset); itemObject.GetComponent<RectTransform>().DOLocalMove(new Vector2(-250f + j * xOffset, 250f + i * yOffset),1.0f); jewelObjects[i, j] = itemObject;在實例化的同時也要記著把每一個Jewel都保存到JewelObjects中。
交換
交換的方法其實在上一篇講JewelManager的時候已經講過了,就是兩個Jewel,調用Move()的方法,互相移動到對方的位置。
匹配
現在介紹匹配的方法MatchJewel(),具體思路是先得到當前Jewel的位置,接著通過上、下、左、右四個方向搜索JewelObjects[,](上面提到過的方便用于保存Jewel的位置),查看是否有與當前位置的Jewel匹配的Jewel。如果有則橫向的保存到matchColList,縱向的則保存到matchRowList中。如果有消除則該方法返回true。
private bool MatchJewel(GameObject obj){Vector3 jewelPosition = GetJewelPosition(obj);int x = (int)jewelPosition.x;int y = (int)jewelPosition.y;List<GameObject> matchRowList = new List<GameObject>();List<GameObject> matchColList = new List<GameObject>();matchRowList.Add(obj.transform.Find("JewelPicture").gameObject);#region 縱向匹配for (int i = x + 1; i <rowSize; i++){if (i < rowSize && Equals(obj.transform.Find("JewelPicture").gameObject.GetComponent<Image>().sprite.name, jewelObjects[i, y].transform.Find("JewelPicture").gameObject.GetComponent<Image>().sprite.name)){matchRowList.Add(jewelObjects[i, y].transform.Find("JewelPicture").gameObject);}elsebreak;}for (int i = x - 1; i >= 0; i--){if (i >= 0 && Equals(obj.transform.Find("JewelPicture").gameObject.GetComponent<Image>().sprite.name, jewelObjects[i, y].transform.Find("JewelPicture").gameObject.GetComponent<Image>().sprite.name)){matchRowList.Add(jewelObjects[i, y].transform.Find("JewelPicture").gameObject);}elsebreak;}#endregionmatchColList.Add(obj.transform.Find("JewelPicture").gameObject);#region 橫向匹配for (int i = y - 1; i >=0; i--){if (i >= 0 && Equals(obj.transform.Find("JewelPicture").gameObject.GetComponent<Image>().sprite.name, jewelObjects[x, i].transform.Find("JewelPicture").gameObject.GetComponent<Image>().sprite.name)){matchColList.Add(jewelObjects[x, i].transform.Find("JewelPicture").gameObject);}elsebreak;}for (int i = y + 1; i <colSize; i++){if (i < colSize && Equals(obj.transform.Find("JewelPicture").gameObject.GetComponent<Image>().sprite.name, jewelObjects[x, i].transform.Find("JewelPicture").gameObject.GetComponent<Image>().sprite.name)){matchColList.Add(jewelObjects[x, i].transform.Find("JewelPicture").gameObject);}elsebreak;}#endregion接著判斷這兩個數組是否大于等于3,如果符合條件則把這些數組中的對象添加到needRemoveJewels中,等待下一步消除的操作。判斷這里有三種情況,一種是橫向連消,一種是縱向連消,還有一種是特殊情況,就是橫向縱向都有消除的情況。
//1.橫向連消if (matchColList.Count >= 3 && matchRowList.Count < 3){for (int i = 0; i < matchColList.Count; i++){needRemoveJewels.Add(matchColList[i]);}//播放爆炸的聲音AudioManager.Instance.PlayAudio("Audio/boom");return true;}//2.縱向連消else if (matchRowList.Count >= 3 && matchColList.Count < 3){for (int i = 0; i < matchRowList.Count; i++){needRemoveJewels.Add(matchRowList[i]);}//播放爆炸的聲音AudioManager.Instance.PlayAudio("Audio/boom");return true;}//3.特殊情況else if (matchColList.Count >= 3 && matchRowList.Count >= 3){matchRowList.RemoveAt(0);for (int i = 0; i < matchRowList.Count; i++){needRemoveJewels.Add(matchRowList[i]);}for (int i = 0; i < matchColList.Count; i++){needRemoveJewels.Add(matchColList[i]);}//播放爆炸的聲音AudioManager.Instance.PlayAudio("Audio/boom");return true;}消除
消除方法RemoveJewel() 是消除從匹配方法得到得needRemoveJewel的數組。
private bool RemoveJewel(){bool needRefill = false;for (int i = 0; i < needRemoveJewels.Count; i++){if (needRemoveJewels[i]!= null){needRemoveJewels[i].GetComponent<JewelPicture>().Fade();needRefill = true;}} JewelsManager.Instance.ResetAllJewelSelected();needRemoveJewels.Clear();isRemove = true;return needRefill;}這里的Fade()方法是在JewelPicture組件中,JewelPicture掛載在Jewel的子對象JewelPicture,因為如果通過Jewel來制作消除動畫,會導致動畫混亂,因為在兩者交換的同時播放了動畫,會出現消除動畫播放錯誤的bug,因此才把消除動畫的方法放在JewelPicture中。這里也使用了協程的方法,因為要控制動畫播放的時間制作出一個間隔。
 JewelPciture.cs
再填充
當Jewel消除了以后,游戲面板就會出現空缺(其實就是Destroy了Jewel的子對象JewelPicture),這個時候就需要把當前格子上面的Jewel的子對象JewelPicture來填充到當前的Jewel中。具體的做法是該Jewel空格子往上拿Jewel的JewelPicture,就是把別人的變成自己的。簡單的說就是我拿你的JewelPicture,你拿上面的JewelPicture,他拿更上面的JewelPicture變?yōu)樽约旱腏ewelPicture。
 
 如上圖所示,這樣操作就相當于上面的Jewel往下掉落下來,填充到空的格子。那么把消除后的空格子填充了以后,被拿走JewelPicture的空格子怎么辦呢?這個時候就需要在空格子的最上面,GamePlayPanel外的位置重新生成JewelPicture并且填充到空的格子,就像InitializedGame()一樣,但是此時不用考慮是否重復的問題,盡管隨機生成就好了。
這里又!又!又!!!用到協程了!!!再解釋一下,這個協程是為了使游戲更流暢,所以waitforsecond是等待了一個動畫時間,其實就是消除動畫播放完以后再執(zhí)行填充的操作嘛。
匹配規(guī)則
接下來講匹配規(guī)則MatchRule(),這里是判斷交換的兩個Jewel是否有消除的情況,如果兩個Jewel都沒有消除的情況則調用Reset的方法,恢復兩個Jewel的位置,如果有消除的情況再調用Remove的方法進行消除的操作,消除完后再啟用協程填充GamePlayPanel。
//判斷匹配的規(guī)則public void MatchRule(){GameObject lastSelected = JewelsManager.Instance.lastSelected;GameObject currentSeleted = JewelsManager.Instance.currentSeleted;bool lastMatch = MatchJewel(lastSelected);bool currentMatch = MatchJewel(currentSeleted);if (!lastMatch&&!currentMatch){JewelsManager.Instance.ResetOriginJewel();}else if( lastMatch || currentMatch){RemoveJewel();StartCoroutine(FillJewels());}}全盤匹配
最后再來講全盤匹配的問題,因為當再次填充以后,有可能會出現三連以及三連以上的情況,所以這個時候需要遍歷JewelObjects[,]來查看是否有匹配的,是否需要消除。如果沒有,不需要的話,那么消消樂的一次移動流程就已經完成啦。如果有匹配的,需要消除的,那就把該對象扔到needRemoveJewels的數組,再調用RemoveJewel把它刪掉,接著再填充,再全盤匹配,再消除,再填充,再全盤匹配…直到沒有匹配的情況出現為止。
private void ReMatchGameBorad(){for (int i = 0; i < rowSize; i++){for (int j = 0; j < colSize; j++){if (jewelObjects[i, j].transform.Find("JewelPicture").gameObject){MatchJewel(jewelObjects[i, j]);}}}//當needRemoveJewels里面有元素才調用RemoveJewel的方法if(needRemoveJewels.Count>0){RemoveJewel();StartCoroutine(FillJewels());}}這里有個另外一個思路,因為在再填充的時候我們是需要移動Jewel的中的JewelPicture,這樣我們可以得到操作過的Jewel,把它們保存到另外一個數組再進行全盤匹配,會比這個遍歷整個JewelObjects省時省力很多。
總結
現在把消消樂的基礎內容都講完啦,做消消樂真的很有樂趣的,特別是每一個模塊做出來就會很有成就感。其實做休閑游戲會比做rpg復雜一些,因為很多邏輯上的問題要處理。往后我會在消消樂中添加一些rpg的元素,制作成一個休閑益智的角色扮演闖關游戲。整個完整項目我已經放到github,有需要的朋友可以down下來,或者有什么建議,游戲設計上的改進,麻煩提出來,因為我太想進步了。
總結
以上是生活随笔為你收集整理的从零开始制作基于Unity引擎的宝石消消乐(三)的全部內容,希望文章能夠幫你解決所遇到的問題。
                            
                        - 上一篇: cxf-spring-pratice-s
 - 下一篇: 浙大计算机学院培养方案,浙大计算机专业培