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赋值:




Unity2D 动态切换shader unity2d地图切换_执行顺序


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元素或碰撞体释放时调用,所以现在你点击宝石,就会选择当前宝石:


Unity2D 动态切换shader unity2d地图切换_执行顺序_02


交换宝石

交换宝石逻辑

在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:


Unity2D 动态切换shader unity2d地图切换_免费版_03


我们看到两个DOTween,一个是付费版本,一个是免费版本,我们使用免费版本就可以了,点击进去,点击‘导入’,会弹出一个窗口,选择全部,并导入:


Unity2D 动态切换shader unity2d地图切换_执行顺序_04


导入完成后,会多出一个文件夹:


Unity2D 动态切换shader unity2d地图切换_Unity2D 动态切换shader_05


现在我们就可以使用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);
}


这里我们使用到了序列Sequencemove1move2是两颗宝石移动的动画,将两个动画插入到序列为0秒的位置,意思就是这两个动画同时进行,每个动画的时间是0.5秒。

现在我们运行程序,就可以看到两颗宝石交换的动画了:


Unity2D 动态切换shader unity2d地图切换_Unity2D 动态切换shader_06