Unity三消算法
- 消除算法图文详解
- 三消算法首要实现的就是找到所有三个或三个以上的可消除对象,但直接找到这些对象是不太现实的,所以我们要将需求拆分。可不可以先获取所有图案相连的对象,进而在获取三消对象,这个算法也是众多三消游戏的一致实现。
获取图案相同的所有相连对象
- 三消算法首要实现的就是找到所有三个或三个以上的可消除对象,但直接找到这些对象是不太现实的,所以我们要将需求拆分。可不可以先获取所有图案相连的对象,进而在获取三消对象,这个算法也是众多三消游戏的一致实现。
/// <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 = ; 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 = ;
int columnCount = ;
//临时列表
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 > ) {
//将临时列表中的Item全部放入BoomList
boomList.AddRange (rowTempList);
//横向消除
horizontalBoom = true;
}
//如果纵向三个以上
if (columnCount > ) {
if (horizontalBoom) {
//剔除自己
boomList.Remove (current);
}
//将临时列表中的Item全部放入BoomList
boomList.AddRange (columnTempList);
}
//如果没有消除对象,返回
if (boomList.Count == )
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 + ; 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 + ; 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 = ; i < tableColumn; i++) {
//计数器
int count = ;
//下落队列
Queue<Item> dropQueue = new Queue<Item> ();
//逐行检测
for (int j = ; j < tableRow; j++) {
if (allItems [j, i] != null) {
//计数
count++;
//放入队列
dropQueue.Enqueue(allItems [j, i]);
}
}
//下落
for (int k = ; 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 = ; i < tableColumn; i++) {
int count = ;
Queue<GameObject> newItemQueue = new Queue<GameObject> ();
for (int j = ; j < tableRow; j++) {
if (allItems [j, i] == null) {
//生成一个Item
GameObject current = (GameObject)Instantiate(Resources.
Load<GameObject> (Util.ResourcesPrefab + Util.Item));
// ObjectPool.instance.GetGameObject (Util.Item, transform);
current.transform.parent = transform;
current.transform.position = allPos [tableRow - , i];
newItemQueue.Enqueue (current);
count++;
}
}
for (int k = ; k < count; k++) {
//获取Item组件
Item currentItem = newItemQueue.Dequeue ().GetComponent<Item>();
//随机数
int random = Random.Range (, 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 == ) {
reduction = true;
}
target.CheckAroundBoom ();
if (GameController.instance.boomList.Count != ) {
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;
}
}
- 当然也有特殊情况,在游戏开始时,如没有设置任何阻止同色的算法,即有可能出现这种状况,我们就要也采用一些算法去防止Bug出现。
- 项目实践
项目实践结束语
当然这个项目是最基础版,只有简单的消除操作,如果加上道具特效,算法会更多,以后在慢慢琢磨品鉴。最后奉上源码,这个项目下落及生成新对象的延迟时间还没有细调,调好后玩起来比较流畅。(内附价值50美元的资源包喔
Unity三消算法的更多相关文章
- unity导弹算法 预计目标点
关于导弹的飞行算法,网上有很多教程.简单算法无非是获取目标点的当前位置,然后导弹朝目标方向移动.高深点的,就是通过计算获取碰撞点然后朝着目标移动.如果你能看懂这个高深算法的话,可以去看原帖:http: ...
- [Unity A*算法]A*算法的简单实现
写在前面:之前看过一点,然后看不懂,也没用过. 最近正好重构项目看到寻路这块,想起来就去查查资料,总算稍微理解一点了,下面记录一下自己的成果(哈哈哈 :> ) 下面分享几篇我觉得挺不错的文章 A ...
- C++ 三消游戏基本实现
最近在研究三消算法,我想试试在完全不借助网络资源的情况下搞定这个东西,所以有些地方可能不是最优的. 代码留此备忘. 1. 3x_desk_event.h 1 #pragma once 2 3 #ifn ...
- 由浅入深学习PBR的原理和实现
目录 一. 前言 1.1 本文动机 1.2 PBR知识体系 1.3 本文内容及特点 二. 初阶:PBR基本认知和应用 2.1 PBR的基本介绍 2.1.1 PBR概念 2.1.2 与物理渲染的差别 2 ...
- 第04组 Alpha冲刺(4/6)
队名:new game 组长博客:戳 作业博客:戳 组员情况 鲍子涵(队长) 燃尽图 过去两天完成了哪些任务 才两天,也就是实现一些功能而已 复习 接下来的计划 实现更多的功能 为这周的比赛准备 还剩 ...
- 第04组 Alpha冲刺(3/6)
队名:new game 组长博客:戳 作业博客:戳 组员情况 鲍子涵(队长) 燃尽图 过去两天完成了哪些任务 才两天,也就是实现一些功能而已 复习 接下来的计划 实现更多的功能 为下周的比赛准备 还剩 ...
- Alpha冲刺(3/6)
队名:new game 组长博客:戳 作业博客:戳 组员情况 鲍子涵(队长) 燃尽图 过去两天完成了哪些任务 才两天,也就是实现一些功能而已 复习 接下来的计划 实现更多的功能 为下周的比赛准备 还剩 ...
- Unity 网络斗地主 牌的一些算法
Unity 网络斗地主 牌的一些算法 在这儿说一下,我的项目是用svn的方式,上传在https://v2.svnspot.com/18666451713.doudizhu这个svn上,大家可以下载T ...
- A星寻路算法入门(Unity实现)
最近简单学习了一下A星寻路算法,来记录一下.还是个萌新,如果写的不好,请谅解.Unity版本:2018.3.2f1 A星寻路算法是什么 游戏开发中往往有这样的需求,让玩家控制的角色自动寻路到目标地点, ...
随机推荐
- mac上使用zsh配置环境变量
Mac配置环境变量的地方 一./etc/profile (建议不修改这个文件 ) 全局(公有)配置,不管是哪个用户,登录时都会读取该文件. 二./etc/bashrc (一般在这个文件中添加系统级环境 ...
- C语言 · 周期字串
算法提高 周期字串 时间限制:1.0s 内存限制:256.0MB 问题描述 右右喜欢听故事,但是右右的妈妈总是讲一些“从前有座山,山里有座庙,庙里有个老和尚给小和尚讲故事,讲的什么呢 ...
- Introduction to MyBatis Generator Mybatis代码生成介绍
Mybatis官方提供了代码生成工具,这里是官方网站: http://mybatis.github.io/generator/index.html 可以自动生成 Java POJOs, Mapper. ...
- Hive Tunning 补充 关于bucket
在前面的几篇文章当中一直有一个概念bucketing不清楚到底是怎么回事. 网友南京-李先森给了他收集的一些资料,如下: Buckets 对指定列计算 hash,根据 hash 值切分数据,目的是为了 ...
- C#内置泛型委托:Action委托
1.什么是Action泛型委托 Action<T>是.NET Framework内置的泛型委托,可以使用Action<T>委托以参数形式传递方法,而不用显示声明自定义的委托.封 ...
- Java设计模式(9)适配器模式(Adapter模式)
适配器模式定义:将两个不兼容的类纠合在一起使用,属于结构型模式,需要有Adaptee(被适配者)和Adaptor(适配器)两个身份. 为何使用适配器模式 我们经常碰到要将两个没有关系的类组合在一起使用 ...
- I/O模型(同步、非同步、阻塞、非阻塞)总结
I/O:同步(synchronous).异步(asynchronous).阻塞(blocking).非阻塞(nonblocking) 1.I/O内部机制 出于安全考虑,用户程序(用户态)是没办法直接操 ...
- 摄像头驱动OV7725学习笔记连载(一):OV7725 电器特性和时序图
OV(豪威科技)已经被中国财团收购.这个昔日的大佬,最终走下神坛. 关于OVsensor的资料包括,OV7725的简介(OmniVsion_OV7725),OV7725的数据手册(OV7725_Dat ...
- Opengl绘制我们的小屋(四)第三人称漫游
本节内容是在第一人称漫游上完成的,请先了解上文中第一人称漫游的实现. 这一节讲下第三人称漫游是如何实现,第三人称,简单来说,就是在你后面会跟着一台摄像机顺着你拍摄. 先看一下失败的尝试.这个方法是把人 ...
- 第三百六十三节,Python分布式爬虫打造搜索引擎Scrapy精讲—elasticsearch(搜索引擎)的mget和bulk批量操作
第三百六十三节,Python分布式爬虫打造搜索引擎Scrapy精讲—elasticsearch(搜索引擎)的mget和bulk批量操作 注意:前面讲到的各种操作都是一次http请求操作一条数据,如果想 ...
- unity导弹算法 预计目标点