【问题标题】:j2me screen flicker when switching between canvases在画布之间切换时j2me屏幕闪烁
【发布时间】:2011-09-09 16:41:25
【问题描述】:

我正在使用 j2me 编写手机游戏。在这个游戏中,我使用了多个 Canvas 对象。 例如,游戏菜单是一个 Canvas 对象,而实际游戏也是一个 Canvas 对象。 我注意到,在某些设备上,当我从一个画布切换到另一个画布时,例如从主菜单切换到游戏,屏幕会瞬间“闪烁”。我正在使用我自己的双缓冲画布。

有没有办法避免这种情况?

【问题讨论】:

    标签: java-me midp lcdui


    【解决方案1】:

    我想说,使用多个画布通常是糟糕的设计。在某些手机上,它甚至会崩溃。最好的方法是使用一个跟踪应用程序状态的画布。然后在paint方法中你会有

    protected void paint(final Graphics g) {
      if(menu) {
        paintMenu(g);
      } else if (game) {
        paintGame(g);
      }
    }
    

    有更好的方法来处理屏幕对象的应用程序状态,这会使设计更简洁,但我想你明白了 :)

    /贾努斯西姆

    【讨论】:

      【解决方案2】:

      你使用双缓冲吗?如果设备本身不支持双缓冲,您应该定义一个屏幕外缓冲区(图像)并首先对其进行绘制,然后将最终结果绘制到真实屏幕。为您的每个画布执行此操作。这是一个例子:

      public class MyScreen extends Canvas {
         private Image osb;
         private Graphics osg;
         //...
      
         public MyScreen()
         {
               // if device is not double buffered
               // use image as a offscreen buffer
               if (!isDoubleBuffered())
               {
                  osb = Image.createImage(screenWidth, screenHeight);
                  osg = osb.getGraphics();
                  osg.setFont(defaultFont);
               }
         }
      
         protected void paint(Graphics graphics)
         {
            if (!isDoubleBuffered())
            {
               // do your painting on off screen buffer first
               renderWorld(osg);
      
               // once done paint it at image on the real screen
               graphics.drawImage(osb, 0, 0, Tools.GRAPHICS_TOP_LEFT);
            }
            else
            {
               osg = graphics;
               renderWorld(graphics);
            }
         }
      }
      

      【讨论】:

      • 我通过使用类似于您的方法定义屏幕外缓冲区来使用双缓冲。闪烁总是在新 Canvas 的主线程开始运行时发生。
      【解决方案3】:

      一个可能的解决方法是使用 Display.callSerially() 同步开关。闪烁可能是由于应用程序在 Canvas 的切换仍在进行时尝试绘制到屏幕造成的。 callSerially() 应该等待重绘完成,然后再尝试再次调用 run()。

      但这一切都完全取决于手机,因为许多设备没有实现 callSerially(),更不用说遵循官方文档中列出的实现了。我所知道的唯一能与 callSerially() 一起正常工作的设备是西门子手机。

      另一种可能的尝试是放置一个像 1000 毫秒这样巨大的 Thread.sleep(),确保您事先调用了 setCurrent() 方法。这样,设备可能会在可视组件尝试绘制之前进行更改。

      最有可能的问题是设备问题,并且保证对闪烁的修复很简单 - 使用一个 Canvas。可能不是你想听到的。 :)

      【讨论】:

      • 我听从了你的建议,在代码中放了一个很长的 Thread.sleep() 。我发现闪烁实际上是在我的 Canvas 的 run() 方法中的第一次 repaint() 之后发生的。有什么想法吗?
      【解决方案4】:

      如果您正在编写游戏,使用 GameCanvas 类可能是个好主意。对于这样的目的,它要好得多,如果使用得当,它应该可以解决您的问题。

      【讨论】:

      • 我最初使用的是 GameCanvas 对象。我也观察到了与该实现相同的“闪烁”行为。
      • 这是因为一些手机甚至没有实现 GameCanvas 后缓冲。
      【解决方案5】:

      假设,为您的应用程序使用 1 个带有状态机器代码的画布是一个好主意。但是,我必须在(MOTO v3)上测试应用程序的唯一设备在资源加载时崩溃,只是因为在 1 个 GameCanvas 中有太多代码/要加载(尚未尝试使用 Canvas)。它和真实一样痛苦,而且我还没有找到解决问题的方法。 如果您有幸拥有大量设备进行测试,那么值得同时实施这两种方法并为每台设备制作游戏版本。

      【讨论】:

      • 我的天啊,哇,我刚刚找到它...基本上一开始我使用了一个 introCanvas、一个 loadingCanvas 和一个 gameOverCanvas,在新版本中(都在 1 个画布/状态机中)我们没有使用一点也不。事实证明,只需从 src 文件夹中清除这些文件即可解决应用程序错误问题:)。太棒了!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-04-06
      • 2014-08-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-05-11
      • 2016-06-10
      相关资源
      最近更新 更多