【问题标题】:What is the fastest way to Render to a JPanel?渲染到 JPanel 的最快方法是什么?
【发布时间】:2013-11-02 12:24:06
【问题描述】:

所以我正在制作某种小型 2D - 游戏引擎。 到目前为止它工作得很好,但是渲染有点紧张,每 1-2 秒有一个延迟(帧冻结半秒)。尽管这几乎不会破坏交易,但它仍然是一个应该解决的烦恼,我显然有点好奇这是为什么。

所以我目前渲染框架的方法是通过操作某个 JPanel 的 g2d 对象:

(img 是绘制的地图。此方法是一个类的一部分,该类具有所有信息,如屏幕的宽度和高度以及相机的位置。(因此 PosX,PosY,width,height 取自 Instace被调用的对象)

public void DrawByManipulatedMapSubimage(BufferedImage img, Graphics2D g2d)
{
    if (isActive)
    {
        BufferedImage img2 = img.getSubimage(PosX, PosY, width, height); 
        g2d.drawImage(img2,0,0,null);
        List<MapObject> MapObjects = Map.getObjectInformation();
        List<UiComponent> UC = this.UI.getUiComponents();

        int l = this.Map.getObjectInformation().size();

        for (int i = 0; i < l; i++)
        {
            MapObject MO = MapObjects.get(i);
            int MOX = MO.getPosX();
            int MOY = MO.getPosY();
            BufferedImage MOB = MO.getCurrentAnimation().getCurrentlyActiveFrameAsBufferedImage();

            g2d.drawImage(MOB, MOX - PosX, MOY - PosY, null);
        }

        for (int i = 0; i < UC.size(); i++)
        {
            UiComponent CC = UC.get(i);
            if (CC.isVisible())
            {
                Point P = CC.getPosition();
                int x = P.x;
                int y = P.y;
                g2d.drawImage(CC.getImg(),x,y,null);
            } 
        }
        try 
        {
            Thread.sleep(0);
        } 
        catch (InterruptedException ex) 
        {
            Logger.getLogger(Viewport.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}

这基本上做的是,它

  1. 根据用户正在查看的位置(以某种方式查看相机)绘制当前活动地图的子图像

  2. 在此之上绘制所有附加 MabObject 的当前动画的 BufferedImage(基本上是所有会发生变化的事物;例如 Player、Npc、移动的树木、宇宙飞船等等)。

    李>
  3. 将所有附加的 UserInterface-Components 绘制在最后两件事之上。 (例如人物肖像之类的东西;没有按钮或任何可交互的东西)

让我好奇的是,这不可能是一个程序使用太多 cpu 以至于它无法跟上渲染的情况,因为该程序在运行带有 x 的情况下具有相同的延迟额外的没有任何。 这个程序也使用了我大约 5% 的 CPU(在 30fps 时)

所以问题必须在其他地方。 您可能有优化它的想法吗?

【问题讨论】:

    标签: java swing rendering game-engine


    【解决方案1】:

    让我好奇的是,这不可能 一个程序使用了太多的 cpu 以至于它跟不上 渲染,因为程序在附加 x 的情况下运行时具有相同的滞后 额外的没有任何。这个程序也使用了我大约 5% 的 CPU(在 30fps)

    • Thread.sleep(int)引起,你不应该使用Thread.sleep(int),只有在你想模拟一些长时间和昂贵的睡眠的情况下,否则使用Timer

      李>
    • Thread.sleep(0) == zero miliseconds 冻结当前 JVM 实例直到循环结束,直到循环被Thread.sleep() 冻结结束,什么都不会发生,

    • Native OS 中的延迟不低于 16 毫秒,25 可能是一个限制,但使用 Timer 代替此值


    g2d.drawImage

    • 今天Java6/7

      1. 应该被JPanel中的覆盖paintComponent调用,
      2. 第一。 paintComponent 内的代码行应该是 super.paintComponent() == 重置所有以前的绘画,否则绘画累积

      3. Swing Timer 以合理的频率延迟或重绘 33-50 毫秒

    • 关于在 Swing 中将当前快照存储在 BufferedImage 中的良好实践,所有 volatile 变量或对象都可以存储在 List&lt;Whatever&gt; 中,在paintComponent 内部到 g2d.drawImage 以及其余的绘画循环里面准备好了array of Objects (List&lt;Whatever&gt;)


    为了获得更好的帮助,请尽快发布 SSCCE,简短、可运行、可编译,大约在上午的问题

    【讨论】:

    • 你应该添加 Swing Timer (50-125) 并在 ActionListener 中更改坐标后调用 container.repaint()
    【解决方案2】:

    由于分配过多,您可能正遭受垃圾收集暂停的困扰。有些方法在分配方面看起来非常可疑(例如 "getCurrentlyActiveFrameAsBufferedImage" )。 使用 VisualGC 检查分配率,然后改进您的程序或尝试获得一个大伊甸园。像bitmaps/byte[]这样的大二进制对象直接分配在OldSpace上,所以如果你创建太多,就会触发很多oldGC暂停。如果是这种情况,调整 Eden 大小将无济于事。

    编辑:通过使用 -verbose:GC 选项运行程序来检查“暂停”是否与 GC 相关

    【讨论】:

      猜你喜欢
      • 2014-05-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-01-09
      • 2017-03-06
      • 2011-08-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多