Java читает и загружает изображения

Я только что закончил делать игру "Сапер", все отлично работает, кроме одной вещи - скорости загрузки изображений в игру. Я заметил, что если в игре есть большое количество ячеек, изображения загружаются очень медленно после щелчка мышью на ячейке, и это происходит быстрее, если у меня меньше ячеек. Есть ли другой способ сделать загрузку изображений намного быстрее, чем тот, который я использовал? Вот метод, который я использовал для загрузки изображений в игру:

   private void draw(Graphics g) {
        BufferedImage gRec =null, flag=null, mine=null, aCount0=null,
            aCount1=null,aCount2 =null,aCount3 =null,aCount4 =null,aCount5 =null,
            aCount6 =null,aCount7 =null,aCount8 = null;
        try {
           gRec = ImageIO.read(new File("/Users/msa_666/Desktop/blank.gif"));
                flag = ImageIO.read(new File("/Users/msa_666/Desktop/bombflagged.gif"));
                mine = ImageIO.read(new File("/Users/msa_666/Desktop/bombdeath.gif"));
                flag = ImageIO.read(new File("/Users/msa_666/Desktop/bombflagged.gif"));
                aCount0 = ImageIO.read(new File("/Users/msa_666/Desktop/open0.gif"));
                aCount1 = ImageIO.read(new File("/Users/msa_666/Desktop/open1.gif"));
                aCount2 = ImageIO.read(new File("/Users/msa_666/Desktop/open2.gif"));
                aCount3 = ImageIO.read(new File("/Users/msa_666/Desktop/open3.gif"));
                aCount4 = ImageIO.read(new File("/Users/msa_666/Desktop/open4.gif"));
                aCount5 = ImageIO.read(new File("/Users/msa_666/Desktop/open5.gif"));
                aCount6 = ImageIO.read(new File("/Users/msa_666/Desktop/open6.gif"));
                aCount7 = ImageIO.read(new File("/Users/msa_666/Desktop/open7.gif"));
                aCount8 = ImageIO.read(new File("/Users/msa_666/Desktop/open8.gif"));
                }
                 catch (IOException e) { 
              e.printStackTrace();
           } 


        if (getCovered() == true && getMarked () == false) {    // gray rectangle
           g.drawImage(gRec,getX(),getY(),w,h,null);

        }
        else if (getCovered()==true && getMarked() ==  true) {  //flag
           g.drawImage(flag,getX(),getY(),w,h,null);

        }
        else if (getCovered()== false && getMined()== true){        //mine
           g.drawImage(mine,getX(),getY(),w,h,null);

        }
        else if ( getCovered() == false && getMined() == false) {   // adjacency count image
            switch (getAdjCount()){
                case 0:
           g.drawImage(aCount0,getX(),getY(),w,h,null);
                break;
                case 1:
           g.drawImage(aCount1,getX(),getY(),w,h,null);
                break;
                case 2:
           g.drawImage(aCount2,getX(),getY(),w,h,null);
                break;
                case 3:
           g.drawImage(aCount3,getX(),getY(),w,h,null);
                break;

                case 4:
           g.drawImage(aCount4,getX(),getY(),w,h,null);
                break;
                case 5:
           g.drawImage(aCount5,getX(),getY(),w,h,null);
                break;
                case 6:
           g.drawImage(aCount6,getX(),getY(),w,h,null);
                break;
                case 7:
           g.drawImage(aCount7,getX(),getY(),w,h,null);
                break;
                case 8:
           g.drawImage(aCount8,getX(),getY(),w,h,null);
                break;


        }
     }
    }

вот слушатель мыши, чтобы перекрасить каждую ячейку после нажатия на нее:

   public void mouseClicked(MouseEvent e) {
      int sRow, sCol;
      sRow= e.getX() / cellHeight;
      sCol = e.getY()/ cellWidth;
      System.out.println(e.getX() +"," +sCol);
      System.out.println(e.getY()+","+sRow);
      if (e.getButton() == MouseEvent.BUTTON1) {
        if( cells[sRow][sCol].getMarked() == false)     
           uncoverCell(cells[sRow][sCol]);
          // cells[sRow][sCol].setCovered(false);
        System.out.println(cells[sRow][sCol].getMined());
        repaint();
     }
     else if (e.getButton() == MouseEvent.BUTTON2) {
     }
     else if (e.getButton() == MouseEvent.BUTTON3) {
        if (cells[sRow][sCol].getMarked() == false){
           cells[sRow][sCol].setMarked(true);
                       repaint();

        }
        else {
           cells[sRow][sCol].setMarked(false);          
           repaint();           
        }
     }

     if (allMinesMarked() && allNonMinesUncovered()){
        System.out.println("You Win");
     }
  }


  public void paintComponent(Graphics g) { 
     for ( int i=0 ; i <rowCount; i++ ) {
        for (int j=0; j<columnCount; j++) {
           cells[i][j].draw(g);
        }
     }

  }

2 ответа

Вы должны сказать нам:

  • Просто где draw(...) называется?
  • Как получить объект Graphics g, который передается в параметр метода draw?

Я предполагаю здесь, поскольку у нас нет всего соответствующего кода, но похоже, что вы перечитываете свои изображения каждый раз, когда хотите отобразить один. Если так, не делай этого. Прочитайте изображения только один раз в начале программы, а затем используйте изображения или, возможно, лучше, Image Icons, полученные, когда они вам нужны.

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

Я сам создал бы Image Icons из изображений, а затем отобразил бы их в JLabel. Когда есть необходимость обменяться изображениями, просто позвоните setIcon(...) на JLabel. Таким образом, нет необходимости даже связываться с paintComponent(...),

Редактировать 2
Например (скомпилируйте и запустите это):

import java.awt.GridLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

import javax.imageio.ImageIO;
import javax.swing.*;

public class SwapIcons {
   private static final int CELL_SIDE_COUNT = 3;
   private ImageCell[] imageCells = new ImageCell[CELL_SIDE_COUNT * CELL_SIDE_COUNT];
   private JPanel mainPanel = new JPanel();

   public SwapIcons(final GetImages getImages) {
      mainPanel.setLayout(new GridLayout(CELL_SIDE_COUNT, CELL_SIDE_COUNT));
      mainPanel.setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2));

      for (int i = 0; i < imageCells.length; i++) {
         imageCells[i] = new ImageCell(getImages);
         mainPanel.add(imageCells[i].getImgLabel());
      }
   }

   public JComponent getMainComponent() {
      return mainPanel;
   }

   private static void createAndShowGui(GetImages getImages) {
      SwapIcons swapIcons = new SwapIcons(getImages);

      JFrame frame = new JFrame("Click on Icons to Change");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.getContentPane().add(swapIcons.getMainComponent());
      frame.pack();
      frame.setLocationByPlatform(true);
      frame.setVisible(true);
   }

   public static void main(String[] args) {
      try {
         final GetImages getImages = new GetImages();
         SwingUtilities.invokeLater(new Runnable() {
            public void run() {
               createAndShowGui(getImages);
            }
         });
      } catch (IOException e) {
         e.printStackTrace();
      }
   }
}

class ImageCell {
   private JLabel imgLabel = new JLabel();
   private GetImages getImages;
   private int iconIndex = 0;

   public ImageCell(final GetImages getImages) {
      this.getImages = getImages;
      imgLabel.setIcon(getImages.getIcon(0));
      imgLabel.addMouseListener(new MyMouseListener());
   }

   public JLabel getImgLabel() {
      return imgLabel;
   }

   private class MyMouseListener extends MouseAdapter {
      @Override
      public void mousePressed(MouseEvent e) {
         iconIndex++;
         iconIndex %= getImages.getIconListSize();
         imgLabel.setIcon(getImages.getIcon(iconIndex));
      }
   }
}

// Simply gets a SpriteSheet and subdivides it into a List of ImageIcons
class GetImages {
   private static final String SPRITE_PATH = "http://th02.deviantart.net/"
         + "fs70/PRE/i/2011/169/0/8/blue_player_sprite_sheet_by_resetado-d3j7zba.png";
   public static final int SPRITE_ROWS = 6;
   public static final int SPRITE_COLS = 6;
   public static final int SPRITE_CELLS = 35;

   private List<ImageIcon> iconList = new ArrayList<ImageIcon>();

   public GetImages() throws IOException {
      URL imgUrl = new URL(SPRITE_PATH);
      BufferedImage mainImage = ImageIO.read(imgUrl);

      for (int i = 0; i < SPRITE_CELLS; i++) {
         int row = i / SPRITE_COLS;
         int col = i % SPRITE_COLS;
         int x = (int) (((double) mainImage.getWidth() * col) / SPRITE_COLS);
         int y = (int) ((double) (mainImage.getHeight() * row) / SPRITE_ROWS);
         int w = (int) ((double) mainImage.getWidth() / SPRITE_COLS);
         int h = (int) ((double) mainImage.getHeight() / SPRITE_ROWS);
         BufferedImage img = mainImage.getSubimage(x, y, w, h);
         ImageIcon icon = new ImageIcon(img);
         iconList.add(icon);
      }
   }

   // get the Icon from the List at index position
   public ImageIcon getIcon(int index) {
      if (index < 0 || index >= iconList.size()) {
         throw new ArrayIndexOutOfBoundsException(index);
      }

      return iconList.get(index);
   }

   public int getIconListSize() {
      return iconList.size();
   }

}

Hovercraft Full Of Eels ответ хороший и будет работать. И это хорошо для автономного приложения, но для апплета или веб-приложения запуска можно дополнительно оптимизировать, имея одно большое изображение и затем копируя его части в видимый графический объект, думая о сетках и используя функцию в объекте java.awt.Graphics. (от javadoc):

открытый абстрактный логический drawImage(изображение img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, наблюдатель ImageObserver)

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

Этот метод сразу возвращается во всех случаях, даже если область изображения, которая должна быть нарисована, еще не была масштабирована, сглажена и преобразована для текущего устройства вывода. Если текущее выходное представление еще не завершено, drawImage возвращает false. По мере того, как становится доступно больше изображений, процесс, который загружает изображение, уведомляет указанного наблюдателя изображения.

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

Параметры: img - указанное изображение для рисования. Этот метод ничего не делает, если img равен нулю. dx1 - координата x первого угла прямоугольника назначения. dy1 - координата y первого угла прямоугольника назначения. dx2 - координата x второго угла прямоугольника назначения. dy2 - координата y второго угла прямоугольника назначения. sx1 - координата x первого угла исходного прямоугольника. sy1 - координата y первого угла исходного прямоугольника. sx2 - координата x второго угла исходного прямоугольника. sy2 - координата y второго угла исходного прямоугольника. Наблюдатель - объект, который будет уведомлен, поскольку больше изображения масштабируется и конвертируется. Возвращает: false, если пиксели изображения все еще меняются; верно иначе.

Это лучше, поскольку для создания нового соединения и загрузки изображения через Интернет требуется несколько секунд, поэтому, если у вас есть одно основное изображение, содержащее все вспомогательные изображения в большой таблице, общее время загрузки, загрузки и рендеринга будет меньше. дополнительная логика для копирования из области тривиальна, может быть.1KB файлового пространства jar:)

Другие вопросы по тегам