文章目录
- 前言
- 开始项目
- 开始
- 一、方块网格生成
- 二、方块交换
- 三、添加交换的动画效果
- 四、水平消除检测
- 五、垂直消除检测
- 六、完善删除功能
- 七、效果优化(移动方块后再进行消除检测)
- 八、方块下落
- 十、方块填充
- 十一、后续
- 源码
- 参考
- 完结
前言
欢迎来到经典消消乐游戏的复刻版!在这个令人上瘾的游戏中,您将体验到无穷的挑战和欢乐。
消消乐是一款经典的益智游戏,旨在通过消除相同的方块来获得高分。您需要在棋盘上寻找相同颜色或形状的方块,并将它们消除以获得积分。随着游戏的进行,难度也会逐渐增加,需要您的观察力、反应能力和策略思维。
我们的团队致力于为您呈现一款精心制作的复刻版本,在保留经典玩法的同时,还增加了一些全新的特色玩法和关卡设计。您将享受到华丽的图形效果、各种有趣的道具和奖励,以及丰富多样的关卡挑战。
挑战自我,突破极限,挖掘隐藏在每个关卡背后的秘密。消除方块,释放您内心的压力,让愉悦的感觉充满您的每一天!
感谢您选择我们的游戏,并希望您在这个充满乐趣和回忆的消消乐世界中度过美好的时光。开始您的消除之旅吧!
祝您玩得愉快!
注意:此版本的消消乐游戏仅供娱乐和休闲目的,请勿用于商业用途。
先来看看实现的最终效果
开始项目
百度盘链接:https://pan.baidu.com/s/12QX7_Jwmc1AITpHYrgfwFQ
提取码:5uvj
开始
一、方块网格生成
新增Block方块脚本
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//方块脚本
public class Block : MonoBehaviour
{
public int RowIndex;//行位置
public int ColIndex;//列位置
public void Init(int row, int col)
{
this.RowIndex = row;
this.ColIndex = col;
}
void Start()
{
}
//根据行列下标设置方块的相对位置
public void ResetPosition()
{
transform.localPosition = new Vector3(ColIndex * 88, -RowIndex * 88, 0);
}
}
新增GameUI 脚本
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GameUI : MonoBehaviour
{
public Transform nodeTf;
public int RowCount = 7;//行数
public int ColCount = 8;//列数
public Block[,] BlockArr;//存储消除方块的二维数组
void Start()
{
InitGrid();
}
// 初始化网格
public void InitGrid()
{
BlockArr = new Block[RowCount, ColCount];//构建二维数组
for (int row = 0; row < RowCount; row++)
for (int col = 0; col < ColCount; col++)
{
Block b = CreateRandomBlock();
b.Init(row, col);
b.ResetPosition();
BlockArr[row, col] = b;
}
}
public Block CreateRandomBlock()
{
int ran = Random.Range(1, 5);
GameObject obj = Instantiate(Resources.Load("Block/block" + ran.ToString()), nodeTf) as GameObject;
return obj.AddComponent<Block>();
}
}
挂载脚本
效果
二、方块交换
修改GameUI,新增交换方法
public Block[,] BlockArr;//存储消除方块的二维数组
public List<Block> SelectBlockArr;//存储选中方块的集合
public static GameUI Instance;
void Awake()
{
Instance = this;
SelectBlockArr = new List<Block>();
}
public void SelectBlock(Block b)
{
//已经选中移除
if (SelectBlockArr.Contains(b))
{
SelectBlockArr.Remove(b);
return;
}
//添加到选中集合
SelectBlockArr.Add(b);
if (SelectBlockArr.Count == 2)
{
//选中两个 方块 交换
//相邻的才能交换
if ((Mathf.Abs(SelectBlockArr[0].RowIndex - SelectBlockArr[1].RowIndex) + Mathf.Abs(SelectBlockArr[0].ColIndex - SelectBlockArr[1].ColIndex)) == 1)
{
SwapBlock(SelectBlockArr[0], SelectBlockArr[1]);
}
SelectBlockArr.Clear();
}
}
public void SwapBlock(Block b1, Block b2)
{
//交换数组位置
BlockArr[b1.RowIndex, b1.ColIndex] = b2;
BlockArr[b2.RowIndex, b2.ColIndex] = b1;
//交换下标
int tempRowIndex = b1.RowIndex;
int tempColIndex = b1.ColIndex;
b1.RowIndex = b2.RowIndex;
b1.ColIndex = b2.ColIndex;
b2.RowIndex = tempRowIndex;
b2.ColIndex = tempColIndex;
//交换位置
b1.ResetPosition();
b2.ResetPosition();
}
Block脚本添加点击事件,调用
using UnityEngine.EventSystems;
public class Block : MonoBehaviour,IPointerClickHandler{
//点击
public void OnPointerClick(PointerEventData eventData)
{
GameUI.Instance.SelectBlock(this);
}
}
效果
三、添加交换的动画效果
引入DOTween,修改Block脚本
//根据行列下标设置方块的相对位置
public void ResetPosition()
{
// transform.localPosition = new Vector3(ColIndex * 88, -RowIndex * 88, 0);
transform.DOLocalMove(new Vector3(ColIndex * 88,-RowIndex * 88,0),0.25f);
}
修改GameUI脚本
public void SelectBlock(Block b)
{
//已经选中移除
if (SelectBlockArr.Contains(b))
{
SelectBlockArr.Remove(b);
b.transform.DOScale(1f, 0.25f);
return;
}
//添加到选中集合
SelectBlockArr.Add(b);
if (SelectBlockArr.Count == 2)
{
//选中两个 方块 交换
//相邻的才能交换
if ((Mathf.Abs(SelectBlockArr[0].RowIndex - SelectBlockArr[1].RowIndex) + Mathf.Abs(SelectBlockArr[0].ColIndex - SelectBlockArr[1].ColIndex)) == 1)
{
SwapBlock(SelectBlockArr[0], SelectBlockArr[1]);
}
SelectBlockArr[0].transform.DOScale(1, 0.25f);
SelectBlockArr[1].transform.DOScale(1, 0.25f);
SelectBlockArr.Clear();
}
else
{
b.transform.DOScale(1.2f, 0.25f);
}
}
效果
四、水平消除检测
修改GameUI代码
public List<Block> DelBlockArr;//存储将要消除的方块
void Awake()
{
DelBlockArr = new List<Block>();
}
public void SelectBlock(Block b)
{
//。。。
//交换
SwapBlock(SelectBlockArr[0], SelectBlockArr[1]);
//检测水平方块
CheckDelHorizontal();
//有删除的方块
if (HasDelBlock())
{
//删除
DelBlockByArr();
}
//。。。
}
//检查水平的方块是否满足消除消除条件
public void CheckDelHorizontal()
{
//遍历每一行
for (int row = 0; row < RowCount; row++)
{
//存储每一行第一列方块的名称
string preName = BlockArr[row, 0].gameObject.name;
int count = 0;//方块名称相同个数的计数值
//从第二列开始遍历
for (int col = 1; col < ColCount; col++)
{
Block b = BlockArr[row, col];
if (b.gameObject.name == preName)
{
//计数加一
count++;
}
else
{
// 判断计数是否大于等于2
if (count >= 2)
{
// 将名称相同的方块添加到要消除的集合中
for (int j = 0; j <= count; j++)
{
// 判断是否已经存在消除队列,不存在再添加到集合
Block delBlock = BlockArr[row, col - 1 - j];
if (DelBlockArr.IndexOf(delBlock) == -1)
{
DelBlockArr.Add(delBlock);
}
}
}
// 记录当前方块名称
preName = b.gameObject.name;
// 计数归0
count = 0;
}
}
//判断一行遍历完后个数是否满足消除情况
if (count >= 2)
{
for
(int j = 0; j <= count; j++)
{
//判断是否已经存在消除队列,不存在再添到集合
Block delBlock = BlockArr[row, ColCount - 1 - j];
if (DelBlockArr.IndexOf(delBlock) == -1)
{
DelBlockArr.Add(delBlock);
}
}
}
}
}
//是否有消除的方块
public bool HasDelBlock()
{
return DelBlockArr.Count > 0;
}
//消除Del集合中的方块
public void DelBlockByArr()
{
for (int i = DelBlockArr.Count - 1; i >= 0; i--)
{
Block b = DelBlockArr[i];
//置空
BlockArr[b.RowIndex, b.ColIndex] = null;
//删除
b.Delete();
}
//清空
DelBlockArr.Clear();
}
Block新增删除方法
//删除
public void Delete()
{
gameObject.GetComponent<Image>().color = Color.red;
}
效果
五、垂直消除检测
//垂直检测
public void CheckDelVertical()
{
//遍历每一行
for (int col = 0; col < ColCount; col++)
{
string preName = BlockArr[0, col].gameObject.name;
int count = 0;//方块名称相同个数的计数值
//从第二列开始遍历
for (int row = 1; row < RowCount; row++)
{
Block b = BlockArr[row, col];
if (b.gameObject.name == preName)
{
//计数加一
count++;
}
else
{
// 判断计数是否大于等于2
if (count >= 2)
{
// 将名称相同的方块添加到要消除的集合中
for (int j = 0; j <= count; j++)
{
// 判断是否已经存在消除队列,不存在再添加到集合
Block delBlock = BlockArr[row - 1 - j, col];
if (DelBlockArr.IndexOf(delBlock) == -1)
{
DelBlockArr.Add(delBlock);
}
}
}
// 记录当前方块名称
preName = b.gameObject.name;
// 计数归0
count = 0;
}
}
//判断一行遍历完后个数是否满足消除情况
if (count >= 2)
{
for(int j = 0; j <= count; j++)
{
//判断是否已经存在消除队列,不存在再添到集合
Block delBlock = BlockArr[RowCount- 1 - j, col];
if (DelBlockArr.IndexOf(delBlock) == -1)
{
DelBlockArr.Add(delBlock);
}
}
}
}
}
效果
六、完善删除功能
修改Block代码
//删除
public void Delete()
{
// gameObject.GetComponent<Image>().color = Color.red;
Destroy(gameObject);
//生成消除特效
GameObject effect = Instantiate(Resources.Load("del")) as GameObject;
effect.transform.position = transform.position;
Destroy(effect, 1);
}
效果
七、效果优化(移动方块后再进行消除检测)
修改Block
//根据行列下标设置方块的相对位置
public Tween ResetPosition()
{
// transform.localPosition = new Vector3(ColIndex * 88, -RowIndex * 88, 0);
return transform.DOLocalMove(new Vector3(ColIndex * 88, -RowIndex * 88, 0), 0.25f);
}
修改GameUI
public void SelectBlock(Block b)
{
//。。。
//交换
SwapBlock(SelectBlockArr[0], SelectBlockArr[1]);
//动画序列
Sequence seq = DOTween.Sequence();
seq.Insert(0, SelectBlockArr[0].ResetPosition());
seq.Insert(0, SelectBlockArr[1].ResetPosition());
seq.AppendCallback(delegate ()
{
//检测水平方块
CheckDelHorizontal();
CheckDelVertical();
//有删除的方块
if (HasDelBlock())
{
//删除
DelBlockByArr();
}
});
//。。。
}
public void SwapBlock(Block b1, Block b2)
{
//。。。
//交换位置
// b1.ResetPosition();
// b2.ResetPosition();
}
效果
八、方块下落
修改GameUI
//方块下落
public void DropBlock()
{
//从倒数第二行开始遍历
for (int row = RowCount - 2; row >= 0; row--)
{
for (int col = 0; col < ColCount; col++)
{
//不为null的方块才能下落
Block b = BlockArr[row, col];
if (b != null) DropBlock(b);
}
}
}
public void DropBlock(Block b)
{
//获得当前方块下方的下标
int rowIndex = b.RowIndex + 1;
int colIndex = b.ColIndex;
if (rowIndex > RowCount - 1)
{
//超出下标
b.ResetPosition();//移动
return;
}
Block next_block = BlockArr[rowIndex, colIndex];
if (next_block != null)
{
//下方有方块不能再下落
b.ResetPosition();
return;
}
else
{
//下方没有方块与null方块进行交换
BlockArr[b.RowIndex, b.ColIndex] = null;
b.RowIndex = rowIndex;
BlockArr[b.RowIndex, b.ColIndex] = b;
//检测是否继续下落
DropBlock(b);
}
}
在删除方块后调用,运行效果
十、方块填充
GameUI新增填充方块方法
//填充方块
public void FillEmptyBlock()
{
Sequence seq = DOTween.Sequence();
for (int row = 0; row < RowCount; row++)
{
for (int col = 0; col < ColCount; col++)
{
Block b = BlockArr[row, col];
if (b == null)
{
b = CreateRandomBlock();
b.Init(row, col);
BlockArr[row, col] = b;
b.transform.localPosition = new Vector3(col * 88, 88, 0);
seq.Insert(0.25f, b.ResetPosition());
}
}
}
seq.AppendCallback(delegate ()
{
//继续检测是否满足消除条件
//检测水平方块
CheckDelHorizontal();
//检测垂直方块
CheckDelVertical();
//有删除的方块
if (HasDelBlock())
{
//删除
DelBlockByArr();
//检测下落
DropBlock();
//填充
FillEmptyBlock();
}
});
}
在检测下落后调用该方法,运行效果
十一、后续
- 后续可以加入计分规则,关卡选择功能
- 攻击图标合成对右边的美少女造成伤害,五角星给我们自己加盾,药品给我们回血,能量球合成积攒攻击力(增加后续攻击、盾或药品的数值,每次使用能量清零)
- 每过几个回合美少女会对我们发起攻击
- 通关会解锁该美少女,或者获取图集,满足爱的收集玩家,有玩下去的欲望
- 加入金币功能,每次通关可以获取,勾起玩家重复游玩关卡的欲望,金币可以用于升级主角,比如提升基础攻击力、血量等
- 制作排行版本功能,可以统计游玩时间,分数,关卡数,解锁美少女图集数,金币数进行排行
后续大家可以自行扩展,这里就不过多赘述了。至于后续是否继续完善开发,就看大家想不想看了。
源码
要啥源码,好好看,好好学!
参考
【视频】https://www.bilibili.com/video/BV1ST4y1y7Jc
完结
赠人玫瑰,手有余香!如果文章内容对你有所帮助,请不要吝啬你的点赞评论和关注
,以便我第一时间收到反馈,你的每一次支持
都是我不断创作的最大动力。点赞越多,更新越快哦!当然如果你发现了文章中存在错误
或者有更好的解决方法
,也欢迎评论私信告诉我哦!
好了,我是向宇
,https://xiangyu.blog.csdn.net
一位在小公司默默奋斗的开发者,出于兴趣爱好,于是最近才开始自习unity。如果你遇到任何问题,也欢迎你评论私信找我, 虽然有些问题我可能也不一定会,但是我会查阅各方资料,争取给出最好的建议,希望可以帮助更多想学编程的人,共勉~