2013-03-30 72 views
1

我剛剛完成了一個掃雷遊戲,除了一件事情之外,所有的功能都是完美的,將圖像加載到遊戲中的速度。我注意到,如果我在遊戲中有大量的單元格,在鼠標單擊單元格後圖像加載速度非常慢,並且如果我的單元格數量較少,它會變得更快。有沒有其他方式可以使加載圖片比我使用的圖片快得多?這裏是我爲了將圖像加載到遊戲中使用的方法: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); 
     } 
    } 

    } 
+0

感謝您更新您的問題,1+。請參閱編輯我的答案。 –

回答

2

您的需要告訴我們:

  • draw(...)叫什麼名字?
  • 如何獲取傳遞到draw方法參數的Graphics對象g?

我在這裏猜測,因爲我們沒有所有相關的代碼,但是看起來好像你每次想要顯示圖像都要重新讀取圖像。如果是這樣,不要這樣做。只讀一次在程序的開始處,然後使用Images或者更好的ImageIcons,當你需要它們的時候獲得。

編輯
感謝張貼更多的代碼,而這實際上證實了我的懷疑:你在重新閱讀中的圖像文件與GUI的每一個重繪。這非常低效,並且會使您的程序變慢。再次,您應該讀取圖像到您的程序一次,然後多次使用它們。

我自己我會從圖像創建ImageIcons,然後將它們顯示在JLabel中。當需要交換圖像時,只需在JLabel上調用setIcon(...)即可。這樣就沒有必要混淆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(); 
    } 

} 
+0

我該如何調用setIcon(...): 'g.drawImage(gRec,getX(),getY(),w,h,null);' 創建JLabels和圖標後,我很困惑 – Muhsag

+0

@ user2070173:你不會。如果你使用了圖標,你甚至不需要使用'paintComponent(...)'方法或必須處理Graphics對象。舉一個例子,以秒爲單位...... –

+0

@ user2070173:參見**編輯2 ** –

0

氣墊船充滿了鰻魚的答案是好的,將工作。 適用於獨立應用程序,但對於小應用程序或網絡啓動應用程序可以進一步優化,具有一個大圖像,然後將其部分複製到可見的圖形對象,請考慮網格並使用java.awt.Graphics中的函數對象(從Javadoc中):

公共抽象布爾的drawImage(圖像IMG, INT DX1, INT DY1, INT DX2, INT DY2, INT SX1, INT SY1, INT SX2, INT SY2, ImageObserver觀察者)

D在指定圖像的指定區域中儘可能多地生成當前可用的圖像,並將其隨時縮放以適合目標可繪製表面的指定區域。透明像素不會影響已經存在的任何像素。

即使所繪製的圖像區域尚未縮放,抖動並轉換爲當前輸出設備,該方法也會立即返回。如果當前輸出表示尚未完成,則drawImage返回false。隨着更多圖像可用,加載圖像的過程會通知指定的圖像觀察者。

此方法始終使用圖像的未縮放版本來渲染縮放的矩形並即時執行所需的縮放。它不使用緩存的縮放版本的圖像進行此操作。圖像從源到目的地的縮放被執行,使得源矩形的第一座標被映射到目的矩形的第一座標,並且第二源座標被映射到第二目的座標。子圖像按需縮放並翻轉以保存這些映射。

參數: img - 要繪製的指定圖像。如果img爲null,則此方法不執行任何操作。 dx1 - 目標矩形第一個角的x座標。 dy1 - 目標矩形第一個角的y座標。 dx2 - 目標矩形第二個角的x座標。 dy2 - 目標矩形第二個角的y座標。 sx1 - 源矩形第一個角的x座標。 sy1 - 源矩形第一個角的y座標。 sx2 - 源矩形的第二個角的x座標。 sy2 - 源矩形第二個角的y座標。 觀察者 - 當更多的圖像被縮放和轉換時被通知的對象。 返回: 如果圖像像素仍然在變化,則返回false;否則爲真。

這是更好的,因爲它需要幾秒鐘來建立一個新的連接,並通過互聯網下載圖像,所以如果你有一個主圖像,所有子圖像在一個大表中,那麼總共需要下載,加載和渲染會少一些。從一個區域複製額外的邏輯是微不足道的.1KB的jar文件空間:)

+0

我創建了一個新的方法來處理讀取和加載圖像,並在主類中調用它一次並解決了問題。無論如何,謝謝你的幫助和你的解釋 – Muhsag