unity井字棋改编——简易计算器
注:本游戏基于潘老师的第三次作业要求,在井字棋的基础上设计出简易计算器
源代码github地址:goodhuahua/unity-game: unity游戏开发学习之旅 (github.com)
游戏代码讲解/实现效果视频:小破站
MVC结构
在真正开始设计之前,我们需要首先了解下什么是MVC模式:
- Model(模型):模型代表游戏的数据和逻辑。在这个游戏中,模型主要包括以下方面的内容:
- 棋盘状态(chessBoard):用于存储棋盘上每个格子的状态,表示棋盘的当前状态。
- 玩家状态(player):表示当前玩家的状态,用于轮流确定下棋的玩家。
- 胜利者状态(winner):表示当前的胜利者,用于判断游戏是否结束。
- 计数器(count):用于记录已经放置的棋子数量。
- View(视图):视图负责游戏界面的展示和用户交互。在这个游戏中,视图主要包括以下方面的内容:
OnGUI()
函数:用于绘制游戏界面,包括棋盘格子的按钮和背景矩形框。- 按钮点击事件:当玩家点击棋盘格子的按钮时,触发相应的事件处理函数。
- Controller(控制器):控制器负责协调模型和视图之间的交互。在这个游戏中,控制器主要包括以下方面的内容:
PutChess(int i, int j)
方法:当玩家点击棋盘格子的按钮时,该方法被调用。它用于更新模型中的棋盘状态,将玩家的棋子放置在指定的格子上,并进行下一步操作(切换玩家、检查胜利条件等)。Init()
方法:用于初始化游戏的状态,包括清空棋盘、重置玩家状态、胜利者状态和计数器。
MVC模式对于整个游戏的开发具有很好的指导作用,能够使我们的代码逻辑性更加紧密。作为一个初学者,我们需要从开始就养成良好的编程习惯,为后续大型游戏的开发奠定良好的基础。
井字棋案例
以下为井字棋案例的代码:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/*
ECS or MVC conception is applied on the small game
Firstly, entitis and their states are defined as the game model.
And then, give some components/controls which can modify the game model.
The end, system handler OnGUI called by game circle provides a game UI view.
*/
public class ChessGame : MonoBehaviour
{
// Entities and their states / Model
private static int player;
private static int count;
private int winner;
private int[,] chessBoard = new int[3, 3];
// System Handlers
void Start()
{
Init();
}
// View render entities / models
// Here! you cannot modify model directly, use components/controls to do it
void OnGUI()
{
GUI.Box(new Rect(210, 25, 300, 300), "");
if (GUI.Button(new Rect(310, 270, 100, 30), "Restart")) Init();
if (!GameOver())
{
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
if (chessBoard[i, j] == 0 && GUI.Button(new Rect(255 + j * 70, 50 + i * 70, 70, 70), ""))
{
PutChess(i, j);
}
else if (chessBoard[i, j] == 1) GUI.Button(new Rect(255 + j * 70, 50 + i * 70, 70, 70), "O");
else if (chessBoard[i, j] == 2) GUI.Button(new Rect(255 + j * 70, 50 + i * 70, 70, 70), "X");
}
}
}
else
{
if (winner != 0)
GUI.Box(new Rect(260, 50, 200, 200), "\n\n\n\n\nCongratulations!\n Player " + winner + " has won.");
else
GUI.Box(new Rect(260, 50, 200, 200), "\n\n\n\n\n\nThis is a draw!");
}
}
// Components
// here! any ui can not be referenced
void Init()
{
player = 1;
winner = 0;
count = 0;
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
chessBoard[i, j] = 0;
}
void PutChess(int i, int j)
{
chessBoard[i, j] = player;
player = 3 - player;
count++;
}
bool GameOver()
{
for (int i = 0; i < 3; i++)
{
if (chessBoard[i, 0] != 0
&& chessBoard[i, 0] == chessBoard[i, 1] && chessBoard[i, 0] == chessBoard[i, 2]) winner = chessBoard[i, 0];
if (chessBoard[0, i] != 0
&& chessBoard[0, i] == chessBoard[1, i] && chessBoard[0, i] == chessBoard[2, i]) winner = chessBoard[0, i];
}
if (chessBoard[0, 0] != 0 && chessBoard[0, 0] == chessBoard[1, 1] && chessBoard[0, 0] == chessBoard[2, 2]) winner = chessBoard[0, 0];
if (chessBoard[0, 2] != 0 && chessBoard[0, 2] == chessBoard[1, 1] && chessBoard[0, 2] == chessBoard[2, 0]) winner = chessBoard[0, 2];
if (count < 9 && winner == 0) return false;
return true;
}
}
具体的运行效果大家可以复制代码到unity中尝试,本博客的重点在于简易计算器的实现。
简易计算器改编
代码剖析
首先大家看看完整的代码实现:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Calculator : MonoBehaviour
{
// Model
private string displayText; // 显示的文本内容
private void Start()
{
Init(); // 初始化
}
private void OnGUI()
{
// View
GUI.Box(new Rect(260, 30, 360, 70), displayText, GUI.skin.textField); // 显示文本框
// 绘制按钮
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
int number = i * 3 + j + 1;
if (GUI.Button(new Rect(255 + j * 70, 100 + i * 70, 70, 70), number.ToString(), GUI.skin.button))
{
// 用户点击按钮,交由 Controller 处理
AppendToDisplay(number.ToString());
}
}
}
// 其他按钮的处理
if (GUI.Button(new Rect(255, 310, 140, 70), "0", GUI.skin.button))
{
AppendToDisplay("0");
}
if (GUI.Button(new Rect(395, 310, 70, 70), ".", GUI.skin.button))
{
AppendToDisplay(".");
}
if (GUI.Button(new Rect(475, 100, 70, 70), "+", GUI.skin.button))
{
AppendToDisplay("+");
}
if (GUI.Button(new Rect(475, 180, 70, 70), "-", GUI.skin.button))
{
AppendToDisplay("-");
}
if (GUI.Button(new Rect(475, 260, 70, 70), "*", GUI.skin.button))
{
AppendToDisplay("*");
}
if (GUI.Button(new Rect(475, 340, 70, 70), "/", GUI.skin.button))
{
AppendToDisplay("/");
}
if (GUI.Button(new Rect(555, 100, 70, 70), "C", GUI.skin.button))
{
ClearDisplay();
}
if (GUI.Button(new Rect(555, 180, 70, 230), "=", GUI.skin.button))
{
Calculate();
}
}
// Controller
private void Init()
{
displayText = ""; // 初始化文本内容为空
}
private void AppendToDisplay(string str)
{
// 将用户点击的按钮文本追加到显示文本中
displayText += str;
}
private void ClearDisplay()
{
// 清除显示文本
displayText = "";
}
private void Calculate()
{
try
{
// 执行计算
var result = eval(displayText);
displayText = result.ToString(); // 更新显示文本为计算结果
}
catch (System.Exception)
{
displayText = "错误"; // 计算错误时显示错误信息
}
}
private double eval(string expression)
{
// 使用系统的 DataTable 类计算表达式结果
var result = new System.Data.DataTable().Compute(expression, null);
return System.Convert.ToDouble(result);
}
}
下面我们来剖析整个代码结构:
同样地,我们使用MVC模式来分析代码结构:
-
Model(模型):
- 模型在这段代码中主要是
displayText
变量,它存储当前显示在计算器界面上的文本内容。这个变量用于表示计算器的数据状态。
- 模型在这段代码中主要是
-
View(视图):
- 视图主要体现在
OnGUI()
方法中,通过调用GUI类的方法来绘制计算器界面。在界面上展示了一个文本框(用于显示计算结果或用户输入的表达式)和一系列的按钮。 - 按钮的点击事件被绑定到不同的操作,例如添加数字、运算符、清除显示等。用户通过点击按钮与视图进行交互。
- 视图主要体现在
-
Controller(控制器):
计算ing:
无效运行报错:
更多实现效果欢迎参考我的b站视频!
提升空间
我们可以看到简易计算器的字体大小,以及整体的样式效果有待提高,但由于时间有限精力有限,笔者尚未对此样式进行优化,未来有机会再作优化。
也欢迎大家访问我的github来改进此计算器,拥抱开源!unity go go go!