PHP群:95885625 Hbuilder+MUI群:81989597 站长QQ:634381967
    您现在的位置: 首页 > 开发编程 > Unity3D教程 > 正文

    Unity三消算法

    作者:张志勇来源:转载浏览:时间:2020-09-30 00:07:50我要评论
    导读:消除算法图文详解三消算法首要实现的就是找到所有三个或三个以上的可消除对象,但直接找到这些对象是不太现实的,所以我们要将需求拆分。可...
    • 消除算法图文详解
      • 三消算法首要实现的就是找到所有三个或三个以上的可消除对象,但直接找到这些对象是不太现实的,所以我们要将需求拆分。可不可以先获取所有图案相连的对象,进而在获取三消对象,这个算法也是众多三消游戏的一致实现。

        获取图案相同的所有相连对象
    /// <summary> /// 填充相同Item列表 /// </summary> public void FillSameItemsList(Item current) { //如果已存在,跳过 if (sameItemsList.Contains (current)) return; //添加到列表 sameItemsList.Add (current); //上下左右的Item Item[] tempItemList = new Item[]{ GetUpItem(current),GetDownItem(current), GetLeftItem(current),GetRightItem(current)}; for (int i = 0; i < tempItemList.Length; i++) { //如果Item不合法,跳过 if (tempItemList [i] == null) continue; if (current.currentSpr == tempItemList [i].currentSpr) { FillSameItemsList (tempItemList[i]); } } }
    • 获取图案相同的对象,一定要以一个对象为基准,这样才能够知道以谁为中心,以这个中心为核心横向及纵向的检测,检测到三个及以上的对象,那说明是可以消除的对象。


      以检测点为中心横向纵向检测
      /// <summary> /// 填充待消除列表 /// </summary> /// <param name="current">Current.</param> public void FillBoomList(Item current) { //计数器 int rowCount = 0; int columnCount = 0; //临时列表 List<Item> rowTempList = new List<Item> (); List<Item> columnTempList = new List<Item> (); ///横向纵向检测 foreach (var item in sameItemsList) { //如果在同一行 if (item.itemRow == current.itemRow) { //判断该点与Curren中间有无间隙 bool rowCanBoom = CheckItemsInterval(true,current,item); if (rowCanBoom) { //计数 rowCount++; //添加到行临时列表 rowTempList.Add (item); } } //如果在同一列 if (item.itemColumn == current.itemColumn) { //判断该点与Curren中间有无间隙 bool columnCanBoom = CheckItemsInterval(false,current,item); if (columnCanBoom) { //计数 columnCount++; //添加到列临时列表 columnTempList.Add (item); } } } //横向消除 bool horizontalBoom = false; //如果横向三个以上 if (rowCount > 2) { //将临时列表中的Item全部放入BoomList boomList.AddRange (rowTempList); //横向消除 horizontalBoom = true; } //如果纵向三个以上 if (columnCount > 2) { if (horizontalBoom) { //剔除自己 boomList.Remove (current); } //将临时列表中的Item全部放入BoomList boomList.AddRange (columnTempList); } //如果没有消除对象,返回 if (boomList.Count == 0) return; //创建临时的BoomList List<Item> tempBoomList = new List<Item> (); //转移到临时列表 tempBoomList.AddRange (boomList); //开启处理BoomList的协程 StartCoroutine (ManipulateBoomList (tempBoomList)); }
      • 当然也有特殊情况,在游戏开始时,如没有设置任何阻止同色的算法,即有可能出现这种状况,我们就要也采用一些算法去防止Bug出现。

        跳跃同行同列Bug
        /// <summary> /// 检测两个Item之间是否有间隙(图案不一致) /// </summary> /// <param name="isHorizontal">是否是横向.</param> /// <param name="begin">检测起点.</param> /// <param name="end">检测终点.</param> private bool CheckItemsInterval(bool isHorizontal,Item begin,Item end) { //获取图案 Sprite spr = begin.currentSpr; //如果是横向 if (isHorizontal) { //起点终点列号 int beginIndex = begin.itemColumn; int endIndex = end.itemColumn; //如果起点在右,交换起点终点列号 if (beginIndex > endIndex) { beginIndex = end.itemColumn; endIndex = begin.itemColumn; } //遍历中间的Item for (int i = beginIndex + 1; i < endIndex; i++) { //异常处理(中间未生成,标识为不合法) if (allItems [begin.itemRow, i] == null) return false; //如果中间有间隙(有图案不一致的) if (allItems [begin.itemRow, i].currentSpr != spr) { return false; } } return true; } else { //起点终点行号 int beginIndex = begin.itemRow; int endIndex = end.itemRow; //如果起点在上,交换起点终点列号 if (beginIndex > endIndex) { beginIndex = end.itemRow; endIndex = begin.itemRow; } //遍历中间的Item for (int i = beginIndex + 1; i < endIndex; i++) { //如果中间有间隙(有图案不一致的) if (allItems [i, begin.itemColumn].currentSpr != spr) { return false; } } return true; } }
      • 接下来就是消除处理了,采用一些动画之类,此处略过,我们来讲解下落算法。下落算法有很多,我们采用的是逐个入位法。


        逐个入位法下落
        /// <summary> /// Items下落 /// </summary> /// <returns>The drop.</returns> IEnumerator ItemsDrop() { isOperation = true; //逐列检测 for (int i = 0; i < tableColumn; i++) { //计数器 int count = 0; //下落队列 Queue<Item> dropQueue = new Queue<Item> (); //逐行检测 for (int j = 0; j < tableRow; j++) { if (allItems [j, i] != null) { //计数 count++; //放入队列 dropQueue.Enqueue(allItems [j, i]); } } //下落 for (int k = 0; k < count; k++) { //获取要下落的Item Item current = dropQueue.Dequeue (); //修改全局数组(原位置情况) allItems[current.itemRow,current.itemColumn] = null; //修改Item的行数 current.itemRow = k; //修改全局数组(填充新位置) allItems[current.itemRow,current.itemColumn] = current; //下落 current.GetComponent<ItemOperation>(). CurrentItemDrop(allPos[current.itemRow,current.itemColumn]); } } yield return new WaitForSeconds (0.2f); StartCoroutine (CreateNewItem()); yield return new WaitForSeconds (0.2f); AllBoom (); }
      • 最后生成新的对象 /// <summary> /// 生成新的Item /// </summary> /// <returns>The new item.</returns> public IEnumerator CreateNewItem() { isOperation = true; for (int i = 0; i < tableColumn; i++) { int count = 0; Queue<Game > newItemQueue = new Queue<Game > (); for (int j = 0; j < tableRow; j++) { if (allItems [j, i] == null) { //生成一个Item Game current = (Game )Instantiate(Resources. Load<Game > (Util.ResourcesPrefab + Util.Item)); // Pool.instance.GetGame (Util.Item, transform); current.transform.parent = transform; current.transform.position = allPos [tableRow - 1, i]; newItemQueue.Enqueue (current); count++; } } for (int k = 0; k < count; k++) { //获取Item组件 Item currentItem = newItemQueue.Dequeue ().GetComponent<Item>(); //随机数 int random = Random.Range (0, randomSprites.Length); //修改脚本中的图片 currentItem.currentSpr = randomSprites [random]; //修改真实图片 currentItem.currentImg.sprite = randomSprites [random]; //获取要移动的行数 int r = tableRow - count + k; //移动 currentItem.GetComponent<ItemOperation> ().ItemMove (r,i,allPos[r,i]); } } yield break; }
      • 当然如果两个图片交换后,无法消除要还原回原来位置 /// <summary> /// Item交换 /// </summary> /// <returns>The exchange.</returns> /// <param name="dir">Dir.</param> IEnumerator ItemExchange(Vector2 dir) { //获取目标行列 int targetRow = item.itemRow + System.Convert.ToInt32(dir.y); int targetColumn = item.itemColumn + System.Convert.ToInt32(dir.x); //检测合法 bool isLagal = GameController.instance.CheckRCLegal (targetRow, targetColumn); if (!isLagal) { GameController.instance.isOperation = false; //不合法跳出 yield break; } //获取目标 Item target = GameController.instance.allItems [targetRow, targetColumn]; //从全局列表中获取当前item,查看是否已经被消除,被消除后不能再交换 Item myItem = GameController.instance.allItems [item.itemRow, item.itemColumn]; if (!target || !myItem) { GameController.instance.isOperation = false; //Item已经被消除 yield break; } //相互移动 target.GetComponent<ItemOperation> ().ItemMove (item.itemRow, item.itemColumn, transform.position); ItemMove (targetRow, targetColumn, target.transform.position); //还原标志位 bool reduction = false; //消除处理 item.CheckAroundBoom(); if (GameController.instance.boomList.Count == 0) { reduction = true; } target.CheckAroundBoom (); if (GameController.instance.boomList.Count != 0) { reduction = false; } //还原 if (reduction) { //延迟 yield return new WaitForSeconds (0.2f); //临时行列 int tempRow, tempColumn; tempRow = myItem.itemRow; tempColumn = myItem.itemColumn; //移动 myItem.GetComponent<ItemOperation> ().ItemMove (target.itemRow, target.itemColumn, target.transform.position); target.GetComponent<ItemOperation> ().ItemMove (tempRow, tempColumn, myItem.transform.position); //延迟 yield return new WaitForSeconds (0.2f); //操作完毕 GameController.instance.isOperation = false; } }
    • 项目实践

      项目实践


      核心UML类图

    当然这个项目是最基础版,只有简单的消除操作,如果加上道具特效,算法会更多,以后在慢慢琢磨品鉴。最后奉上源码,这个项目下落及生成新对象的延迟时间还没有细调,调好后玩起来比较流畅。(内附价值50美元的资源包喔
    转载请注明(B5教程网)原文链接:https://b5.mxunkeji.com/content-130-6018-1.html
    相关热词搜索: