一,作业要求
用Unity实现井字棋
要求做到实体(数据),部件(逻辑),系统(交互与呈现)三者分离
二,实现效果
录制演示视频如下:
三,实现过程及项目说明
1,定义数据
private int [,] board = new int [3,3];
private int turn = 0;
private int square_size = Screen.width / 10;
private int menu_width = Screen.width / 5, menu_height = Screen.width / 10;
private int mode = 0;
private GUIStyle bigStyle, yellowStyle, redStyle;
public Texture2D empty, icon1, icon2;
public Texture2D background;
依次是:
表示棋盘的一个二维数组
表示下棋顺序的turn
定义主菜单界面和每个棋格大小的参数
表示游戏模式,0表示主菜单,1表示游戏进行中,2表示游戏已结束
三种字体,应用于菜单界面和最后显示获胜者提示
2,OnGui函数的设计
void OnGUI() {
switch(mode) {
case 0:
mainMenu();
break;
case 1:
playerVsPlayer();
break;
case 2:
playerVsPlayer();
break;
}
}
Ongui函数,就是它决定游戏每一帧应该怎么画,这里用switch来分别实现三种模式的交互模式。
我把mode1和mode2基本上写在一起了,但是中间试了很多种情况才最后实现了想要的效果。
3,主菜单的设计
void mainMenu() {
string aa = "";
GUIStyle bb = new GUIStyle();
bb.normal.background = background;
GUI.Label(new Rect(0, 0, Screen.width, Screen.height), aa, bb);
GUI.Label(new Rect(Screen.width / 2 - menu_width * 0.8f, Screen.height * 0.1f, menu_width, menu_height), "Main Menu", bigStyle);
if (GUI.Button(new Rect(Screen.width / 2 - menu_width / 2, Screen.height * 2 / 7, menu_width, menu_height), "Start!",redStyle)) {
mode = 1;
}
}
上面四行实现的是背景图片,后面实现两个文本,一个是label的,一个是button的start,label不能点击,button的可以点击,点击start开始游戏,进入模式1
4,检查游戏结果
int checkresult() {
int res = -1;
for (int i = 0; i < 3; ++i) {
if (board[i,0] != 0 && board[i,0] == board[i,1] && board[i,0] == board[i,2]) {
res = board[i,0];
break;
}
}
if (res == -1)
for (int j = 0; j < 3; ++j) {
if (board[0,j] != 0 && board[0,j] == board[1,j] && board[0,j] == board[2,j]) {
res = board[0,j];
break;
}
}
if (res == -1)
if (board[1,1] != 0 && (board[0,0] == board[1,1] && board[1,1] == board[2,2] || board[0,2] == board[1,1] && board[2,0] == board[1,1])) {
res = board[1,1];
}
if (res == -1) {
int cnt = 0;
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 3; ++j){
if (board[i,j] == 0) {
cnt++;
break;
}
}
}
if (cnt == 0) {
res = 3;
}
}
if (res == -1) return 0;
return res;
}
第一个checkresult函数检查游戏结果,用了两个变量来确定游戏的状态,这里主要是与游戏逻辑相关的,不在赘述,最后返回几个不同的值交给下一步中的函数做判断。
5,检查游戏状态
void checkState() {
int res = checkresult();
if (res == 0) return ;
if (res == 1) {
if (mode == 1 || mode == 2) {
GUI.Label(new Rect(Screen.width / 2 - 3 * square_size, Screen.height / 2, square_size * 1.5f, square_size * 0.8f), "Sunflower wins!", yellowStyle);
mode = 2;
}
}
else if (res == 2) {
if (mode == 1 || mode == 2) {
GUI.Label(new Rect(Screen.width / 2 - 3 * square_size, Screen.height / 2, square_size * 1.5f, square_size * 0.8f), "Peashooter wins!", yellowStyle);
mode = 2;
}
}
else if (res == 3) {
if (mode == 1 || mode == 2) {
GUI.Label(new Rect(Screen.width / 2 - 3 * square_size, Screen.height / 2, square_size * 1.5f, square_size * 0.8f), "Tie!", yellowStyle);
mode = 2;
}
}
}
res为0,无变化,说明游戏还能继续,为1时,1号玩家获胜,为2时,2号玩家获胜,为3时,平局,根据对应状况,改变mode的值。
6,玩家落棋函数
void playerVsPlayer() {
string aa = "";
GUIStyle bb = new GUIStyle();
bb.normal.background = background;
GUI.Label(new Rect(0, 0, Screen.width, Screen.height), aa, bb);
if(mode == 1 || mode == 2)
{
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 3; ++j) {
switch(board[i,j]) {
case 0:
if (GUI.Button(new Rect(Screen.width / 2 + (i - 1.5f) * square_size, Screen.height / 2 + (j - 1.5f)* square_size, square_size, square_size), empty)) {
if(mode != 2)
{
board[i,j] = turn + 1;
turn = 1 - turn;
}
}
break;
case 1:
GUI.Button(new Rect(Screen.width / 2 + (i - 1.5f) * square_size, Screen.height / 2 + (j - 1.5f) * square_size, square_size, square_size), icon1);
break;
case 2:
GUI.Button(new Rect(Screen.width / 2 + (i - 1.5f) * square_size, Screen.height / 2 + (j - 1.5f) * square_size, square_size, square_size), icon2);
break;
}
}
}
}
checkState();
if(mode == 1 || mode ==2)
{
if (GUI.Button(new Rect(Screen.width - square_size , Screen.height - square_size * 0.7f, square_size, square_size * 0.7f), "Reset")) {
reset();
mode = 1;//注意
}
if (GUI.Button(new Rect(0 , Screen.height - square_size * 0.7f, square_size * 1.6f, square_size * 0.7f), "Return to Menu")) {
reset();
mode = 0;
}
}
}
最开始四行画出背景不说了,其他主要是用PlayerMove函数实现玩家的落子,并在该函数中运行checkstate检查游戏状态,这里花了点时间,调试,mode=1,mode=2这两个状态的位置,最后终于实现了想要的效果,即当出现胜方或平局后,再点击button无变化,且屏幕上始终显示“甲赢了”或“平局”的结果,要求玩家必须点击“Reset”或者“back to menu”才可以。
四,项目地址
基本上上一步中就是全部的代码了,完整代码:github链接