Philip Andersson
Philip Andersson

Reputation: 100

Move Image on JFrame without repaint()

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

Upvotes: 1

Views: 8038

Answers (5)

camickr
camickr

Reputation: 324118

(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.

Upvotes: 1

toto2
toto2

Reputation: 5326

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.)

Upvotes: 0

trashgod
trashgod

Reputation: 205785

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.

Upvotes: 4

pif
pif

Reputation: 96

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

Upvotes: 2

Jeffrey
Jeffrey

Reputation: 44808

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

Upvotes: 2

Related Questions