利用IMGUI实现井字棋小游戏

这是3D游戏编程课程的第一次作业,主要是为了我们熟悉OnGUI事件,并提升我们的API文档阅读能力。
作业展示视频链接:点我直达
因此,在开始正文之前,先贴一下官方API手册中的IMGUI部分的链接~点我直达

仔细阅读API文档之后,我可以了解到,Unity3D中的IMGUI的控制和传统的界面控制有所不同,我平时更加适应的是Listener模式,即对UI事件进行监听,监听到事件后进行操作,改变UI界面。但是Unity3D中,界面是不断刷新的,因此,想要改变界面,就应该在设计界面的时候,在相应的地方使用变量,实际操作时,改变变量的值即可改变界面的显示。

因此,我在项目中,设计了3个变量。

    private int[] chessState;   //存储棋盘上每个棋子位的状态,空为0,下了X为1,下了O为-1
    private int onTurn;     //存储接下来落子的顺序 首先是X下,为1,O为-1
    private int info;   //存储游戏状态信息,等待开始状态为0,对弈状态为1,有一方获胜为2,平局为3

并在Start()函数中进行初始化。

    private void Start()
    {            
        chessState = new int[9];  //对三个变量进行初始化
        onTurn = 1;
        info = 0;
    }

接下来,要做的是设计棋盘,首先是选择布局方式,官方提供给我们的一共有两种布局方式,手动布局和自动布局,由于我不想输一堆乱七八糟的数字,所以我选择了自动布局的方式。自动布局一共分了五行三列。在OnGUI()函数中。代码如下:

    private void OnGUI() //采用自动布局方式,分为3列五行,居中显示
    {
        GUILayout.BeginArea(new Rect(Screen.width/2-75, Screen.height/2-125, 150, 250));
        GUILayout.BeginVertical();
        GUILayout.BeginHorizontal();
        InitChess(0);
        InitChess(1);
        InitChess(2);
        GUILayout.EndHorizontal();
        GUILayout.BeginHorizontal();
        InitChess(3);
        InitChess(4);
        InitChess(5);
        GUILayout.EndHorizontal();
        GUILayout.BeginHorizontal();
        InitChess(6);
        InitChess(7);
        InitChess(8);
        GUILayout.EndHorizontal();
        GUILayout.BeginHorizontal();
        GUILayout.Label(InfoMap(info));
        GUILayout.EndHorizontal();
        GUILayout.BeginHorizontal();
        if (GUILayout.Button("ReStart"))
        {
            ResetGame();
        }
        GUILayout.EndHorizontal();
        GUILayout.EndVertical();
        GUILayout.EndArea();

        CheckWin();
    }

OnGUI函数中,要做的主要就是以上几件事情。首先,利用GUILayout的BeginArea,BeginVertical,BeginHorizontal函数进行布局,其次,根据InitChess函数装载显示棋盘和更改棋盘,利用Lable标签进行游戏信息的显示,设置ReStart按钮帮助用户重新开始游戏。设置检查对局状态的函数CheckWin()。关于函数的命名,有一点挺有意思的,VS会提示我函数名的命名首字母要大写,这和别的语言不太一样。
接下来我一个一个介绍这些函数。首先是InitChess();

    private void InitChess(int x)  //用于生成棋盘与棋子的方法
    {
        if (GUILayout.Button(ChessMap(chessState[x])))
        {
            if (chessState[x] == 0 && info < 2)
            {
                chessState[x] = onTurn;
                onTurn = -onTurn;
            }
        }
    }

输入的参数是棋盘格子的序号,一共九个格子,从左往右从上到下依次编号,创建格子时,要对其状态进行判断,这个格子上是空的,是放了“X”棋子,还是放了“O”棋子,这些信息被存储在chessState这个变量中。当按钮被点击时,需要判断这个按钮上是不是已经有棋子了,还有现在是不是已经有人获胜了,如果是的话,就不需要操作,只有在该格子没有棋子且两人还在对弈状态时,才可以下子。下子后,要更改chessState变量中该格子的状态,并将onTurn中存储的信息改变。另外,为了方便显示棋子,我还写了一个工具函数,用于将棋子状态转换为具体显示的信息。该工具函数如下:

    private string ChessMap(int x)  //工具函数,将chessState内的值转化为显示的棋子
    {
        switch (x)
        {
            case 0: return "";
            case 1: return "X";
            case -1: return "O";
            default: return "wrong";
        }
    }

然后是设置显示游戏信息的标签

GUILayout.Label(InfoMap(info));

同样,为了方便显示,我又写了一个工具函数,如下:

    private string InfoMap(int x)   //工具函数,将info的值转化为具体的游戏信息与提示
    {
        switch (x)
        {
            case 0: return "Prapre to start the game!";
            case 1: return "It's " + ChessMap(onTurn) + "'s turn.";
            case 2: return ChessMap(-onTurn) + " win!";
            case 3: return "You are about the same!";
            default: return "wrong!";
        }
    }

这里需要注意一点,就是自动布局和手动布局中空间的创建方式是不一样的,在手动布局中,是GUI.Lable,而在自动布局中,是GUILayout.Lable。
接下来是ReStart按钮,用于重置游戏,其实本质就是重置一开始设置的变量,并没有啥技术含量。

    private void ResetGame()    //初始化游戏
    {
        for (int i = 0; i < 9; i++)
        {
            chessState[i] = 0;
            onTurn = 1;
            info = 1;
        }
    }

最后是一个检查是否获胜或者平局的CheckWin函数。共有八种获胜的方式,这里采用穷举法,而对于平局的判断,则是判断在没有获胜的情况下,棋盘是否已经被下满。

    private void CheckWin()  //检查是否有一方获胜或者平局,通过穷举八种或者的情况判断获胜,在未获胜的情况下棋子下满即为平局。
    {
        if (Math.Abs(chessState[0]+chessState[1]+chessState[2])==3 ||
            Math.Abs(chessState[3] + chessState[4] + chessState[5]) == 3 ||
            Math.Abs(chessState[6] + chessState[7] + chessState[8]) == 3 ||
            Math.Abs(chessState[0] + chessState[3] + chessState[6]) == 3 ||
            Math.Abs(chessState[1] + chessState[4] + chessState[7]) == 3 ||
            Math.Abs(chessState[2] + chessState[5] + chessState[8]) == 3 ||
            Math.Abs(chessState[0] + chessState[4] + chessState[8]) == 3 ||
            Math.Abs(chessState[2] + chessState[4] + chessState[6]) == 3 )
        {
            info = 2;
        }
        else
        {
            bool draw = true;
            for (int i = 0; i < 9; i++)
            {
                if (chessState[i] == 0)
                {
                    draw = false;
                    break;
                }
            }
            if (draw) info = 3;
        }
    }

以上就是代码的全部内容。
下面是游戏界面和使用情况。
利用IMGUI实现井字棋小游戏_第1张图片
利用IMGUI实现井字棋小游戏_第2张图片
完整代码和项目信息请参考我的Giyhub。点我直达

你可能感兴趣的:(Unity3D学习)