前言

游戏需要实现一个类似GTA5和蜘蛛侠游戏中的电路解密功能,记录下来以供日后复习和他人参考。

需求

Unity2019 解密 unity 解密游戏_Unity


游戏玩法是把右上角电源、右下角电源还有的游戏左下角终点连接在一起获得胜利,终点不能旋转,其他方块点击旋转90度,而且从两个电源出来的路径要高亮显示。游戏一共有五种方块(其中十字形相当于两个一组成,不是向其他三个方向散开)。

Unity2019 解密 unity 解密游戏_游戏功能_02

Unity2019 解密 unity 解密游戏_Unity2019 解密_03

Unity2019 解密 unity 解密游戏_Unity2019 解密_04

Unity2019 解密 unity 解密游戏_游戏功能_05

Unity2019 解密 unity 解密游戏_Unity2019 解密_06

思路

这种模式诈一看有点复杂,理清了思路就好做了。我一共写了两个类实现这个功能,一个是方块类,另一个是管理类。每个方块添加一个方块类,方块类起到设置方块类型,保存方块方块朝向,点击旋转并且改变朝向调用管理类方法的作用。管理类负责实现判断逻辑和路径高亮。总体思路就是将对应的方块赋值给管理类数组,然后点击方块调用管理类的递归方法,通过当前方块的流向和方块类行判断所要执行的递归方法。



Unity2019 解密 unity 解密游戏_Unity2019 解密_07


代码

代码写得有些杂乱,有没有隐性bug也不得而知。重要的是思路,代码只是给大家一个参考。

Square类

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;

//记录方块的类型
public enum SquareType
{
    Yi,
    Er,
    San,
    Si,
    Shi
}
public class Square : MonoBehaviour,IPointerClickHandler
{
    [HideInInspector]
    public int up = 0;//表示方块方向,最开始用了四个方向,其实一个就可以判断
    public SquareType type;//public方块类型,可以在外部修改

    //点击旋转90度,up方向也随之改变,并且调用管理类封装的方法
    public void OnPointerClick(PointerEventData eventData)
    {
        if(eventData.button == PointerEventData.InputButton.Left)
        {
            transform.Rotate(0, 0, -90);
            up = (up + 1) % 4;
            SquareManager.manager.StartConnect();
        }
    }
}

SquareManager类

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.UI;

//两个目标点
public enum SquareTarget
{
    TargetPoint1,
    TargetPoint2
}
public class SquareManager : MonoBehaviour
{
    public static SquareManager manager;//单例

    //储存所有方块
    public Square[] squares1;
    public Square[] squares2;
    public Square[] squares3;
    public Square[] squares4;
    public Square[,] squares = new Square[4,4];

    Dictionary<Vector2, List<int>> road = new Dictionary<Vector2, List<int>>();//路径

    //数组最大维度
    private const int MAX = 3;
    private const int MIN = 0;

    private SquareTarget target ;

    //判断是否完成
    bool isChecked1, isChecked2;

    //记录Connect方法执行第一次,第一次执行不存储上一个点
    bool isFirstConnect = true;

    private void Awake()
    {
        if (manager == null)
            manager = this;
    }

    //初始化数组
    void Start()
    {
        for(int i = MIN; i <= MAX; i++)
        {
            for (int j = MIN; j <= MAX; j++)
            {
                if (i == 0)
                {
                    squares[j, i] = squares1[j];
                }
                if (i == 1)
                {
                    squares[j, i] = squares2[j];
                }
                if (i == 2)
                {
                    squares[j, i] = squares3[j];
                }
                if (i == 3)
                {
                    squares[j, i] = squares4[j];
                }
            }
        }

        StartConnect();
    }

    //核心方法,根据来的流向和方块类型还有方块状态判断向下递归
    public bool CheckConnect(int x, int y, int comeDir, int lastX, int lastY, int lastDir)
    {
        //保存上一步方块,保存当前方块的话会导致一直高亮
        if (!isFirstConnect)
        {
            if (road.ContainsKey(new Vector2(x, y)) && road[new Vector2(x, y)].Contains(comeDir))
                return false;
            if (!road.ContainsKey(new Vector2(lastX, lastY)))
            {
                road.Add(new Vector2(lastX, lastY), new List<int>() { lastDir });
            }
            else
            {
                road[new Vector2(lastX, lastY)].Add(lastDir);
            }
        }
        else
        {
            isFirstConnect = false;
        }
        //越界返回
        if (x > 3 || x < 0 || y > 3 || y < 0)
            return false;
        //结束条件
        switch (target)
        {
            case SquareTarget.TargetPoint1:
                if (x == 3 && y == 0)
                {
                    if (squares[x, y].up == 2 && comeDir == 0)
                    {
                        if (!road.ContainsKey(new Vector2(x, y)))
                        {
                            road.Add(new Vector2(x, y), new List<int>() { comeDir });
                        }
                        else if (!road[new Vector2(x, y)].Contains(comeDir))
                        {
                            road[new Vector2(x, y)].Add(comeDir);
                        }
                        isChecked1 = true;
                        Debug.Log("-----------------------------Success1-------------------------------");
                        return true;
                    }
                }
                break;
            case SquareTarget.TargetPoint2:
                if (x == 0 && y == 0)
                {
                    if ((squares[x, y].up == 2 || squares[x, y].up == 0) && comeDir == 1)
                    {
                        if (!road.ContainsKey(new Vector2(x, y)))
                        {
                            road.Add(new Vector2(x, y), new List<int>() { comeDir });
                        }
                        else if (!road[new Vector2(x, y)].Contains(comeDir))
                        {
                            road[new Vector2(x, y)].Add(comeDir);
                        }

                        isChecked2 = true;
                        Debug.Log("-----------------------------Success2-------------------------------");
                        return true;
                    }
                }
                break;
        }

        //上0 右1 下2 左3
        //根据条件递归
        switch (comeDir)
        {
            case 0:
                switch (squares[x, y].type)
                {
                    case SquareType.Yi:
                        if (squares[x, y].up == 0 || squares[x, y].up == 2)
                        {
                            CheckConnect(x, y - 1, 0, x, y, comeDir);
                        }
                        else
                        {
                            return false;
                        }
                        break;
                    case SquareType.Er:
                        if (squares[x, y].up == 1)
                        {
                            CheckConnect(x - 1, y, 1, x, y, comeDir);
                        }
                        else if (squares[x, y].up == 2)
                        {
                            CheckConnect(x + 1, y, 3, x, y, comeDir);
                        }
                        else
                        {
                            return false;
                        }
                        break;
                    case SquareType.San:
                        if (squares[x, y].up == 0)
                        {
                            CheckConnect(x - 1, y, 1, x, y, comeDir);
                            CheckConnect(x, y - 1, 0, x, y, comeDir);
                        }
                        else if (squares[x, y].up == 1)
                        {
                            CheckConnect(x - 1, y, 1, x, y, comeDir);
                            CheckConnect(x + 1, y, 3, x, y, comeDir);
                        }
                        else if (squares[x, y].up == 2)
                        {
                            CheckConnect(x + 1, y, 3, x, y, comeDir);
                            CheckConnect(x, y - 1, 0, x, y, comeDir);
                        }
                        else
                        {
                            return false;
                        }
                        break;
                    case SquareType.Si:
                        if (squares[x, y].up == 0 || squares[x, y].up == 2)
                        {
                            CheckConnect(x + 1, y, 3, x, y, comeDir);
                        }
                        else if (squares[x, y].up == 1 || squares[x, y].up == 3)
                        {
                            CheckConnect(x - 1, y, 1, x, y, comeDir);
                        }
                        else
                        {
                            return false;
                        }
                        break;
                    case SquareType.Shi:
                        CheckConnect(x, y - 1, 0, x, y, comeDir);
                        break;
                }
                break;
            case 1:
                switch (squares[x, y].type)
                {
                    case SquareType.Yi:
                        if (squares[x, y].up == 1 || squares[x, y].up == 3)
                        {
                            CheckConnect(x - 1, y, 1, x, y, comeDir);
                        }
                        else
                        {
                            return false;
                        }
                        break;
                    case SquareType.Er:
                        if (squares[x, y].up == 2)
                        {
                            CheckConnect(x, y + 1, 2, x, y, comeDir);
                        }
                        else if (squares[x, y].up == 3)
                        {
                            CheckConnect(x, y - 1, 0, x, y, comeDir);
                        }
                        else
                        {
                            return false;
                        }
                        break;
                    case SquareType.San:
                        if (squares[x, y].up == 1)
                        {
                            CheckConnect(x, y + 1, 2, x, y, comeDir);
                            CheckConnect(x - 1, y, 1, x, y, comeDir);
                        }
                        else if (squares[x, y].up == 2)
                        {
                            CheckConnect(x, y + 1, 2, x, y, comeDir);
                            CheckConnect(x, y - 1, 0, x, y, comeDir);
                        }
                        else if (squares[x, y].up == 3)
                        {
                            CheckConnect(x, y - 1, 0, x, y, comeDir);
                            CheckConnect(x - 1, y, 1, x, y, comeDir);
                        }
                        else
                        {
                            return false;
                        }
                        break;
                    case SquareType.Si:
                        if (squares[x, y].up == 0 || squares[x, y].up == 2)
                        {
                            CheckConnect(x, y + 1, 2, x, y, comeDir);
                        }
                        else if (squares[x, y].up == 1 || squares[x, y].up == 3)
                        {
                            CheckConnect(x, y - 1, 0, x, y, comeDir);
                        }
                        else
                        {
                            return false;
                        }
                        break;
                    case SquareType.Shi:
                        CheckConnect(x - 1, y, 1, x, y, comeDir);
                        break;
                }
                break;
            case 2:
                switch (squares[x, y].type)
                {
                    case SquareType.Yi:
                        if (squares[x, y].up == 0 || squares[x, y].up == 2)
                        {
                            CheckConnect(x, y + 1, 2, x, y, comeDir);
                        }
                        else
                        {
                            return false;
                        }
                        break;
                    case SquareType.Er:
                        if (squares[x, y].up == 0)
                        {
                            CheckConnect(x - 1, y, 1, x, y, comeDir);
                        }
                        else if (squares[x, y].up == 3)
                        {
                            CheckConnect(x + 1, y, 3, x, y, comeDir);
                        }
                        else
                        {
                            return false;
                        }
                        break;
                    case SquareType.San:
                        if (squares[x, y].up == 0)
                        {
                            CheckConnect(x - 1, y, 1, x, y, comeDir);
                            CheckConnect(x, y + 1, 2, x, y, comeDir);
                        }
                        else if (squares[x, y].up == 2)
                        {
                            CheckConnect(x + 1, y, 3, x, y, comeDir);
                            CheckConnect(x, y + 1, 2, x, y, comeDir);
                        }
                        else if (squares[x, y].up == 3)
                        {
                            CheckConnect(x - 1, y, 1, x, y, comeDir);
                            CheckConnect(x + 1, y, 3, x, y, comeDir);
                        }
                        else
                        {
                            return false;
                        }
                        break;
                    case SquareType.Si:
                        if (squares[x, y].up == 0 || squares[x, y].up == 2)
                        {
                            CheckConnect(x - 1, y, 1, x, y, comeDir);
                        }
                        else if (squares[x, y].up == 1 || squares[x, y].up == 3)
                        {
                            CheckConnect(x + 1, y, 3, x, y, comeDir);
                        }
                        else
                        {
                            return false;
                        }
                        break;
                    case SquareType.Shi:
                        CheckConnect(x, y + 1, 2, x, y, comeDir);
                        break;
                }
                break;
            case 3:
                switch (squares[x, y].type)
                {
                    case SquareType.Yi:
                        if (squares[x, y].up == 1 || squares[x, y].up == 3)
                        {
                            CheckConnect(x + 1, y, 3, x, y, comeDir);
                        }
                        else
                        {
                            return false;
                        }
                        break;
                    case SquareType.Er:
                        if (squares[x, y].up == 0)
                        {
                            CheckConnect(x, y - 1, 0, x, y, comeDir);
                        }
                        else if (squares[x, y].up == 1)
                        {
                            CheckConnect(x, y + 1, 2, x, y, comeDir);
                        }
                        else
                        {
                            return false;
                        }
                        break;
                    case SquareType.San:
                        if (squares[x, y].up == 0)
                        {
                            CheckConnect(x, y + 1, 2, x, y, comeDir);
                            CheckConnect(x, y - 1, 0, x, y, comeDir);
                        }
                        else if (squares[x, y].up == 1)
                        {
                            CheckConnect(x, y + 1, 2, x, y, comeDir);
                            CheckConnect(x + 1, y, 3, x, y, comeDir);
                        }
                        else if (squares[x, y].up == 3)
                        {
                            CheckConnect(x, y - 1, 0, x, y, comeDir);
                            CheckConnect(x + 1, y, 3, x, y, comeDir);
                        }
                        else
                        {
                            return false;
                        }
                        break;
                    case SquareType.Si:
                        if (squares[x, y].up == 0 || squares[x, y].up == 2)
                        {
                            CheckConnect(x, y - 1, 0, x, y, comeDir);
                        }
                        else if (squares[x, y].up == 1 || squares[x, y].up == 3)
                        {
                            CheckConnect(x, y + 1, 2, x, y, comeDir);
                        }
                        else
                        {
                            return false;
                        }
                        break;
                    case SquareType.Shi:
                        CheckConnect(x + 1, y, 3, x, y, comeDir);
                        break;
                }
                break;
            default:
                return false;
        }
        return false;
    }

    //路径高亮
    void OnOffLight()
    {

        foreach (var item in squares)
        {
            if (item.type == SquareType.Si)
            {
                item.transform.GetChild(0).gameObject.SetActive(false);
                item.transform.GetChild(1).gameObject.SetActive(false);
            }
            else if (item.type == SquareType.Shi)
            {
                item.transform.GetChild(0).gameObject.SetActive(false);
                item.transform.GetChild(1).gameObject.SetActive(false);
                item.transform.GetChild(2).gameObject.SetActive(false);
            }
            else
            {
                item.transform.GetChild(0).gameObject.SetActive(false);
            }
        }
        foreach (var item in road.Keys)
        {
            if (squares[(int)item.x, (int)item.y].type == SquareType.Si)
            {
                if (squares[(int)item.x, (int)item.y].up == 0)
                {
                    foreach (var dirs in road[item])
                    {
                        if (dirs == 2 || dirs == 3)
                        {
                            squares[(int)item.x, (int)item.y].transform.GetChild(1).gameObject.SetActive(true);
                        }
                        if (dirs == 0 || dirs == 1)
                        {
                            squares[(int)item.x, (int)item.y].transform.GetChild(0).gameObject.SetActive(true);
                        }
                    }
                }
                if (squares[(int)item.x, (int)item.y].up == 1)
                {
                    foreach (var dirs in road[item])
                    {
                        if (dirs == 3 || dirs == 0)
                        {
                            squares[(int)item.x, (int)item.y].transform.GetChild(1).gameObject.SetActive(true);
                        }
                        if (dirs == 2 || dirs == 1)
                        {
                            squares[(int)item.x, (int)item.y].transform.GetChild(0).gameObject.SetActive(true);
                        }
                    }
                }
                if (squares[(int)item.x, (int)item.y].up == 2)
                {
                    foreach (var dirs in road[item])
                    {
                        if (dirs == 2 || dirs == 3)
                        {
                            squares[(int)item.x, (int)item.y].transform.GetChild(0).gameObject.SetActive(true);
                        }
                        if (dirs == 0 || dirs == 1)
                        {
                            squares[(int)item.x, (int)item.y].transform.GetChild(1).gameObject.SetActive(true);
                        }
                    }
                }
                if (squares[(int)item.x, (int)item.y].up == 3)
                {
                    foreach (var dirs in road[item])
                    {
                        if (dirs == 3 || dirs == 0)
                        {
                            squares[(int)item.x, (int)item.y].transform.GetChild(0).gameObject.SetActive(true);
                        }
                        if (dirs == 2 || dirs == 1)
                        {
                            squares[(int)item.x, (int)item.y].transform.GetChild(1).gameObject.SetActive(true);
                        }
                    }
                }
            }
            else if (squares[(int)item.x, (int)item.y].type == SquareType.Shi)
            {
                if (squares[(int)item.x, (int)item.y].up == 0 || squares[(int)item.x, (int)item.y].up == 2)
                {
                    foreach (var dirs in road[item])
                    {
                        if (dirs == 0 || dirs == 2)
                        {
                            squares[(int)item.x, (int)item.y].transform.GetChild(0).gameObject.SetActive(true);
                        }
                        if (dirs == 3 || dirs == 1)
                        {
                            squares[(int)item.x, (int)item.y].transform.GetChild(1).gameObject.SetActive(true);
                        }
                    }
                }
                if (squares[(int)item.x, (int)item.y].up == 1 || squares[(int)item.x, (int)item.y].up == 3)
                {
                    foreach (var dirs in road[item])
                    {
                        if (dirs == 0 || dirs == 2)
                        {
                            squares[(int)item.x, (int)item.y].transform.GetChild(1).gameObject.SetActive(true);
                        }
                        if (dirs == 3 || dirs == 1)
                        {
                            squares[(int)item.x, (int)item.y].transform.GetChild(0).gameObject.SetActive(true);
                        }
                    }
                }
                if (squares[(int)item.x, (int)item.y].transform.GetChild(0).gameObject.activeSelf && squares[(int)item.x, (int)item.y].transform.GetChild(1).gameObject.activeSelf)
                {
                    squares[(int)item.x, (int)item.y].transform.GetChild(2).gameObject.SetActive(true);
                }
            }
            else
            {
                squares[(int)item.x, (int)item.y].transform.GetChild(0).gameObject.SetActive(true);
                
            }
        }
    }

    //统一调用
        public void StartConnect()
    {
        target = SquareTarget.TargetPoint2;
        isFirstConnect = true;
        CheckConnect(3, 3, 1,3,3,1);

        //这一步是为了实现从第二个点向外路径高亮
        target = SquareTarget.TargetPoint2;
        isFirstConnect = true;
        CheckConnect(3, 0, 1, 3, 0, 1);
        OnOffLight();
        road.Clear();

        target = SquareTarget.TargetPoint1;
        isFirstConnect = true;
        CheckConnect(3, 3, 1,3,3,1);
        road.Clear();

        if (isChecked1 && isChecked2)
        {
            Debug.Log("-----------------------------Success-------------------------------");
        }

        isChecked1 = false;
        isChecked2 = false;
    }
}