我正在用Java制作游戏。基本上,我有两个不同的“飞机”更新,我需要照顾。基础层是实际的游戏绘画本身。它只是一个覆盖整个JFrame的JPanel,并且使用它的Graphics对象。
我使用固定的时间步来处理这些第一次图形更新。我已经覆盖了paintComponent()
方法,什么都不做,因为我已经编写了一个自定义render(float interpolation)
方法来处理这个问题,以防止不必要的更新。
但是,除了原始鼠标点击和键盘输入之外,此面板不能输入任何内容。我需要能够创建各种菜单,文本框等,它们也在屏幕上。喜欢各种能力,甚至通常出现在大多数游戏左上角的“菜单”按钮。
为了处理输入,例如创建按钮,我有第二个应用了setOpaque(false)
的JPanel。然后我创建了我可能需要的各种Swing组件,例如JButton。
要包含两个JPanel,我使用JLayeredPane,并正确设置它们的图层,如下所示。这样输入层应始终位于实际游戏层之上。
下面的代码显示了我如何相互创建和添加Swing组件。 addLoginDialog()
是一种为登录添加Swing组件的方法。它已经过测试并且运行正常,并不是问题。
private void initComponents()
{
//This code is inside of the JFrame
wholePane = new JLayeredPane();
add(wholePane);
guiPanel = new GUIPanel();
guiPanel.setOpaque(false);
gamePanel = new RPGPanel();
gamePanel.setOpaque(false);
wholePane.add(gamePanel, JLayeredPane.DEFAULT_LAYER);
wholePane.add(guiPanel, JLayeredPane.POPUP_LAYER);
guiPanel.addLoginDialog();
}
因此,当我运行代码时,我会发现可怕的闪烁。这是从我的固定时间步长〜每秒60次运行的代码。
public void handleRepaint()
{
//I don't use repaint() for the game drawing so I can be sure that fps is controlled.
Graphics g = gamePanel.getGraphics();
gamePanel.render(g);
g.dispose();
wholePane.repaint();
}
我认为问题在于,更新屏幕的两种不同系统是冲突的。标准paintComponent()
系统适用于更多静态屏幕,但是当我需要一致更新并跟踪fps时,我无法随机更新。
但是,对于输入层,我只想像Swing一样更新。当鼠标移动到按钮上时,移动I组件或调整其大小等等
另外,请注意屏幕闪烁的方式:背景图像变为空白,然后重复再次返回。输入面板总是在那里,但实际上是在游戏绘图后面绘制的,这不应该发生,因为它被放在默认图层中。我知道它并没有完全消失的原因是因为游戏绘画是部分透明的,所以我可以在它下面看到,我添加的按钮仍然存在。
我的主要问题是,如何阻止闪烁? 为什么在JLayeredPane中位于较低层的Panel上进行游戏绘制时,游戏绘图是否在输入组件之上绘制?我认为最重要的是,导致闪烁?谢谢你的帮助。
答案 0 :(得分:1)
为什么游戏绘图是在输入组件之上绘制的 当在较低的面板上进行游戏绘图时 JLayeredPane中的图层?
主要是因为你已经规避了Swing的工作方式。
让我们从Graphics
上下文是共享资源(通常每个本地对等体有一个Graphics
上下文)的事实开始,也就是说,每个组件都获得相同的上下文,这意味着,当你使用自己的绘画程序时,你基本上是在绘制其他所有东西。
RepaintManager负责决定应该绘制什么和何时绘制。所以你现在拥有的是两个艺术家在同一个画布上战斗,想要同时在它上面画画,这只是弄得一团糟。
加入Swing的绘画过程不是线程安全的,你最终会陷入困境。
如果你绝对必须拥有控制权,那么你需要从等式中删除Swing的绘画引擎。
首先看一下Passive vs. Active Rendering
ps-使用BufferStrategy