Unity3D学习笔记(2)——用GUI制作井字棋游戏

        本来拿gui来做游戏蛮怪的,但这却是一个熟悉gui的不错的途径。今天我就学着使用GUI.Button做了一个十分简单的井字棋游戏。上个成品图:


首先创建一个C#脚本文件,去掉Update方法,因为这里我不会用到它。然后添加OnGUI方法。声明两个私有变量,一个用来记录是谁的回合, 假定turn为1是圈圈的回合,turn为-1是叉叉的回合。另一个变量为3*3的二维数组,用来记录当前九宫格的状态,假定1代表格子里是圈圈,2代表格子里是叉叉。函数reset用来初始化个参数,在脚本被调用时(Start)执行一次。

using UnityEngine;
using System.Collections;

public class NewBehaviourScript : MonoBehaviour {

	private int turn = 1;	//记录是谁的回合
	private int[,] state = new int[3,3];	//九方格数据
	
	//参数初始化
	void Start() {
		reset();
	}

	void OnGUI() {

	}

	//重置参数
	void reset() {
		turn = 1;
		for (int i=0; i<3; ++i) {
			for (int j=0; j<3; ++j) {
				state[i,j] = 0;
			}
		}
	}
}

        接着在OnGUI里面用一个两重循环添加出九宫格Button。为了让button点击时能发生变化(修改button的text),开始我以为能通过获得button的对象,然后通过对象的OnClick事件来处理,但查阅了资料发现几乎不可能做到,后来发现OnGUI类似一个绘图的方法,每一帧都会清理掉上一帧的所有对象,即刷屏。因此必须另外想办法。而这个办法便是使用state二维数组记录九宫格的状态。除此之外,必须添加一个check方法来决定游戏是否结束,一旦游戏结束,那么就需要一个Label来显示游戏结果,并且不再允许玩家点击Buttons。Reset按钮可以重置游戏,即调用reset方法。


void OnGUI() {
		if (GUI.Button(new Rect(20,300,100,50),"Reset"))
			reset();
		int result = check();  // 返回0代表游戏没有结束,1代表圈圈赢,2代表叉叉赢。
		if (result==1) {
			GUI.Label(new Rect(50,230,100,50),"O wins!");
		}
		else if (result==2) {
			GUI.Label(new Rect(50,230,100,50),"X wins!");
		}
		for (int i=0; i<3; ++i) {
			for (int j=0; j<3; ++j) {
				if (state[i,j]==1)
					GUI.Button(new Rect(i*50,j*50,50,50),"O");
				if (state[i,j]==2)
					GUI.Button(new Rect(i*50,j*50,50,50),"X");
				if(GUI.Button(new Rect(i*50,j*50,50,50),"")) {
					if (result==0) {
						if (turn == 1)
							state[i,j] = 1;
						else
							state[i,j] = 2;
						turn = -turn;
					}
				}
			}
		}
	}

        查看游戏是否结束,无非就是看有没有连成一线的圈圈或者叉叉。粗暴一点的办法就是列出所有可能的情况,简单一点的就可以使用循环,先横向一排排看过去,再纵向一列列看过去,有一样的非零状态就直接返回该状态即可。最后再看看斜向的两种情况,一样且非零的话直接返回中间交点的状态值就可以了。


//判断游戏结束条件
	int check() {
		// 横向连线
		for (int i=0; i<3; ++i) {
			if (state[i,0]!=0 && state[i,0]==state[i,1] && state[i,1]==state[i,2]) {
				return state[i,0];
			}
		}
		//纵向连线
		for (int j=0; j<3; ++j) {
			if (state[0,j]!=0 && state[0,j]==state[1,j] && state[1,j]==state[2,j]) {
				return state[0,j];
			}
		}
		//斜向连线
		if (state[1,1]!=0 &&
		    state[0,0]==state[1,1] && state[1,1]==state[2,2] ||
		    state[0,2]==state[1,1] && state[1,1]==state[2,0]) {
			return state[1,1];
		}
		return 0;
	}

        好了,井字棋游戏就做好了,本来我还想加个AI,思路挺简单的,在玩家每次点击一个按钮后,首先检查自己有没有赢的可能,再判断玩家有没有赢的可能,有的话直接封住,没有的话优先给自己创造机会。不过想想井字棋9个格就那几种走法,会玩的最后肯定打平,除非要做一个几乎没有边界的棋盘,不过那AI就没那么简单了。最后上一个完整的代码,代码直接作为组件挂载在主摄像机上就能跑了。


using UnityEngine;
using System.Collections;

public class jingziqi : MonoBehaviour {

	private int turn = 1;	//记录是谁的回合
	private int[,] state = new int[3,3];	//九方格数据

	//参数初始化
	void Start() {
		reset();
	}

	void OnGUI() {
		if (GUI.Button(new Rect(20,300,100,50),"Reset"))
			reset();
		int result = check();
		if (result==1) {
			GUI.Label(new Rect(50,230,100,50),"O wins!");
		}
		else if (result==2) {
			GUI.Label(new Rect(50,230,100,50),"X wins!");
		}
		for (int i=0; i<3; ++i) {
			for (int j=0; j<3; ++j) {
				if (state[i,j]==1)
					GUI.Button(new Rect(i*50,j*50,50,50),"O");
				if (state[i,j]==2)
					GUI.Button(new Rect(i*50,j*50,50,50),"X");
				if(GUI.Button(new Rect(i*50,j*50,50,50),"")) {
					if (result==0) {
						if (turn == 1)
							state[i,j] = 1;
						else
							state[i,j] = 2;
						turn = -turn;
					}
				}
			}
		}
	}

	//重置参数
	void reset() {
		turn = 1;
		for (int i=0; i<3; ++i) {
			for (int j=0; j<3; ++j) {
				state[i,j] = 0;
			}
		}
	}

	//判断游戏结束条件
	int check() {
		// 横向连线
		for (int i=0; i<3; ++i) {
			if (state[i,0]!=0 && state[i,0]==state[i,1] && state[i,1]==state[i,2]) {
				return state[i,0];
			}
		}
		//纵向连线
		for (int j=0; j<3; ++j) {
			if (state[0,j]!=0 && state[0,j]==state[1,j] && state[1,j]==state[2,j]) {
				return state[0,j];
			}
		}
		//斜向连线
		if (state[1,1]!=0 &&
		    state[0,0]==state[1,1] && state[1,1]==state[2,2] ||
		    state[0,2]==state[1,1] && state[1,1]==state[2,0]) {
			return state[1,1];
		}
		return 0;
	}
}

        在学习Unity自带的GUI过程中,我发现大家普遍提倡使用Unity的第三方库NGUI来代替GUI,看来NGUI更适合实际的游戏开发。



没有更多推荐了,返回首页