离散仿真引擎基础作业与练习(二)

离散仿真引擎基础作业与练习(二)

二、编程实践,小游戏

  • 游戏内容: 井字棋 或 贷款计算器 或 简单计算器 等等
  • 技术限制: 仅允许使用 IMGUI 构建 UI
  • 作业目的:

    • 提升 debug
    • 能力 提升阅读 API 文档能力

    制作思路:
    首先我们想想井字棋是怎么玩的:有两个玩家(player)、轮流下棋(turn)、棋子分黑白(mark)、棋盘3X3(state)、最后分胜负手(winner);于是我们可以声明这些变量:

    char markForPlayer1 = '@';//玩家1的棋子
    char markForPlayer2 = '#';//玩家2的棋子
    int winner;//0表示没有人获胜,1表示玩家1获胜,2表示玩家2获胜;
    int turn;//表示当前是那个玩家的回合,1表示玩家1的回合,2表示玩家2的回合;
    char[,] state = new char[3, 3];//使用字符表示每个方格的状态;

    开始游戏的时候初始化:

    void Start () {
        //初始化:
        winner = 0;
        turn = 1;//玩家1先手
        for(int i =0; i < 3; i++)
        {
            for(int j = 0; j < 3; j++)
            {
                state[i,j] = ' ' ;//棋盘为空
            }
        }
    }

    然后就是渲染棋盘了,重置棋盘(reset)和棋盘上每个位置都做成按钮可以按下;输赢信息和轮次信息不能按下,做成label。
    之后这里就需要一些API的帮助了,根据官方文档: bool GUI.Button(new Rect(double x,double y,double width,double height), “name”)这个函数非常好用,它可以在位置(x,y)创建一个名字name,宽度width,高度height的button,并且返回一个bool值表示这个按钮是否被按下。最终写出每次显示的页面(写在OnGUI函数中,这个函数每一帧被多次调用,以保证不停刷新页面):

    private void OnGUI()
    {
       //先检查有没有玩家获胜:
       getWinner();
       //根据是否有胜负手决定是否显示相关信息,使用label显示信息
       if(winner != 0)
       {
           if (winner == 1)
           {
               GUI.Label(new Rect(labelPositionX,labelPositionY-labelHeight,labelWidth,labelHeight), " Player1 win!");
           } else
           {
               GUI.Label(new Rect(labelPositionX, labelPositionY - labelHeight, labelWidth, labelHeight), " Player2 win!");
           }
       }
    
       //显示现在是谁的回合,使用label显示轮次信息
       if (turn == 1)
       {
           GUI.Label(new Rect(labelPositionX, labelPositionY, labelWidth, labelHeight), "Player1's turn");
       }
       else
       {
           GUI.Label(new Rect(labelPositionX, labelPositionY, labelWidth, labelHeight), "Player2's turn");
       }
    
       //显示整个游戏主界面,每次都打印3X3方格,根据每个方格状态信息(是黑子还是白子占据还是没有棋子)填充button
       for (int i = 0; i < 3; i++)
       {
           for(int j = 0; j < 3; j++)
           {
               if (state[i,j] == ' ')
               {
                   //如果有玩家点击未落子的点就显示落下的棋子并且交换回合
                   if (GUI.Button(new Rect(buttonPositionX + i * buttonWidth, buttonPositionY + j * buttonHeight, buttonWidth, buttonHeight), "" + state[i, j])&&winner==0)
                   {
                       state[i, j] = (turn==1?markForPlayer1:markForPlayer2);
                       turn = 3 - turn;//交换回合
                   }
               } else
               {
                   //显示棋盘的黑白子
                   GUI.Button(new Rect(buttonPositionX + i * buttonWidth, buttonPositionY + j * buttonHeight, buttonWidth, buttonHeight), "" + state[i, j]);
               }
    
           }
       }
    

    其中的getwinner函数如下,直接遍历三行三列以及两个对角线:

    void getWinner()
    {
        for (int i = 0; i < 3; i++)
        {
            if (state[i,0] == state[i, 1]&& state[i, 0] == state[i, 2]&&state[i,0]!=' ')
            {
                if (state[i,0] == markForPlayer1)
                {
                    winner = 1;
                } else
                {
                    winner = 2;
                }
            }
        }
        for (int i = 0; i < 3; i++)
        {
            if (state[0, i] == state[1, i] && state[0, i] == state[2, i] && state[0, i] != ' ')
            {
                if (state[0,i] == markForPlayer1)
                {
                    winner = 1;
                }
                else
                {
                    winner = 2;
                }
            }
        }
        if(state[0,0] == state[2,2]&& state[0, 0] == state[1,1] && state[1, 1] != ' ')
        {
            if(state[1,1]==markForPlayer1)
            {
                winner = 1;
            } else
            {
                winner = 2;
            }
        }
        if (state[0, 2] == state[1, 1] && state[1, 1] == state[2, 0] && state[1, 1] != ' ')
        {
            if (state[1, 1] == markForPlayer1)
            {
                winner = 1;
            }
            else
            {
                winner = 2;
            }
        }
    }

    然后基本就完成了,不过这个棋盘还只够玩家玩一次,,,还应该能够重置棋盘(相当于重新初始化一次,所以就直接调用start了):

        //玩家可以重玩
    if (GUI.Button(new Rect(resetPositionX, resetPositionY, resetWidth, resetHeight), "reset"))
    {
        Start();
    }

    然后就完成了,完整代码如下:

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class littleGame : MonoBehaviour {
        char markForPlayer1 = '@';
        char markForPlayer2 = '#';
        int winner;//0表示没有人获胜,1表示玩家1获胜,2表示玩家2获胜;
        int turn;//表示当前是那个玩家的回合,1表示玩家1的回合,2表示玩家2的回合;
        char[,] state = new char[3, 3];//使用字符表示每个方格的状态;
        //这个是两个label的位置大小信息
        int labelPositionX = 420;
        int labelPositionY = 360;
        int labelWidth = 80;
        int labelHeight = 40;
        //这个是reset按钮的位置大小信息
        int resetPositionX = 440;
        int resetPositionY = 520;
        int resetWidth = 40;
        int resetHeight = 40;
        //这个是棋盘每个格子的位置大小信息
        int buttonPositionX = 400;
        int buttonPositionY = 400;
        int buttonWidth = 40;
        int buttonHeight = 40;
    
        // Use this for initialization
        void Start () {
            //初始化:
            winner = 0;
            turn = 1;
            for(int i =0; i < 3; i++)
            {
                for(int j = 0; j < 3; j++)
                {
                    state[i,j] = ' ' ;
                }
            }
        }
        //检查是否有玩家获胜的函数:
        void getWinner()
        {
            for (int i = 0; i < 3; i++)
            {
                if (state[i,0] == state[i, 1]&& state[i, 0] == state[i, 2]&&state[i,0]!=' ')
                {
                    if (state[i,0] == markForPlayer1)
                    {
                        winner = 1;
                    } else
                    {
                        winner = 2;
                    }
                }
            }
            for (int i = 0; i < 3; i++)
            {
                if (state[0, i] == state[1, i] && state[0, i] == state[2, i] && state[0, i] != ' ')
                {
                    if (state[0,i] == markForPlayer1)
                    {
                        winner = 1;
                    }
                    else
                    {
                        winner = 2;
                    }
                }
            }
            if(state[0,0] == state[2,2]&& state[0, 0] == state[1,1] && state[1, 1] != ' ')
            {
                if(state[1,1]==markForPlayer1)
                {
                    winner = 1;
                } else
                {
                    winner = 2;
                }
            }
            if (state[0, 2] == state[1, 1] && state[1, 1] == state[2, 0] && state[1, 1] != ' ')
            {
                if (state[1, 1] == markForPlayer1)
                {
                    winner = 1;
                }
                else
                {
                    winner = 2;
                }
            }
        }
        //每一帧都刷新屏幕:显示最新的状态
        private void OnGUI()
        {
            //先检查有没有玩家获胜:
            getWinner();
            if(winner != 0)
            {
                if (winner == 1)
                {
                    GUI.Label(new Rect(labelPositionX,labelPositionY-labelHeight,labelWidth,labelHeight), " Player1 win!");
                } else
                {
                    GUI.Label(new Rect(labelPositionX, labelPositionY - labelHeight, labelWidth, labelHeight), " Player2 win!");
                }
            }
    
            //显示现在是谁的回合
            if (turn == 1)
            {
                GUI.Label(new Rect(labelPositionX, labelPositionY, labelWidth, labelHeight), "Player1's turn");
            }
            else
            {
                GUI.Label(new Rect(labelPositionX, labelPositionY, labelWidth, labelHeight), "Player2's turn");
            }
    
            //显示整个游戏主界面
            for (int i = 0; i < 3; i++)
            {
                for(int j = 0; j < 3; j++)
                {
                    if (state[i,j] == ' ')
                    {
                        if (GUI.Button(new Rect(buttonPositionX + i * buttonWidth, buttonPositionY + j * buttonHeight, buttonWidth, buttonHeight), "" + state[i, j])&&winner==0)
                        {
                            state[i, j] = (turn==1?markForPlayer1:markForPlayer2);
                            turn = 3 - turn;//交换回合
                        }
                    } else
                    {
                        GUI.Button(new Rect(buttonPositionX + i * buttonWidth, buttonPositionY + j * buttonHeight, buttonWidth, buttonHeight), "" + state[i, j]);
                    }
    
                }
            }
    
            //玩家可以重玩
            if (GUI.Button(new Rect(resetPositionX, resetPositionY, resetWidth, resetHeight), "reset"))
            {
                Start();
            }
        }
    }
    

题外话:井字棋必定平局

emmm,其实这个东西挺容易做的,所以做完了以后我就想着做个人机对战,但是自己试着画了一下,发现
这个游戏如果双方都使用最优策略是一定会打平的,然后去网上搜了一下的确这样,比较好的分析看这里:井字棋分析

猜你喜欢

转载自blog.csdn.net/ousuixin/article/details/79720165