赞
踩
之前小编查询发的资料小编本人也不太理解,所以这里又找了一个讲的个很详细的文章,整理过后发出来大家一起分享!
消除算法图文详解
三消算法首要实现的就是找到所有三个或三个以上的可消除对象,但直接找到这些对象是不太现实的,所以我们要将需求拆分。可不可以先获取所有图案相连的对象,进而在获取三消对象,这个算法也是众多三消游戏的一致实现。
获取图案相同的所有相连对象
// 填充相同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
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。