Unity游戏制作(一)

Unity游戏制作(一)

实验内容

  1. 编程实践:井字棋

实验环境

  • Windows

  • Unity 2020.3.18

技术日记

一、ECS框架

ECS,即 Entity-Component-System(实体-组件-系统) 的缩写,其模式遵循组合优于继承原则,游戏内的每一个基本单元都是一个实体,每个实体又由一个或多个组件构成,每个组件仅仅包含代表其特性的数据(即在组件中没有任何方法)。

一个使用ECS架构开发的游戏基本结构如下图所示:在这里插入图片描述

二、实验部分

1.使用说明

新建tictactoe文件,然后直接把tictactoe.cs文件挂在主摄像头main camera即可。

2. 代码注释
本次实验,共设置了设置了七个函数,其功能分别如下
  • ResetGame() :初始化游戏参数
void ResetGame(){
        playersTurn = false;
        firstTurn = true;
        board = new string[rows, cols];
        playerScore = new int[rows + cols + 2]; 
        computerScore = new int[rows + cols + 2];
        winner = null;
        moves = 0;
}

playersTurn设置为非玩家的回合、fisrtTurn设置为true,即启动游戏时为第一回合。初始化board,玩家分数playerScore和电脑分数computerScore,并把winner定义为空,moves移动步数定义为0。

  • Start():启动游戏
void Start(){
        ResetGame();
        delta = new Vector2Int[4] { new Vector2Int(-1, 0), new Vector2Int(0, -1), new Vector2Int(1, 0), new Vector2Int(0, 1) };
        screenCenterX = Screen.width / 2;
        screenCenterY = Screen.height / 2;
        boardWidth = rows * gridWidth + (rows - 1) * gridMargin;
        boardHeight = cols * gridHeight + (cols - 1) * gridMargin;

        boardX = screenCenterX - boardWidth / 2;
        boardY = screenCenterY - boardHeight / 2;
    }

首先调用ResetGame()函数初始化参数,然后设置好boardscreenCenter的位置

  • InRange():判断行、列是否在正确的范围内
bool InRange(int row, int col){
        return row >= 0 && row < rows && col >= 0 && col < cols;
}

定义了const int rows = 3const int cols = 3,因此此函数作用即判断行、列是否在正确的范围内。

  • AddScore():判断能否增加分数,如果可以的话记录分数增加。
void AddScore(int[] score, int row, int col){
        if (row == col){
            score[rows + cols]++;
        }

        if (row + col == rows - 1){
            score[rows + cols + 1]++;
        }

        score[row]++;
        score[rows + col]++;
        moves++;
        CheckBoard();
}
  • GameBoard():控制游戏面板,即主要程序,控制玩家和电脑的落子。
void GameBoard(){
        float boardWidth = rows * gridWidth + (rows - 1) * gridMargin;
        float boardHeight = cols * gridHeight + (cols - 1) * gridMargin;

        float boardX = screenCenterX - boardWidth / 2;
        float boardY = screenCenterY - boardHeight / 2;

        if(!playersTurn && winner == null){
            int row = -1, col = -1;
            if(firstTurn){
                row = Random.Range(0, rows);
                col = Random.Range(0, cols);
                firstTurn = false;
            }else{
                for(int i = 0; i < delta.Length; i++){
                    Vector2Int tmp = delta[i];
                    int r = Random.Range(i, delta.Length);
                    delta[i] = delta[r];
                    delta[r] = tmp;
                }

                for(int i = 0; i < delta.Length; ++i){
                    Vector2Int tryMove = delta[i] + playerLastMove;
                    int tryRow = tryMove.x;
                    int tryCol = tryMove.y;
                    if(InRange(tryRow, tryCol) && board[tryRow, tryCol] == null){
                        row = tryRow;
                        col = tryCol;
                        break;
                    }
                }

                if (row == -1 && col == -1){
                    for(int r = 0; r < rows; ++r){ 
                        for(int c = 0; c < cols; ++c){ 
                            if(board[r, c] == null)
                            {
                                row = r;
                                col = c;
                                break;
                            }
                        }
                    }
                }
            }
            playersTurn = !playersTurn;
            board[row, col] = "O";
            AddScore(computerScore, row, col);
        }

        for(int row = 0; row < 3; ++row){
            for(int col = 0; col < 3; ++col){
                float gridX = boardX + row * (gridWidth + gridMargin);
                float gridY = boardY + col * (gridHeight + gridMargin);

                bool clicked = GUI.Button(new Rect(gridX, gridY, gridWidth, gridHeight), board[row, col]);

                if(clicked && board[row, col] == null && playersTurn && winner == null){
                    board[row, col] = "X";
                    AddScore(playerScore, row, col);
                    playerLastMove = new Vector2Int(row, col);
                    playersTurn = !playersTurn;
                }
            }
        }
    }
  • Controls():控制标签的位置,给出提示信息。
    void Controls(){
        float controlWidth = boardWidth;
        float controlHeight = gridHeight;

        float statusTextX = boardX;
        float statusTextY = boardY - (gridHeight + gridMargin);

        float resetButtonX = boardX;
        float resetButtonY = boardY + rows * (gridHeight + gridMargin);

        if(GUI.Button(new Rect(resetButtonX, resetButtonY, controlWidth, controlHeight), "Restart")) {
            ResetGame();
        }

        string message;
        if(winner == null){
            message = playersTurn ? "Your turn" : "Computer's turn";
        }else{
            if(winner == "You"){
                message = winner + " win!";
            }else{
                message = winner + " wins!";
            }
        }
        GUI.Label(new Rect(statusTextX, statusTextY, controlWidth, controlHeight), message);
    }

游戏的标签部分,显示了“Restart”按钮和游戏信息message

  • CheckBoard():判断是玩家赢还是电脑赢、还是打成平手
void CheckBoard(){
        for(int i = 0; i < playerScore.Length; ++i){
            if(playerScore[i] == rows){
                winner = "You";
            }

            if (computerScore[i] == rows){
                winner = "Computer";
            }
        }

        if (moves == rows * cols && winner == null){
            winner = "Nobody";
        }
    }

因为rows是个常量为3,因此当玩家的分数为3,则玩家获胜,否则电脑获胜,如果总步数达到了九步,且分不出胜负,则打成平手。

  • OnGUI() :游戏场景渲染之后调用的函数
void OnGUI(){
        GUI.skin = skin;
        GameBoard();
        Controls();
  }

实验总结

在完成本次实验中,一开始对井字棋游戏的代码编写没有思路,以为是通过防止2D方块完成。通过查找资料后,发现是通过写代码以及UI界面,并直接把.cs文件挂到主摄像头去,因此才完成代码的编写。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值