我正在開發一個簡單的2D遊戲。每個勾號,我想檢查一個效果隊列,它將啓動一個特定效果的線程(淡入淡出轉換,音頻淡入淡出等)。例如,按下菜單屏幕上的「播放」將向該隊列添加一個「FadeOut」消息,該消息將被處理,並啓動一個線程來繪製一個黑色矩形,並在我的GamePanel上增加一個alpha值。我將重寫paintComponent()並將我的Graphics對象發送給我的GameStateManager,GameStateManager將Graphics對象傳遞給當前狀態的draw()。我目前沒有一個效果狀態(也許我應該)將paintComponent()圖形對象路由到,但是我將我的gamepanel傳遞給了我的效果線程,我可以在其中使用getGraphics()來繪製它。由於遊戲循環仍然在渲染遊戲,所以直接繪製矩形到GamePanel只會導致閃爍。如何使用getGraphics()覆蓋在PaintComponent()外部繪製到JPanel的BufferedImage()
我發現我可以繪製一個帶有增加alpha的BufferedImage的黑色矩形,將複合設置爲AlphaComposite.Src(這會導致新繪圖替換舊繪圖),然後通過遊戲面板繪製BufferedImage。問題是繪製到遊戲面板的BufferedImages不會被每個繪製覆蓋,所以淡出很快就會發生,因爲這些不同alpha的黑色BufferedImages彼此堆疊在一起。
我寫了這個簡短的程序來測試複合設置,看看什麼是重寫。所有繪圖都在draw()中完成,這將是我在效果線程中的run()。
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class ScratchPad extends JPanel implements Runnable
{
private JFrame oFrame = null;
private Thread oGameThread = null;
private Graphics2D oPanelGraphics = null;
private Graphics2D oImageGraphics = null;
private BufferedImage oImage = null;
public static void main(String args[]) throws Exception
{
new ScratchPad();
}
public ScratchPad()
{
createFrame();
initPanel();
addAndShowComponents();
oGameThread = new Thread(this, "Game_Loop");
oGameThread.start();
}
private void addAndShowComponents()
{
oFrame.add(this);
oFrame.setVisible(true);
}
private void initPanel()
{
this.setOpaque(true);
this.setBackground(Color.cyan);
}
private void createFrame()
{
oFrame = new JFrame("Fade");
oFrame.setSize(700, 300);
oFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
oFrame.setLocationRelativeTo(null);
}
public void run()
{
oImage = new BufferedImage(200, 200, BufferedImage.TYPE_INT_ARGB);
while(true)
{
try
{
draw();
Thread.sleep(100);
}
catch(InterruptedException e)
{
}
}
}
private void draw()
{
oPanelGraphics = (Graphics2D)this.getGraphics();
oImageGraphics = oImage.createGraphics();
oImageGraphics.setComposite(AlphaComposite.Src);
oImageGraphics.setColor(new Color(0,0,0,90));
oImageGraphics.fillRect(0, 0, oImage.getWidth(), oImage.getHeight());
oPanelGraphics.drawImage(oImage, 10, 10, null);
oImageGraphics.setColor(new Color(0,0,0,60));
oImageGraphics.fillRect(0, 0, oImage.getWidth(), oImage.getHeight());
oPanelGraphics.drawImage(oImage, 220, 10, null);
oImageGraphics.setColor(new Color(0,0,0,30));
oImageGraphics.fillRect(0, 0, oImage.getWidth(), oImage.getHeight());
oPanelGraphics.drawImage(oImage, 430, 10, null);
// Drawing this image over location of first image, should overwrite first
// after setting composite to 'Src'
oPanelGraphics.setComposite(AlphaComposite.Src);
oImageGraphics.setColor(new Color(0,0,0,10));
oImageGraphics.fillRect(0, 0, oImage.getWidth(), oImage.getHeight());
oPanelGraphics.drawImage(oImage, 10, 10, null);
oImageGraphics.dispose();
oPanelGraphics.dispose();
}
} // end class
有趣的是設定在「oPanelGraphics」複合引起的任何Alpha使用BufferedImage走開,導致完全不透明的黑色圖像上畫出來,這是以前沒有的圖像。即使將顏色設置爲黑色以外的其他顏色也沒有效果。
什麼也有趣的是,對於BufferedImage的設定合成到:
oImageGraphics.setComposite(AlphaComposite.SrcIn);
導致什麼可顯示。關於在Java2D中合成圖形的Oracle文檔聲明瞭'SrcIn':
「如果源和目標中的像素重疊,則只會渲染重疊區域中的源像素。」
因此,我希望這與AlphaComposite.Src獲得的行爲相同。
也許有人在那裏可以揭示這些複合材料正在發生什麼,以及如何實現我想要的效果。
無法在面板中重寫onDraw(Graphics g2d)而不是執行此draw()方法嗎? –
@MarcosVasconcelos是的,那就是我目前正在做的。然而,我在遊戲中處理效果的想法(轉換,屏幕和音頻淡入和淡出)是有動作的(點擊菜單上的「播放」或角色在某個圖塊上行走)將消息添加到被檢查的隊列每場比賽打勾。這些效果會觸發一個線程並在那裏進行處理,並且遊戲循環可以繼續。我目前沒有將我的paintComponent()提供的Graphics對象路由到我的Effects類。這就是爲什麼我在效果線程中使用getGraphics – WhitJackman
根據你的代碼,你根本不重寫'paintComponent',而是使用'getGraphics',這是不推薦的,因爲你試圖更新UI之外的UI Swing定義的繪畫循環的上下文。你也不應該處理你沒有創建的'Graphics'上下文。我也沒有看到'BufferedImage'的重點。你也似乎沒有任何關於動畫假設如何在Swing中工作的概念 – MadProgrammer