【问题标题】:Java game lag, too many if statement?Java 游戏卡顿,if 语句太多?
【发布时间】:2016-06-22 01:06:43
【问题描述】:

我正在开发一款基于 Atari 游戏冒险的 Java 游戏。我得到了基本的 KeyListener 部分工作正常,但随后我添加了另一个 if 语句,使用另一个类来测试玩家是否会撞墙,如果是这样,则停止移动。我使用的方法也使用了 if 语句,当我运行代码时,它有很大的滞后。我先尝试了一个while循环,但这使它滞后更糟。无论如何,让这不会滞后这么多?运行一个程序似乎并不复杂,我仍然需要添加另一个 if 语句才能移动到另一个房间,所以我必须做一些事情来大幅减少延迟。

这是课程:

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);
   }
}

我这里使用的draw room方法只是将房间的背景放置到位。

这里是 Environment 类的 isWall 方法:

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;      
   } 

convertImage 方法只是将房间的图像转换为一个 int 数组,用于颜色的值。 -3584 是墙壁的颜色。可能这是滞后的原因,但这似乎是每个房间自动完成墙壁的最佳方式。

我也尝试了一个计时器,但要么我做错了,要么就是没有帮助。

如果需要,我可以提供更多我的代码,但我们将不胜感激。我对这种东西比较陌生,所以我很可能错过了一些重要的东西。谢谢。

【问题讨论】:

    标签: java jpanel keylistener


    【解决方案1】:

    这里的延迟几乎肯定不是来自if 语句。这些真的很快。我认为更大的问题在于isWall。请注意,每当您想检查是否存在墙时,您都需要

    1. 打开一个文件,
    2. 读取文件内容,
    3. 将文件内容从图像转换为像素网格,并
    4. 只读取一个像素。

    与查看内存中的值相比,从磁盘读取文件非常慢。例如,普通磁性硬盘的工作转速约为 7200 RPM,因此寻道时间以毫秒为单位。另一方面,您的处理器每秒可以执行大约 10 亿次操作,因此其他操作需要纳秒。这意味着磁盘读取比其他操作慢大约一百万倍,这几乎肯定是你得到延迟的地方!

    要解决此问题,请考虑重写您的 isWall 代码,以便您只读取文件并进行一次转换,完成此操作后,只需查找您需要的图像部分。这会将大量(非常缓慢的)文件读取转换为一个(缓慢但不可避免的)文件读取,然后是大量快速内存读取。

    【讨论】:

      【解决方案2】:

      您移动墙壁的距离似乎比移动播放器的距离更远。

      你的玩家对象是否有可能因为连续产生“blocked = true”而被卡在墙上?

      您的角色在各个方向上都获得 +- 3,但是您的墙似乎不一致,范围从 8 到 20 到 5 左到 20 右。

      【讨论】:

      • 我可能对变量的命名很糟糕,moveY 和 moveX 更多的是给出理论运动,所需的不一致距离是暂时的,只是为了让它在我的测试中看起来更好一点,因为有些墙壁玩家在它接触到墙壁之前就“撞”了它,而在某些墙壁上,由于 x 和 y 没有标记块的边缘,它部分进入了墙壁。无论如何,这不是问题,它可以很好地移动(不是更好,感谢其中一些答案)。
      【解决方案3】:

      这是@templatetypedef 答案的扩展。

      您可能需要考虑在游戏开始时缓存所有墙壁,而不是在调用 isWall 方法时加载图像文件。

      所以我在想;

      1. 有一个以<String, Integer> 为键的HashMap 数据结构。其中 String 是您的坐标。例如。坐标字符串 = "100,238"
      2. 解析目录中的所有 .png 图像文件并将坐标存储为键,值可以是任何虚拟值,例如 1 或 2。
      3. 然后在调用 isWall() 时。给定 X 和 Y 坐标,构建第 1 点中提到的坐标字符串并检查键是否存在。如果是,那么我们就知道它是一堵墙,否则就不是。

      这应该会大大减少 I/O 磁盘争用。

      将来,如果您想扩展解决方案以合并诸如 isTreasureChest() 或 isMonster() 之类的 API。它可以通过构建一个不可变的类调用“Room”或“Tile”来表示对象来扩展。然后修改 HashMap 以接收<String, Room>

      【讨论】:

      • 存储不是墙的坐标有什么意义?只需存储墙壁,如果坐标不是地图/集合,那么它就不是墙壁。这会减少地图/集合所需的内存。
      • 好主意。由于调用者的意图是检查 X,Y 是否是一堵墙。但是存储所有东西有好处,例如,如果调用者想要检查其他东西,而不仅仅是墙壁。例如。 hasTreasureChest 或 hasMonster 等。然后可以修改 value 参数以包含这些标志。
      • 嗯,是的,那么他需要某种Room 类,并为某个坐标添加更多标志。但我仍然不会使用字符串作为坐标:P。问题在于,您需要在构建这些字符串的任何地方重复两个特定事实:值的顺序(x,y 或 y,x)和分隔符字符。在我看来,一个专门的不可变类是最好的。
      • 完全同意你的看法。但我可能会使用“Tile”这个名称:P 稍后我有时间会调整解决方案。
      猜你喜欢
      • 2014-04-25
      • 1970-01-01
      • 2014-09-20
      • 1970-01-01
      • 1970-01-01
      • 2020-12-04
      • 2015-08-13
      • 2016-11-29
      • 1970-01-01
      相关资源
      最近更新 更多