2016-01-20 103 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

这是用于半透明叠加,但不适用于原始海报实际需要的背景图像。 –