Unity3D井字棋小游戏
一、 一些小问题
由于这是第一次作业,业务不太熟悉,在完成的过程中遇到了一些问题,在此记录下来。
-
OnGUI()函数是每隔一段时间自动执行的,因此尽量在避免在该函数中出现次数过多的循环甚至死循环,这样可能会导致游戏无法运行,甚至整个Unity程序无法响应,最后只能任务管理器强行关闭... -
Game视角和整个游戏build and run之后的视角大小是不一样的,比如ctrl+B之后运行的游戏视角是正常的,但在点击运行按钮在程序中看到的视角是不全的。 -
一开始想要找一些图片作为游戏背景,但发现无论怎么调节图片的大小,始终无法铺满整个游戏界面,甚至当调到一定大小之后再往大调图片不会再有变化了,后来发现这是与图片本身的大小有关,因此在选择图片的时候还需要考虑其自身的大小。
二、 实现过程和方法
1. 设计思路
2. 具体函数及数据
不同系统之间要实现低耦合,故不同系统之间只留有几个接口,如GUI渲染系统则主要是利用OnGUI()函数对游戏界面进行渲染,在OnGUI()函数中,将前端收到的消息传递给后端玩家系统或游戏整体系统,具体的表现为当按钮被按下时调用玩家系统或游戏整体系统相应的函数。因此,OnGUI()函数中除了界面的渲染以外,其它基本都是函数的调用。
(1)数据部分
定义的数据如下,三个共有变量接受传入的图片,在OnGUI函数中对界面起到装饰效果。isStart变量标志游戏的状态,mode变量标志游戏模式,board二维数组是棋盘的模拟,turn表示当前轮到哪位玩家下棋。
? ?public Texture2D point;
? ?public Texture2D victory;
? ?public Texture2D balance;
?
? ?bool isStart;
? ?int mode;// 0-单人模式 1-双人模式
? ?int [,]board = new int[3,3];//0-无棋子 1-O棋子,2-X棋子
? ?int turn;// 0-player1 1-player2
? ?int chooseTurn = 0;//0-当前无需选择,1-当前需选择玩家轮次
(2)GUI渲染系统
OnGUI()函数
主要分为三部分:
void OnGUI(){
? ?GUIStyle labelStyle = new GUIStyle();
? ?GUIStyle titleStyle = new GUIStyle();
? ?GUIStyle chessStyle = new GUIStyle();
?
? ?labelStyle.fontSize = 30;
? ?titleStyle.fontSize = 100;
? ?chessStyle.fontSize = 80;
? ?chessStyle.alignment = TextAnchor.MiddleCenter;
?
? ?GUI.Label(new Rect (680, 10, 600, 150),"Tic Tac Toe",titleStyle);
? ?if(isStart){
? ? ? ?if(mode == 0 && chooseTurn == 0){
? ? ? ? ? ?GUI.Label(new Rect (80, 80, 600, 150),"单人模式游戏中...",labelStyle);
? ? ? ? ? ?singleMode();// 调用单人模式函数
? ? ? }
? ? ? ?if(mode == 1){
? ? ? ? ? ?GUI.Label(new Rect (80, 80, 600, 150),"双人模式游戏中...",labelStyle);
? ? ? ? ? ?doubleMode();// 调用双人模式函数
? ? ? ? ? ?GUI.Label(new Rect (250, 680, 600, 150),"轮到玩家1下棋",labelStyle);
? ? ? ? ? ?GUI.Label(new Rect (250, 840, 600, 150),"轮到玩家2下棋",labelStyle);
? ? ? ? ? ?// 玩家轮次切换提示
? ? ? ? ? ?if(turn == 0){ ?
? ? ? ? ? ? ? ?GUI.Label(new Rect (0, 650, 200, 150),point);
? ? ? ? ? }
? ? ? ? ? ?else{
? ? ? ? ? ? ? ?GUI.Label(new Rect (0, 800, 200, 150),point);
? ? ? ? ? }
?
? ? ? }
?
? }
? ?else{
? ? ? ?GUI.Label(new Rect (80, 80, 600, 150),"请选择模式...",labelStyle);
? }
? ?// 若点击单人模式,则通过设置mode变量进入单人模式,并将游戏状态置为开始
? ?if(GUI.Button(new Rect (80, 200, 200,100), "单人模式")){
? ? ? ?chooseTurn = 1;
? ? ? ?if(!isStart){
? ? ? ? ? ?mode = 0;
? ? ? ? ? ?isStart = true;
? ? ? }
? }
? ?// 单人模式玩家选择先后或后手
? ?if(chooseTurn == 1){
? ? ? ?if(GUI.Button(new Rect(50, 680, 300, 150),"先手")){
? ? ? ? ? ?turn = 0;
? ? ? ? ? ?chooseTurn = 0;
? ? ? }
? ? ? ?if(GUI.Button(new Rect(50, 840, 300, 150),"后手")){
? ? ? ? ? ?turn = 1;
? ? ? ? ? ?chooseTurn = 0;
? ? ? }
? }
? ?// 若点击单人模式,则通过设置mode变量进入双人模式,并将游戏状态置为开始
? ?if(GUI.Button(new Rect (80, 350,200,100), "双人模式")){
? ? ? ?if(!isStart){
? ? ? ? ? ?mode = 1;
? ? ? ? ? ?isStart = true;
? ? ? }
? }
? ?// 渲染棋盘
? ?for (int i=0; i<3; ++i) { ? ?
? ? ? ?for (int j=0; j<3; ++j) { ? ?
? ? ? ? ? ?if (board [i, j] == 1){
? ? ? ? ? ? ? ?GUI.Button (new Rect (580 + i * 250, 220 + j * 250, 250, 250),"O",chessStyle);
? ? ? ? ? } ? ?
? ? ? ? ? ?if (board [i, j] == 2){
? ? ? ? ? ? ? ?GUI.Button (new Rect (580 + i * 250, 220 + j * 250, 250, 250),"X",chessStyle); ?
? ? ? ? ? } ?
? ? ? } ?
? }
? ?// 渲染游戏结果
? ?switch (isEnd()){ ?
? ? ? ?case 0:
? ? ? ? ? ?break;
? ? ? ?case 1:
? ? ? ? ? ?GUI.Label(new Rect (1500, 150, 600, 150),"先手玩家获胜!",labelStyle);
? ? ? ? ? ?GUI.Label(new Rect(1400,200,600,550),victory);
? ? ? ? ? ?break;
? ? ? ?case 2:
? ? ? ? ? ?GUI.Label(new Rect (1500, 150, 600, 150),"后手玩家获胜!",labelStyle);
? ? ? ? ? ?GUI.Label(new Rect(1400,200,600,550),victory);
? ? ? ? ? ?break;
? ? ? ?case 3:
? ? ? ? ? ?GUI.Label(new Rect (1500, 150, 600, 150),"平局",labelStyle);
? ? ? ? ? ?GUI.Label(new Rect(1400,200,600,550),balance);
? ? ? ? ? ?break;
? ? ? ?default:
? ? ? ? ? ?break;
? }
? ?// 若点击重新开始,则清空棋盘并重置游戏数据
? ?if(GUI.Button (new Rect (80, 500, 200, 100),"重新开始")){
? ? ? ?reset();
? }
?
?
}
(3)玩家系统
bool putChess(int i,int j){
? ?if(isEnd() != 0){
? ? ? ?return false;
? }
? ?if (board[i,j] == 0) { ? ?
? ? ? ?if (turn == 0){
? ? ? ? ? ?board [i, j] = 1;
? ? ? } ? ? ?
? ? ? ?else{
? ? ? ? ? ?board [i, j] = 2;
? ? ? } ? ?
? ? ? ?return true; ?
? } ?
? ?return false;
}
void randomPut(){
? ?int i;
? ?int j;
? ?while(true){
? ? ? ?i = (int)Random.Range(0,3);
? ? ? ?j = (int)Random.Range(0,3);
? ? ? ?if(board[i,j]==0){
? ? ? ? ? ?putChess(i,j);
? ? ? ? ? ?changeTurn();
? ? ? ? ? ?break;
? ? ? }
? }
}
(4)游戏整体系统
-
Start() 游戏项目开始运行时的对游戏数据进行初始化,实际上就是调用reset()函数 void Start(){
? ?reset();
} -
reset() 重置游戏数据,包括棋盘数据,游戏状态,玩家轮次 void reset(){
? ?for(int i = 0;i < 3;++i){
? ? ? ?for(int j = 0;j < 3;++j){
? ? ? ? ? ?board[i,j] = 0;
? ? ? }
? }
? ?turn = 0;
? ?isStart = false;
} -
isEnd() 判断通过判断代表棋盘的二维数组中的数据来判断当前游戏形势。 // 0 - 还未结束
// 1 - player1 win
// 2 - player2 win
// 3 - 平局
int isEnd(){
? ?int count = 0;
? ?for (int i = 0; i < 3; i++) {
? ? ? ?for (int j = 0; j < 3; j++) {
? ? ? ? ? ?if (board [i, j] != 0)
? ? ? ? ? ? ? ?count++;
? ? ? }
? }
? ?// 一行
? ?for (int i=0; i<3; ++i) { ? ?
? ? ? ?if (board[i,0]!=0 && board[i,0]==board[i,1] && board[i,1]==board[i,2]) { ? ?
? ? ? ? ? ?return board[i,0]; ? ?
? ? ? } ? ?
? } ? ?
? ?// 一列
? ?for (int j=0; j<3; ++j) { ? ?
? ? ? ?if (board[0,j]!=0 && board[0,j]==board[1,j] && board[1,j]==board[2,j]) { ? ?
? ? ? ? ? ?return board[0,j]; ? ?
? ? ? } ? ?
? } ? ?
? ?// 对角线
? ?if (board[1,1]!=0 && ? ?
? ? ? ?board[0,0]==board[1,1] && board[1,1]==board[2,2] || ? ?
? ? ? ?board[0,2]==board[1,1] && board[1,1]==board[2,0]) { ? ?
? ? ? ?return board[1,1]; ? ?
? } ? ?
? ?if (count == 9){
? ? ? ?return 3;
? }
? ?return 0;
} -
changeTurn() 修改玩家轮次 void changeTurn(){
? ?turn = 1 - turn;
} -
singleMode() 单人模式下的游戏逻辑,若轮到真人玩家,则等到真人玩家点击棋盘下棋,否则由randomPut()函数代表电脑玩家随机下棋。 void singleMode(){
? ?for (int i=0; i<3; ++i) { ? ?
? ? ? ?for (int j=0; j<3; ++j) { ? ?
? ? ? ? ? ?if (GUI.Button (new Rect (580 + i * 250, 220 + j * 250, 250, 250),"")) { ? ?
? ? ? ? ? ? ? ?if(turn == 0){
? ? ? ? ? ? ? ? ? ?if(putChess(i,j)){
? ? ? ? ? ? ? ? ? ? ? ?changeTurn();
? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? }
? ? ? ? ? }
?
? ? ? } ?
? }
? ?if(turn == 1 && isEnd() == 0){
? ? ? ?randomPut();
? }
} -
doubleMode() 双人模式下的游戏逻辑,当前玩家下完棋之后改变轮次由另一位玩家下棋。 void doubleMode(){
? ?for (int i=0; i<3; ++i) { ? ?
? ? ? ?for (int j=0; j<3; ++j) { ? ?
? ? ? ? ? ?if (GUI.Button (new Rect (580 + i * 250, 220 + j * 250, 250, 250),"")) { ? ?
? ? ? ? ? ? ? ?if(putChess(i,j)){
? ? ? ? ? ? ? ? ? ?changeTurn();
? ? ? ? ? ? ? }
? ? ? ? ? }
? ? ? } ?
? }
}
三、效果展示
视频链接
四、项目地址
huanghj78/Unity-Homework - 码云 - 开源中国 (gitee.com)
|