Grid单例模式
向Grid.cs中添加一个静态变量:
public static Grid Instance;
在Awake
函数中赋值:
private void Awake()
{
Instance = this;
}
在Unity中,所有Awake
函数的执行顺序先于所有的Start
函数,因此,在Block.cs中,我们可以获取到Grid的单例:
private Grid grid;
private void Start()
{
grid = Grid.Instance;
}
选择宝石
在Grid.cs中声明如下变量:
public GameObject Selected;
-
Selected
用于保存选择图片的预制体。
在Unity中为Selected
赋值:
在Start
函数中初始化Selected
:
void Start () {
Map = new Block[Width, Height];
MapNum = new int[Width, Height];
Selected = Instantiate(Selected, transform.position, Quaternion.identity) as GameObject;
Selected.SetActive(false);
InitMapNum();
InitMap();
}
SetActive
方法会禁用物体的一切组件,所以一开始我们并不会看见它。
在Block.cs中添加两个基本方法:
private void SelectedBlock()
{
grid.Selected.transform.position = transform.position;
grid.Selected.SetActive(true);
}
private void UnSelectedBlock()
{
grid.Selected.SetActive(false);
}
-
SelectedBlock
方法将Selected
图片放于当前宝石位置,并使其可见。 -
UnSelectedBlock
方法将Selected
图片隐藏。
在Block.cs中添加如下函数:
private void OnMouseUpAsButton()
{
SelectedBlock();
}
OnMouseUpAsButton
函数会在鼠标点击GUI元素或碰撞体释放时调用,所以现在你点击宝石,就会选择当前宝石:
交换宝石
交换宝石逻辑
在Grid.cs中声明如下变量:
public bool IsClickedFirst = false;
public Block FirstBlock;
public Vector2 FirstBlockPos;
-
IsClickedFirst
用于判断是否点击了第一块宝石。 -
FirstBlock
用于保存点击的第一块宝石。 -
FirstBlockPos
保存了点击的第一块宝石的位置。
然后添加如下基本函数:
private void SelectFirstBlock()
{
grid.FirstBlock = this;
grid.FirstBlockPos = new Vector2(transform.position.x, transform.position.y);
SelectedBlock();
}
SelectFirstBlock
函数会记录第一次点击的宝石,并选择当前宝石。
private bool IsNeighbor()
{
if (Mathf.Abs(transform.position.x - grid.FirstBlockPos.x) +
Mathf.Abs(transform.position.y - grid.FirstBlockPos.y) == 1)
return true;
return false;
}
IsNeighbor
函数用于判断当前宝石和第一块宝石是不是相邻的宝石,相邻的宝石可以交换。
private void SwapArray(int x1, int y1, int x2, int y2)
{
int n = grid.MapNum[x1, y1];
grid.MapNum[x1, y1] = grid.MapNum[x2, y2];
grid.MapNum[x2, y2] = n;
Block b = grid.Map[x1, y1];
grid.Map[x1, y1] = grid.Map[x2, y2];
grid.Map[x2, y2] = b;
}
SwapArray
函数会将两块宝石在宝石地图中的位置交换。
private void SwapBlocks()
{
SwapArray((int)transform.position.x, (int)transform.position.y,
(int)grid.FirstBlockPos.x, (int)grid.FirstBlockPos.y);
Vector2 thisPos = transform.position;
transform.position = grid.FirstBlockPos;
grid.FirstBlock.transform.position = thisPos;
grid.FirstBlockPos = thisPos;
}
SwapBlocks
函数用于交换两颗宝石,首先交换他们在宝石地图数组中的位置,然后在交换他们在现实世界中的位置。
然后我们修改OnMouseUpAsButton
函数:
private void OnMouseUpAsButton()
{
grid.IsClickedFirst = !grid.IsClickedFirst;
if (grid.IsClickedFirst)
{
// 添加选择图标
SelectFirstBlock();
}
else
{
// 取消选择图标
UnSelectedBlock();
// 判断是否相邻
if (!IsNeighbor())
{
grid.IsClickedFirst = !grid.IsClickedFirst;
SelectFirstBlock();
return;
}
// 交换宝石位置
SwapBlocks(false);
}
}
现在我们就可以交换两颗相邻宝石的位置了。
DOTween美化动画
现在交换两颗宝石我们是直接改变其位置,有一个DOTween插件可以轻松的实现一系列动画,现在我们要使用DOTween动画插件来使我们的交换动作看起来更顺畅。打开Asset Store窗口,搜索DOTween:
我们看到两个DOTween,一个是付费版本,一个是免费版本,我们使用免费版本就可以了,点击进去,点击‘导入’,会弹出一个窗口,选择全部,并导入:
导入完成后,会多出一个文件夹:
现在我们就可以使用DOTween了,首先在Block.cs中加入命名空间:
using System.Collections;
using DG.Tweening;
然后修改SwapBlocks
函数:
private void SwapBlocks()
{
SwapArray((int)transform.position.x, (int)transform.position.y,
(int)grid.FirstBlockPos.x, (int)grid.FirstBlockPos.y);
Vector2 thisPos = transform.position;
Vector2 thatPos = grid.FirstBlockPos;
grid.FirstBlockPos = thisPos;
Sequence seq = DOTween.Sequence();
Tweener move1 = transform.DOMove(thatPos, 0.5f);
Tweener move2 = grid.FirstBlock.transform.DOMove(thisPos, 0.5f);
seq.Insert(0f, move1);
seq.Insert(0f, move2);
}
这里我们使用到了序列Sequence
,move1
和move2
是两颗宝石移动的动画,将两个动画插入到序列为0秒的位置,意思就是这两个动画同时进行,每个动画的时间是0.5秒。
现在我们运行程序,就可以看到两颗宝石交换的动画了: