Search code examples
javaswingpaintkeylistenerimageicon

Moving a background image in Swing


hello im new in programming and we have a project.We created a simple racing game with a moving background but I'm stuck on my code and i don't know how to do it. i need a moving background when the game starts please somebody help me. I'm begging T_T

enter image description here

here is my code:

public class Game extends JFrame implements KeyListener, ActionListener {

    Random s = new Random();
    int x = 0, y = 50, a = 0, b = 250, f = 900, a1 = 0, b2 = 350, a2 = 0, b3 = 150;
    int Move;
    int value;
    JLabel spriteLabel1 = new JLabel(new ImageIcon("ss.gif"));
    JLabel spriteLabel2 = new JLabel(new ImageIcon("ss.gif"));
    JLabel spriteLabel3 = new JLabel(new ImageIcon("ss.gif"));
    JLabel spriteLabel4 = new JLabel(new ImageIcon("ss.gif"));
    JLabel background = new JLabel(new ImageIcon("geren.png"));
    Timer T1 = new Timer(5000, this);
    Timer T = new Timer(5, this);

    public static void main(String args[]) {
        new Game();
    }

    public Game() {
        Container c = getContentPane();
        c.setLayout(null);
        c.add(spriteLabel1);
        c.add(spriteLabel2);
        c.add(spriteLabel3);
        c.add(spriteLabel4);
        c.add(background);
        background.setBounds(0, 0, 1024, 768);
        addKeyListener(this);
        setSize(1000, 750);
        setVisible(true);
    }

    public void paint(Graphics g) {
        super.paint(g);
        spriteLabel1.setBounds(x, y, 60, 1000);
        spriteLabel2.setBounds(a, b, 60, 800);
        spriteLabel3.setBounds(a1, b2, 60, 500);
        spriteLabel4.setBounds(a2, b3, 60, 650);
    }

    public void keyPressed(KeyEvent e) {
        String k = e.getKeyText(e.getKeyCode());
        if (k.equals("D")) {
            if (a != f) {
                x = x + 15;
                spriteLabel1.setIcon(new ImageIcon("ss.gif"));
                repaint();
                if (x > f) {
                    x = f;
                    spriteLabel1.setIcon(new ImageIcon("ss.gif"));
                    //JOptionPane.showMessageDialog(null,"Congratulations!! 
                    //Sanji wins!","Result",JOptionPane.PLAIN_MESSAGE,
                    //new ImageIcon("evolve sanji.gif"));
                    //System.exit(0);
                }
                repaint();
            }
        }
        T.stop();
    }

    if(k.equals ( 
        "D")) 
    {
        if (x != f) {
            T.start();
            Move = 3;
        }
    }

    public void keyReleased(KeyEvent e) {
    }

    public void keyTyped(KeyEvent e) {
    }

    public void actionPerformed(ActionEvent e) {
        if (Move == 3) {
            a = a + (s.nextInt(3));
            a = a + value;
            if (a > f) {
                a = f;
            }
            spriteLabel2.setIcon(new ImageIcon("ss.gif"));
            spriteLabel2.setBounds(a, b, 100, 800);
        }
        if (a == f) {
            if (Move == 3) {
                a1 = a1 + (s.nextInt(3));
                a1 = a1 + value;
                if (a1 > f) {
                    a1 = f;
                }
                spriteLabel3.setIcon(new ImageIcon("ss.gif"));
                spriteLabel3.setBounds(a1, b2, 100, 500);
            }
            if (Move == 3) {
                a2 = a2 + (s.nextInt(5));
                a2 = a2 + value;
                if (a2 > f) {
                    a2 = f;
                }
                spriteLabel4.setIcon(new ImageIcon("ss.gif"));
                spriteLabel4.setBounds(a2, b3, 100, 650);
            }

        }
    }
}

Solution

  • Here's the spoiler

    enter image description here

    Here's the meat

    There a a few things I see you doing wrong:

    • Constantly creating new Images. Just use the same image.

    • I would, instead of using label, just paint an Image/BufferedImage onto the painting surface.

    • Forget two timers. You can make due with one. It's just how you manage your state.

    • Don't do any logic in the paint method. In your current case, since are not even painting anything, you don't even need it. In my example though I do paint the image.

    • Don't Paint on JFrame and override paint. Override paintComponent instead in a JPanel and add that panel to the frame.

    • Finally, the key ingredient, use the method (from Graphics) -

      public abstract boolean drawImage(Image img,
              int dx1,
              int dy1,
              int dx2,
              int dy2,
              int sx1,
              int sy1,
              int sx2,
              int sy2,
              ImageObserver observer)
      

      You can get a better explanation about it in this post. Basically, the s points are the source image, so you can just move the sx1 and sx2 during the animation, and it will move the part of the image to be drawn at the d points of the painting surface.

    If you don't know how to really do custom painting, I suggest you run through Performing Custom Painting

    Here's the full example

    (Note the image I used for the background was 2000x350)

    import java.awt.Color;
    import java.awt.Dimension;
    import java.awt.FlowLayout;
    import java.awt.Graphics;
    import java.awt.Image;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.awt.image.BufferedImage;
    
    import javax.imageio.ImageIO;
    import javax.swing.ImageIcon;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.SwingUtilities;
    import javax.swing.Timer;
    
    public class MovingBackgroundDemo {
    
        public MovingBackgroundDemo() {
            JFrame frame = new JFrame();
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.add(new AnimatingPanel());
            frame.pack();
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
        }
    
        private class AnimatingPanel extends JPanel {
            private static final int DIM_W = 350;
            private static final int DIM_H = 350;
            private static final int INCREMENT = 10;
    
            private BufferedImage backgroundImage;
            private Image runnerImage;
    
            private int dx1, dy1, dx2, dy2;
            private int srcx1, srcy1, srcx2, srcy2;
            private int IMAGE_WIDTH;
    
            public AnimatingPanel() {
                initImages();
                initImagePoints();
                Timer timer = new Timer(40, new ActionListener() {
                    public void actionPerformed(ActionEvent e) {
                        moveBackground();
                        repaint();
                    }
                });
                timer.start();
    
                FlowLayout layout = (FlowLayout)getLayout();
                layout.setHgap(0);
                layout.setVgap(0);
            }
    
            @Override
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
                g.setColor(Color.WHITE);
                g.fillRect(0, 0, getWidth(), getHeight());
                g.drawImage(backgroundImage, dx1, dy1, dx2, dy2, srcx1, srcy1,
                        srcx2, srcy2, this);
                g.drawImage(runnerImage, 0, 0, getWidth(), getHeight(), this);
            }
    
            @Override
            public Dimension getPreferredSize() {
                return new Dimension(350, 350);
            }
    
            private void initImagePoints() {
                dx1 = 0;
                dy1 = 0;
                dx2 = DIM_W;
                dy2 = DIM_H;
                srcx1 = 0;
                srcy1 = 0;
                srcx2 = DIM_W;
                srcy2 = DIM_H;
            }
    
            private void initImages() {
                try {
                    runnerImage = new ImageIcon(getClass().getResource("runner.gif")).getImage();
                    backgroundImage = ImageIO.read(getClass().getResource(
                            "background.png"));
                    IMAGE_WIDTH = backgroundImage.getWidth();
                    System.out.println(IMAGE_WIDTH);
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
    
            private void moveBackground() {
                if (srcx1 > IMAGE_WIDTH) {
                    srcx1 = 0 - DIM_W;
                    srcx2 = 0;
                } else {
                    srcx1 += INCREMENT;
                    srcx2 += INCREMENT;
                }
            }
        }
    
        public static void main(String[] args) {
            SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                    new MovingBackgroundDemo();
                }
            });
        }
    }