数字配对——Unity3D小游戏

数字配对——Unity3D小游戏

游戏规则介绍

在一个n×n的棋盘中,有n×n÷2组相同数字。
玩家每次点开一个格子,显示当前格子的数字,下一次点开的数字如果和上一次的相同,那么就匹配成功。如果不相同,那么就隐藏这两次点开的数字。把所有的数字都点开匹配,则游戏结束。
点开一次算一次操作步数,完成游戏所需的操作步数越少越好。

简单来说,就是一个考验记忆力的游戏,能够记住越多点开过的数字,越快完成游戏。(当然运气好也可以快速通关)

游戏效果

难度1和难度2的游玩展示

下面是游戏中的一些画面。
左侧从上到下依次是:剩余未配对数字组数、当前难度等级、重新开始按钮。
配对

完成游戏的显示效果:
黄字提示完成游戏,并告诉你共用了多少步来完成。
游戏结束

以下是难度等级2的棋盘(6×6)
难度升级
总共设置了0~3四个难度等级,分别对应2×2,4×4,6×6,8×8四种棋盘大小。
点击左侧中间的按钮(难度等级)来调节当前难度,点击一次,难度加一级,到达3难度以后变回0难度。

游戏实现

首先创建一个空对象,用于执行脚本。
接着在Assets创建C#脚本文件Game.cs(具体代码写在Game.cs中)

在这里插入图片描述

代码采用MVC框架,即Model-View-Controller(模型-视图-控制器) 模式

先定义一些所需的数据模型

    private static int size = 4;//棋盘行、列格子数
    private int[,] chessBoard;//实际棋盘数字
    private bool[,] showBoard;//是否显示棋盘格子
    private int cell_size = 60;//每个格子长、宽
    private int showed;//已翻开未配对的数字 (-1表示不存在)
    private int showed_i, showed_j;//已翻开未配对的数字的坐标 (-1表示不存在)
    private int count;//步数
    private int remain;//剩余未匹配的数字对
    private int mode = 1;//游戏难度

再定义视图,即游戏显示界面。

 void Start()//进行游戏初始化
    {
        Init();
    }
 void OnGUI()//一直渲染
    {
        //数字字体设置
        GUIStyle fontStyle = new GUIStyle();
        fontStyle.alignment = TextAnchor.MiddleCenter;
        fontStyle.fontSize = cell_size / 2;
        fontStyle.normal.textColor = Color.white;
        //背景框
        GUI.Box(new Rect(250, 100, size * cell_size + 10, size * cell_size + 10), "");
        //提示剩余未配对
        GUI.Box(new Rect(100, 100, 100, 50), "remain:\n " + remain + " pairs");
        //重开按钮
        if (GUI.Button(new Rect(100, 250, 100, 50), "Restart")) Init();
        //选择难度
        if (GUI.Button(new Rect(100, 180, 100, 60), "Difficulty Level\n" + mode))
        {
            //点击提升难度
            AddDifficulty();
        }
        //方格棋盘
        if (!GameOver())
        {
            for (int i = 0; i < size; i++)
            {
                for (int j = 0; j < size; j++)
                {
                    //还没翻开的格子,点击方格翻开
                    if (showBoard[i, j] == false && GUI.Button(new Rect(255 + j * cell_size, 105 + i * cell_size, cell_size, cell_size),""))
                    {
                        FlopCell(i, j);
                    }
                    else if (showBoard[i, j] == true )//翻开的格子
                    {
                        GUI.Button(new Rect(255 + j * cell_size, 105 + i * cell_size, cell_size, cell_size), chessBoard[i, j] + "", fontStyle);
                    }
                }
            }
        }
        else//游戏结束提示
        {
            fontStyle.fontSize = 20;
            fontStyle.normal.textColor = Color.yellow;
            GUI.Box(new Rect(250, 10, 200, 100), "Congratulations! \n You have finished in \n " + count + " steps!", fontStyle);
        }
    }

最后写控制器函数,用于处理数据交互,修改模型的数据

    void Init()
    {
        chessBoard = new int[size, size];
        showBoard = new bool[size, size];
        count = 0;//步数清零
        remain = size * size / 2;//共有格子数的一半的数字对
        showed = showed_i = showed_j = -1;//已翻开数字和坐标都不存在
        int k = 0;
        for (int i = 0; i < size; i++)
            for (int j = 0; j < size; j++)
            {
                chessBoard[i, j] = (k++) / 2;
                showBoard[i, j] = false;
            } 
        Shuffle(chessBoard);
    }
    IEnumerator Wait(int i,int j)
    {
        yield return new WaitForSeconds(0.3f);
        showBoard[i, j] = showBoard[showed_i, showed_j] = false;
        showed = showed_i = showed_j = -1;
    }
    //随机洗牌
    void Shuffle(int[,] deck)
    {
        for (int i = 0; i < size * size ; i++)
        {
            int temp = deck[i / size, i % size];
            int randomIndex = Random.Range(i, size * size );
            deck[i / size, i % size] = deck[randomIndex / size, randomIndex % size];
            deck[randomIndex / size, randomIndex % size] = temp;
        }
    }
    void AddDifficulty()
    {
        if (mode < 3)//难度等级范围0-3
            mode++;
        else mode = 0;
        size = (mode + 1) * 2;
        Init();
    }
    //翻开方格
    void FlopCell(int i, int j)
    {
        count++;
        showBoard[i, j] = true;
        if (showed == -1)//未有翻开or翻开的都配对
        {
            showed = chessBoard[i, j];
            showed_i = i;
            showed_j = j;
        }
        else//已经有一个翻开但未配对的格子
            if (showed == chessBoard[i, j])//上次翻开的与这次翻开的匹配
            {
                remain--;
                showed = showed_i = showed_j = -1;
            }
            else//不匹配
            {
                StartCoroutine(Wait(i,j));//等待0.3s后盖上
            }
    }
    bool GameOver()
    {
        if (remain <= 0)
            return true;
        return false;
    }

这个小游戏实现的关键,在于如何处理翻开格子。
不难想到,需要记录上一次翻开的数字(showed)是什么,从而判断这次翻开的数字是否匹配。
而如果不匹配,还需要重新盖上这两个格子,所以还需要上一次翻开的格子坐标(showed_i, showed_j)才能实现。
另外,除了一个记录数字的二维数组(chessboard),还用了一个同样大小的数组(showboard)来存储当前格子是否需要翻开。

在实现了这些之后,游戏基本能正常运行了。但是很快就发现了一个被忽略的问题:玩家看不到第二次翻开时,这个不匹配的数字是什么。因为计算机执行速度极快,显示的数字一闪而过,玩家根本无法察觉这个数字是什么。
这就需要等待执行了。通过网上资料,学到了如何使用协程执行等待函数,从而实现翻开的数字等一小会再消失。

总结

在开发这个小游戏的过程中,学到了如何在Unity中等待执行代码,对于GUI的一些组件的基本熟悉了,同时也对MVC框架模式有了更深的体会。看着自己亲自完成游戏,虽然简陋,但有股莫名的自豪感!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值