三消游戏算法图文详解
来源:互联网 发布:淘宝商店转让 编辑:程序博客网 时间:2024/05/29 14:35
之前小编查询发的资料小编本人也不太理解,所以这里又找了一个讲的个很详细的文章,整理过后发出来大家一起分享!
消除算法图文详解
三消算法首要实现的就是找到所有三个或三个以上的可消除对象,但直接找到这些对象是不太现实的,所以我们要将需求拆分。可不可以先获取所有图案相连的对象,进而在获取三消对象,这个算法也是众多三消游戏的一致实现。
获取图案相同的所有相连对象
// 填充相同Item列表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]); } }}
获取图案相同的对象,一定要以一个对象为基准,这样才能够知道以谁为中心,以这个中心为核心横向及纵向的检测,检测到三个及以上的对象,那说明是可以消除的对象。
以检测点为中心横向纵向检测
// 填充待消除列表public void FillBoomList(Item current){ //计数器 int rowCount = 0; int columnCount = 0; //临时列表 List rowTempList = new List (); List columnTempList = new List (); //横向纵向检测 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 tempBoomList = new List (); //转移到临时列表 tempBoomList.AddRange (boomList); //开启处理BoomList的协程 StartCoroutine (ManipulateBoomList (tempBoomList));}
当然也有特殊情况,在游戏开始时,如没有设置任何阻止同色的算法,即有可能出现这种状况,我们就要也采用一些算法去防止Bug出现。
跳跃同行同列Bug
/// <summary>/// 检测两个Item之间是否有间隙(图案不一致)/// </summary>/// <param name="isHorizontal">是否是横向</param>/// <param name="begin">检测起点</param>/// <param name="end">监测终点</param>/// <returns></returns>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 dropQueue = new Queue(); //逐行检测 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(). 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 newItemQueue = new Queue(); for (int j = 0; j < tableRow; j++) { if (allItems[j, i] == null) { //生成一个Item GameObject current = (GameObject)Instantiate(Resources. Load(Util.ResourcesPrefab + Util.Item)); // ObjectPool.instance.GetGameObject (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(); //随机数 int random = Random.Range(0, randomSprites.Length); //修改脚本中的图片 currentItem.currentSpr = randomSprites[random]; //修改真实图片 currentItem.currentImg.sprite = randomSprites[random]; //获取要移动的行数 int r = tableRow - count + k; //移动 currentItem.GetComponent().ItemMove(r, i, allPos[r, i]); } } yield break; }
当然如果两个图片交换后,无法消除要还原回原来位置
这里写代码片 /// <summary> /// Item交换 /// </summary> /// <param name="dir">The exchange</param> /// <returns>Dir</returns> 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().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().ItemMove(target.itemRow, target.itemColumn, target.transform.position); target.GetComponent().ItemMove(tempRow, tempColumn, myItem.transform.position); //延迟 yield return new WaitForSeconds(0.2f); //操作完毕 GameController.instance.isOperation = false; } }
项目实践
项目实践
核心UML类图
结束语
当然这个项目是最基础版,只有简单的消除操作,如果加上道具特效,算法会更多,以后在慢慢琢磨品鉴。最后奉上源码,这个项目下落及生成新对象的延迟时间还没有细调,调好后玩起来比较流畅。
链接:链接:http://pan.baidu.com/s/1hrBfXdU 密码:6uqw
阅读全文
0 0
- 三消游戏算法图文详解
- 三消游戏算法剖析
- KMP 算法图文详解
- 三消游戏死局算法的解析
- 三消游戏(三)
- CentOS 6.4安装教程图文详解之三
- kettle入门(三) 之kettle连接hadoop&hdfs图文详解
- Window下PHP三种运行方式图文详解
- 网络管理常用命令之三 - Netstat 命令详解(图文)
- Window下PHP三种运行方式图文详解
- Window下PHP三种运行方式图文详解
- 三消游戏知识点
- 三消游戏思路
- unity3D教程 : 游戏算法开发(三)
- 数三游戏算法新解
- "插入排序"算法-之通俗易通图文+代码详解
- 百度分词算法详解【三】
- sift算法原理详解(三)
- 一次HTTP请求中的缓存
- ???Weather Patterns
- Jedis连接池实例
- VMProtect1.09分析
- 汇编语言程序设计知识点(第一章:进制转换)
- 三消游戏算法图文详解
- SSH免密登陆
- Git学习第三天
- Java实训课8
- Java paint与paintComponent的区别与联系
- Java中传值与传引用的三种情况
- Java OutOfMemory异常
- Linux inotify&pthread编程机制
- caffe在中断之后的模型继续训练