RacistPlatypus
RacistPlatypus

Reputation: 1

Java game lag, too many if statement?

I'm working on a game in java, based on the Atari game adventure. I got the basic KeyListener part working fine, but then I added another if statement, using another class, to test if if the player was going to hit a wall, and stopping movement if that was the case. The method I used also used if statements, and when I ran the code, it had MAJOR lag. I tried a while loop first, but that made it lag even worse. Anyway to make this not lag so much? It doesn't seem that complex a program to run, and I still have to add yet another if statement to make be able to move into another room, so I have to do something to massively cut down on the lag.

Here is the class:

class Player extends JPanel implements KeyListener{
   private char c = 'e';
   int x = 400;
   int y = 400;
   int mapX = 0;
   int mapY = 0;


   public Player() {
      this.setPreferredSize(new Dimension(800, 500));
      addKeyListener(this);  
   }

   public void addNotify() {
      super.addNotify();
      requestFocus();
   }
   public void paintComponent(Graphics g) {
      super.paintComponent(g);
      Environment Layout = new Environment();
      Layout.drawRoom(mapX,mapY,g);
      g.fillRect(x , y , 20, 20);       
   }
   public void keyPressed(KeyEvent e) { }
   public void keyReleased(KeyEvent e) { }
   public void keyTyped(KeyEvent e) {
      c = e.getKeyChar();
      repaint();
      Environment Layout = new Environment();
      if(Layout.isWall(x,y,c)){}
      else{
         if (c == 'a'){
            x = x - 3;
         }
         else if (c == 'w'){
            y = y - 3;
         }
         else if (c == 's'){
            y = y + 3;
         }
         else if (c == 'd'){
            x = x + 3;
         }         
      }
   }

   public static void main(String[] s) throws IOException{
      JFrame f = new JFrame();
      f.getContentPane().add(new Player());
      f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      f.pack();
      f.setVisible(true);
   }
}

The draw room method I used in this was just to put the background of the room into place.

Here is the isWall method from the Environment class:

public boolean isWall(int moveX, int moveY, char let){
      BufferedImage room = null;
      try {
         room = ImageIO.read(new File(xNum + "," + yNum + ".png"));
      } 
      catch (IOException e) {
      }  
      int[][] walls = convertImage(room);   
      boolean blocked = false;
      if(let == 'w') {
         if(walls[moveY-8][moveX] == -3584){blocked = true;}
      }
      else if(let == 's') {
         if(walls[moveY+20][moveX] == -3584){blocked = true;}
      }
      else if(let == 'a') {
         if(walls[moveY][moveX-5] == -3584){blocked = true;}
      }
      else if(let == 'd') {
         if(walls[moveY][moveX+20] == -3584){blocked = true;}
      }
      return blocked;      
   } 

the convertImage method just converts the image of the room into an int array, for the value of the colors. -3584 is the color of the walls. It's possible this is what's lagging it, but this seemed like the best way for each room to have the walls done automatically.

I also tried a timer, but either I did that wrong, or it just didn't help.

I can give more of my code if that's needed, but help with this would be much appreciated. I'm relatively new to this kind of stuff, so it's likely I'm missing something big. Thanks.

Upvotes: 0

Views: 247

Answers (3)

Samuel Toh
Samuel Toh

Reputation: 19268

This is an extension to @templatetypedef's answer.

Instead of loading the image files upon calling the isWall method, you might want to consider caching all of the walls on game start.

So I am thinking;

  1. have a HashMap data structure keyed by <String, Integer>. Where String is your coordinates. E.g. coordinate string = "100,238"
  2. parse all the .png image files in the directories and store the coordinates as key and the value can just be any dummy value like 1 or 2.
  3. Then when isWall() is invoked. Given the X and Y coordinate, build the coordinate string as mentioned in point 1 and check if the key exists. If it does then we know it is a piece of wall else not.

This should drastically reduce the I/O disk contention.

In future, if you would like to extend the solution to incorporate APIs like isTreasureChest() or isMonster(). It can be extended by building a immutable class call "Room" or "Tile" to represent the object. Then modify the HashMap to take in <String, Room>.

Upvotes: 0

Aidan
Aidan

Reputation: 767

You appear to be moving your walls further than you are moving your player.

Is it possible that your player object is getting stuck in a wall there by producing "blocked = true" continuously?

Your character gets +- 3 in every direction, however your walls seem inconsistent and range from 8 up to 20 down to 5 left to 20 right.

Upvotes: 0

templatetypedef
templatetypedef

Reputation: 372814

The lag here is almost certainly not from the if statements. Those are really fast. I think the bigger issue is in isWall. Notice that any time you want to check for whether a wall is present, you

  1. Open a file,
  2. read the file contents,
  3. convert the file contents from an image to a grid of pixels, and
  4. read exactly one pixel.

Reading files from disk is extremely slow compared to looking at values in memory. For example, a regular magnetic hard drive works at around 7200 RPM, so the seek time is measured in milliseconds. On the other hand, your processor can do about a billion operations per second, so other operations take nanoseconds. That means that a disk read is roughly a million times slower than other operations, which is almost certainly where you're getting the lag from!

To fix this, consider rewriting your isWall code so that you only read the file and do the conversion once and, having done that, then just look up the part of the image you need. This converts doing tons of (glacially slow) file reads to one single (slow but inevitable) file read followed by tons of fast memory reads.

Upvotes: 4

Related Questions