XOR'ing BufferedImages onto a Graphics2D object
i've begun programming a game in java, and was wondering how one would XOR a sprite onto a Graphics2D object. i know about Graphics2D's setXORMode() method, but i'm unsure how to apply it correctly.
if you aren't sure what XOR logic is for displaying sprites, here is a good link to show a graphical example. the images are in black and white, but the concept applies to colored images as well.
Re: XOR'ing BufferedImages onto a Graphics2D object
Quote:
i know about Graphics2D's setXORMode() method, but i'm unsure how to apply it correctly.
What have you tried? It's a two-liner to use that mode: set the color, then set the XOR color.
To get better help sooner, post a SSCCE (Short, Self Contained, Compilable and Executable) example that demonstrates the problem.
db
Re: XOR'ing BufferedImages onto a Graphics2D object
i tried to make it short but it still ended up relatively long.. here's the code:
Code java:
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import javax.swing.*;
import java.io.File;
import javax.imageio.ImageIO;
public class Example extends JFrame{
MyPanel panel;
BufferedImage bg, sprite;
public static void main(String[] args){
new Example();
}
public Example(){
mainLoop();
}
public void mainLoop(){
try{
bg = ImageIO.read(new File("")); // your file
sprite = ImageIO.read(new File("")); // your file
}
catch(java.io.IOException e){
e.printStackTrace();
}
JFrame frame = new JFrame();
frame.setSize(200,200);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
panel = new MyPanel(bg, sprite);
frame.getContentPane().add(panel);
panel.getInputMap().put(KeyStroke.getKeyStroke("RIGHT"),"moveRight");
panel.getActionMap().put("moveRight",moveRight);
frame.setVisible(true);
while(true){
panel.updateScreen();
}
}
Action moveRight = new AbstractAction() {
public void actionPerformed(ActionEvent e) {
panel.xPos += 3;
}
};
}
class MyPanel extends JPanel{
BufferedImage buffer = new BufferedImage(200,200,BufferedImage.TYPE_4BYTE_ABGR);
Graphics2D g2d;
BufferedImage sprite;
int xPos = 0;
public MyPanel(BufferedImage bg,BufferedImage sp){
g2d = buffer.createGraphics();
g2d.drawImage(bg,null,0,0);
sprite = sp;
}
// issue lies here.
public void updateScreen(){
Graphics2D screen = (Graphics2D) this.getGraphics();
g2d.setXORMode(Color.WHITE);
g2d.drawImage(sprite,null,xPos,30);
screen.drawImage(buffer,null,0,0);
g2d.drawImage(sprite,null,xPos,30);
}
}
if you take out g2d.setXORMode(Color.WHITE); , the program runs as expected. the sprite bufferedimage moves across the screen if you hold down the right arrow key.
however, it leaves image debris. i know that i could have my method draw the background, and then draw the sprite every frame, but that is slow. what i am trying to do is use XORMode so that you draw the sprite to the buffer, display the buffer (so the user sees the sprite), and then XOR the sprite again, leaving the buffer as just the background.
edit: and i just noticed i had Example implement JFrame but made a JFrame object in the class anyway.. ignore that and the many other flaws. this was written at around 1 in the morning.
Re: XOR'ing BufferedImages onto a Graphics2D object
First, I would highly recommend doing all your painting using the paintComponent method, and not have your own infinite 'mainLoop'. The EDT takes care of all of this for you and then some. If you need to redraw for animation, use a SwingTimer. Changing your code to using the EDT should take care of the immediate problem of sprite 'trails'.
Re: XOR'ing BufferedImages onto a Graphics2D object
Never never never use getGraphics() of a Component. Recommended reading, in line with copeg's recommendation:
Lesson: Performing Custom Painting (The Java™ Tutorials > Creating a GUI With JFC/Swing)
Don't forget to invoke the super implemetation at the head otf the paintComponent override, unless your custom painting fills the entire area with non-transparent pixels.
db
Re: XOR'ing BufferedImages onto a Graphics2D object
Quote:
Originally Posted by
Darryl.Burke
why not? i had it working using paintComponent, but it was at least 5 times slower than using a buffer. plus, if i need to, i can using a SwingTimer to control the painting of the screen manually. basically, what's the advantage of an EDT over manually creating a buffer? and lastly, can anyone answer my original question, how to use XORMode when dealing with moving sprites?
Re: XOR'ing BufferedImages onto a Graphics2D object
Quote:
Originally Posted by
nemo
why not?
Because you don't know what state the Graphics component is in, and accessing it from a different thread (eg the main thread as opposed the EDT thread) makes matters much worse. Things like window resizes, events, and/or layouts can change the graphics object. Meaning it can get wiped out, transformed, or worse set to null while you are trying to access it, resulting in unexpected behavior. And when I say unexpected I mean unexpected - it may work now but down the line you never know. Using paintComponent ensures you will paint to a Graphics object with the expected behavior.
Quote:
i had it working using paintComponent, but it was at least 5 times slower than using a buffer. plus, if i need to, i can using a SwingTimer to control the painting of the screen manually.
If its that much slower that it is noticeable to a human, you should profile the code and fix the bottleneck. Things you are doing should be lightning fast, and if they are not there are always ways to fix it and speed it up.
Quote:
basically, what's the advantage of an EDT over manually creating a buffer?
No unexpected behavior I mentioned above, Listeners (ActionListener, MousetListener, KeyListener, etc...) already managed for you, more assurance the code is portable..are just a few. And you aren't manually creating a buffer, you are retrieving the one created for you by Swing in the EDT.
Quote:
and lastly, can anyone answer my original question, how to use XORMode when dealing with moving sprites?
I haven't played with this option for some time, so shouldn't lead you astray with my assumptions.