- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在开发一个简单的 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
)一遍又一遍,将继续在之前绘制的内容之上应用这些更改以下是我所讨论内容的一个非常基本的示例。它需要一个“基本”图像(这可能是游戏的“基本”状态,但我使用了静态图像)和顶部的绘画效果。
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/
在 drawToScreen 方法内调用 getGraphics() 时,我的 JPanel 预览返回 null。 Test 类也扩展了 JPanel,因为它被保存在 TabbedPane 中。该类还
很难说出这里问的是什么。这个问题是含糊的、模糊的、不完整的、过于宽泛的或修辞性的,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开它,visit the help center 。 已关
我正在尝试在扩展了 JComponent 类的地方呈现自定义 Swing 组件。 为了简化组件需求,让我们将我的组件总结为需要渲染几个字符串,每个字符串都有自己的字体。 我需要我的组件的大小完全符合我
我的应用程序看起来像这样,我在 draw() 方法中遇到空指针异常,准确地说是在 g.drawImage(img, 0, 0, null) 处 package com.ochs.game; impor
我正在做一个选择工具,我已经提供了这些解决方案,在第一个使用 JPanel getGraphics 方法中,我在鼠标拖动的地方绘制一个椭圆形,在第二个中,我重写 PaintComponent 方法来绘
我有一个带有 JPanel 和 PaintComponent() 的类。我还有一个实现 Runnable 的类,我计划在线程启动后将图像绘制到 PaintComponent 上。我的构造函数接收 JP
嗨,我是 java GUI 编程新手。我创建了 Jframe(MainFrame) 并添加了 JPanel(OutPanel),其中还有另一个 Jpanel(InnerPanel)。我尝试在 Inne
我开始学习用 Java 创建游戏,我使用的其中一种方法包括 BufferedImage。这是我得到的错误: "Exception in thread "main" java.lang.NullPoin
由于 Java 只支持单继承,我希望直接在 JPanel 的实例上绘制,它是类 面板。我从成员那里获取了一个 Graphics 的实例,然后在上面绘制我想要的任何东西。 我怎么能不继承 JCompon
我有底部导航,我也替换了 标记为 FragmentContainerView它给了我关于它没有设置 NavController 的错误,然后我被发布 this问题并解决了问题,但是当方向更改并在底部导
我想知道出了什么问题。我以前曾这样做过,但由于某种原因,这次我无法让它发挥作用。 我在 Netbeans 中设计了该项目。最相关的部分是 initTiras 方法,它应该绘制一些东西,但它没有。我包含
我正在尝试一个充当按钮但使用图像进行显示的对象。我的问题是,当调用 getGraphics() 时,它返回 null。我到处找也没找到原因? 我的构造函数的代码是...... public class
我在这里遇到了一些困难。我在尝试解决这个问题时在其他地方读到,你永远不应该 getGraphics()。问题是,我无法使用 Paint()/PaintComponent() 方法提供的 Graphic
下面是代码(我在这个类中扩展了 JFrame)(Point 'size' 是屏幕的大小): setVisible(true); backBuffer = createImage(size.x, siz
public void saveImage(String path){ BufferedImage image = (BufferedImage) createImage(500, 500);
如果我正在使用 JPanel,getGraphics 返回的 Graphics 对象与在 paintComponent 方法中传递的 Graphics 对象有什么区别? 最佳答案 getGraphic
我在调用 BufferedImage.getGraphics() 方法的某些框架 API 时遇到问题,从而导致内存泄漏。这个方法的作用是它总是调用 BufferedImage.createGraphi
如何在没有类(扩展 JFrame)的情况下绘制对象?我找到了 getGraphics 方法,但它没有绘制对象。 import javax.swing.*; import java.awt.*; pub
(这是 previous 问题的后续) 将 BufferedImage 从一种类型转换为另一种类型或制作副本的标准推荐方法是使用 getGraphics().drawImage() ( example
MadProgrammer 发表了评论here声明您永远不应该使用 Component.getGraphics,我普遍同意这一点:在几乎所有情况下,它都是错误的。 但以我多年前创建的这个类为例。我正在
我是一名优秀的程序员,十分优秀!