探索 JR 与 GUI 的融合:Balls and Boxes 游戏实践
1. GUI 与 JR 的融合趋势
在当今的软件开发领域,图形用户界面(GUI)正变得越来越普遍、强大、灵活且易于使用。例如,Swing 和 AWT 工具包使 Java 程序能够轻松地包含 GUI 元素。GUI 不仅提升了用户体验,还在可视化并发程序的执行过程中发挥着重要作用。下面将通过一个名为“Balls and Boxes”(简称 BnB)的简单游戏,详细介绍如何将 JR 与 Swing 结合使用。
2. BnB 游戏概述
2.1 游戏基本信息
BnB 是一款多人游戏,可在多个系统上进行,每个系统对应一名玩家。当然,它也支持单系统单玩家模式,在单系统中既可以只显示一个窗口,也可以显示多个窗口。玩家通过系统的键盘和鼠标与游戏进行交互。
2.2 游戏界面与元素
游戏窗口包含菜单、按钮和棋盘区域。每个窗口都有唯一的标识符(0, 1, 2, …),并按标识符从左到右排列。棋盘区域包含两种“玩具”:球和盒子,还有一条随机移动的文本消息。具体操作及元素规则如下:
|操作/元素|规则|
| ---- | ---- |
|菜单|每次点击菜单会创建一个绿色或橙色的球|
|按钮|每次点击按钮会创建一个蓝色球和一个红色球|
|球|自动从左到右移动,在窗口的顶部和底部之间曲折移动,碰到顶部或底部会反弹。初始位置随机选择,到达右边界后会移动到右侧的下一个窗口或回到第一个窗口,移动一定次数后消失|
|盒子|在用户键盘控制下移动,到达左或右边界时会移动到前一个或下一个窗口,不能超出顶部或底部边界,在游戏期间一直存在|
2.3 游戏窗口示例
graph LR
classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;
A(窗口 0):::process --> B(窗口 1):::process
B --> C(窗口 2):::process
C --> A
A -->|球和盒子移动| B
B -->|球和盒子移动| C
C -->|球和盒子移动| A
3. BnB 代码概述
3.1 代码结构
BnB 程序由以下几个主要类组成:
-
Main
:主程序,为每个玩家创建一个窗口,并将它们放置在各自的虚拟机上。
-
Window
:代表一个窗口,创建游戏所需的图形组件,如菜单、按钮和棋盘。
-
SwingApplication
:创建按钮。
-
Board
:棋盘类,创建并控制棋盘上的玩具。
-
Toy
:所有玩具的基类,其派生类包括 Ball、Box 和 Mtext。
-
KeyInput
:处理键盘输入。
-
MouseInput
:处理鼠标输入。
3.2 图形组件绘制
在使用 Swing 的程序中,每个图形组件都提供了
paintComponent
方法,该方法在框架重绘时被调用。在 BnB 程序中,
Board
类提供了
paintComponent
方法,负责绘制棋盘上的所有玩具。按钮和菜单有预定义的
paintComponent
方法。框架在检测到内容变化(如按钮被点击)或接收到显式的重绘请求时会重绘自身。不过,由于 Swing 的事件驱动特性,重绘请求不一定会立即执行,多个重绘请求可能会被合并为一个。Swing 还提供了
paintImmediately
方法,用于需要立即绘制的情况。
3.3 各主要类详细分析
3.3.1 Main 类
Main 类为每个玩家创建一个
Window
,并将它们放置在各自的虚拟机上。虚拟机可以在命令行指定的物理机上创建,若未指定则在本地主机上创建。然后,它为每个棋盘提供所有棋盘的远程引用,以便棋盘之间可以传递球和盒子。与其他类似代码不同的是,这里使用了额外的
goahead
操作,确保所有棋盘在启动
ballManager
之前都已收到它们的链接,并且向每个棋盘发送了所有棋盘的引用,方便后续添加新功能。
3.3.2 Window 类
Window 类创建游戏所需的图形组件,包括棋盘、按钮和菜单。代码较为详细,以指定所有所需的图形特性。它将按钮和棋盘放置在一个名为
mainPanel
的 JPanel 中,并设置了用于退出游戏和将焦点设置到棋盘的监听器。通过传递棋盘的
startBall
操作的能力,使按钮和菜单能够创建新球。
3.3.3 Button 类
SwingApplication
类创建按钮,该代码对参考代码进行了轻微修改。按钮会记录点击次数,每次点击会创建一个蓝色球和一个红色球,使用棋盘的
startBall
操作来创建球。
3.3.4 Board 类
Board 类创建棋盘并控制玩具的移动,使用
myToys
列表来管理棋盘上的玩具。当玩具从一个棋盘移动到另一个棋盘时,会从当前棋盘的
myToys
中移除,并添加到新棋盘的
myToys
中。棋盘代码还包含一个启动过程,用于处理棋盘的启动(接收所有棋盘的远程引用)并创建初始的球和盒子。对于每种玩具,棋盘提供一个管理器来控制其移动。
-
MtextManager
:最简单的管理器,因为每个棋盘上只有一个
Mtext
对象,且该对象不会移动到其他棋盘。它首先创建一个
Mtext
对象,然后进入一个无限循环,随机选择文本的新位置,通知对象更新位置,请求重绘棋盘,然后随机休眠一段时间。
-
BallManager
:创建和控制球的代码较为复杂。
Board
类为球提供了
start
和
restart
操作。
start
操作用于创建新球,
restart
操作在球从一个棋盘移动到另一个棋盘时使用。
ballManager
进程最多循环
iters
次,每次循环计算球的新位置,处理边界情况,如球到达顶部或底部时反弹,到达左右边界时发送消息到相邻棋盘的
restartBall
操作。
-
BoxManager
:盒子的创建和控制与球类似,但
boxManager
接收字符输入来确定盒子的移动方向。当盒子离开当前棋盘时,当前棋盘上的管理器终止,盒子被传递到相邻棋盘,由新的
boxManager
管理。
3.3.5 Toy 类
Toy
类是所有玩具的抽象基类,提供了玩具共有的字段和方法,并且是可序列化的,以便在不同虚拟机上的棋盘之间传递玩具。
Ball
和
Box
类继承自
Toy
类,每个类都有一个
mydraw
方法,用于在玩具的当前位置绘制球或盒子。
3.3.6 Input 类
KeyInput
和
MouseInput
类用于向棋盘提供输入。
KeyInput
类接收一个字符输入能力,只发送有意义的字符并处理游戏退出。
MouseInput
类结构类似,但在这个游戏中,棋盘不使用鼠标点击事件,因此传递了一个空操作能力作为鼠标点击参数。
3.4 代码同步与重绘
myToys
集合被声明为
synchronizedList
,
paintComponent
方法使用 Java 的
synchronized
语句来提供对
myToys
集合的互斥访问,确保在重绘时其他进程不会修改
myToys
。不过,一般不建议混合使用 Java 和 JR 的同步机制,但这里的操作简单且安全,因为被
synchronized
语句阻塞的线程不会无限阻塞,也不会干扰 JR 的静止检测。
4. BnB 程序的其他要点
4.1 常量与焦点设置
BnB 代码中有许多常量,如用于指定窗口和玩具大小的常量。这些常量本可以通过命令行参数指定,但为了简化代码展示而未采用。在 BnB 中,由于棋盘由包含另一个面板(棋盘)和按钮的主面板组成,键盘焦点会在这两个组件之间切换。可以通过按 Tab 键在组件间更改焦点,并且当窗口激活(鼠标移入窗口)时,代码会将焦点设置到棋盘区域。不过,是否需要设置焦点取决于程序所使用组件的具体结构。
4.2 JR 与 Swing 的交互问题
JR 的正常行为是在程序静止时终止程序。但当前 JR 实现无法感知 Swing(或 AWT)事件,这些事件与 JR 程序异步发生。例如,当一个使用 Swing 的 JR 程序阻塞等待键盘字符输入(如
boxManager
中)或鼠标点击,且程序中没有其他进程时,JR 实现会认为程序静止并终止它。BnB 程序不会终止,因为其
MtextManager
执行一个无阻塞(除了休眠)的无限循环,JR 实现能感知到这种情况。为防止此类终止,有两种方法:
- 使用命令行选项(具体细节可参考相关文档)。
- 使用一个额外的“休眠”进程,让其休眠时间长于程序执行时间,或在无限循环中进行任意时长的休眠。
4.3 Swing 的其他有用特性
Swing 包含许多其他有用的特性,以下是一些在编写 JR 程序时可能有用的部分特性列表:
|特性|描述|
| ---- | ---- |
|多种按钮和菜单|提供丰富的界面元素选择|
|键盘菜单选择|可使用“加速器”通过键盘选择菜单|
|其他类型的框架|如文本框架可实现不同系统用户间的聊天,或在每个窗口中显示小状态窗口展示所有棋盘情况|
|图像支持|可以用图片替代简单图形,如用猫的图片替代盒子的矩形|
|动画定时器|用于实现动画效果|
4.4 Swing 与 AWT 的比较
BnB 程序使用了 Swing,但也可以用 AWT 编写。Swing 非常灵活,但由于选项众多而较为复杂;AWT 是较低级的工具包,可能更容易学习。不过,Swing 似乎是更推荐的选择,因为 Swing 程序在任何系统上都能呈现相同的图形显示,而 AWT 程序依赖于主机的本地窗口系统,不能保证这一点,这种可移植性在许多应用中非常重要。
5. 扩展与优化建议
5.1 游戏功能扩展
可以对 BnB 程序进行多种修改以增加游戏的趣味性,以下是一些具体的扩展建议:
1.
球的移动方向
:
- 让球可以随机选择从右到左或从左到右移动。
- 扩展菜单,让用户可以选择球的移动方向,菜单创建的球按所选方向移动。
2.
盒子的移动规则
:
- 允许盒子从棋盘顶部到底部或从底部到顶部环绕移动。
- 当没有按键输入时,盒子保持最后指定的方向移动。
3.
添加障碍物
:在棋盘上添加障碍物,球可以穿过障碍物,而盒子不能。
4.
新玩具
:添加三角形玩具,整个游戏中只有一个三角形玩具,在每个棋盘的相同位置显示,它会随机且定期(如每秒一次)移动。
5.
特殊按键功能
:
- 按下 ‘c’ 键,盒子直接移动到其初始创建的棋盘。
- 按下 ‘p’ 键,游戏在所有窗口中暂停,直到在同一窗口再次按下任意键。
6.
鼠标交互
:
- 在棋盘内点击鼠标,将盒子移动到鼠标位置,如果盒子在其他棋盘,移动到指定位置。
- 在棋盘内点击鼠标,将键盘焦点设置到该棋盘。
5.2 计分系统
可以修改 BnB 程序,为每个玩家设置计分系统,并在每个玩家的显示屏上显示当前分数。例如,当满足以下条件时奖励分数:
- 盒子与球在屏幕上碰撞。
- 盒子与另一个盒子碰撞,且第一个盒子不在其主棋盘上。
- 盒子发射的子弹击中球,这需要让盒子能够发射子弹,并进行其他相关更改,如改变盒子形状以指示射击方向,允许盒子旋转(如通过 ‘a’ 键逆时针旋转,’s’ 键顺时针旋转)以调整射击角度。
5.3 其他应用开发
除了扩展 BnB 游戏,还可以开发其他包含 GUI 的分布式 JR 程序进行动画或可视化,以下是一些可能的应用示例:
-
游戏类
:如扑克、乒乓球、海战、大富翁、吃豆人等。
-
严肃应用类
:如最短路径查找、分布式编译、缓存模拟、多处理器可视化等。
开发时可先构建一个简单的原型,展示所选应用的基本并发方面,然后逐步完善并添加更多功能。
graph LR
classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;
A(初始原型):::process --> B(功能添加):::process
B --> C(完善优化):::process
C --> D(最终应用):::process
通过以上对 BnB 游戏的介绍和扩展建议,我们可以看到 JR 与 GUI 结合的强大潜力,无论是在游戏开发还是其他应用领域,都能为用户带来丰富的交互体验。希望这些内容能为开发者提供一些思路,激发更多创新的应用开发。
超级会员免费看

被折叠的 条评论
为什么被折叠?



