2016-01-20 100 views
4

我正在製作一個玩家在迷宮中漫遊的2D遊戲。 screenshot of the GUISwing簡單覆蓋

我想實現某種形式的「黑暗」,甚至一些周圍玩家一個透明狀黑色包圍一樣簡單,像這樣的: mock-up screenshot

我用搖擺中發現的問題儘管這是可能的,但這意味着必須重新繪製所有內容,每當它發生時就會產生惱人的「閃爍」效果。有沒有辦法做出某種疊加,或者只是在Swing中做這些事的一個好方法?我現在對圖形用戶界面/可視化的東西不是很有經驗,所以如果可能的話,我想堅持用Swing。

編輯:這是我的方法來繪製背景,即在地板,牆壁和退出:

public final void paintBG(Graphics g){ 
    g.setColor(Color.LIGHT_GRAY); // Screen background 
    g.fillRect(0, 0, getWidth(), getHeight()); 
    // Draw the Walls of the maze 
    // scalex and y are for scaling images/walls within the maze since I let users specify how big they want the maze 
    for (int j = 0; j < this.height; j++, y += scaley) { 
     x = 20; 
     for (int i = 0; i < this.width; i++, x += scalex) { 
      if (!(maze[j][i].northwall.isBroken())) // If the north wall isn't broken 
      { 
       g.drawImage(walltile, x, y, scalex, scaley/5, null); // Draw a wall there (image, xpos, ypos, width, height, observer) 
      } 
      if (!(maze[j][i].eastwall.isBroken())) // etc 
      { 
       g.drawImage(walltile, x + scalex, y, scalex/5, scaley, null); 
      } 
      if (!(maze[j][i].southwall.isBroken())) { 
       g.drawImage(walltile, x, y + scaley, scalex, scaley/5, null); 
      } 
      if (!(maze[j][i].westwall.isBroken())) { 
       g.drawImage(walltile, x, y, scalex/5, scaley, null); 
      } 

      if ((j == mazeinfo.getTargetM()) && (i == mazeinfo.getTargetN())) { 
       // Draw the exit 
       g.drawImage(jeep, x + (scalex/2), y + (scaley/2), cx, cy, null); 
       g.setColor(Color.LIGHT_GRAY); 
       if (maze[j][i].northwall.isEdge()) { 
        // Paint over the edge creating a 'way out' 
        g.fillRect(x, y, scalex, scaley/4); 
       } else if (maze[j][i].eastwall.isEdge()) { 
        g.fillRect(x + scalex, y, scalex/4, scaley); 
       } else if (maze[j][i].southwall.isEdge()) { 
        g.fillRect(x, y + scaley, scalex, scaley/4); 
       } else if (maze[j][i].westwall.isEdge()) { 
        g.fillRect(x, y, scalex/4, scaley); 
       } 
      } 
     } 
    } 
} 

我再有「paintPlayer」和「paintEnemy」的方法每次移動時畫的精靈。背景僅在開始時繪製一次。

+0

謝謝你的代碼 - 請出示您的組件的實際油漆或的paintComponent方法以及。 –

+0

見編輯回答。 –

+0

對於[示例](http://stackoverflow.com/questions/15488853/java-mouse-flashlight-effect/15489299#15489299),[示例](http://stackoverflow.com/questions/15309611/how-to -draw-a-transparent-background/15309868#15309868),[示例](http://stackoverflow.com/questions/23709070/how-to-disable-java-awt-graphics-fillrectint-x-int-y- int-width-int-heights/23709320#23709320),[example](http://stackoverflow.com/questions/18388942/clear-portion-of-graphics-with-underlying-image/18392674#18392674) – MadProgrammer

回答

4

可能性:

  • 您可以直接在頂層窗口,如一個JFrame繪圖。如果是這樣,請不要繪製JPanel的paintComonent方法,以便使用自動雙緩衝availabe。
  • 您可能正在閱讀繪畫方法中的圖像,如果是,則不要。這些方法只能繪畫和繪畫,而且必須非常快速。
  • 您可能不會在繪畫方法中使用BufferedImage,但會重新創建圖像,如果是這樣,則不要。使用Graphics#drawImage(...)繪製BufferedImage。
  • 也許你的動畫代碼是關閉的。您可能會從paint或paintComponent中調用repaint(),這是永遠不應該做的事情。
  • 和可能的猜測可以繼續下去...

編輯

您的代碼表明你可能被重新油漆每幅畫迭代迷宮 - 不要做這個。相反,將上面的代碼繪製到BufferedImage中,然後在paintComponent方法中繪製該圖像。如果牆壁在結構上發生變化,則更改BufferedImage。

請注意,迷宮的邏輯結構(告訴哪個牆打開,關閉的非可視數據)應該是程序數據的一部分,而不是其代碼。

3

這裏是一個使用Oracle的Swing UI文檔中的LayerUI的例子。只需將AlphaComposite常數改爲較暗。

以下是一個LayerUI子類,只要鼠標在面板內移動,就繪製一個半透明的圓。

class SpotlightLayerUI extends LayerUI<JPanel> { 
    private boolean mActive; 
    private int mX, mY; 

    @Override 
    public void installUI(JComponent c) { 
    super.installUI(c); 
    JLayer jlayer = (JLayer)c; 
    jlayer.setLayerEventMask(
     AWTEvent.MOUSE_EVENT_MASK | 
     AWTEvent.MOUSE_MOTION_EVENT_MASK 
    ); 
    } 

    @Override 
    public void uninstallUI(JComponent c) { 
    JLayer jlayer = (JLayer)c; 
    jlayer.setLayerEventMask(0); 
    super.uninstallUI(c); 
    } 

    @Override 
    public void paint (Graphics g, JComponent c) { 
    Graphics2D g2 = (Graphics2D)g.create(); 

    // Paint the view. 
    super.paint (g2, c); 

    if (mActive) { 
     // Create a radial gradient, transparent in the middle. 
     java.awt.geom.Point2D center = new java.awt.geom.Point2D.Float(mX, mY); 
     float radius = 72; 
     float[] dist = {0.0f, 1.0f}; 
     Color[] colors = {new Color(0.0f, 0.0f, 0.0f, 0.0f), Color.BLACK}; 
     RadialGradientPaint p = 
      new RadialGradientPaint(center, radius, dist, colors); 
     g2.setPaint(p); 
     g2.setComposite(AlphaComposite.getInstance(
      AlphaComposite.SRC_OVER, .6f)); 
     g2.fillRect(0, 0, c.getWidth(), c.getHeight()); 
    } 

    g2.dispose(); 
    } 

    @Override 
    protected void processMouseEvent(MouseEvent e, JLayer l) { 
    if (e.getID() == MouseEvent.MOUSE_ENTERED) mActive = true; 
    if (e.getID() == MouseEvent.MOUSE_EXITED) mActive = false; 
    l.repaint(); 
    } 

    @Override 
    protected void processMouseMotionEvent(MouseEvent e, JLayer l) { 
    Point p = SwingUtilities.convertPoint(e.getComponent(), e.getPoint(), l); 
    mX = p.x; 
    mY = p.y; 
    l.repaint(); 
    } 
} 

爲了讓您的播放器更新聚光燈的中心,請創建一個播放器移動事件並註冊LayerUI以偵聽更新。請參閱下面的JLayer鏈接中的setLayerEventMask()示例。

來源:How to Decorate Components with the JLayer Class

+0

這是用於半透明疊加,但不適用於原始海報實際需要的背景圖像。 –