1

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

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

(img 是绘制的地图。此方法是具有所有信息的类的一部分,例如屏幕的宽度和高度以及相机的位置。(因此 PosX,PosY,宽度,高度取自对象的实例这被称为)

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. 在此之上绘制所有附加 MabObjects 的当前动画的 BufferedImage(基本上是所有会发生变化的东西;比如 Player、Npcs、移动的树木、宇宙飞船等等)。

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

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

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

4

2 回答 2

3

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

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

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

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


g2d.drawImage

  • 今天Java6/7

    1. 应由 override paintComponentin调用JPanel
    2. 第一个。里面的代码行paintComponent应该是super.paintComponent()==重置所有以前的绘画,否则绘画累积

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

  • 它是关于在 Swing 中将当前快照存储在绘画中的良好实践BufferedImage,并且所有易失性变量或对象都可以存储在中List<Whatever>,在 paintComponent 到 g2d.drawImage 中,其余的绘画在准备好的array of Objects ( List<Whatever>)中循环


为了获得更好的帮助,请尽快发布SSCCE,简短,可运行,可编译,即将发布

于 2013-11-02T13:05:08.807 回答
0

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

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

于 2013-11-02T14:40:10.513 回答