成都unity3d培训
达内成都会计中心

13408446380

热门课程

Unity教程之三消游戏算法

  • 时间:2018-02-06 11:28
  • 发布:成都达内
  • 来源:成都达内

前言

目前的游戏市场可谓日渐萧条,分分钟就逼死众多产品经理,三消游戏可谓一把温柔的弯刀,从女人这块获取到了一大片的市场,动不动就做个几百关,相互之间还有攀比,果然女人的钱还是更好赚一些的。当然,三消游戏确实有很大的优势,不浪费太多时间,不那么烧脑,简单有趣。但如果要做一款集成性很高的三消游戏,对于开发者而言也并不是那么简单,毕竟要用到很多算法,相比所谓的FPS、MMORPG有另一层次的深度。今天,成都unity3d培训就给大家简单分享一下三消中的核心算法,以及在Unity中的实现。

消除算法图文详解

三消算法首要实现的就是找到所有三个或三个以上的可消除对象,但直接找到这些对象是不太现实的,所以我们要将需求拆分。可不可以先获取所有图案相连的对象,进而在获取三消对象,这个算法也是众多三消游戏的一致实现。

【Unity三消算法】

获取图案相同的所有相连对象

///

/// 填充相同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]);

}

}

}

获取图案相同的对象,一定要以一个对象为基准,这样才能够知道以谁为中心,以这个中心为核心横向及纵向的检测,检测到三个及以上的对象,那说明是可以消除的对象。

【Unity三消算法】

以检测点为中心横向纵向检测

///

///

/// 填充待消除列表///

///

///

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出现。

【Unity三消算法】

跳跃同行同列Bug

///

/// 检测两个Item之间是否有间隙(图案不一致)

///

/// 是否是横向.

/// 检测起点.

/// 检测终点.

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;

}

}

接下来就是消除处理了,采用一些动画之类,此处略过,我们来讲解下落算法。下落算法有很多,我们采用的是逐个入位法。

【Unity三消算法】

逐个入位法下落

///

/// Items下落

///

/// The drop.

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

}

最后生成新的对象

///

/// 生成新的Item

///

/// The new item.

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;

}

当然如果两个图片交换后,无法消除要还原回原来位置

///

/// Item交换

///

/// The exchange.

/// Dir.

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;

}

}

项目实践

【Unity三消算法】

项目实践

【Unity三消算法】

核心UML类图

结束语

当然这个项目是最基础版,只有简单的消除操作,如果加上道具特效,算法会更多,以后在慢慢琢磨品鉴。最后奉上源码,这个项目下落及生成新对象的延迟时间还没有细调,调好后玩起来比较流畅。

此文章由成都unity3d培训机构的小编转载自网络感谢你的关注,如有侵权请联系我们

上一篇:头盔式HUD和十字光标
下一篇:Unity3D教程之UI解决方案
选择城市和中心
贵州省

广西省

海南省