Java:使用Swing编写游戏的程序设计

4

我是相对来说比较新的游戏开发者。我已经研究游戏开发和制作游戏2-3个月了,使用的是Java语言。

一直以来,我都是用Swing进行图形处理(也就是整个游戏显示在JPanel上,使用Graphics2D对象)。到目前为止,这个方法还没有出现过问题。

但最近,在我的最新项目中出现了一个问题:某些方法无论何时被调用,时间间隔都不一致(有时每15-16毫秒运行一次,有时开始每3000毫秒运行一次)。

我进行了一些沉闷的调试和研究,并发现这种情况可能是因为我没有正确地处理Swing和线程造成的。

我的整个游戏循环都在非EDT线程的run()方法里面运行。所以我一直在修改Swing元素,导致问题显而易见。

当我找到这个问题时,我想:

“嘿,我可以简单地使用SwingUtilities.invokeLater()使游戏循环在EDT中运行!”

但接着我想到,就像“禁止”在EDT外部操作Swing元素一样,也会在EDT内部操纵非Swing对象会有问题(我觉得……这个说法正确吗?)。

如果是的话,那么我不知道如何在使用Swing时安全地开发游戏,以避免涉及Swing和线程的奇怪问题。

我的问题是:

如何使用Swing安全地开发游戏?有哪些好的准则需要严格遵守,以避免涉及Swing和线程的问题?每个使用Swing的游戏开发者都应该了解哪些指令呢?

对于我来说,这非常重要,因为我非常想用Java进行游戏开发,但如果我不能理解这个问题,我永远无法顺利开发游戏。

谢谢您的帮助。


根据我的经验,使用单个非EDT线程是有效的。 - Darkhogg
@Darkhogg 怎么回事?我认为在没有EDT的情况下从外部操纵JPanel应该会引起问题。 - Aviv Cohn
Swing是一个小部件库,具有按钮、复选框等控件……实际上,它适用于数据和生产力应用程序。对于游戏来说,你只需要一个像素缓冲区或OpenGL缓冲区来进行绘制即可。您是否考虑过lwjgl或jogl?即使是2D游戏也是如此。 - user2684301
在最糟糕的情况下,你可以手动绘制GUI(例如绘制一个矩形,然后在其上绘制字符串等),但我不建议这样做。 - WVrock
只是过了两年,我想说在Swing(或任何其他“GUI”)中开发游戏是疯狂的,因为有专门用于此目的的多媒体库。同样的道理也适用于另一种情况:尝试仅使用多媒体库来开发整个GUI... - Ericson Willians
1个回答

3
只要您不修改的是面板上绘制的图形,大部分情况下您就可以正常运行。就像单个非EDT线程在大多数情况下工作一样。只要您不添加或删除任何GUI元素、不调整大小、不隐藏等等,Swing就不会干扰其内部细节,从而导致您的线程和EDT之间出现竞态条件——这在大多数情况下都不会发生问题。
即使用户最小化面板时,您的非EDT代码正在绘制,也不会导致崩溃——面板可能会丢弃其旧的图形上下文,并开始使用新的图形上下文,但旧的上下文将保持有效,直到您释放它(这与C++不同,C++中delete立即使对象无效,这会导致另一个线程仍然使用本地指针时崩溃)。
问题在于,如果您使用“我还没有看到出现错误的情况,对我总是奏效”的方法,那么您就依赖于未定义的行为,只要更新JVM,您的代码就可能开始崩溃。
您能做的最好的事情是在EDT线程上设置GUI,在不同的线程上运行游戏逻辑,在定时器上每20毫秒(或您想要的帧率)调用面板的repaint()。然后,有一个类对象,保存显示当前游戏状态所需的所有内容。在同步的代码块内,让面板的paint()生成自己的对象副本,并在主线程计算游戏需要的任何内容时使用该副本。当然,主线程也应该使用相同的同步来写入类对象。这样,您就可以得到可能的最大线程分离。
仅在EDT上运行整个游戏线程可能行不通,因为您的游戏进行的任何可能需要一段时间的操作都会导致UI冻结。任何需要大量UI资源的事情都会影响您的游戏逻辑。
顺便问一下,您确定最初的问题(每隔一段时间出现长时间延迟,但不总是)不是垃圾回收的结果吗?我见过这种情况多次;如果您不使用并行垃圾回收器,则GC可能会运行数十秒钟并阻塞其他所有内容。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接