How do you double buffer in java for a game? - java

So in the game I'm working on, I have a marble follow the mouse, but when it does this the screen flickers.
The background includes two jpegs and 9 rectangles. How would I go about double buffering this? Here is the code for the main window.
/**
* Write a description of class Window here.
*
* #author (your name)
* #version (a version number or a date)
*/
public class Window extends JApplet implements MouseMotionListener
{
private BufferedImage image;
private BufferedImage side;
private int mouseX;
private int mouseY;
public Window(){
try {
image = ImageIO.read(new File("Backgrounds/violet.jpg"));
side = ImageIO.read(new File("Backgrounds/side margin.jpg"));
} catch (IOException ex) { }
}
private void delay(int delay)
{
try {
Thread.sleep(delay);
} catch (InterruptedException e) {}
}
public void init()
{
this.addMouseMotionListener(this);
}
public void paint (Graphics page)
{
page.drawImage(image, 0, 0, null);
page.setColor(Color.blue);
page.fillRect(0, 0, 160, 160);
page.setColor(Color.black);
page.fillRect(15, 15, 130, 130);
page.setColor(Color.green);
page.fillRect(340, 0, 160, 160);
page.setColor(Color.black);
page.fillRect(355, 15, 130, 130);
page.setColor(Color.yellow);
page.fillRect(0, 340, 160, 160);
page.setColor(Color.black);
page.fillRect(15, 355, 130, 130);
page.setColor(Color.red);
page.fillRect(340, 340, 160, 160);
page.setColor(Color.black);
page.fillRect(355, 355, 130, 130);
page.drawImage(side, 500, 0, null);
page.drawString(Score.getScore(), 560, 110);
//conveyors
page.setColor(Color.gray);
page.fillRect(235, 0, 30, 160);
//marble
delay(100);
page.fillOval(mouseX, mouseY , 40, 40);
}
public void mouseMoved(MouseEvent e)
{
mouseX = e.getX();
mouseY = e.getY();
repaint();
}
public void mouseDragged(MouseEvent e)
{
}
}

Double buffering is conceptually pretty simple, instead of drawing your objects one by one, you draw them on an image and then tell the renderer to draw that entire image. This eliminates the flickering.
Here's an example of how you might do this (source)
class DoubleBufferedCanvas extends Canvas {
public void update(Graphics g) {
Graphics offgc;
Image offscreen = null;
Dimension d = size();
// create the offscreen buffer and associated Graphics
offscreen = createImage(d.width, d.height);
offgc = offscreen.getGraphics();
// clear the exposed area
offgc.setColor(getBackground());
offgc.fillRect(0, 0, d.width, d.height);
offgc.setColor(getForeground());
// do normal redraw
paint(offgc);
// transfer offscreen to window
g.drawImage(offscreen, 0, 0, this);
}
}
Nowdays, you don't have to implement this yourself, you can use the BufferStrategy and releated classes. See lakam99's answer for an example of that .

Swing supports double buffering automatically, so you don't need to code anything.
Just call setDoubleBuffered(true) on your top-level component (typically a JPanel) and it should all work.
See: setDoubleBuffered

Another solution is to use a library that will double buffer for you. Since you are using Java2D I am assuming you want to keep everything pretty lightweight and lower level. I think Slick2D does a great job of providing simple, 2d drawing and input functions without getting in your way. It feels like a more elegant version of Java2D, but is written on OpenGL. Once you make a few applications with pure Java, I think moving to Slick2D is a GREAT idea. This is not a direct solution to your issue, but since it has already been solved I thought Id offer some advice that will make your Java game development life easier. Check it out if you get a chance http://slick.cokeandcode.com/

I think your problem is not double buffering. You must add super.paint(page); at the first line of your paint method.

Related

How to make smiley face that follows the cursor of the mouse

I'm trying to draw a SMiley Face that moves when the mouse is moved or dragged using AWT and Swing.
I have tried to implement the MouseMotionListener but I'm not sure what I'm doing wrong because I don't see it working. Below is the code:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class SmileyFace extends JPanel implements MouseMotionListener {
private int x, y;
public SmileyFace() {
addMouseMotionListener(this);
}
public void mouseDragged(MouseEvent e) {
x = e.getX();
y = e.getY();
repaint();
}
public void mouseMoved(MouseEvent e) {
x = e.getX();
y = e.getY();
repaint();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.YELLOW);
g.fillOval(100, 100, 200, 200);
g.setColor(Color.BLACK);
g.drawOval(100, 100, 200, 200);
g.drawOval(155, 155, 10, 10);
g.drawOval(230, 155, 10, 10);
g.drawArc(150, 200, 100, 50, 0, -180);
}
}
I wish to know what I've not done correctly.
You're not updating the smiley face when the mouse is moved with the appropriate x and y coordinates. Set the private int x, y; to the coordinates that you would like to be the default and replace the coordinates in the circle drawing section with those (for the elements like the eyes and mouth, add/subtract appropriate amounts onto their values). Once the mouse moves, the variables should be updated and the smiley will be moved.

JPanel drawing chart in a loop. need help for swing gui

I am trying to draw charts in a tab of a JTabbedPane. Each tab contains a JPanel but my code drawing charts to tab which is opened in front of me, not to constant tab.
public class Grafik extends JPanel {
public Grafik(){
try {
//this block for opening ready chart images to using in panel.
Arayuz.imageGrafikSicaklik = ImageIO.read(new FileImageInputStream(new File("Sıcaklık.png")));
Arayuz.imageGrafikBasinc = ImageIO.read(new FileImageInputStream(new File("Basınç.png")));
Arayuz.imageGrafikHiz = ImageIO.read(new FileImageInputStream(new File("Hız.png")));
Arayuz.imageGrafikYukseklik = ImageIO.read(new FileImageInputStream(new File("Yükseklik.png")));
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void paint(Graphics g) {
super.paint(g);
g.setColor(Color.WHITE);
g.drawImage(Arayuz.imageGrafikSicaklik, 36, 16, Arayuz.imageGrafikSicaklik.getWidth(), Arayuz.imageGrafikSicaklik.getHeight(), this);
g.drawImage(Arayuz.imageGrafikBasinc, 736, 16, Arayuz.imageGrafikBasinc.getWidth(), Arayuz.imageGrafikBasinc.getHeight(), this);
g.drawImage(Arayuz.imageGrafikHiz, 36, 398, Arayuz.imageGrafikHiz.getWidth(), Arayuz.imageGrafikHiz.getHeight(), this);
g.drawImage(Arayuz.imageGrafikYukseklik, 740, 398, Arayuz.imageGrafikYukseklik.getWidth(), (Arayuz.imageGrafikYukseklik.getHeight()*1009)/1000, this);
//Arayuz.ggg = Arayuz.grafikPaneli.getGraphics();
}
public void grafikCizimSıcaklık(JPanel grafikpaneli, int startX, double instantHeat){
Graphics cizici = grafikpaneli.getGraphics();
cizici.drawLine(startX,(int) (280 - (instantHeat / 3) * 20), startX + 3, (int) (280 - (instantHeat / 3) * 20));
}
First of all while I am watching chart's Tab, everything is correct for now.
When I switch to another tab, charts will be deleted and starting to draw in that tab and that is my problem.
The first chart deleted and charts are continue in another tab which is i am watching.
I hope that I can explain my problem correctly. Thanks for everything from now.
You could use a JLabel and put the image, otherwise you should put the background image by overwriting the paintcomponent().
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(image, 0, 0, this);
}
You class should extends JPanel and you need an Image:
private BufferedImage image;
try {
image = ImageIO.read(new File("HERE ADD YOUR IMG PATH));
} catch (IOException ex) {
logger.error("errorImgPath" + ex.toString());
}

Different animation on different display. Android

I have problem with animation in android.
My animations working good only on 1080x1920 480dpi display. But i don't know how made app for any display.
If I use method from http://www.i-programmer.info/programming/android/8797-android-adventures-beginning-bitmap-graphics.html?start=4 Animations run, ok but made shadows, so no rewrite display if I write on display something I not delete thise from display.
If I use method. Main activity have one threat
public class UpdateThread implements Runnable {
#Override
public void run() {
while(bez){
try {
myThread.sleep(50);
} catch (Exception ex) {}
MainActivity.this.updateHandler.sendEmptyMessage(0);
}
}
and Class Game who every 50ms do
public void update() {
x += 1;
y += 2;
}
And on draw method in this class
protected void onDraw(Canvas canvas) {
Plocha pozadie = new Plocha(paint, canvas, X0, Y0, vzdialenost);
if (nehra==true) {
paint.setStrokeWidth(13F);
paint.setStyle(Paint.Style.STROKE);
LevelUp(level);
paint.setTypeface(Typeface.DEFAULT_BOLD);
paint.setStyle(Paint.Style.FILL);
pozadie.vypis(paint, canvas, "Score", 100, 100, 6);
pozadie.vypis(paint, canvas, Integer.toString(zasah), 90, 200, 9);
pozadie.vypis(paint, canvas, "Level", 850, 100, 6);
pozadie.vypis(paint, canvas, Integer.toString(level), 850, 200, 8);
pozadie.vypis(paint, canvas, "Clicks", 1080 / 2 - 100, 100, 7);
pozadie.vypis(paint, canvas, Integer.toString(click), 1080 / 2, 200, 9);
}
everything be okay (y) but only one type display.
If use
Bitmap b = Bitmap.createBitmap(1080,
1920,Bitmap.Config.ARGB_8888);
this.canvas = new Canvas(b);
this.canvas.drawColor(Color.WHITE);
this.b=b;
and rewrite some parts of code
application result is these canvas
protected void onDraw( Canvas canvas ) {
I don't know why...
ImageView im=(ImageView)findViewById(R.id.imageView222);
game = new Game(this,im);
setContentView(game);
I think so If I save setContentView(game); to imageview. will be everything okay. But I try and every ideas finish more errors.
I'm sad from...
Thanks from some ideas.

Java Passing 2D Graphic as a Parameter

I have a function that is drawing an image and then saving it immediately after but the problem is that it seems to be drawing it twice, once for the view on the screen and then once to save it to the disk
public class myFrame {
public static void main(String[] args) {
JFrame lv_frame = new JFrame();
// setup jframe here
lv_frame.add(new image());
lv_frame.setVisible(true);
}
}
class image extends JPanel {
public void paintComponent(Graphics graphic) {
super.paintComponent(graphic);
draw(graphic);
save();
}
public void draw(Graphics graphic) {
Graphics2D graphic2D = (Graphics2D) graphic;
graphic2D.fillArc(0, 0, 250, 250, 0, 90);
}
public void save() {
BufferedImage image = new BufferedImage(250, 250, BufferedImage.TYPE_4BYTE_ABGR_PRE);
Graphics2D graphic2D = image.createGraphics();
try {
File output = new File("file.png");
// is it possible to use the graphic I've already
// drawn here instead of re-drawing?
draw(graphic2D);
ImageIO.write(image, "png", output);
} catch(IOException log) {
System.out.println(log);
}
}
}
I have a function draw which creates the image on the gui screen and another function save which saves it to the disk but the save function is calling draw as well.
Is it possible to save the image that has already been drawn without re-calling the draw function as it is being done in my code?
I was answering your question on Display to GUI and Save to Disk with a Single Object/Variable, however it was closed probably due to the similar nature of your question.
I think there are several issues which you seemed confused with and I would like to write my solution here which also addresses your question in your duplicated post.
Is it possible to save the image that has already been drawn without re-calling the draw function as it is being done in my code?
Don't be confused between drawing an image on the Panel and saving it. The following shows a working example on saving a drawn image.
class DrawingSpace extends JPanel
{
private BufferedImage buf;
public DrawingSpace(){
setPreferredSize(new Dimension(200, 200));
buf = new BufferedImage(200, 200, BufferedImage.TYPE_INT_ARGB);
drawOnBuffer();
}
public void drawOnBuffer(){
Graphics g = buf.createGraphics();
g.setColor(Color.BLUE);
g.fillOval(0,0,200,200);
g.setColor(Color.RED);
g.fillOval(50,50,100,100);
g.dispose();
}
public void saveBufferAsImage(String pathname){
String fmt = "";
if(!(pathname == null || pathname.equals(""))){
fmt = pathname.substring(pathname.lastIndexOf(".")+1);
File outputfile = new File(pathname);
try{
ImageIO.write(buf, fmt, outputfile);
}catch(IOException ioe){System.out.println("Unable to save file");}
}
}
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
g.drawImage(buf, 0, 0, 200, 200, null); //Only for user to see
}
}
To save an image, you not necessarily have to draw and display it in the JPanel first. Note that I created a BufferedImage called buf and I am drawing on buf. Once I have drawn onto a BufferedImage, I can simply save that image as a file (I don't have to draw it to the panel first).
Notice that I did the following:
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
g.drawImage(buf, 0, 0, 200, 200, null); //Only for user to see
}
g.drawImage(buf, 0, 0, 200, 200, null) will draw whatever on buf onto the JPanel. It can be deleted and the saving will still work. When I draw it on the panel, it is only for the user to see the outcome of the drawing.
To test the program:
class SaveImageRunner{
public static void main(String[] args){
SwingUtilities.invokeLater(new Runnable(){
#Override
public void run(){
JFrame frame = new JFrame("Saving a buffered image");
DrawingSpace ds = new DrawingSpace();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(ds);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
ds.saveBufferAsImage("BlueCircle.png");
}
});
}
}
Saved Image:
Some pointers on drawing:
paintComponent(Graphics) shall only contain codes for drawing and nothing else. Do not implement your codes for saving the image to a file inside here.
Try not to create a new BufferedImage in the paintComponent(Graphics). If not, a new instance of a BufferedImage will be created on every repaint.
Change the place where you create the graphics2D object and reuse it.
Try this out.
public class myFrame {
public static void main(String[] args) {
JFrame lv_frame = new JFrame();
// setup jframe here
lv_frame.add(new image());
lv_frame.setVisible(true);
}
}
class image extends JPanel {
public void paintComponent(Graphics graphic) {
super.paintComponent(graphic);
// Image and graphics are now created here
BufferedImage image = new BufferedImage(250, 250, BufferedImage.TYPE_4BYTE_ABGR_PRE);
Graphics2D graphic2D = image.createGraphics();
draw(graphic2D);
save(image);
}
public void draw(Graphics graphic) {
Graphics2D graphic2D = (Graphics2D) graphic;
graphic2D.fillArc(0, 0, 250, 250, 0, 90);
}
public void save(BufferedImage image) {
try {
File output = new File("file.png");
ImageIO.write(image, "png", output);
} catch(IOException log) {
System.out.println(log);
}
}
}
EDIT
I have found the answer in another post. It is not a bad idea to make the drawing twice. What you are doing is, like #Hovercraft says in this post, separating the screen drawing from the writing to files so that you don't see your graphics drawing performance hurt.
I have tried to make the drawing only once but you have no easy method to store the drawing Graphics object. Probably, it is implemented to prevent this. If you see the way the method works, you are given the Graphics object with the only purpose to draw on it. Using it in other ways could impact the performance.

Java Double Buffering - Only Every Other Frame Drawn

I'm trying to develop a full-screen application, but I'm having issues with double buffers.
public void create ()
{
window = new JWindow ();
window.setIgnoreRepaint (true);
GraphicsEnvironment.getLocalGraphicsEnvironment ().getDefaultScreenDevice ().setFullScreenWindow (window);
window.setVisible (true);
window.createBufferStrategy (2);
}
public void renderCycle ()
{
BufferStrategy strategy = window.getBufferStrategy ();
while (true)
{
render ((Graphics2D) strategy.getDrawGraphics ());
strategy.show ();
}
}
public void render (Graphics2D g)
{
g.setColor (Color.WHITE);
g.drawString ("Veikia", 100, 100);
}
I see a heavy flickering - it seems as if the text is drawn only on every other buffer and remaining buffers contain white background. What could be the problem?
I just tried this MultiBufferTest. I didn't see any rendering artifact until the lag period fell below the monitor's corresponding refresh rate. Your example appears to have no delay between frames.
I added a few lines to show the frame period:
...
g.fillRect(0, 0, bounds.width, bounds.height);
g.setColor(Color.black); // added
g.drawString(String.valueOf(lag), 100, 100); // added
bufferStrategy.show();
...

Categories

Resources