1

マインスイーパ ゲームの作成を終えたところです。ゲームに画像をロードする速度を除いて、すべてが完全に機能します。ゲーム内に多数のセルがあると、セルをマウスでクリックした後の画像の読み込みが非常に遅くなり、セルの数が少ないと速くなることに気付きました。私が使用したものよりもはるかに速く画像をロードする他の方法はありますか? 画像をゲームにロードするために使用した方法は次のとおりです。

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

  }
4

2 に答える 2

2

あなたは私たちに伝える必要があります:

  • どこでdraw(...)呼び出されますか?
  • draw メソッドのパラメーターに渡される Graphics オブジェクト g を取得するにはどうすればよいでしょうか。

関連するコードがすべて揃っているわけではないので、ここでは推測していますが、画像を表示するたびに画像を再読み込みしているように見えます。もしそうなら、これをしないでください。プログラムの開始時に一度だけ画像を読み取り、必要なときに取得した画像またはおそらくより適切な ImageIcons を使用します。

編集
より多くのコードを投稿していただきありがとうございます。実際、これは私の疑いを裏付けています。GUI を再描画するたびに画像ファイルを再読み込みしています。これは非常に非効率的であり、プログラムの速度を低下させます。繰り返しますが、一度イメージをプログラムに読み込んでから、それらを複数回使用する必要があります。

私自身、画像から ImageIcons を作成し、それらを 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();
   }

}
于 2013-03-30T12:33:05.100 に答える
0

Hovercraft Full Of Eels 回答は適切であり、機能します。スタンドアロン アプリの場合は問題ありませんが、アプレットまたは Web 起動アプリの場合は、1 つの大きな画像を作成し、その一部を表示可能なグラフィックス オブジェクトにコピーして、グリッドを考え、java.awt.Graphics オブジェクトの関数を使用することで、さらに最適化できます。 (javadoc から):

public abstract boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, ImageObserver オブザーバー)

指定されたイメージの指定された領域を現在利用可能な限り描画し、その場でスケーリングして、宛先ドローアブル サーフェスの指定された領域内に収まるようにします。透明なピクセルは、既に存在するピクセルには影響しません。

このメソッドは、描画されるイメージ領域がまだ現在の出力デバイス用にスケーリング、ディザリング、および変換されていない場合でも、すべての場合にすぐに戻ります。現在の出力表現がまだ完成していない場合、drawImage は false を返します。より多くの画像が利用可能になると、画像をロードするプロセスは、指定された画像オブザーバーに通知します。

このメソッドは常に、スケーリングされていないバージョンのイメージを使用してスケーリングされた四角形をレンダリングし、必要なスケーリングをオンザフライで実行します。この操作では、イメージのキャッシュされたスケーリングされたバージョンは使用されません。ソースから宛先への画像のスケーリングは、ソース矩形の最初の座標が宛先矩形の最初の座標にマッピングされ、2 番目のソース座標が 2 番目の宛先座標にマッピングされるように実行されます。これらのマッピングを維持するために、サブイメージは必要に応じてスケーリングおよび反転されます。

パラメータ: img - 描画する指定されたイメージ。img が null の場合、このメソッドは何もしません。dx1 - コピー先の四角形の最初の角の x 座標。dy1 - コピー先の四角形の最初の角の y 座標。dx2 - コピー先の四角形の 2 番目の角の x 座標。dy2 - コピー先の四角形の 2 番目の角の y 座標。sx1 - ソース四角形の最初の角の x 座標。sy1 - ソース四角形の最初の角の y 座標。sx2 - ソース四角形の 2 番目の角の x 座標。sy2 - ソース矩形の 2 番目の角の y 座標。observer - より多くの画像がスケーリングおよび変換されると通知されるオブジェクト。戻り値: 画像のピクセルがまだ変化している場合は false。それ以外の場合は true。

これは、新しい接続を確立してインターネット経由で画像をダウンロードするのに数秒かかるため、より優れています。したがって、大きなテーブルにすべてのサブ画像を含む 1 つのメイン画像がある場合、ダウンロード、読み込み、およびレンダリングの合計時間は短くなります。領域からコピーする追加のロジックは些細なことで、おそらく .1KB の jar ファイル スペースです :)

于 2013-03-30T16:07:30.350 に答える