2011-03-19 77 views
1

我想通过重写我的JPanel的更新方法来实现我的游戏在Java中的双重缓冲,我做所有常见的代码等,仍然不会工作,它抛出一个堆栈溢出错误,下面是具体的错误:使用覆盖更新方法的Java双缓冲区抛出堆栈溢出

Exception in thread "AWT-EventQueue-0" java.lang.StackOverflowError 
     at java.awt.Rectangle.<init>(Rectangle.java:193) 
     at java.awt.Rectangle.<init>(Rectangle.java:208) 
     at sun.awt.image.BufImgSurfaceData.getBounds(BufImgSurfaceData.java:369) 
     at sun.java2d.loops.GraphicsPrimitive.convertFrom(GraphicsPrimitive.java:533) 
     at sun.java2d.loops.GraphicsPrimitive.convertFrom(GraphicsPrimitive.java:523) 
     at sun.java2d.loops.MaskBlit$General.MaskBlit(MaskBlit.java:171) 
     at sun.java2d.loops.Blit$GeneralMaskBlit.Blit(Blit.java:186) 
     at sun.java2d.pipe.DrawImage.blitSurfaceData(DrawImage.java:927) 
     at sun.java2d.pipe.DrawImage.renderImageCopy(DrawImage.java:550) 
     at sun.java2d.pipe.DrawImage.copyImage(DrawImage.java:54) 
     at sun.java2d.pipe.DrawImage.copyImage(DrawImage.java:982) 
     at sun.java2d.SunGraphics2D.drawImage(SunGraphics2D.java:2979) 
     at sun.java2d.SunGraphics2D.drawImage(SunGraphics2D.java:2964) 
     at epicgame.Menu.displayMenu(Menu.java:71) 
     at epicgame.GUI$1.paintComponent(GUI.java:64) 
     at javax.swing.JComponent.paint(JComponent.java:1029) 
     at epicgame.GUI$1.update(GUI.java:117) 
     at epicgame.GUI$1.paintComponent(GUI.java:98) 
     at javax.swing.JComponent.paint(JComponent.java:1029) 

我的代码是不是特别复杂或者:

mainPanel = new JPanel() 
     { 
      @Override protected void paintComponent(Graphics g) 
      { 
       //super.paintComponent(g); 

       if(menuEnabled == 1) 
       { 
        Menu.displayMenu(g, mainPanel); 
       } 
       else if(gameNum == 1) 
       { 
        StreetFighter.StreetFighter(g, mainPanel); 

        // Calls the controls method within the controls class. 
        Controls.controls(Calendar.getInstance().getTimeInMillis() - timeOld); 
        timeOld = Calendar.getInstance().getTimeInMillis(); 
       } 
       else if(gameNum == -1) 
       { 
        Menu.scoreBoard(g, mainPanel); 
        if(loaded != true) 
        { 
         Menu.loadScoreBoard(mainPanel); 
         loaded = true; 
        } 
       } 
       if(gameNum > 0) 
       { 
        if(longcat == true && longcatloaded != true) 
        { 
         Extras.loadLongCat(); 
         longcatloaded = true; 
        } 
        if(longcatloaded == true && longcat == true) 
        { 
         Extras.displayLongCat(g, mainPanel); 
        } 
       } 

       // Causes an infinite loop, e.g makes the screen render over and over. 
       //repaint(); 
       update(g); 
      } 

      @Override public void update(Graphics g) 
      { 
       System.err.println("Updating screen and using double buffer!"); 

       // initialize buffer 
       if(dbImage == null) 
       { 
        dbImage = createImage (this.getSize().width, this.getSize().height); 
        dbg = dbImage.getGraphics(); 
       } 
       // clear screen in background 
       dbg.setColor (getBackground()); 
       dbg.fillRect (0, 0, this.getSize().width, this.getSize().height); 
       // draw elements in background 
       dbg.setColor (getForeground()); 

       paint(dbg); 

       // draw image on the screen 
       g.drawImage (dbImage, 0, 0, this); 

       try 
       { 
        Thread.sleep(200); 

       } 
       catch (InterruptedException ex) 
       { 
        System.err.print("cant delay repaint."); 
       } 
      } 
     }; 

我希望有人能指出我哪里错了,我我想这可能与更新被调用的次数有关,或者可能的更新是错误的方法?

回答

1

请不要拨打或update()方法从paintComponent()

也不要在任何绘画方法中调用Thread.sleep()。相反,创建一个线程,每x毫秒更新一次游戏模型,然后在您的自定义组件上调用repaint(),以覆盖paintComponent(),以便绘制游戏状态。

+0

我会用什么来双缓冲呢? – 2011-03-19 03:11:16

+0

+1 Double缓冲是'JPanel'的一个特性;只需使用相关的构造函数。这是一个[示例](http://stackoverflow.com/questions/3256941)。 – trashgod 2011-03-19 03:17:23

0

您需要在每一帧完成后调用g.dispose(),否则它将永远不会从内存中释放,并且会出现您看到的堆栈溢出错误。 http://download.oracle.com/javase/1.3/docs/api/java/awt/Graphics.html

+0

在我更新的方法我还收到堆栈溢出的底部添加此之后。帮帮我。 – 2011-03-19 03:07:40

+0

只有在直接从组件或其他Graphics对象创建的情况下才需要。另外,它可能有助于引用更新的API。 – trashgod 2011-03-19 03:24:08

+0

API链接是Google的第一个结果,很确定它仍然适用。不知道什么时候需要处理的细节,但是如果你在Java中进行双缓冲,那么你正在进行主动渲染(而不是被动渲染),这需要你在每个处理器之后手动执行'dispose()'调用框架呈现。 – Bleaourgh 2011-03-19 03:27:54

1

您在组件的paintComponent中调用paint,这将导致组件继续重新绘制自己。这将导致StackOverflowException。此外,API告诫一个关于应用程序中调用明确开发商paint

Invoked by Swing to draw components. Applications should not invoke paint directly, but should instead use the repaint method to schedule the component for redrawing.

This method actually delegates the work of painting to three protected methods: paintComponent, paintBorder, and paintChildren. They're called in the order listed to ensure that children appear on top of component itself. Generally speaking, the component and its children should not paint in the insets area allocated to the border. Subclasses can just override this method, as always. A subclass that just wants to specialize the UI (look and feel) delegate's paint method should just override paintComponent.

+0

我需要这个,因为我整个游戏的基础依赖于它的持续清爽。 :/ – 2011-03-19 03:17:57

+1

@Luke:一种解决方法是每当修改值(或定期使用定时器或执行器服务)时检查变量'gameNum'和'menuEnabled'。如果它们满足一定的条件,则设置一个'global'标志并随后调用'repaint'(可能还有'removeAll')。然后,在'paintComponent'中检查该标志并执行相应的绘图。 – mre 2011-03-19 03:26:15

+0

谢谢,我将来会考虑到这一点。 – 2011-03-19 03:40:15