3D游戏编程-井字棋
作业要求
利用unity制作井字棋小游戏。
项目配置
Windows 10 Unity 2020.3.17f1c1
项目演示
视频演示
点击此处可以前往
文字说明
- 在Asset>Scenes中create一个C# script,命名为Chess_1
- 编辑Chess_1,输入项目代码并且保存
- 将Chess_1拖拉到Main Camera
- 运行,预览的比例使用Free Aspect即可
- 井字棋起手者为O,点击下方九宫格棋盘就可以游玩,并且在任何时候都可以进行restart
项目截图
实现过程和方法(算法)
ECS框架
Entity,是一个Component的组合,它的意义就在于对其上的Component进行生命周期管理。(如一个cube,它是一个entity,他有自己的坐标,偏角,缩放的属性)
Component,是一个只包含数据的组件,将每个可能单独使用的对象属性归纳,里面只有数据没有任何方法,每个Entity是由多个Component组合而成,共享一个生命周期。(如坐标,偏角,缩放这些属性就是component)
System,是用来处理数据的系统,里面只有方法,没有任何数据,每个System只关注于干好一件事情,它只关心那件事作用于游戏世界里同类的一组对象的每单个个体,或是这类对象的某种特定的交互行为。
项目构思
井字棋的entity有:
- 九宫格(matrix),实际上是九宫格的每一个格子;
- 回合轮次。
component:
- 格子的component就是每一个格子目前的状态,是被O所下、被X所下、还是为空;
- 轮次的component是轮到玩家O还是玩家X。
system:
- reset,重置整个棋盘;
- check是检查当前步是否出现胜者,或者是否平局;
- click用作处理当一个格子被下棋之后,修改格子的状态。
而UI的部分分为两个,一个是文字显示目前的回合轮到哪一位玩家,以及战况;一个是游戏的界面, 包括背景、九宫格的按钮和restart按钮。
算法
- 建立二维数组matrix记录棋盘,0表示格子为空,1表示玩家O下棋,2表示玩家X下棋。
- click函数负责修改格子的状态,以及回合轮次。
- 每次刷新时,check函数检查棋盘有没有竖线、横线、斜线是相同的(为1或者2,不能为0),有的话则出现胜者;或者检查棋盘是否已经下满九个棋子并且没有胜者,此时平手。
- 棋盘的情况要反映在UI上,于是OnGUI显示的bottom根据matrix[i,j]的状态,显示“O”、“X”、空白
- 对战情况的文字UI也根据有否出现胜者而改变显示(这个依赖result的输出来告知),并且每个回合轮到哪位玩家也要显示。
项目代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Chess_1 : MonoBehaviour
{
GUIStyle myStyle;
private int turn = 1;
private int chess_num = 0;
private int[,] matrix = new int[3,3];
int middle = Screen.width / 2;
void reset(){
turn = 1;
chess_num = 0;
for(int i = 0 ; i < 3 ; i ++){
for(int j = 0 ; j < 3 ; j ++)
matrix[i,j] = 0;
}
print("game reseted.");
}
int check(){
for(int i = 0 ; i < 3 ; i ++){
if(matrix[i,0] != 0 && (matrix[i,0] == matrix[i,1] && matrix[i,0] == matrix[i,2]) ){
return matrix[i,0];
}
if(matrix[0,i] != 0 && (matrix[0,i] == matrix[1,i] && matrix[0,i] == matrix[2,i]) ){
return matrix[0,i];
}
}
if(matrix[0,0] != 0 && (matrix[0,0] == matrix[1,1] && matrix[0,0] == matrix[2,2]) ){
return matrix[0,0];
}
if(matrix[0,2] != 0 && (matrix[0,2] == matrix[1,1] && matrix[0,2] == matrix[2,0]) ){
return matrix[0,2];
}
if (chess_num < 9) return 0;
return 3;
}
void result(int res){
switch(res){
case 0:
if(turn == 1)
GUI.Box(new Rect(middle - 45, 55, 100, 35), "O is going");
else if(turn == 2)
GUI.Box(new Rect(middle - 45, 55, 100, 35), "X is going");
break;
case 1:
GUI.Box(new Rect(middle - 45, 55, 100, 35), "O Win!");
break;
case 2:
GUI.Box(new Rect(middle - 45, 55, 100, 35), "X Win!");
break;
case 3:
GUI.Box(new Rect(middle - 45, 55, 100, 35), "Draw!");
break;
}
}
void click(int i, int j){
matrix[i,j] = turn;
chess_num ++;
if(turn == 1)
turn = 2;
else
turn = 1;
}
void OnGUI(){
GUI.Box(new Rect(middle - 120, 30, 252, 330), "tictactoe");
if (GUI.Button(new Rect(middle - 35, 95, 75, 30), "Restart")){
reset();
}
int res = check();
for(int i = 0 ; i < 3 ; i ++){
for(int j = 0 ; j < 3 ; j ++){
if(matrix[i,j] == 1){
GUI.Button(new Rect(middle - 120 + i*84, 135 + j*70 , 84, 70), "O");
}
if(matrix[i,j] ==2){
GUI.Button(new Rect(middle - 120 + i*84, 135 + j*70 , 84, 70), "X");
}
if(GUI.Button(new Rect(middle - 120 + i*84, 135 + j*70 , 84, 70), "")){
click(i,j);
}
}
}
result(res);
}
}
项目笔记
int middle = Screen.width;
int middle = Screen.height;
GUI.Box(new Rect(middle - 45, 55, 100, 35), "O is going");
GUI.Button(new Rect(middle - 120 + i*84, 135 + j*70 , 84, 70), "X");
public Texture2D X;
GUI.Button(new Rect(middle - 120 + i*84, 135 + j*70 , 84, 70), X);
参考资料
- 框架设计:浅谈ECS设计思想(一)
- Unity3D笔记(二)使用GUI做井字棋小游戏
- Unity3d 游戏设计(一)井字棋
|