gpt4 book ai didi

java - 如何使用 getGraphics() 覆盖 PaintComponent() 外部绘制到 JPanel 的 BufferedImage

转载 作者:行者123 更新时间:2023-12-02 12:10:05 27 4
gpt4 key购买 nike

我正在开发一个简单的 2D 游戏。每个刻度,我想检查一个效果队列,该队列将启动一个线程以实现某种效果(淡入淡出过渡、音频淡入和淡出等)。例如,按菜单屏幕上的“Play”将向此队列添加一条“FadeOut”消息,该消息将被处理并启动一个线程在我的 GamePanel 上绘制一个具有不断增加的 alpha 值的黑色矩形。

我正在重写paintComponent()并将我的Graphics对象发送到我的GameStateManager,后者将Graphics对象传递到当前状态的draw()。我目前没有效果状态(也许我应该)来将 PaintComponent() 图形对象路由到,但我确实将游戏面板传递到效果线程,在那里我可以使用 getGraphics() 在其上绘图。直接在 GamePanel 上绘制矩形只会导致闪烁,因为游戏循环仍在渲染游戏。

我发现我可以在 BufferedImage 上绘制一个增加 alpha 的黑色矩形,将合成设置为 AlphaComposite.Src (这会导致新的绘制替换旧的),然后在游戏面板上绘制 BufferedImage。问题是绘制到游戏面板的 BufferedImages 不会在每次绘制时被覆盖,因此淡出发生得非常快,因为这些不同 alpha 的黑色 BufferedImages 只是相互堆叠。

我编写了这个简短的程序来测试复合设置并查看哪些内容被覆盖。所有的绘制都是在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 相同的行为。

也许有人可以阐明这些复合 Material 的情况,以及如何实现我想要的效果。

最佳答案

您“似乎”正在尝试做的事情存在许多问题

  • 请勿调用getGraphics在一个组件上。这可以返回 null并且仅返回 Swing 绘制周期中最后绘制内容的快照。您在其上绘制的任何内容都将在下一个绘制周期中被删除
  • 您也不应该处置 Graphics您没有创建上下文,这样做可能会影响 Swing 绘制的其他组件
  • 绘画是复合,这意味着绘画是相同的Graphics context (或 BufferedImage )一遍又一遍,将继续在之前绘制的内容之上应用这些更改
  • 您似乎也不知道动画应该如何工作。您不需要尝试在单次渲染中绘制淡入淡出效果(结果无法应用到屏幕),而是需要在每个周期应用一个阶段,并允许在下一次渲染运行之前将其更新到屏幕。

以下是我所讨论内容的一个非常基本的示例。它需要一个“基本”图像(这可能是游戏的“基本”状态,但我使用了静态图像)和顶部的绘画效果。

Fade to black

import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Test {

public static void main(String[] args) {
new Test();
}

public Test() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}

JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}

public class TestPane extends JPanel {

private Engine engine;
private Image frame;

public TestPane() {
engine = new Engine();
engine.setEngineListener(new EngineListener() {
@Override
public void updateDidOccur(Image img) {
frame = img;
repaint();
}
});
engine.start();

addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
engine.addEffect(new FadeOutEffect(Color.BLACK));
}
});
}

@Override
public Dimension getPreferredSize() {
return engine.getSize();
}

@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (frame != null) {
Graphics2D g2d = (Graphics2D) g.create();
g2d.drawImage(frame, 0, 0, null);
g2d.dispose();
}
}

}

public interface EngineListener {

public void updateDidOccur(Image img);
}

public class Engine {

// This is the "base" image, without effects
private BufferedImage base;
private Timer timer;
private EngineListener listener;

private List<Effect> effects = new ArrayList<Effect>(25);

public Engine() {
try {
base = ImageIO.read(new File("/Volumes/Big Fat Extension/Dropbox/MegaTokyo/megatokyo_omnibus_1_3_cover_by_fredrin-d4oupef 50%.jpg"));
} catch (IOException ex) {
ex.printStackTrace();
}

timer = new Timer(10, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
int width = base.getWidth();
int height = base.getHeight();
BufferedImage frame = new BufferedImage(width, height, base.getType());
Graphics2D g2d = frame.createGraphics();
g2d.drawImage(base, 0, 0, null);
Iterator<Effect> it = effects.iterator();
while (it.hasNext()) {
Effect effect = it.next();
if (!effect.applyEffect(g2d, width, height)) {
it.remove();
}
}
g2d.dispose();
if (listener != null) {
listener.updateDidOccur(frame);
}
}
});
}

public void start() {
timer.start();
}

public void stop() {
timer.stop();
}

public void addEffect(Effect effect) {
effects.add(effect);
}

public void setEngineListener(EngineListener listener) {
this.listener = listener;
}

public Dimension getSize() {
return base == null ? new Dimension(200, 200) : new Dimension(base.getWidth(), base.getHeight());
}

}

public interface Effect {
public boolean applyEffect(Graphics2D context, int width, int height);
}

public class FadeOutEffect implements Effect {

private int tick = 0;
private Color fadeToColor;

public FadeOutEffect(Color fadeToColor) {
this.fadeToColor = fadeToColor;
}

@Override
public boolean applyEffect(Graphics2D context, int width, int height) {
tick++;
float alpha = (float) tick / 100.0f;
if (alpha > 1.0) {
return false;
}
Graphics2D g2d = (Graphics2D) context.create();
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha));
g2d.setColor(fadeToColor);
g2d.fillRect(0, 0, width, height);
g2d.dispose();
return true;
}

}

}

请记住,每个效果或更改都应该应用在同一个“主循环”中,这意味着您不应该有多个线程,事实上,由于 Swing 不是线程安全的,因此您应该尽可能避免任何额外的线程。此示例使用 Swing Timer充当“主循环”,因为 ActionLister actionPerformed方法在 EDT 上下文中调用,从而可以安全地更新 UI。它还提供了一个简单的同步方法,因为 actionPerformed 期间无法绘制 UI。方法被调用

关于java - 如何使用 getGraphics() 覆盖 PaintComponent() 外部绘制到 JPanel 的 BufferedImage,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46607762/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com