面向对象的程序设计在游戏开发中使用(五):基本计算器

作者:Kingfeng 奶牛关 2019-08-19

我并不是游戏开发的从业人员,甚至连软件开发都不是,但至少我是程序员。
我认为,一个【面向对象】的理念在学习过程中的重要性远大于对于代码本身含义的认识。 这一点可以在诸多书籍中得到论证,但很奇怪的一件事是,绝大部分的视频入门教程和并没有过多的强调这一点。

系列收藏夹:https:/cowlevel.net/collection/3476202

自此,我们对面向对象已经有了一个很全面的了解。但是我们写代码的时候要怎么做呢?

从这篇文章开始,我们将完成一个简单的计算器,并且逐步添加他的功能。
我们会使用Godot引擎的gds编程语言,这个引擎同样支持一种可视化的编辑方法,给苦于学习编程语言又想制作一款游戏的人有相当的帮助。

网络上有许多Godot的入门教程,我个人也有在考虑撰写一些相应的内容
虽然我不是职业游戏开发者,但是我希望进入这个领域的人从最开始编程就拥有良好的习惯,这也是本文的目的 如果未来有机会,我会从文档和编程的角度为大家介绍这个引擎,但并不能说是教学,因为对于这个引擎实际上的应用我也有许多不明白的地方。
至于选择这个引擎的原因,本来我打算使用ruby来编写这部分的代码,使得代码更加直观。但是作为教学使用,会浪费大量的时间来解释特性,而且毕竟是游戏开发,使用游戏引擎总是更好。

本内容的代码已经上传至 码云

1 分析项目

计算器由什么组成的,我们要按钮,要一个显示屏,然后用一个核心逻辑来控制这一切

按钮每次按下会“轻拍”一下核心逻辑,并递给它一个数或者符号,

而显示屏定时询问核心逻辑要显示什么。

除此之外,计算器的功能就是对数字进行计算,我们的核心逻辑在收到等于号后吧公式丢给负责计算的员工。

所以我们还需要公式类,数字类和计算类,但我们可能会在下篇文章在完成这部分的细节

2 界面

作为基本的交互,我们需要做个计算器。由按钮和显示构成
  1. func _process(delta):
  2.         text = BusiLogic.get_str()
  3. #每帧从核心逻辑更新字符
  4.         pass
复制代码

标签每次更新(_process会被每帧调用)时会向核心逻辑查询最新的字符串并显示
出于效率考虑,将显示工具注册给核心逻辑,由核心逻辑调用并更新文本更加优秀,但显然管理这个标签的刷新并不是核心逻辑的工作,如果未来对这显示内容需要进行扩展,需要显示额外内容,这些内容可能由其他部分控制,会牵扯到核心逻辑已经完成代码的修改。

根据封装的原则,我们不希望按钮自身的数据受到可能的污染,这对于一个计算器按钮,可能不会有什么问题,在更大部分的环境下,我们可能需要对输入的数据进行验证和隔离来保证错误的输入不会使后续的工作受到困惑

另外,当我们添加按钮的功能,我们可以不用改变按钮的创建,而只是将新的功能定义在函数里

  1. func bt_set_data(dat, is_num):
  2.         bt_dat = dat
  3.         bt_is_num = is_num
  4.         pass
复制代码

3 按钮按下

在设计上,当按钮按下后,我们会通知核心逻辑自己按下的按钮

  1. func enPressed():
  2.         BusiLogic.buttonEnPress(bt_get_data())
  3.         pass
  4. func bt_get_data():
  5.         return {"dat": bt_dat, "is_num": bt_is_num}
  6.         pass
复制代码

由于对按钮的使用时固定而且特殊的,并不需要额外的接口提供给双方。

如果未来,我们的核心逻辑内,有多个与按钮地位相等的工具,这些代码会遭到大量的更改。会造成诸多不可预料的问题,我们可能会使用一个输入输出的接口类来完成这些交换,来保证按钮对任何的输入,和任何对核心业务的输入都畅通无阻。

  1. func buttonEnPress(btn):
  2.         if btn["is_num"]:
  3.                 tNum*= 10
  4.                 tNum+= btn["dat"]
  5.                 math_str += str(btn["dat"])
  6.         else:
  7.                 math_arr.push_back(tNum)
  8.                 math_arr.push_back(btn["dat"])
  9.                 math_str += BT_TEXT[ btn["dat"] ]
  10.         pass
复制代码

4 计算功能

我们当下设计的计算器是简单的加减计算器,输入数字时屏幕显示数字,输入符号时会计算之前的结果,输入等于号时显示结果,其后输入数字和符号将不会继续前面的结果。

对于这种过程,我们在核心逻辑接收单个数字和符号的输入,并将其转化为正常的数字,以及对符号进行判断。同时,我们需要在计算类设定三种交互,提供数字+符号,返回之前的结果,提供等于号返回结果并清空,提供清楚号清除内容。

我们在数学类中实现这些功能。

  1. func comp(form):
  2.         var tNum = 0
  3.         if symb == BusiLogic.BT["ADD"]:
  4.                 tNum = num1 + form[0]
  5.         elif symb == BusiLogic.BT["SUB"]:
  6.                 tNum = num1 - form[0]
  7.         else:
  8.                 print("ERR",form)
  9.                 tNum = 0
  10.         num1 = tNum
  11.         symb = form[1]
  12.         if symb == BusiLogic.BT["EQU"]:
  13.                 clear()
  14.         return tNum
  15.         pass
复制代码

这段程序符合我们所设计的计算流程,返回答案,如果是减号在返回答案之后清空。

但是等号与清空在数学运算中并不相等,显然这段程序超出了管理范围,在数学上等号运算理应会返回本来的数字,因此我们进行修改,将等号加入前面的判断。

  1. elif symb == BusiLogic.BT["EQU"]:
  2.                 tNum = num1
复制代码

在核心业务层次上,我们会针对两种情况进行清理,当我们按下C,或者在按下等号后输入数字

  1. func buttonEnPress(btn):
  2.         if btn["is_num"]:
  3.                 if en_equ :
  4.                         math.clear()
  5.                         en_equ = false
  6.                 tNum*= 10
  7.                 tNum+= btn["dat"]
  8.                 math_str = str(tNum)
  9.         else:
  10.                 if btn["dat"] == BT["CLR"]:
  11.                         math.clear()
  12.                         math_str = "0"
  13.                 else :
  14.                         en_equ = false
  15.                         math_str = str(math.comp([tNum, btn["dat"]]))
  16.                         tNum = 0
  17.                         if btn["dat"] == BT["EQU"]: en_equ = true
  18.         pass
复制代码

自此,我们计算器的雏形已经完成了,我们继承了原有的标签和按钮,把他们改造成了自己想要的样子,并对他们需要的内容进行了简单的封装。

然后我们创造了核心逻辑类负责管理数据的走向,创建了计算类负责对数值进行计算,并且解决了等于号计算中的越权行为。

但是我们的计算方法并不适合复杂的,具有不同优先级的同个公式整体运算,比如先乘除后加减的遵守。同样,我们的数字也只支持系统默认的数字,我们或许需要对于分数或者复数的计算功能。

显然在现有的代码中对这些功能进行扩展是十分灾难性的,我们在后续内容将大幅度改写代码,添加乘除运算,并规划未来发展的方向,使得我们的程序可以更加轻易的扩展。

系列文章
面向对象的程序设计在游戏开发中使用(一):类
面向对象的程序设计在游戏开发中使用(二):方法
面向对象的程序设计在游戏开发中使用(三):三大特性
面向对象的程序设计在游戏开发中使用(四):五大原则

面向对象的程序设计在游戏开发中使用(五):基本计算器
面向对象的程序设计在游戏开发中使用(六):数与抽象数

面向对象的程序设计在游戏开发中使用(七):享受劳动果实

作者:Kingfeng
来源:奶牛关
原地址:https://cowlevel.net/article/2053433


最新评论
暂无评论
参与评论

商务合作 查看更多

编辑推荐 查看更多