一、MVC架构
MVC(Model-View-Controller)是一种广泛使用的软件架构模式,旨在将应用程序的不同部分分离,以提高可维护性、可扩展性和组织性。MVC 模式将应用程序分为三个核心组件:模型(Model)、视图(View)和控制器(Controller)。
模型是应用程序的核心部分,负责管理数据、业务逻辑和状态。它直接与数据源进行交互,例如数据库或外部 API,并处理获取、存储和更新数据的任务。
视图是用户界面部分,负责呈现模型的数据并接受用户输入。视图从模型中获取数据,并以适当的格式显示出来,只关注如何展示信息,而不涉及业务逻辑。
控制器充当模型和视图之间的中介,处理来自视图的用户输入,调用模型的相应方法,并根据需要更新视图。控制器接收用户的动作(如按钮点击),并据此决定如何响应。
二、计算器代码实现
1. 模型
模型用于进行数学计算。CalculatorModel类里维护一个expression变量,存储表达式,使用 C# 的 System.Data.DataTable 来计算。
using System;
using System.Data;
using UnityEngine;
public class CalculatorModel : MonoBehaviour
{
private string expression = ""; // 当前输入的表达式
public string GetExpression()
{
return expression;
}
// 计算结果
public bool ComputeResult()
{
try
{
// 使用 C# 的 System.Data.DataTable 来计算表达式
var result = new System.Data.DataTable().Compute(expression, null);
expression = result.ToString(); // 保存计算结果,继续计算
return true;
}
catch (System.Exception ex)
{
expression = "";
Debug.LogError("计算错误: " + ex.Message); // 打印详细的错误信息
return false;
}
}
// 添加到表达式
public void Add(string input)
{
//Debug.Log(input);
expression += input;
}
// 删除表达式的最后一个字符
public void DeleteLastCharacter()
{
if (expression.Length > 0)
{
expression = expression.Substring(0, expression.Length - 1);
}
}
// 清除表达式
public void ClearExpression()
{
expression = "";
}
}
2. 视图
本项目的视图主要用于表达式显示,界面和按钮等已在场景里铺设好。
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Events;
using TMPro;
public class CalculatorUI : MonoBehaviour
{
public TextMeshProUGUI resultText; // 显示输入和结果的Text
public void SetResultText(string text)
{
resultText.text = text;
}
}
3. 控制器
控制器用于模型和视图之间的交互,负责按钮点击触发事件,修改模型类CalculatorModel里的表达式,并将表达式传输给视图类CalculatorUI ,更新视图。
using UnityEngine;
using UnityEngine.UI;
using TMPro;
public class CalculatorController : MonoBehaviour
{
public CalculatorModel model; // 数据模型
public CalculatorUI view; // 用户界面
// 按钮文本映射
public Button[] numberButtons; // 数字按钮数组
public Button[] operatorButtons; // 运算符按钮数组
public Button delButton; // 删除按钮
public Button acButton; // 清除按钮
public Button dotButton; // 小数点按钮
public Button equalsButton; // 计算按钮
public void Start()
{
// 打印出按钮事件监听器的数量
Debug.Log("Number Button 0 Listeners: " + numberButtons[0].onClick.GetPersistentEventCount());
// 确保按钮点击事件只绑定一次
foreach (Button btn in numberButtons)
{
btn.onClick.RemoveAllListeners(); // 移除所有监听器
string input = btn.GetComponentInChildren<TextMeshProUGUI>().text;
if (string.IsNullOrEmpty(input))
{
Debug.Log("000");
}
else
{
btn.onClick.AddListener(() => OnNumberButtonClick(input));
}
}
foreach (Button btn in operatorButtons)
{
btn.onClick.RemoveAllListeners(); // 移除所有监听器
string input = btn.GetComponentInChildren<TextMeshProUGUI>().text;
if (string.IsNullOrEmpty(input))
{
Debug.Log("000");
}
else
{
btn.onClick.AddListener(() => OnOperatorButtonClick(input));
}
}
// 删除按钮
delButton.onClick.RemoveAllListeners(); // 移除所有监听器
delButton.onClick.AddListener(OnDeleteButtonClick);
// 清除按钮
acButton.onClick.RemoveAllListeners(); // 移除所有监听器
acButton.onClick.AddListener(OnClearButtonClick);
// 小数点按钮
dotButton.onClick.RemoveAllListeners(); // 确保只绑定一次
dotButton.onClick.AddListener(OnDotButtonClick);
// 等号按钮
equalsButton.onClick.RemoveAllListeners();
equalsButton.onClick.AddListener(OnEqualsButtonClick);
}
// 数字按钮点击事件
public void OnNumberButtonClick(string number)
{
//Debug.Log(number);
Debug.Log("Number Button: " + number + " Clicked"); // 输出按钮名称
model.Add(number);
view.SetResultText(model.GetExpression());
}
// 运算符按钮点击事件
public void OnOperatorButtonClick(string operatorSymbol)
{
//Debug.Log(operatorSymbol);
Debug.Log("Operator Button: " + operatorSymbol + " Clicked"); // 输出按钮名称
if (operatorSymbol == "×")
operatorSymbol = "*";
else if(operatorSymbol == "÷")
operatorSymbol = "/";
model.Add(operatorSymbol);
view.SetResultText(model.GetExpression());
}
// 小数点按钮点击事件
public void OnDotButtonClick()
{
Debug.Log("Dot Button Clicked");
model.Add(".");
view.SetResultText(model.GetExpression());
}
// 删除按钮点击事件
public void OnDeleteButtonClick()
{
Debug.Log("Delete Button Clicked");
model.DeleteLastCharacter();
view.SetResultText(model.GetExpression());
}
// 清除按钮点击事件
public void OnClearButtonClick()
{
Debug.Log("Clear Button Clicked");
model.ClearExpression();
view.SetResultText("0");
}
// 等号按钮点击事件,执行计算
public void OnEqualsButtonClick()
{
Debug.Log("Equal Button Clicked");
if (model.ComputeResult())
{
view.SetResultText(model.GetExpression());
}
else
{
view.SetResultText("Error");
}
}
// 监听键盘输入(可选)
public void Update()
{
// 监听键盘输入
foreach (char c in Input.inputString)
{
if (char.IsDigit(c)) // 如果是数字
{
OnNumberButtonClick(c.ToString());
}
else if (c == '*') // 处理乘法
{
OnOperatorButtonClick("×"); // 使用 * 代替 ×
}
else if (c == '/') // 处理除法
{
OnOperatorButtonClick("÷"); // 使用 / 代替 ÷
}
else if ("+-".Contains(c.ToString())) // 处理加减法
{
OnOperatorButtonClick(c.ToString());
}
else if (c == '\b') // 回退键 (Backspace)
{
OnDeleteButtonClick();
}
else if (c == '.') //小数点
{
OnDotButtonClick();
}
else if (c == '=') // 回车键或等号
{
OnEqualsButtonClick();
}
}
// 监听回车键(Enter)以触发等号
if (Input.GetKeyDown(KeyCode.Return) || Input.GetKeyDown(KeyCode.KeypadEnter))
{
OnEqualsButtonClick();
}
}
}
三、项目展示
总体效果:
视频
Rec 0001