2015-07-11 3 views
1

Я написал программу, основанную на некоторых примерах, для имитации игры жизни Конвей. Каждая ячейка в игре либо живая, либо мертвая, и они хранятся в массиве целых чисел int[][], этот массив всегда не менее 1000 * 1000, а это значит, что есть миллионы ячеек.Java-paintComponent самый эффективный способ рисования миллионов квадратов из массива

Итерации через массив, чтобы найти применение всех различных правил, являются точными и не особенно интенсивны в ЦП. Тем не менее, метод, используемый для рисования этих прямоугольников на JFrame, может привести к 90% использования процессора на моем Xeon E3 1246 V3 (I7 4770). При размерах массива 2000^2 это может привести к жесткой блокировке Windows 10 полностью.

@Override 
    protected void paintComponent(Graphics g) { 
     liveCells = 0; 
     super.paintComponent(g); 
     Color gColor = g.getColor(); 
     if(!backgroundWork || isPaused) { 
      for (int row = 0; row < grid.length; row++) { 
       for (int column = 0; column < grid[row].length; column++) { 
        //Checking if the cell is alive. 
        if (grid[row][column] == 1) { 
         liveCells++; 
         g.setColor(Color.red); 
         g.fillRect(column * UIScale, row * UIScale, UIScale, UIScale); 

        } 
       } 
      } 
     } 

     g.setColor(gColor); 
     if (isPaused) { 
      g.drawString("The game is paused", 0, 30); 
      g.drawString("Generation: " + generationCounter, 0, 10); 
      g.drawString("Living cells: " + liveCells, 150, 10); 
     } else { //If the game is running 
      g.drawString("Generation: " + generationCounter++, 0, 10); 
      g.drawString("Living cells: " + liveCells, 100, 10); 
     } 
     g.setColor(gColor); 
     try { 
      /* Sleep for some microseconds. */ 
      TimeUnit.MICROSECONDS.sleep(sleepTimer); 
     } catch (InterruptedException ex) { 
      System.err.println("An InterruptedException was caught: " + ex.getMessage()); 
     } 
    } 

я вижу совершенно ясно, что рисунок клеток является проблемой, с тем чтобы позволить программе работать быстрее, я уже добавил способ изменить переменную backgroundWork, которая отключает обновляет сетку прямоугольники. Включение или выключение этого параметра приводит к различиям до 80% при загрузке процессора диспетчера задач.

С помощью текущего метода рисования сетки я не вижу способа сделать это намного быстрее, поскольку все ячейки независимы друг от друга, и обычно их не будет больше 3, в любом случае, так что нет причин для реализации способа рисования нескольких одновременно.

Может кто-нибудь предложить способ ускорить текущий процесс или другой способ рисования квадратов. Спасибо за любую помощь.

+1

Рассматривали ли вы непосредственно листать биты в Растр BufferedImage, в этом от от EDT, а затем рисовать изображение в вашем методе paintComponent? –

+0

Итак, что-то похожее на это http://stackoverflow.com/questions/14416107/int-array-to-bufferedimage –

+0

Мне нужно было бы адаптировать его для размещения ячеек разных размеров. В настоящее время g.fillRectangle рисует квадрат со сторонами UIScale. В зависимости от того, что для него установлено, может быть представлено от 1 до 1 между значениями в массиве и пикселями на экране или 4 * 4 пикселя для одного элемента массива. –

ответ

0

Этот метод, предложенный Судно на воздушной подушке Full Of Угри (хорошее название, кстати) гораздо быстрее, чем то, что я использовал previously-

@Override 
protected void paintComponent(Graphics g) { 
    liveCells = 0; 

    BufferedImage BI = new BufferedImage(UIDimensions, UIDimensions, BufferedImage.TYPE_INT_RGB); 

    super.paintComponent(g); 
    Color gColor = g.getColor(); 
    if(!backgroundWork || isPaused) { 
     for (int row = 0; row < grid.length; row++) { 
      for (int column = 0; column < grid[row].length; column++) { 
       //Checking if the cell is alive. 
       if (grid[row][column] == 1) { 
        liveCells++; 
        if(UIScale != 1) { 
         //TODO- Draw squares larger than one pixel 
        } else { 
         BI.setRGB(column, row, 16711680); 
        } 

        //The old code is commented out below 

        //g.setColor(Color.red); 
        //Drawing the colour in a 4x4 pixel square. With a window of 1000x1000, there are 250x250 organisms, hence the /4 everywhere 
        //g.fillRect(column * UIScale, row * UIScale, UIScale, UIScale); 
        //The way that this works is that it draws rectangles at the coordinates of the grid. 
        //The graphics on the screen aren't a grid themselves, they are just lots of squares 
       } else { 
        BI.setRGB(column, row, 16777215); 
       } 
      } 
     } 
     g.drawImage(BI, 0, 0, null); 
    } 

    g.setColor(gColor); 

    if (isPaused) { //If the game is paused (isPaused is true) 
     g.drawString("The game is paused", 0, 30); 
     g.drawString("Generation: " + generationCounter, 0, 10); 
     g.drawString("Living cells: " + liveCells, 150, 10); 
    } else { //If the game is running 
     g.drawString("Generation: " + generationCounter++, 0, 10); 
     g.drawString("Living cells: " + liveCells, 100, 10); 
    } 
    g.setColor(gColor); 
    try { 
     /* Sleep for some seconds. */ 
     TimeUnit.MICROSECONDS.sleep(sleepTimer); 
    } catch (InterruptedException ex) { 
     System.err.println("An InterruptedException was caught: " + ex.getMessage()); 
    } 
} 
+2

Я бы не рекомендовал, чтобы вы когда-либо вызывали сон в потоке событий Swing, и это происходит вдвойне в методе paintComponent. Я удивлен, что это не заставляет ваше приложение спать. –

+1

Дальнейшие замечания: 1. ** Действительно ** не делайте этого 'sleep' там! 2. Не создавайте новый BufferedImage каждый раз. Вероятно, вы должны создать его только один раз (а именно, когда вы создаете «сетку»). 3. Чтобы «рисовать квадрат размером более одного пикселя», вы можете просто выполнить '((Graphics2D) g) .scale (uiScale, uiScale);' перед вызовом 'drawImage'. 4. Не используйте эти десятичные константы.Вместо этого используйте hex: '0xFF000000' непрозрачный черный,' 0xFFFF0000' непрозрачен красным, '0xFF00FF00' = зеленый,' 0xFF0000FF' = синий и т. Д. – Marco13

Смежные вопросы