渲染到JPanel的最快方法是什么?

时间:2013-11-02 12:24:07

标签: java swing rendering game-engine

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

所以我当前渲染帧的方法是操纵某个JPanel的g2d对象:

(img是绘制的地图。此方法是具有屏幕宽度和高度以及相机位置等所有信息的类的一部分。(因此,Posx,PosY,宽度,高度取自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. 绘制所有附加的MabObjects的当前动画的BufferedImage(基本上是由于更改的所有内容;如播放器,Npcs,移动树,太空飞船等等)。

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

  4. 令我好奇的是,这不是一个程序正在使用如此多的cpu以至于无法跟上渲染的情况,因为程序具有与附加x运行相同的滞后额外的,没有任何。 此程序也使用了我的CPU的大约5%(30fps)

    所以问题必须在其他地方。 你有没有想过优化它?

2 个答案:

答案 0 :(得分:3)

  

令我好奇的是,这不是一个案例   程序正在使用如此多的CPU,它无法跟上   渲染,因为程序具有相同的滞后运行x附加   额外的,没有任何。此程序也占用了我大约5%的CPU(at   30fps)的

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

  • Thread.sleep(0) == zero miliseconds冻结当前JVM实例,直到循环结束,没有任何反应,直到这个循环被Thread.sleep()冻结,

  • 本机操作系统中的
  • 延迟不低于16毫秒,25可能是限制,但使用Timer代替此值


  

g2d.drawImage

    今天Java6/7

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

    4. Swing Timer以合理的频率33-50毫秒延迟或重新粉刷

  • 关于在Swing中绘制以便在BufferedImage中存储当前快照的良好实践,并且所有易变变量或对象都可以存储在List<Whatever>中,在paintComponent中存储到g2d.drawImage并用于休息在准备好的array of Object s(List<Whatever>

  • 内循环绘画

更快地发布SSCCE,简短,可运行,可编辑,大约上午问题

答案 1 :(得分:0)

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

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