views:

551

answers:

2

Hi,

I'm learning Java by making a small game in a JApplet. I got a little problem with my sprite's animation.

Here is the code :

this.sprite.setBounds(0,0,20,17);

this.sprite.setIcon(this.rangerDown);
for(int i = 0; i< 16;i++)
{
    this.sprite.setBounds(this.sprite.getX(), this.sprite.getY()+1, 20, 17);
    this.sprite.update(this.sprite.getGraphics());

    try{
        Thread.currentThread().sleep(100);
    }catch(InterruptedException e){
}

}

It left some flicker during the animation. Once the animation end, the flicker disappears, but it's kind of ugly... I guess there is some step I missed. I use this method because it gives the better result for now, but I would like to stay without AWT if possible, using Swing instead.

Any ideas how to get rid of the flicker?

Thanks for reading.

Screenshoot (Can't post images, sorry).

+2  A: 

This is not a shadow. Its the border of your sprite. It just happens to be black and appears as a shadow. If you change the amount you shift your sprite (lets say by 50 pixels, not just 1) you will see what i mean.

To fix it what you need to do is to draw the background as well each time you update the location of your sprite. Although this will probably produce flickering.

The correct way to do it is to change the way you draw your objects. You need to override the paintComponent method of your panel and then simply call repaint each time you have updated the locations of your sprites.

EDIT:

See this code sample for basic usage. NOTE: This is NOT how you should write animation using Threads. I wrote that to show you what goes in the paintComponent method and wrote the animation Thread to show you that the "shadow" you mentioned is gone. NEVER have a non ending run loop in a thread :)

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;

import javax.swing.JFrame;
import javax.swing.JPanel;


public class Test {

    public static void main(String[] args) {
     JFrame f = new JFrame("Test");
     MyPanel c = new MyPanel();
     f.getContentPane().add(c);
     f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
     f.setSize(350, 100);
     f.setVisible(true);
    }

}

class MyPanel extends JPanel {

    int x = 0;
    boolean toTheRight = true;

    public MyPanel() {
     new Thread(new Runnable() {

      @Override
      public void run() {
       while (true) {
        x = (toTheRight)?x+5:x-5;
        if (x>300)
         toTheRight = false;
        if (x<0)
         toTheRight = true;
        repaint();
        try {
         Thread.sleep(50);
        } catch (InterruptedException e) {
         e.printStackTrace();
        }
       }
      }
     }).start();
    }

    @Override
    protected void paintComponent(Graphics g) {
     Graphics2D g2 = (Graphics2D)g.create();
     g2.setPaint(Color.white);
     g2.fillRect(0, 0, getWidth(), getHeight());
     g2.setPaint(Color.red);
     g2.fillOval(x-2, 50, 4, 4);
    }

}
Savvas Dalkitsis
Thanks for the answer. Is there a way to do it with Swing ? It seems quite a complex method for a simple thing.
Cheshire
This is the default way to draw custom things on panels with swing. You override paintComponent which provides you with a Graphics object which you can safely cast to a Graphics2D object and do your thing. This method ensures also that your drawing will be double buffered so you wont have to worry about flickering.
Savvas Dalkitsis
Ok, the word 'flickering' let me find infos on Google. I'll continue to search for a simple solution. Thanks again.
Cheshire
you might also want to show you appreciation by upvoting the answer along accepting it :P :P :P
Savvas Dalkitsis
I can't : 15 rep' needed. Sorry.
Cheshire
hehe true. :) forgot about that...
Savvas Dalkitsis
A: 

The problem is double buffering.

In Applets: Double buffering is done almost automatically. Call repaint() instead of paint in your method.

In Swing, there are many ways to do it. I usually go for the BufferStrategy route. When you're initializing your frame, do this:

JFrame frame;
... code to init frame here
frame.createBufferStrategy(2);

Then in your draw methods:

Graphics g = getBufferStrategy().getDrawGraphics();
..code to do drawing here...
g.dispose();
getBufferStrategy().show();
Cobalt
If I change "this.sprite.update(this.sprite.getGraphics());" to "this.sprite.repaint()", there is no animation : only the last position's sprite is visible. I believe the repaint() method is only truly used when the program got nothing else to do. However, I did see that solution elsewhere, so I probably don't use the repaint() method correctly. It is in a JApplet, I never used JFrame (isn't getContentPane() the JFrame's remplacement in JApplets ?). Well, I use update() because it gives the best result, but I would like to stay with Swing as much as possible.
Cheshire