用Unity3D实现简单的井字棋小游戏
用Unity3D實(shí)現(xiàn)簡(jiǎn)單的井字棋小游戲
項(xiàng)目地址
井字棋小游戲
完成效果圖
實(shí)現(xiàn)思路
首先定義游戲的數(shù)據(jù)部分:
/* 井字棋中每一個(gè)棋格中的邏輯控制常量,代表這個(gè)棋格的狀態(tài) */ private const int NOPLAYER = 0; // 0代表這個(gè)棋格沒(méi)有玩家 private const int PLAYER1 = 1; // 1代表玩家1占據(jù)這個(gè)棋格 private const int PLAYER2 = 2; // 2代表玩家2占據(jù)這個(gè)棋格/* 整個(gè)游戲需要用到的邏輯控制變量 */ private int gameTurn = PLAYER1; // 游戲回合,PLAYER1代表這個(gè)游戲回合是玩家1的,PLAYER2代表是玩家2的回合 private int totalMoves = 0; // 兩個(gè)玩家總共進(jìn)行的回合數(shù) private int totalPlayer = 0; // 游戲的玩家數(shù),0代表還未選擇游戲模式,1代表與電腦進(jìn)行對(duì)決,2代表雙人游戲 private int [,] chessBoard = new int [3, 3]; // 井字棋盤/* 井字棋棋格的布局設(shè)置 */ private static int buttonWidth = 80; // 每個(gè)棋格的寬度 private static int buttonHeight = 80; // 每個(gè)棋格的高度 // 井字棋中最左上角第一個(gè)棋格的橫坐標(biāo)位置 private static int firstButtonX = (Screen.width - 3 * TicTacToe.buttonWidth) / 2; // 井字棋中最左上角第一個(gè)棋格的縱坐標(biāo)位置 private static int firstButtonY = Screen.height - 3 * TicTacToe.buttonHeight - 10;/* 游戲界面設(shè)計(jì)用到的變量 */ public Texture2D backgroundImage; // 游戲背景圖片 public GUISkin gameSkin; // 游戲控件的皮膚風(fēng)格接著確定游戲界面組成部分:
可以看到,游戲界面由四個(gè)部分組成:背景、標(biāo)題、提示框、按鈕,其中按鈕又分為游戲模式選擇按鈕、棋格按鈕、重置按鈕三個(gè)部分,所以在最終顯示場(chǎng)景的OnGUI()方法中,只有一個(gè)PlayGameSystem()方法,在PlayGameSystem()方法中,只有AddBackground()、AddTitle()、AddTip()、AddButton()四個(gè)方法,分別添加背景、標(biāo)題、提示框、按鈕這四個(gè)部分。
在AddBackground()、AddTitle()這兩個(gè)方法中,沒(méi)有使用到什么復(fù)雜的邏輯,直接創(chuàng)建背景和標(biāo)題即可:
/* 添加游戲背景 */ void AddBackground() {GUIStyle backgroundStyle = new GUIStyle();// 設(shè)置游戲背景圖片backgroundStyle.normal.background = backgroundImage;GUI.Label(new Rect(0, 0, 710, 388), "", backgroundStyle); }/* 添加游戲標(biāo)題 */ void AddTitle() {// 設(shè)置標(biāo)題樣式GUIStyle titleStyle = new GUIStyle();titleStyle.fontSize = 40;titleStyle.fontStyle = FontStyle.Bold;titleStyle.normal.textColor = Color.black;// 標(biāo)題顯示內(nèi)容為TicTacToe GameGUI.Label(new Rect(Screen.width / 2 - 150, 20, 300, 50), "TicTacToe Game", titleStyle); }在AddTip()這個(gè)方法中,除了設(shè)置皮膚風(fēng)格外,還有一個(gè)GetTipText()方法,根據(jù)游戲的不同狀態(tài)和是否有贏家,提示框的顯示內(nèi)容都在其中進(jìn)行處理,方法代碼如下:
/* 添加提示框 */ void AddTip() {// 選擇Label的皮膚風(fēng)格GUI.skin = gameSkin;// 根據(jù)是否有贏家獲得提示框中的內(nèi)容string text = GetTipText();// 繪制出提示框GUI.Label(new Rect(Screen.width / 2 - 320, 70, 650, 50), text); }/* 根據(jù)是否有贏家獲得提示框中的內(nèi)容 */ string GetTipText() {// 檢查是否有贏家int winner = CheckWinner();switch (winner) {// 如果沒(méi)有贏家case NOPLAYER:// 如果總玩家數(shù)為0,即還未選擇游戲模式,那么提示選擇游戲模式if (totalPlayer == 0) {return "Please choose a game mode.";} else if (totalMoves == 0) { // 如果總回合數(shù)為0,說(shuō)明還未開始游戲,提示點(diǎn)擊棋格并進(jìn)行游戲return "Click and play the game.";} else if (totalMoves == 9) { // 如果總回合數(shù)為9,說(shuō)明游戲結(jié)束且無(wú)玩家勝出,提示沒(méi)有贏家return "No Winner!";} else {// 如果是單人模式且游戲正在進(jìn)行,提醒正在進(jìn)行單人游戲模式if (totalPlayer == 1) {return "1 Player Mode Playing...";} else if (totalPlayer == 2) { // 如果是雙人模式且游戲正在進(jìn)行,提醒正在進(jìn)行雙人游戲模式return "2 Players Mode Playing...";}return "";}// 如果玩家1勝出case PLAYER1:// 提示框顯示玩家1勝出return "Player1(O) Wins!";// 如果玩家2勝出case PLAYER2:// 提示框顯示玩家2勝出return "Player2(X) Wins!";default:return "";} }檢查是否有贏家,需要用到表示棋盤狀態(tài)的一個(gè)二維數(shù)組chessBoard,聲明如下:
private int [,] chessBoard = new int [3, 3]; // 井字棋盤在這個(gè)用二維整型數(shù)組表示的棋盤中,0代表棋格沒(méi)有玩家,1代表玩家1占據(jù)這個(gè)棋格,2代表玩家2占據(jù)這個(gè)棋格,用CheckWinner()方法對(duì)這個(gè)棋盤進(jìn)行檢查,可以知道是否存在贏家,代碼如下(NOPLAYER代表0,PLAYER1代表1,PLAYER2代表2):
/* 檢查是否有贏家 */ int CheckWinner() {// 一共有8種贏的情況,首先檢查3行3列的6種贏的情況for (int i = 0; i < 3; ++i) {if (chessBoard[i, 0] != NOPLAYER && chessBoard[i, 0] == chessBoard[i, 1] && chessBoard[i, 1] == chessBoard[i, 2]) {// 有玩家勝出,那么游戲回合置為NOPLAYER,返回這個(gè)玩家對(duì)應(yīng)的值,1代表玩家1,2代表玩家2gameTurn = NOPLAYER;return chessBoard[i, 0];}if (chessBoard[0, i] != NOPLAYER && chessBoard[0, i] == chessBoard[1, i] && chessBoard[1, i] == chessBoard[2, i]) {gameTurn = NOPLAYER;return chessBoard[0, i];}}// 檢查對(duì)角線的2種贏的情況if (chessBoard[1, 1] != NOPLAYER) {if ((chessBoard[0, 0] == chessBoard[1, 1] && chessBoard[1, 1] == chessBoard[2, 2]) || (chessBoard[0, 2] == chessBoard[1, 1] && chessBoard[1, 1] == chessBoard[2, 0])) {gameTurn = NOPLAYER;return chessBoard[1, 1];}}// 沒(méi)人勝出,那么返回NOPLAYER,代表沒(méi)有贏家return NOPLAYER; }根據(jù)游戲狀態(tài)和贏家判斷,就會(huì)在提示框顯示相應(yīng)的內(nèi)容。
最后是AddButton()方法,里面處理設(shè)置按鈕風(fēng)格以外,由三個(gè)方法AddGameButton()、AddResetButton()、AddChooseGameModeButton()組成,分別是添加棋盤、添加重置按鈕、添加游戲模式選擇按鈕:
/* 添加按鈕實(shí)現(xiàn)的井字棋格和功能按鈕 */ void AddButton() {// 選擇按鈕的皮膚風(fēng)格GUI.skin = gameSkin;// 添加井字棋格AddGameButton();// 添加重置按鈕AddResetButton();// 添加游戲模式選擇按鈕AddChooseGameModeButton(); }在AddResetButton()、AddChooseGameModeButton()方法中,沒(méi)有用到過(guò)于復(fù)雜的邏輯,只有用到一個(gè)InitGameWithTotalPlayer(int playersNum)的初始化游戲方法,代碼如下:
/* 添加重置按鈕 */ void AddResetButton() {GUIStyle resetStyle = new GUIStyle("button");resetStyle.fontSize = 20;// 按下重置按鈕,游戲被初始化if (GUI.Button(new Rect(firstButtonX + 3 * buttonWidth + 50, Screen.height - 70, 80, 50), "Reset", resetStyle)) {InitGameWithTotalPlayer(totalPlayer);} }/* 添加游戲模式選擇按鈕 */ void AddChooseGameModeButton() {GUIStyle resetStyle = new GUIStyle("button");resetStyle.fontSize = 20;// 按下單人游戲模式按鈕,游戲被初始化,游戲玩家人數(shù)變?yōu)?if (GUI.Button(new Rect(firstButtonX - 200, Screen.height - 2 * buttonHeight - 40, 180, 50), "1 Player Mode", resetStyle)) {InitGameWithTotalPlayer(1);}// 按下雙人游戲模式按鈕,游戲被初始化,游戲玩家人數(shù)變?yōu)?if (GUI.Button(new Rect(firstButtonX - 200, Screen.height - buttonHeight - 40, 180, 50), "2 Players Mode", resetStyle)) {InitGameWithTotalPlayer(2);} }/* 用游戲的玩家數(shù)初始化游戲 */ void InitGameWithTotalPlayer(int playersNum) {// 游戲回合從Player1開始gameTurn = PLAYER1;// 總進(jìn)行回合數(shù)設(shè)為0totalMoves = 0;// 設(shè)置游戲的玩家數(shù)totalPlayer = playersNum;// 棋盤的每一格都還沒(méi)被玩家占據(jù)for (int i = 0; i < 3; ++i) {for (int j = 0; j < 3; ++j) {chessBoard[i, j] = NOPLAYER;}} }在AddGameButton()方法中,按照坐標(biāo)從左往右,從上往下設(shè)置棋格按鈕的樣式和功能,用到的是GetGameButtonText(int xIndex, int yIndex)和SetGameButtonFunction(int xIndex, int yIndex)方法,這個(gè)方法根據(jù)游戲模式以及chessBoard中的棋格狀態(tài),設(shè)置按鈕的功能和內(nèi)容,代碼如下:
/* 添加井字棋格 */ void AddGameButton() {// 按照坐標(biāo)從左往右,從上往下設(shè)置棋格按鈕的樣式和功能for (int xIndex = 0; xIndex < 3; ++xIndex) {for (int yIndex = 0; yIndex < 3; ++yIndex) {// 按照橫縱坐標(biāo)找到棋格相應(yīng)的位置int buttonX = firstButtonX + xIndex * buttonWidth;int buttonY = firstButtonY + yIndex * buttonHeight;string text = GetGameButtonText(xIndex, yIndex);if (GUI.Button(new Rect(buttonX, buttonY, buttonWidth, buttonHeight), text)) {SetGameButtonFunction(xIndex, yIndex);}}} }/* 根據(jù)橫坐標(biāo)和縱坐標(biāo)獲取棋盤相應(yīng)位置從而獲取井字棋格內(nèi)容 */ string GetGameButtonText(int xIndex, int yIndex) {// 按照橫縱坐標(biāo)找到棋格相應(yīng)的位置int buttonX = firstButtonX + xIndex * buttonWidth;int buttonY = firstButtonY + yIndex * buttonHeight;// 獲取對(duì)應(yīng)坐標(biāo)中棋格的信息int Player = chessBoard[yIndex, xIndex];switch (Player) {// 如果這個(gè)棋格中為NOPLAYERcase NOPLAYER:// 設(shè)置按鈕中不顯示任何內(nèi)容return "";// 如果這個(gè)棋格中為PLAYER1case PLAYER1:// 棋格中顯示內(nèi)容為Oreturn "O";// 如果這個(gè)棋格中為PLAYER2case PLAYER2:// 棋格中顯示內(nèi)容為Xreturn "X";default:return "";} }/* 根據(jù)橫坐標(biāo)和縱坐標(biāo)獲取棋盤相應(yīng)位置從而設(shè)置相應(yīng)棋格功能 */ void SetGameButtonFunction(int xIndex, int yIndex) {int Player = chessBoard[yIndex, xIndex];switch (Player) {// 如果這個(gè)棋格中為NOPLAYERcase NOPLAYER:// 如果還未選擇游戲模式,那么進(jìn)行提示,且點(diǎn)擊按鈕無(wú)反應(yīng)if (totalPlayer == 0) {return;}// 選擇游戲模式并點(diǎn)擊棋格后,該棋格設(shè)置為這個(gè)游戲回合對(duì)應(yīng)的玩家,游戲回合轉(zhuǎn)換,總回合數(shù)加一chessBoard[yIndex, xIndex] = gameTurn;gameTurn = (gameTurn == PLAYER1 ? PLAYER2 : PLAYER1);totalMoves++;// 如果是單人游戲模式且游戲還未結(jié)束,那么電腦直接來(lái)走一步if (totalPlayer == 1 && totalMoves < 9 && CheckWinner() == NOPLAYER) {ComputerMove();}break;// 如果這個(gè)棋格中為PLAYER1,無(wú)反應(yīng)case PLAYER1:break;// 如果這個(gè)棋格中為PLAYER2,無(wú)反應(yīng)case PLAYER2:break;} }最后在PlayGameSystem()方法中添加背景、標(biāo)題、提示框、游戲按鈕,游戲就可以運(yùn)行了,代碼如下:
/* 進(jìn)行游戲 */ void PlayGameSystem() {AddBackground(); // 添加游戲背景AddTitle(); // 添加游戲標(biāo)題AddTip(); // 添加提示框AddButton(); // 添加游戲按鈕 }void OnGUI() {PlayGameSystem(); }游戲截圖:
玩家1勝出:
玩家2勝出:
打成平局:
總結(jié)
以上是生活随笔為你收集整理的用Unity3D实现简单的井字棋小游戏的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 操作系统实验报告18:硬盘柱面访问调度算
- 下一篇: 用Unity3D实现简单的牧师与魔鬼游戏