2012-11-20 35 views
0

我正在實現一個棋盤遊戲,其中每個玩家有幾個單位,並且每個單位都向使用我使用以下方法從文件中讀取的公共圖像向用戶顯示。我在應用程序啓動時閱讀這個圖像,並在稍後使用它。在這種情況下使用緩存生成BufferedImages?

private static BufferedImage readBufferedImage (String imagePath) { 
     try { 
      InputStream is = IconManager.class.getClassLoader().getResourceAsStream(imagePath); 
      BufferedImage bimage = ImageIO.read(is); 
      is.close(); 
      return bimage; 
     } catch (Exception e) { 
      return null; 
     } 
    } 

單位與位於該共同圖像的頂部各種豐富多彩的令牌不同。

之前,我只加幾個commonImages到JPanel並標記使用其漂浮於commonImage

頂部
//at startup 
    ImageIcon commonImage = new ImageIcon(readBufferedImage("image.png")); 
    ... 
    JPanel panel = new JPanel(); 
    panel.add(commonImage); 
    panel.add(commonImage); 

    //located JLabels with token on the top of each commonImage   

不過,現在我想用JScrollPane的,而不是的JPanel的JLabel實現的,所以我認爲它在將其展示給用戶之前,將drawString()和drawImage()提供給每個commonImage是一種更好的方法。

我估計的單位數量大約爲20.所以現在每個單位我都需要生成帶有各種令牌配置的動態單獨BufferedImage。

問題是我應該緩存已經生成的BufferedImages,這取決於令牌配置從緩存中提取,如果圖像之前已經生成了相同的配置?

+0

如果您可以緩存部分或全部結果,則重繪速度會更快。例如,您可以生成每個令牌的「BuffereImage」並將其繪製,再加上每條路徑上的公共圖像。由於常見圖像是共享資源,它會更好(恕我直言)嘗試,只保留一個副本(而不是將圖像和文本合併成一個圖像) - 這當然歸結於單位數量和大小。內存摺衷爲每個單元生成一個單一的圖像,因爲在那裏「令牌」可能是可協商的。你認爲繪製任何一種方法都很容易 – MadProgrammer

+0

「它會更好(恕我直言)嘗試,只保留一個副本(而不是將圖像和文本合併成一個圖像)」 - @MadProgrammer,但如何實現這一點?我已經完成了JLabels的浮動工作,但從現在開始,我將所有內容都放入了ScrollPane中,因此當滾動發生時相應地移動JLabels會非常複雜,並且當通用圖像由於滾動而變得不可見時,隱藏其中的一部分。 –

+0

滾動窗格將照顧它。事實上,您可以將現有面板轉儲到滾動窗格中,並根據需要調整遊戲板的大小,屏幕窗格將爲您處理它。 – MadProgrammer

回答

1

你問這個問題取決於幾個因素:

  1. 需要多長時間來生成從頭
  2. 需要多長時間檢查前
  3. 如何生成圖像的圖像大每個圖像將是
  4. 圖像的概率被重用

因此,沒有HAV對你的申請有很好的瞭解,沒有人能夠準確地爲你提供準確的答案。

一般來說,如果你只是移動令牌,應該很快實施updatepaintComponent面板繪圖方法。如果您保存基本圖像,標記圖像和當前生成的圖像(基本上是您所建議的),我不會預料性能問題。關鍵是要在你自定義的update方法中更新圖像,並且始終在paintComponent方法中繪製當前生成的圖像。

更新

例如,您可以使用類似下面的代碼緩存當前顯示:

private BufferedImage cachedImage; 
... 

@Override 
public void paintComponent(Graphics g){ 
    //If the image needs to be refreshed draw it to the cache first 
    if(cachedImage == null){ 
     cachedImage = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_4BYTE_ABGR); 
     super.paintComponent(cachedImage.getGraphics()); 
    } 

    //Draw the image from cache 
    g.drawImage(cachedImage, 0, 0, this); 
} 

如果要清除高速緩存,在你的方法,做了更新,倒是設定cachedImage = null;

但在你的情況,

  • 您遇到的200x200規模的任何性能問題將與您正在進行的圖紙數量有關。由於我猜測你並不關心幀/秒速率,我懷疑你會遇到性能問題(你可以收集時間來準確瞭解需要多長時間才能繪製 - 我估計在100毫秒以內)
  • 最簡單的做法是緩存令牌圖像和它們的字符串(我假設它們很少改變),但仍然動態地創建令牌佈局。 (在你的情況下任何其他性能提升都不會那麼容易)。
  • 緩存屏幕的先前渲染將基本上破壞擺動顯示模型(使用它沒有多少意義 - 只需自己做佈局)。這實際上適用於任何容器的緩存。
+0

1.對於每個單元完整圖像,它是Graphics.drawString的一次和最多10次Graphics.fill(new Rectangle())或Graphics.draw(new Rectangle())。最多20個單位。 2.我認爲這是短時間,如果我將它們保存在HashMap中 3.最大200x200 4.對於少量令牌,概率很高並且隨着令牌數量的增加而減少 –

+0

目前我根本沒有使用update和paintComponent方法。我只是使用JLabel.setIcon(圖標);這些方法如何幫助我? –

+0

@NikolayKuznetsov在回答中添加了更新以解決您的一些問題。關於你的2):你需要有一種方法來查找哈希映射中的圖像 - 所以你必須建立一個大關鍵,然後在哈希映射中查找它(這可能比它值得的開銷更大)。 基本上你必須看看你會改善用戶體驗的程度。如果需要100ms,用戶可能甚至不會注意到延遲(仍然假設你沒有做動畫)。最重要的是,使用緩存的可能性會隨着你需要更多(更多的令牌)而降低 - 這是一個不錯的理由。 –