Component.setBounds invoking Component.repaint?

后端 未结 1 1471
遥遥无期
遥遥无期 2020-12-07 04:58

So I\'m making a game and I have the EnemyAI as well as the player and they both extend JPanel. The world has a null layo

相关标签:
1条回答
  • 2020-12-07 05:32

    This is a normal behavior and it's why you can't modify state inside paintComponent. We don't have control over when repaints happen: the system does them on its own sometimes.

    Here's an example of what I mean, which you shouldn't be doing:

    public class PlayerPane extends JPanel{
        ...
    
        public void paintComponent(Graphics g){
            ...
    
            // modifying index
            if(index == images.length-1){
                index = 0;
            } else {
                index++;
            }
        }
    }
    

    You need to go through all of your code looking for every place you've modified a variable like this inside paintComponent, and move it out to somewhere else.

    As a side note, you should also move your ImageIO.read calls so they are not inside paintComponent. Load your images once when the program starts, in to static variables or something like that.

    And as a general tip, you should look in to animation with just painting instead of trying to animate components. It will do you huge favors in the long run for a game.


    So in summary:

    • Keep paintComponent stateless.
    • Wrap images with game/animation state in non-UI objects.
    • Paint these images in paintComponent.

    Here's a minimal example which demonstrates this by animating shapes falling down the window:

    falling shapes

    import java.net.*;
    import javax.swing.*;
    import javax.imageio.*;
    import java.awt.image.*;
    import java.awt.event.*;
    import java.awt.Dimension;
    import java.awt.Color;
    import java.awt.Graphics;
    import java.util.List;
    import java.util.ArrayList;
    import java.util.Random;
    
    class FallingShapes implements Runnable {
        public static void main(String[] args) {
            SwingUtilities.invokeLater(new FallingShapes());
        }
    
        @Override
        public void run() {
            List<Entity> entities = new ArrayList<Entity>();
    
            int w = 0;
            int h = 0;
    
            for (BufferedImage img : Resources.images) {
                entities.add(new Entity(img));
    
                w += img.getWidth();
                h += img.getHeight();
            }
    
            PaintPanel p = new PaintPanel(entities);
            p.setPreferredSize(new Dimension(w, (2 * h)));
    
            JFrame f = new JFrame();
    
            f.setContentPane(p);
            f.pack();
            f.setLocationRelativeTo(null);
            f.setResizable(false);
            f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            f.setVisible(true);
    
            new Animator((1000 / 60), p, entities).start();
        }
    
        static class Animator implements ActionListener {
            int period;
            JPanel context;
            int height;
            List<Entity> entities;
    
            Animator(int period, JPanel context, List<Entity> entities) {
                this.context  = context;
                this.height   = context.getHeight();
                this.period   = period;
                this.entities = entities;
            }
    
            @Override
            public void actionPerformed(ActionEvent a) {
                for (Entity e : entities) {
                    double dist =
                        (period / 1000.0) * (height * e.rate);
    
                    e.y += dist;
                    e.y %= height;
                }
    
                context.repaint();
            }
    
            void start() {
                Random r = new Random();
                int    x = 0;
                for (Entity e : entities) {
                    e.x    = x;
                    e.y    = r.nextInt(height);
                    e.rate = (0.25 + (0.75 * r.nextDouble()));
    
                    x += e.width;
                }
    
                new Timer(period, this).start();
            }
        }
    
        static class Entity {
            BufferedImage img;
    
            double x, y, rate;
            int width, height;
    
            Entity(BufferedImage img) {
                this.img    = img;
                this.width  = img.getWidth();
                this.height = img.getHeight();
            }
    
            void paint(Graphics g, JPanel context) {
                int x = (int) Math.round(this.x);
                int y = (int) Math.round(this.y);
                g.drawImage(img, x, y, null);
    
                int cHeight = context.getHeight();
                if ((y + height) > cHeight) {
                    g.drawImage(img, x, y - cHeight, null);
                }
            }
        }
    
        static class PaintPanel extends JPanel {
            List<Entity> entities;
    
            PaintPanel(List<Entity> entities) {
                this.entities = entities;
    
                setBackground(Color.white);
            }
    
            @Override
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
    
                for (Entity e : entities) {
                    e.paint(g, this);
                }
            }
        }
    
        static class Resources {
            static final String[] paths = {
                "http://i.stack.imgur.com/wCF8S.png",
                "http://i.stack.imgur.com/5v2TX.png",
                "http://i.stack.imgur.com/F0JHK.png",
                "http://i.stack.imgur.com/4EVv1.png",
                "http://i.stack.imgur.com/xj49g.png",
            };
    
            static final List<BufferedImage> images =
                new ArrayList<BufferedImage>();
            static {
                for (String path : paths) {
                    try {
                        images.add(ImageIO.read(new URL(path)));
                    } catch (Exception e) {
                        throw new AssertionError(e);
                    }
                }
            }
        }
    }
    

    (Images from here.)

    Other useful examples of animation and painting:

    • Java Bouncing Ball
    • Java game loop (painting) freezes my window
    • Is this the correct way of using Java 2D Graphics API?
    0 讨论(0)
提交回复
热议问题