Component.setBounds calling Component.repaint?

So, I am making a game, and I have EnemyAI

as well player

, and they both extend JPanel

. The world has a layout null

, so I use setBounds();

to "move" (I actually just move the image of the world) entities

( player

and AI

) and position them correctly. But when I add (something like, I tested for the smallest possible number) 5, it calls repaint()

entirely on its own. This makes the player visually walk in place. The more objects I add, the faster the spacing turns out (i.e. 5 entities calls repaint()

much slower than 500).

NOTE: window

in the below class there is only JFrame

.

Main class:

public class Game(){
public static boolean fighting = false;
public static void startGame(){
    WorldPanel game = new WorldPanel();
    game.setPreferredSize(new Dimension(window.getWidth(), window.getHeight()));
    PlayerPane player = new PlayerPane(32,32, "Player 1");
    game.addKeyListener(new KeyListener(){

        public void keyPressed(KeyEvent arg0) {
            if(fighting == false){
                move(player, game, arg0.isShiftDown(), arg0.getKeyCode());
            } else {
                System.out.println("Fighting = " + fighting);
            }
        }
        @Override
        public void keyReleased(KeyEvent arg0) {    
            gameTimer.stop();
            player.setIndex(0);
            game.repaint();
        }
        @Override
        public void keyTyped(KeyEvent arg0) {
        }
    });
    window.add(game);
    game.setLayout(null);
    game.requestFocus();
    setImages(player, PLAYER_DOWN);
    player.setDrawY(349);
    player.setDrawX(493);
    player.updateBounds();
    game.add(player);
    entities.add(player);
    addEntities(game);
    redoWindow();
}
public static void updateEntityBounds(){
    PlayerPane player = null;
    EnemyAI enemy = null;
    for(int i = 0; i < entities.size(); i++){
        if(i == 0){
            player = (PlayerPane) entities.get(i);
        } else {
            enemy = (EnemyAI) entities.get(i);
            if(enemy.getBounds().intersects(player.getBounds())){
                startFight(i);
            }
        }
        if(player != null){
            player.updateBounds();
        }
        if(enemy != null){
            enemy.updateBounds();
        }
    }
}
public static void addEntities(WorldPanel game){
    EnemyAI enemies[] = new EnemyAI[5];
    for(int i = 0; i < enemies.length; i++){
        if(i%6 == 0){
            try{
                enemies[i] = new EnemyAI(32,32, ImageIO.read(new File("H:\\Java\\Game\\src\\res\\SlimeLv3Still.png")));
                enemies[i].start();
            }catch(IOException e){
                e.printStackTrace();
            }
        }else if (i % 2 == 0){
            try{
                enemies[i] = new EnemyAI(32,32, ImageIO.read(new File("H:\\Java\\Game\\src\\res\\SlimeLv2Still.png")));
                enemies[i].setEnX(enemies[i].getRandomX());
                enemies[i].setEnY(enemies[i].getRandomY());
                enemies[i].start();
            }catch(IOException e){
                e.printStackTrace();
            }
        } else {
            try{
                enemies[i] = new EnemyAI(32,32, ImageIO.read(new File("H:\\Java\\Game\\src\\res\\SlimeLv1Still.png")));
                enemies[i].setEnX(enemies[i].getRandomX());
                enemies[i].setEnY(enemies[i].getRandomY());
                enemies[i].start();
            }catch(IOException e){
                e.printStackTrace();
            }
        }
        game.add(enemies[i]);
        entities.add(enemies[i]);
    }
}
    public static void move(PlayerPane player, WorldPanel game, boolean shiftDown, int keyPressed){
     gameTimer = new Timer(50, new ActionListener(){
        public void actionPerformed(ActionEvent e){
            updateEntityBounds();
            redoWindow();
            gameTimer.stop();
        }
    });
    if(gameTimer.isRepeats()){
        gameTimer.setRepeats(false);
    }
        if(shiftDown){
            if(keyPressed == KeyEvent.VK_W && ((game.getImageY() == 0 && player.getDrawY() > 10) || player.getDrawY() >= 349)){
                player.setDrawY(player.getDrawY() - 2);
                setImages(player, PLAYER_UP);
                gameTimer.start();
            } else
            if(keyPressed == KeyEvent.VK_S && ((game.getImageY() == -3868 && player.getDrawY() < 681) || player.getDrawY() <= 349)){
                player.setDrawY(player.getDrawY() + 2);
                setImages(player, PLAYER_DOWN);
                gameTimer.start();
            } else
            if(keyPressed == KeyEvent.VK_A && ((game.getImageX() == 0 && player.getDrawX() > 10) || player.getDrawX() > 493 )){
                player.setDrawX(player.getDrawX() - 2);
                setImages(player, PLAYER_LEFT);
                gameTimer.start();
            } else
            if(keyPressed == KeyEvent.VK_D && ((game.getImageX() == -5126 && player.getDrawX() < player.getHeight() - 10) || player.getDrawX() < 493 )){
                player.setDrawX(player.getDrawX() + 2);
                setImages(player, PLAYER_RIGHT);
                gameTimer.start();
            } else
            if(keyPressed == KeyEvent.VK_W && game.getImageY() < 0){
                if(game.getImageY() == -1){
                    game.setImageY(game.getImageY() + 1);
                } else {
                    game.setImageY(game.getImageY() + 2);
                }
                for(int i = 1; i < entities.size(); i++){
                    EnemyAI enemy = (EnemyAI)entities.get(i);
                    enemy.setEnY(enemy.getEnY() + 2);
                }
                setImages(player, PLAYER_UP);
                gameTimer.start();
            } else
            if(keyPressed == KeyEvent.VK_A && game.getImageX() < 0){
                if(game.getImageX() == -1){
                    game.setImageX(game.getImageX() + 1);
                } else {
                    game.setImageX(game.getImageX() + 2);
                }
                for(int i = 1; i < entities.size(); i++){
                    EnemyAI enemy = (EnemyAI)entities.get(i);
                    enemy.setEnX(enemy.getEnX() + 2);
                }
                setImages(player, PLAYER_LEFT);
                gameTimer.start();
            } else
            if(keyPressed == KeyEvent.VK_S && game.getImageY() > -3868){
                if(game.getImageY() == -3867){
                    game.setImageY(game.getImageY() - 1);
                } else {
                    game.setImageY(game.getImageY() - 2);
                }
                for(int i = 1; i < entities.size(); i++){
                    EnemyAI enemy = (EnemyAI)entities.get(i);
                    enemy.setEnY(enemy.getEnY() - 2);
                }
                setImages(player, PLAYER_DOWN);
                gameTimer.start();
            } else
            if(keyPressed == KeyEvent.VK_D && game.getImageX() > -5126){
                if(game.getImageX() == -5125){
                    game.setImageX(game.getImageX() - 1);
                } else {
                    game.setImageX(game.getImageX() - 2);
                }
                for(int i = 1; i < entities.size(); i++){
                    EnemyAI enemy = (EnemyAI)entities.get(i);
                    enemy.setEnX(enemy.getEnX() - 2);
                }
                setImages(player, PLAYER_RIGHT);
                gameTimer.start();

            }
        } else {
            if(keyPressed == KeyEvent.VK_W && ((game.getImageY() == 0 && player.getDrawY() > 10) || player.getDrawY() > 349)){
                player.setDrawY(player.getDrawY() - 1);
                setImages(player, PLAYER_UP);
                gameTimer.start();
            } else
            if(keyPressed == KeyEvent.VK_S && ((game.getImageY() == -3868 && player.getDrawY() < 681) || player.getDrawY() < 349)){
                player.setDrawY(player.getDrawY() + 1);
                setImages(player, PLAYER_DOWN);
                gameTimer.start();
            } else
            if(keyPressed == KeyEvent.VK_A && ((game.getImageX() == 0 && player.getDrawX() > 10) || player.getDrawX() > 493 )){
                player.setDrawX(player.getDrawX() - 1);
                setImages(player, PLAYER_LEFT);
                gameTimer.start();
            } else
            if(keyPressed == KeyEvent.VK_D && ((game.getImageX() == -5126 && player.getDrawX() < player.getHeight() - 10) || player.getDrawX() < 493 )){
                player.setDrawX(player.getDrawX() + 1);
                setImages(player, PLAYER_RIGHT);
                gameTimer.start();
            } else
                if(keyPressed == KeyEvent.VK_W && game.getImageY() < 0){
                game.setImageY(game.getImageY() + 1);
                setImages(player, PLAYER_UP);
                for(int i = 1; i < entities.size(); i++){
                    EnemyAI enemy = (EnemyAI)entities.get(i);
                    enemy.setEnY(enemy.getEnY() + 1);
                }
                gameTimer.start();
            } else
            if(keyPressed == KeyEvent.VK_A && game.getImageX() < 0){
                game.setImageX(game.getImageX() + 1);
                setImages(player, PLAYER_LEFT);
                for(int i = 1; i < entities.size(); i++){
                    EnemyAI enemy = (EnemyAI)entities.get(i);
                    enemy.setEnX(enemy.getEnX() + 1);
                }
                gameTimer.start();

            } else
            if(keyPressed == KeyEvent.VK_S && game.getImageY() > -3868){
                game.setImageY(game.getImageY() - 1);
                setImages(player, PLAYER_DOWN);
                for(int i = 1; i < entities.size(); i++){
                    EnemyAI enemy = (EnemyAI)entities.get(i);
                    enemy.setEnY(enemy.getEnY() - 1);
                }
                gameTimer.start();                              
            } else
            if(keyPressed == KeyEvent.VK_D && game.getImageX() > -5126){
                game.setImageX(game.getImageX() - 1);
                setImages(player, PLAYER_RIGHT);
                for(int i = 1; i < entities.size(); i++){
                    EnemyAI enemy = (EnemyAI)entities.get(i);
                    enemy.setEnX(enemy.getEnX() - 1);
                }
                gameTimer.start();
            }
        }
    }
}

      

Player:

public class PlayerPane extends JPanel{
    private static final long serialVersionUID = 8946273935579723365L;
    private ImageIcon images[] = new ImageIcon[9];
    public static final int PLAYER_FRAMES = 9;
    private String name;
    private int index;
    private int imageX, imageY;
    private int HP = 100;



    public PlayerPane(int width, int height, String playerName) {
            setPreferredSize(new Dimension(width, height));
            imageX = imageY = 0;
            name = playerName;
        //      Border border = BorderFactory.createBevelBorder(BevelBorder.RAISED);
        //      PlayerPane.this.setBorder(border);
        }
        public String getName(){
            return name;
        }
        public void paintComponent(Graphics g){
            try {
                g.drawImage(ImageIO.read(new File("H:\\Java\\Game\\src\\res\\TransparentImg.png")),0,0,getWidth(),getHeight(), null);
            } catch (IOException e) {
                e.printStackTrace();
            }
                g.drawImage(images[index].getImage(), 0,0, null);

            if(index == images.length-1){
                index = 0;
            } else {
                index++;
            }
        }
        public void setIndex(int index){
            this.index = index;
        }
        public void stop(){
            index = 0;
        }
        public void addImage(ImageIcon image, int x){
            images[x] = image;
        }
        public void setDrawX(int x){
            imageX = x;
        }
        public void setDrawY(int y){
            imageY = y;
        }
        public int getDrawY(){
            return imageY;
        }
        public int getDrawX(){
            return imageX;
        }
        public void updateBounds(){
            setBounds(imageX, imageY, 32,32);
        }
        public int getHP(){
                return HP;
            }
            public void setHP(int hp){
                HP = hp;
            }
        }

      

EnemyAI class:

public class EnemyAI extends AI{
    private static final long serialVersionUID = -2417438750134536982L;

    private Rectangle rect;
    private BufferedImage backgroundImg;
    private int HP = 1;
    private int damage = 15;

    public EnemyAI(int width, int height, BufferedImage backgroundImg){
        super();
        rect = new Rectangle(width, height);
        this.backgroundImg = backgroundImg;
    }
    @Override
    public void paintComponent(Graphics g) {
        try{
            g.drawImage(ImageIO.read(new File("H:\\Java\\Game\\src\\res\\TransparentImg.png")), 0,0,null);
        }catch(IOException e){
            e.printStackTrace();
        }

        g.drawImage(backgroundImg, 0, 0, null);
    }
    public boolean intersects(Rectangle r){
        return rect.intersects(r);
    }
    public int getRandomX(){
        Random ran = new Random();
        int rand = ran.nextInt(6144);
        return rand;
    }
    public int getRandomY(){
        Random ran = new Random();
        int rand = ran.nextInt(4608);
        return rand;
    }
    public int getHP(){
        return HP;
    }
    public void setHP(int hp){
        HP = hp;
    }
    public int getDamage(){
        return damage;
    }
}

      

AI class that extends the class above:

public abstract class AI extends JPanel implements Runnable{
    private static final long serialVersionUID = 283692586329054555L;

    private boolean running = false;
    private Thread moveThread;
    private int x = 0, y = 0;

    public AI(){
        moveThread = new Thread(this);
    }
    public void start(){
        running = true;
        moveThread.start();
    }
    public void stop(){
        running = false;
    }
    public boolean isRunning(){
        return running;
    }

    public void run(){
        while(running){
            if(Game.fighting == false){
                Random direction = new Random();
                int dir = direction.nextInt(4);
                switch(dir){
                case 1: 
                    if(this.getX() < Game.getWindowWidth()){
                    this.setEnX(this.getX() + 1);
                    }
                    break;
                case 2:
                    if(this.getX() > 0){
                        this.setEnX(this.getX() - 1);
                    }
                    break;
                case 3:
                    if(this.getX() < Game.getWindowHeight()){
                        this.setEnY(this.getY() + 1);
                    }
                    break;
                case 4:
                    if(this.getX() < 0){
                        this.setEnY(this.getY() - 1);
                    }
                    break;
                }
                updateBounds();
                try{
                    Thread.sleep(200);
                }catch(InterruptedException e){
                    e.printStackTrace();
                }
            }
        }
    }
    public void setEnX(int x){
        this.x = x;
    }
    public void setEnY(int y){
        this.y = y;
    }
    public int getEnX(){
        return x;
    }
    public int getEnY(){
        return y;
    }
    public void updateBounds(){
        setBounds(x, y, 32,32);
    }
    public abstract void paintComponent(Graphics g);
}

      

I realize that I just threw a lot of code at you guys. I tried not to do this, but in hindsight I am trying to provide an example that works. If I missed any code, please tell me and I will add it.

Anyway, I need to know how to make the setBounds()

terminate call repaint()

(other than using less than 5 entities

). Also, when adding, entities

I removed EnemyAI.start()

and it stopped it. Therefore, I have reason to believe that the problem is in the AI

class method run()

. Which is pretty much just calling setBounds()

.

+1


source to share


1 answer


This is normal behavior and therefore you cannot change state internally paintComponent

. We have no control over when replications happen: the system does it by itself.

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 have to go through all your code looking for every place where you changed a variable like this inside paintComponent

and move it somewhere else.

As a side note, you should also move your calls around ImageIO.read

so they aren't inside paintComponent

. Load your images once at program start, in static

variables or something like that.

And as a general tip, you should look into animation just by drawing instead of trying to animate the components. Ultimately, this will bring you huge advantages in the game.


So, in short:



  • Keep paintComponent

    undaunted.
  • Wrapping game / animation state images in non-UI objects.
  • Draw these images into paintComponent

    .

Here's a minimal example that demonstrates this by animating shapes falling through a 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 are from here .)

Other useful examples of animation and painting:

+4


source







All Articles