我正在制作一个简单的2D游戏。每次滴答,我都想检查一个效果队列,该队列将启动一个线程以获得特定效果(淡入淡出过渡、音频淡入淡出等)。例如,在菜单屏幕上按“播放”将向该队列添加“淡出”消息,该消息将被处理并启动一个线程,以在我的游戏面板上绘制一个黑色矩形,并增加阿尔法值。
我重写了绘制组件(),并将我的图形对象发送到我的游戏状态管理器,它将图形对象传递到当前状态的绘制()。我目前没有一个效果状态(也许我应该)来将绘制组件()图形对象路由到,但我确实将我的游戏面板传递到我的效果线程,在那里我可以使用getGraphics()来绘制它。直接向游戏面板绘制一个矩形只会导致闪烁,因为gameloop仍在渲染游戏。
我发现我可以绘制一个黑色矩形,将alpha增加到一个BufferedImage,将composite设置为AlphaComposite。Src(这会导致新绘图替换旧绘图)然后在游戏面板上绘制BuffereImage。问题是绘制到游戏面板的BuffereImage不会在每次绘制时被覆盖,因此淡出会很快发生,因为这些不同字母的黑色BuffereImage只是堆叠在一起。
我编写了这个简短的程序来测试复合设置并查看什么被覆盖。所有绘图都在绘图()中完成,这将是我在效果线程中的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”会导致缓冲区图像的任何alpha消失,从而在之前的图像上绘制出完全不透明的黑色图像。即使将颜色设置为黑色以外的颜色也没有效果。
同样有趣的是将BufferedImage的复合设置为:
oImageGraphics.setComposite(AlphaComposite.SrcIn);
导致不显示任何内容。关于在Java2D中合成图形的Oracle文档为“SrcIn”说明了这一点:
如果源和目标中的像素重叠,则仅渲染重叠区域中的源像素
因此,我希望它具有与AlphaComposite相同的行为。Src。
也许有人可以解释一下这些复合材料是怎么回事,以及我怎样才能达到我想要的效果。
你“似乎”想要做的事情有很多问题
getGraphics
。这可以返回null
,并且仅返回Swing绘制周期中最后绘制的内容的快照。您绘制的任何内容都将在下一个绘制周期中被擦除Graphics
上下文,这样做可能会影响Swing绘制的其他组件Graphics
上下文(或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 html" target="_blank">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不是线程安全的,如果可能的话,您应该避免拥有任何额外的线程。此示例使用SwingTimer
充当“主循环”,因为ActionLister
的actionPerform
方法是在EDT的上下文中调用的,因此可以安全地从更新UI。它还提供了一个简单的同步方法,因为在调用actionPerform
方法时无法绘制UI
问题内容: 我正在做一项家庭作业,我应该制作一个程序,使您可以绘制自定义形状和线条,并在屏幕上移动它们。 最初,我使用公共空隙进行绘画,但是当我调用重绘时,形状会闪烁。 因此,我切换到。但是,当我尝试绘制形状时,没有任何显示。我相信这是因为它不在顶部绘画。 框架在3行中有3个面板。 我想绘制的面板自然是Draw Box面板。 这是我目前拥有的代码: 问题答案: 您的Main类扩展了JPanel,具
将显示JFrame和JPanel,但paintComponent方法不在JPanel上绘制。我只看到我添加的JLabel、JTextField和JButton,而没有看到应该在JPanel上绘制的内容。
我是java图形的新手,很难掌握从一个方法(绘制组件())绘制所有图形的整个概念。我只是很好奇,看看我们是否可以在绘制组件之外绘制图形。这可能吗?是否可以在main方法中写一行,如:fillRect(100,100, 500,400);并让它绘制一个矩形?如果可能,是否根据Java常规? 基本上,我想问的是,你是否可以在paintComponent类之外绘制图形,这是常规的吗。
我在想哪里出了问题。我以前做过这个,但由于某种原因,这次我不能让它工作。 我用Netbeans设计了这个项目。最相关的部分是initTiras方法,它被认为可以绘制一些东西,但它没有。我包含了NetBeans生成的代码。 这是代码的最简化版本,但它仍然没有绘制任何内容。 所以我在项目中创建了一个新的框架。然后我把一个JPanel放进去(在设计模式下)。JPanel称为ElPanel和JFrame
问题内容: 我有使用内联样式的标记,但是我无权更改此标记。如何仅使用CSS覆盖文档中的内联样式?我不想使用jQuery或JavaScript。 HTML: CSS: 问题答案: 覆盖内联样式的唯一方法是使用CSS规则旁边的关键字。以下是一个示例。 重要笔记: 使用不是一个好的做法。因此,您应避免同时使用内联样式。 将关键字添加到任何CSS规则后,该规则就可以 强行优先 于该元素的 所有其他CSS规