1

I'm trying to build a 2d game.

I have a background-image that static and an Image of the character. When i press a move-key (WASD) the Mainclass (were the keylistener is) calling a function in a class called Player The function is changing the location of the character (Image). And after this function is called i use repaint() to repaint the character on new position. If i remove the background i can see the old images still left from the other positions. So this meens i have to repaint the player and the background for each step.

There might be a better solution for this? Worst case scenario: It's an onlinegame and there are many players moving around and each 100 milliseconds the repaint is called for update every players posisions. I have a feeling this will take out all the memory of the players computer or at least the game will not feel so good

mKorbel
  • 109,525
  • 20
  • 134
  • 319
  • 2
    If you can determine a bounding rectangle for the player, you could have only that part of the background repainted after the character moves away from it. Should keep things speedy. If the character moves smoothly, rather than "jump" one tile at a time, the rectangle to repaint could be made even smaller. If characters can move diagonally, you'll need two rectangles, though. – G_H Aug 19 '11 at 00:24
  • try to override paintComponent() of a jcomponent like what thrashgod said (i used a jpanel inside the jframe) and use bufferedimage of java.awt.image. that's what i did. – pif Aug 19 '11 at 01:33

5 Answers5

4

Don't paint directly in the JFrame content pane. Instead, override paintComponent() in a JComponent. This AnimationTest draws into a JPanel, which is double buffered by default. The example also shows one approach to examining the time budget devoted to painting.

Community
  • 1
  • 1
trashgod
  • 203,806
  • 29
  • 246
  • 1,045
  • See also these [examples](http://stackoverflow.com/questions/6887296/how-to-make-an-image-move-while-listening-to-a-keypress-in-java). – trashgod Aug 19 '11 at 01:04
2

As far as I know, there is no other solution. Repainting every 100 ms generally isn't too memory intensive on most computers.

Jeffrey
  • 44,417
  • 8
  • 90
  • 141
  • OKey, thank you for the fast answer. Then it is as i thought. It's just that when i take steps, sometimes, the player Image will flash. It's not a huge problem but it gave me this feelings that im doing it the wrong way. But as you say, there is no other solution then i continue... thanks! – Philip Andersson Aug 19 '11 at 00:09
  • If the image is flashing, you could try [double buffering](http://en.wikipedia.org/wiki/Multiple_buffering#Double_buffering_in_computer_graphics) or even [triple buffering](http://en.wikipedia.org/wiki/Multiple_buffering#Triple_buffering). – Jeffrey Aug 19 '11 at 00:12
2

I think repaint is the only solution, I once created a 2d car simulation game and that's what i do, I also change the coordinates of all Car objects and then repaint the whole thing. I tried to simulate 2000 Car objects running at 100 ms repaint on all of them without trouble. hehe fun

pif
  • 96
  • 6
  • for the record i override paintComponent() [not repaint()] of a jPanel and used java.awt.image.BufferedImage for my cars. lolz still fun – pif Aug 19 '11 at 01:35
1

(i used a jpanel inside the jframe) and use bufferedimage of java.awt.image

Instead you can try using a JLabel with Icons. Then all you do is invoke the setLocation(...) method of the label. The Swing RepaintManager will look after repainting the old location and the new location.

Here's an example to get you started. This example uses separate Timers for each image. In your game you would reset the location of all images at the same time when your single Timer fires.

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class AnimationBackground extends JLabel implements ActionListener
{
    int deltaX = 2;
    int deltaY = 3;
    int directionX = 1;
    int directionY = 1;

    public AnimationBackground(
        int startX, int startY,
        int deltaX, int deltaY,
        int directionX, int directionY,
        int delay)
    {
        this.deltaX = deltaX;
        this.deltaY = deltaY;
        this.directionX = directionX;
        this.directionY = directionY;

        setIcon( new ImageIcon("dukewavered.gif") );
        setSize( getPreferredSize() );
        setLocation(startX, startY);
        new javax.swing.Timer(delay, this).start();
    }

    public void actionPerformed(ActionEvent e)
    {
        Container parent = getParent();

        //  Determine next X position

        int nextX = getLocation().x + (deltaX * directionX);

        if (nextX < 0)
        {
            nextX = 0;
            directionX *= -1;
        }

        if ( nextX + getSize().width > parent.getSize().width)
        {
            nextX = parent.getSize().width - getSize().width;
            directionX *= -1;
        }

        //  Determine next Y position

        int nextY = getLocation().y + (deltaY * directionY);

        if (nextY < 0)
        {
            nextY = 0;
            directionY *= -1;
        }

        if ( nextY + getSize().height > parent.getSize().height)
        {
            nextY = parent.getSize().height - getSize().height;
            directionY *= -1;
        }

        //  Move the label

        setLocation(nextX, nextY);
    }

    public static void main(String[] args)
    {
        JPanel panel = new JPanel(null)
        {
            Image image = new ImageIcon("mong.jpg").getImage();

            protected void paintComponent(Graphics g)
            {
                g.drawImage(image, 0, 0, getWidth(), getHeight(), null);
                super.paintComponent(g);
            }
        };
        panel.setOpaque(false);
//      panel.add( new AnimationBackground(10, 10, 2, 3, 1, 1, 10) );
        panel.add( new AnimationBackground(300, 100, 3, 2, -1, 1, 20) );
        panel.add( new AnimationBackground(200, 200, 2, 3, 1, -1, 20) );
        panel.add( new AnimationBackground(50, 50, 5, 5, -1, -1, 20) );
//      panel.add( new AnimationBackground(0, 000, 5, 0, 1, 1, 20) );
        panel.add( new AnimationBackground(0, 200, 5, 0, 1, 1, 80) );

        JFrame frame = new JFrame();
        frame.setContentPane(panel);
        frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
        frame.setSize(400, 400);
        frame.setLocationRelativeTo( null );
        frame.setVisible(true);
    }
}

You will need to provide a background image and an image for the label where the code creates an ImageIcon.

camickr
  • 321,443
  • 19
  • 166
  • 288
0

There is efficient to redraw only part of your component. Read this tutorial.

Basically you have to call component.repaint(posX, posY, length, height) twice: once at he old player image position (will repaint the background) and then at the new position.

(This solution was also proposed by G_H in the comments.)

toto2
  • 5,306
  • 21
  • 24