1

I have a set of sprites that I am calling in a Java game, and when I had 3 sprites it worked fine, but when I add a fourth sprite, the repaint method is only called every other time.

Here is my minimal example,

Main class:

public class Maze extends JPanel implements ActionListener{

/**
 * @param args
 */
int stage;
int dir;
int x = 32;
int y = 32;
Rectangle r = new Rectangle(x,y,10,10);
Draw D = new Draw();
public static ArrayList<Rectangle> walls = new ArrayList<Rectangle>();
public ArrayList<Image> spritesl = new ArrayList<Image>();
public ArrayList<Image> spritesd = new ArrayList<Image>();
public ArrayList<Image> spritesr = new ArrayList<Image>();
public ArrayList<Image> spritesu = new ArrayList<Image>();
BufferedImage image;
public Maze() throws IOException{
    setBackground(Color.black);
    setSize(672,672);
    Timer timer = new Timer(2000,this);
    timer.addActionListener(this);
    timer.start();
    //add sprites
    for(int i = 1; i<5; i += 1){
        spritesl.add(image = ImageIO.read(new File("C:/Users/Dave/Desktop/Sprites/left" + i + ".png")));
    }
    for(int i = 1; i<5; i += 1){
        spritesd.add(image = ImageIO.read(new File("C:/Users/Dave/Desktop/Sprites/down" + i + ".png")));
    }
    for(int i = 1; i<5; i += 1){
        spritesr.add(image = ImageIO.read(new File("C:/Users/Dave/Desktop/Sprites/right" + i + ".png")));
    }
    for(int i = 1; i<5; i += 1){
        spritesu.add(image = ImageIO.read(new File("C:/Users/Dave/Desktop/Sprites/up" + i + ".png")));
    }
}
public static void main(String[] args) throws IOException {
    JFrame frame = new JFrame();
    Maze ate = new Maze();
    frame.addKeyListener(new Input());
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.getContentPane().add(ate);
    frame.setPreferredSize(new Dimension(688, 709));//16, 37
    frame.setVisible(true);
    frame.pack();
}
@Override
public void paintComponent(Graphics g){
    super.paintComponent(g);
    Graphics2D g2 = (Graphics2D) g;
    //call wall drawer
    g.setColor(Color.gray);
    D.draw(g);
    g.setColor(Color.red);
    //set animation
    if(dir == 1){
        g.drawImage(spritesu.get(stage-1),x,y, this);
    }else if(dir == 2){
        g.drawImage(spritesr.get(stage-1),x,y, this);
    }else if(dir == 3){
        g.drawImage(spritesd.get(stage-1),x,y, this);
    }else if(dir == 4){
        g.drawImage(spritesl.get(stage-1),x,y, this);
    }
    System.out.println("set");
}
@Override
public void actionPerformed(ActionEvent e) {
    boolean up =false;
    boolean right =false;
    boolean down =false;
    boolean left =false;

    //next part tests each direction for collisions
    if(Input.right){
        right = true;
        x += 4;
        if(x>672-32){
            x -= 4;
            right = false;
        }else{
            for(int i = 0; i < walls.size(); i += 1){
                if(new Rectangle(x, y, 30, 30).intersects(walls.get(i))){
                    x -= 4;
                    right = false;
                }
            }
        }
    }
    if(Input.left){
        left = true;
        dir=4;
        x-=4;
        if(x<0){
            x += 4;
            left = false;
        }else{
            for(int i = 0; i < walls.size(); i += 1){
                if(new Rectangle(x, y, 32, 32).intersects(walls.get(i))){
                    x += 4;
                    left = false;
                }
            }
        }
    }
    if(Input.down){
        down = true;
        dir=3;
        y+=4;
        if(y>672-32){
            y -= 4;
            down = false;
        }else{
            for(int i = 0; i < walls.size(); i += 1){
                if(new Rectangle(x, y, 32, 32).intersects(walls.get(i))){
                    y -= 4;
                    down = false;
                }
            }
        }
    }
    if(Input.up){
        up = true;
        dir=1;
        y-=4;
        if(y<0){
            y += 4;
            up = false;
        }else{
            for(int i = 0; i < walls.size(); i += 1){
                if(new Rectangle(x, y, 32, 32).intersects(walls.get(i))){
                    y += 4;
                    up = false;
                }
            }
        }
    }
    //sets direction of animation
    if(left||down||right||up){
        if(left){
            dir = 4;
        }
        if(down){
            dir = 3;
        }
        if(right){
            dir = 2;
        }
        if(up){
        dir = 1;
        }
        stage += 1;
        if(stage >= 4 || stage <= 0){
            stage = 1;
        }
        System.out.println(stage);
    }
    repaint();
}
}

My input tester(probably not necessary, but its needed for the game to run):

public class Input implements KeyListener {
public static boolean left = false;
public static boolean right = false;
public static boolean up = false;
public static boolean down = false;
public static boolean space = false;
//test for keys
@Override
public void keyPressed(KeyEvent e) {
        int key = e.getKeyCode();
    if (key == KeyEvent.VK_LEFT)
        left = true;
    if (key == KeyEvent.VK_RIGHT)
        right = true;
    if (key == KeyEvent.VK_UP)
        up = true;
    if (key == KeyEvent.VK_DOWN)
        down = true;
    if (key == KeyEvent.VK_SPACE)
        space = true;
}
@Override
public void keyReleased(KeyEvent e) {
        int key = e.getKeyCode();
    if (key == KeyEvent.VK_LEFT)
        left = false;
    if (key == KeyEvent.VK_RIGHT)
        right = false;
    if (key == KeyEvent.VK_UP)
        up = false;
    if (key == KeyEvent.VK_DOWN)
        down = false;
    if (key == KeyEvent.VK_SPACE)
        space = false;
}
@Override
public void keyTyped(KeyEvent e) {}
}

and my Draw class:

public class Draw {
public void draw(Graphics g){
    //draw everything
    Maze.walls.clear();
    g.fillRect(0, 0, 672, 32);
    g.fillRect(0, 0, 32, 672);
    g.fillRect(0, 640, 320, 32);
    g.fillRect(352, 640, 320, 32);
    g.fillRect(640, 0, 32, 320);
    g.fillRect(640, 352, 32, 320);

    Maze.walls.add(new Rectangle(0, 0, 672, 32));
    Maze.walls.add(new Rectangle(0, 0, 32, 672));
    Maze.walls.add(new Rectangle(0, 640, 320, 32));
    Maze.walls.add(new Rectangle(352, 640, 320, 32));
    Maze.walls.add(new Rectangle(640, 0, 32, 320));
    Maze.walls.add(new Rectangle(640, 352, 32, 320));
}
}

now, this works and cycles three stages, but as soon as I change the stage max to 5, it only paints on stages 2 and 4, which are exactly the same. Can anyone tell me what I am doing wrong?

Hiblah200
  • 27
  • 1
  • 5
  • 5
    I'm not sure what's causing your problem, but I will suggest that you not re-read your sprite images in on each iteration of your Timer. Just read them all in once at the beginning of the program and pop them into variables; else you're slowing down your program performance needlessly. – Hovercraft Full Of Eels Mar 22 '14 at 14:12
  • 2
    Consider creating and posting a [minimal example program](http://stackoverflow.com/help/mcve). – Hovercraft Full Of Eels Mar 22 '14 at 14:14

1 Answers1

2

Swing "Timers coalesce events by default." As noted by @HOFE, re-reading your sprite images is likely slowing things down enough to trigger the effect. Instead, read the images into a List<Image> when the program starts.

trashgod
  • 203,806
  • 29
  • 246
  • 1,045
  • Your suggestion is good, 1+, but I'm *guessing* that this is not his problem as it wouldn't explain why only the even number of stages are painted. I'm guessing that his problem lies elsewhere, but who really knows based on what he's posted? I think that if he needs our help, he is going to have to put in the effort to create and post his [minimal example program](http://stackoverflow.com/help/mcve), but my suggestion seems to be falling on deaf ears. – Hovercraft Full Of Eels Mar 22 '14 at 16:21
  • 1
    @HovercraftFullOfEels: Good point; I'd expect disk latency & cache effects to be more stochastic. Hiblah200: [profiling](http://stackoverflow.com/q/2064427/230513) your application may offer some insight. – trashgod Mar 22 '14 at 16:28
  • @trashgod thanks for the suggestion. I'm kind of new to the swing syntax. – Hiblah200 Mar 22 '14 at 17:04