3D游戏编程与设计 井字棋

作业要求

  • 游戏内容: 井字棋 或 贷款计算器 或 简单计算器 等等
  • 技术限制: 仅允许使用 IMGUI 构建 UI
  • 作业目的:
    • 了解 OnGUI() 事件,提升 debug 能力
    • 提升阅读 API 文档能力 

游戏预览

start开始游戏:

游戏结束,restart可重新开始游戏:

前置知识学习

OnGUI

查阅官方文档可得 :OnGUI: Called multiple times per frame in response to GUI events. The Layout and Repaint events are processed first, followed by a Layout and keyboard/mouse event for each input event.

即OnGUI每帧都会调用多次,先处理布局和重绘事件,再处理输入引起的布局、鼠标键盘事件。

GUI相关脚本

查阅脚本文档:GUI.Buttonicon-default.png?t=L892https://docs.unity3d.com/ScriptReference/GUI.Button.htmlGUI.Labelicon-default.png?t=L892https://docs.unity3d.com/ScriptReference/GUI.Label.htmlRecticon-default.png?t=L892https://docs.unity3d.com/ScriptReference/Rect.html其中Rect原点为左上,向右为正x,向下为正y。

分析设计

该游戏不需要实际的GameObject,事务逻辑通过OnGUI即可进行处理,所以使用一个空GameObject挂载一个脚本就可以完成游戏的编写。

棋盘通过矩阵来表示,UI实现使用GUI.Button。OnGUI每一帧都会执行,因此每次执行的逻辑是:

  • 判断是否开始游戏,绘制start\restart按钮,按下按钮触发相应事件
  • 判断游戏是否结束
  • 根据矩阵绘制棋盘,按下按钮触发相应事件

使用ECS,将实体、部件、系统三者分离,因此代码主要分为OnGUI负责交互与呈现,win、remake、start负责逻辑,变量负责数据。

代码实现

变量

    private int[, ] matrix = new int[3, 3];            // 矩阵表示九个格子
    private int player = 1;                            // 当前下棋玩家
    private bool start = false;                        // 游戏是否开始

 start

void Start()
{
    remake();            // 重置游戏
}

remake

重置关于游戏的各种变量。

    void remake()
    {
        start = false;
        player = 1;
        for(int i = 0; i < 3; i++)
        {
            for (int j = 0; j < 3; j++)
            {
                matrix[i, j] = 0;            // 重置棋盘
            }
        }
    }

win

判断是否有玩家胜利、平局、继续游戏。

    int win()
    {
        // 计算行的和是否为3或-3判断胜利
        for (int i = 0; i < 3; i++)
        {
            int sum = 0;
            for (int j = 0; j < 3; j++)
            {
                sum += matrix[i, j];
            }

            if (sum == 3)
            {
                return 1;
            }
            else if (sum == -3)
            {   
                return 2;
            }
        }

        // 计算列的和是否为3或-3判断胜利        
        for (int i = 0; i < 3; i++)
        {
            int sum = 0;
            for (int j = 0; j < 3; j++)
            {
                sum += matrix[j, i];
            }

            if (sum == 3)
            {
                return 1;
            }
            else if (sum == -3)
            {
                return 2;
            }
        }

        // 计算对角线的和是否为3或-3判断胜利
        int lr = matrix[0, 0] + matrix[1, 1] + matrix[2, 2];
        int rl = matrix[2, 0] + matrix[1, 1] + matrix[0, 2];
        if (lr == 3 || rl == 3)
        {
            return 1;
        }
        else if (lr == -3 || rl == -3)
        {
            return 2;
        }

        // 若棋盘未满,继续游戏
        for (int i = 0; i < 3; i++)
        {
            for (int j = 0; j < 3; j++)
            {
                if (matrix[i, j] == 0)
                {
                    return 0;
                }
            }
        }

        // 棋盘满则平局
        return 3;
    }

OnGUI

绘制棋盘、按钮。

    private void OnGUI()
    {
        // start和restart按钮
        if (start)
        {
            if (GUI.Button(new Rect(0, 300, 100, 50), "restart"))
            {
                remake();
            }
        }
        else
        {
            if(GUI.Button(new Rect(0, 300, 100, 50), "start"))
            {
                start = true;
            }
        }

        // 判断游戏是否结束
        int res = win();
        if (res == 3)                // 平局
        {
            GUI.Label(new Rect(0, 350, 100, 50), "draw");
        }
        else if (res == 1)            // X赢
        {
            GUI.Label(new Rect(0, 350, 100, 50), "X win");
        }
        else if (res == 2)            // O赢
        {
            GUI.Label(new Rect(0, 350, 100, 50), "O win");
        }

        // 绘制棋盘
        for (int i = 0; i < 3; i++)
        {
            for (int j = 0; j < 3; j++)
            {
                if (matrix[i, j] == 1)            //X子
                {
                    GUI.Button(new Rect(100 * i, 100 * j, 100, 100), "X");
                }
                else if (matrix[i, j] == -1)            // O子
                {
                    GUI.Button(new Rect(100 * i, 100 * j, 100, 100), "O");
                }
                else            // 空格子
                {
                    if (GUI.Button(new Rect(100 * i, 100 * j, 100, 100), ""))
                    {
                        if (start)            // 下子,并更改玩家
                        {
                            matrix[i, j] = player;
                            player = -player;
                        }
                    }
                }
            }
        }
    }

总结

  • 了解OnGUI事件,学习如何使用Button、Label编写按钮与标签;
  •  通过项目阅读了Unity的相关文档;
  • 将ECS简单运用到项目中,实现三者分离。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java井字棋是一种基于控制台输入的井字棋游戏,可以通过编写代码来实现。下面是关于Java井字棋游戏编程代码的介绍。 首先,我们需要定义一个二维数组来表示井字棋盘: ```java char[][] board = new char[3][3]; ``` 然后,我们需要将井字棋盘初始化为一个空的棋盘: ```java for(int i=0; i<3; i++){ for(int j=0; j<3; j++){ board[i][j] = '-'; } } ``` 接下来,我们需要实现控制台输入。可以使用Scanner类来读取用户的输入: ```java Scanner scanner = new Scanner(System.in); ``` 然后,我们需要让用户输入棋子的位置。可以使用以下方式来实现: ```java System.out.print("Enter row and column number (example: 1 2) : "); int row = scanner.nextInt(); int column = scanner.nextInt(); ``` 接着,我们需要根据用户输入的位置来更新井字棋盘。可以使用以下方法来实现: ```java board[row-1][column-1] = currentPlayer; ``` 在更新棋盘后,我们需要检查胜负情况。可以使用以下方法来实现: ```java public boolean checkWinner(char[][] board, char currentPlayer){ for(int i=0; i<3; i++){ if(board[i][0] == currentPlayer && board[i][1] == currentPlayer && board[i][2] == currentPlayer){ return true; } if(board[0][i] == currentPlayer && board[1][i] == currentPlayer && board[2][i] == currentPlayer){ return true; } } if(board[0][0] == currentPlayer && board[1][1] == currentPlayer && board[2][2] == currentPlayer){ return true; } if(board[0][2] == currentPlayer && board[1][1] == currentPlayer && board[2][0] == currentPlayer){ return true; } return false; } ``` 最后,我们需要交替切换玩家。可以使用以下方式来实现: ```java if(currentPlayer == 'X'){ currentPlayer = 'O'; }else{ currentPlayer = 'X'; } ``` 以上就是Java井字棋游戏编程代码的基本实现。完整代码请见下方: ```java import java.util.Scanner; public class TicTacToe { public static void main(String[] args) { char[][] board = new char[3][3]; char currentPlayer = 'X'; Scanner scanner = new Scanner(System.in); for(int i=0; i<3; i++){ for(int j=0; j<3; j++){ board[i][j] = '-'; } } printBoard(board); while(true){ System.out.print("Enter row and column number (example: 1 2) : "); int row = scanner.nextInt(); int column = scanner.nextInt(); board[row-1][column-1] = currentPlayer; printBoard(board); if(checkWinner(board, currentPlayer)){ System.out.println(currentPlayer + " has won the game!"); break; } if(isDraw(board)){ System.out.println("It's a draw!"); break; } if(currentPlayer == 'X'){ currentPlayer = 'O'; }else{ currentPlayer = 'X'; } } } public static void printBoard(char[][] board){ System.out.println("-------------"); for(int i=0; i<3; i++){ System.out.print("| "); for(int j=0; j<3; j++){ System.out.print(board[i][j] + " | "); } System.out.println(); System.out.println("-------------"); } } public static boolean checkWinner(char[][] board, char currentPlayer){ for(int i=0; i<3; i++){ if(board[i][0] == currentPlayer && board[i][1] == currentPlayer && board[i][2] == currentPlayer){ return true; } if(board[0][i] == currentPlayer && board[1][i] == currentPlayer && board[2][i] == currentPlayer){ return true; } } if(board[0][0] == currentPlayer && board[1][1] == currentPlayer && board[2][2] == currentPlayer){ return true; } if(board[0][2] == currentPlayer && board[1][1] == currentPlayer && board[2][0] == currentPlayer){ return true; } return false; } public static boolean isDraw(char[][] board){ for(int i=0; i<3; i++){ for(int j=0; j<3; j++){ if(board[i][j] == '-'){ return false; } } } return true; } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值