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

Java 渲染到JPanel的最快方法是什么?,java,swing,rendering,game-engine,Java,Swing,Rendering,Game Engine,所以我正在制作一些小型2D游戏引擎。 到目前为止,它工作得很好,但是渲染有点抖动,每1-2秒有一个延迟(帧冻结半秒)。尽管这很难成为交易的破坏者,但它仍然是一个需要解决的问题,我显然有点好奇为什么会这样 因此,我当前渲染帧的方法是通过操纵某个JPanel的g2d对象: (img是绘制的地图。此方法是一个类的一部分,该类包含所有信息,如屏幕的宽度和高度以及相机的位置。(因此,PosX、PosY、width、height是从调用它的对象的位置获取的) public void DrawbyManufa

所以我正在制作一些小型2D游戏引擎。 到目前为止,它工作得很好,但是渲染有点抖动,每1-2秒有一个延迟(帧冻结半秒)。尽管这很难成为交易的破坏者,但它仍然是一个需要解决的问题,我显然有点好奇为什么会这样

因此,我当前渲染帧的方法是通过操纵某个JPanel的g2d对象:

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

public void DrawbyManufacturedMapsuImage(BuffereImage img,Graphics2D)
{
如果(isActive)
{
BuffereImage img2=img.getSubimage(PosX,PosY,width,height);
g2d.drawImage(img2,0,0,null);
List MapObjects=Map.getObjectInformation();
List UC=this.UI.getUiComponents();
int l=this.Map.getObjectInformation().size();
对于(int i=0;i
这基本上就是,它

  • 根据用户从何处查看(某种方式的摄影机视图),绘制当前活动地图的子图像

  • 在上面绘制所有附加对象(基本上是由于更改而产生的所有内容;如播放器、NPC、移动的树、宇宙飞船等)的当前动画的BuffereImage

  • 在最后两个组件上绘制所有附加的UserInterface组件。 (比如人物肖像;没有按钮或任何可交互的东西)

  • 让我好奇的是,这不可能是一个程序使用如此多的cpu以至于无法跟上渲染速度的情况,因为该程序在运行x附加程序时与没有附加程序时具有相同的延迟。 此外,该程序使用了大约5%的CPU(每秒30帧)

    所以问题一定出在别的地方。 您是否有优化它的想法

    让我好奇的是,这不可能 一个程序占用了太多的cpu以至于跟不上 渲染,因为程序在附加x的情况下运行时具有相同的延迟 这个程序使用了我5%的CPU(至少 30帧/秒)

    • 由于
      Thread.sleep(int)
      的原因,您不应该使用Thread.sleep(int),只有在您想要模拟一些长时间和昂贵的睡眠的情况下,否则就使用Timer

    • Thread.sleep(0)
      ==
      0毫秒
      冻结当前JVM实例直到循环结束,在该循环被
      Thread.sleep()冻结之前不会发生任何事情

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


    g2d.drawImage

    • 今天的
      Java6/7

    • 应通过
      JPanel
      中的覆盖
      paintComponent
      调用
    • 1.
      paintComponent
      内的代码行应为
      super.paintComponent()
      ==重置所有以前的绘制,否则绘制累积

    • 以33-50毫秒的合理频率延迟或重新喷漆

    • 在Swing中绘制时,将当前快照存储在
      buffereImage
      中是一种很好的做法,所有易失性变量或对象都可以存储在
      List
      中,在paintComponent内部存储到g2d.drawImage中,其余的绘制将循环到已准备好的
      对象数组中(
      List



    为了获得更好的帮助,请尽快发布一个简短、可运行、可编译的凌晨问题

    由于分配过多,您可能会遇到垃圾收集暂停。有些方法对于分配非常可疑(例如“GetCurrentlyActiveframeasBuffereImage”)。 使用VisualGC检查分配率,然后改进您的程序或尝试获得一个大的eden。位图/byte[]等大型二进制对象直接分配到OldSpace上,因此如果创建太多,将触发大量oldGC暂停。如果是这种情况,调整eden大小将无济于事

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

    您应该在ActionListener中更改坐标后调用container.repaint()添加Swing计时器(50-125)
    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);
            }
        }
    }