【发布时间】:2018-03-18 09:06:34
【问题描述】:
我正在开发一个简单的 2D 游戏。每个滴答声,我都想检查一个效果队列,该队列将为特定效果启动一个线程(淡入淡出过渡,音频淡入淡出等)。例如,在菜单屏幕上按“播放”将向此队列添加“淡出”消息,该消息将被处理并启动一个线程以在我的 GamePanel 上绘制一个具有递增 alpha 值的黑色矩形。
我正在重写paintComponent() 并将我的Graphics 对象发送到我的GameStateManager,它会将Graphics 对象传递给当前状态的draw()。我目前没有将paintComponent() 图形对象路由到的效果状态(也许我应该),但我确实将我的游戏面板传递给我的效果线程,在那里我可以使用getGraphics() 来绘制它。直接在 GamePanel 上绘制一个矩形只会导致闪烁,因为游戏循环仍在渲染游戏。
我发现我可以在 BufferedImage 中绘制一个增加 alpha 的黑色矩形,将合成设置为 AlphaComposite.Src(这会导致新绘制替换旧绘制),然后在游戏面板上绘制 BufferedImage。问题是绘制到游戏面板的 BufferedImage 不会在每次绘制时都被覆盖,因此淡出发生得非常快,因为这些不同 alpha 的黑色 BufferedImage 只是相互堆叠。
我编写了这个简短的程序来测试复合设置并查看被覆盖的内容。所有的绘图都是在 draw() 中完成的,这将是我在效果线程中的 run()。
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class ScratchPad extends JPanel implements Runnable
{
private JFrame oFrame = null;
private Thread oGameThread = null;
private Graphics2D oPanelGraphics = null;
private Graphics2D oImageGraphics = null;
private BufferedImage oImage = null;
public static void main(String args[]) throws Exception
{
new ScratchPad();
}
public ScratchPad()
{
createFrame();
initPanel();
addAndShowComponents();
oGameThread = new Thread(this, "Game_Loop");
oGameThread.start();
}
private void addAndShowComponents()
{
oFrame.add(this);
oFrame.setVisible(true);
}
private void initPanel()
{
this.setOpaque(true);
this.setBackground(Color.cyan);
}
private void createFrame()
{
oFrame = new JFrame("Fade");
oFrame.setSize(700, 300);
oFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
oFrame.setLocationRelativeTo(null);
}
public void run()
{
oImage = new BufferedImage(200, 200, BufferedImage.TYPE_INT_ARGB);
while(true)
{
try
{
draw();
Thread.sleep(100);
}
catch(InterruptedException e)
{
}
}
}
private void draw()
{
oPanelGraphics = (Graphics2D)this.getGraphics();
oImageGraphics = oImage.createGraphics();
oImageGraphics.setComposite(AlphaComposite.Src);
oImageGraphics.setColor(new Color(0,0,0,90));
oImageGraphics.fillRect(0, 0, oImage.getWidth(), oImage.getHeight());
oPanelGraphics.drawImage(oImage, 10, 10, null);
oImageGraphics.setColor(new Color(0,0,0,60));
oImageGraphics.fillRect(0, 0, oImage.getWidth(), oImage.getHeight());
oPanelGraphics.drawImage(oImage, 220, 10, null);
oImageGraphics.setColor(new Color(0,0,0,30));
oImageGraphics.fillRect(0, 0, oImage.getWidth(), oImage.getHeight());
oPanelGraphics.drawImage(oImage, 430, 10, null);
// Drawing this image over location of first image, should overwrite first
// after setting composite to 'Src'
oPanelGraphics.setComposite(AlphaComposite.Src);
oImageGraphics.setColor(new Color(0,0,0,10));
oImageGraphics.fillRect(0, 0, oImage.getWidth(), oImage.getHeight());
oPanelGraphics.drawImage(oImage, 10, 10, null);
oImageGraphics.dispose();
oPanelGraphics.dispose();
}
} // end class
有趣的是,在“oPanelGraphics”上设置合成会导致 BufferedImage 的任何 alpha 消失,从而导致在先前存在的图像上绘制完全不透明的黑色图像。即使将颜色设置为黑色以外的颜色也没有效果。
另外有趣的是将 BufferedImage 的合成设置为:
oImageGraphics.setComposite(AlphaComposite.SrcIn);
不显示任何内容。关于在 Java2D 中合成图形的 Oracle 文档为“SrcIn”声明了这一点:
“如果源和目标中的像素重叠,则仅渲染重叠区域中的源像素。”
所以,我希望这具有与 AlphaComposite.Src 相同的行为。
也许有人可以解释一下这些复合材料发生了什么,以及我如何才能达到我想要的效果。
【问题讨论】:
-
您不能覆盖面板中的 onDraw(Graphics g2d) 而不是执行此 draw() 方法吗?
-
@MarcosVasconcelos 是的,这就是我目前正在做的事情。但是,我在游戏中处理效果(过渡、屏幕和音频淡入淡出)的想法是让动作(单击菜单上的“播放”,或角色在某些图块上行走)将消息添加到队列中以进行检查每个游戏打勾。这些效果将触发一个线程并在那里进行处理,并且游戏循环可以继续进行。我目前没有将我的 paintComponent() 提供的 Graphics 对象路由到我的 Effects 类。这就是我在效果线程中使用 getGraphics 的原因
-
根据您的代码,您根本没有覆盖
paintComponent,而是使用getGraphics,这是不推荐的,因为您试图在摆动定义的油漆周期。您也不应该处置不是您创建的Graphics上下文。我也看不出BufferedImage的意义。对于动画在 Swing 中的工作方式,您似乎也没有任何概念 -
根据我的理解(很少),您真正需要的是一个输入(没有应用效果)和输出,应用了效果。这意味着在每个绘制周期中,您都拥有原始的、未更改的图像,然后根据它们的属性和使用时间来应用效果
标签: java swing graphics alpha java-2d