Java 2D游戏没有明显原因而放慢速度

时间:2017-07-30 17:03:30

标签: java performance

我在java中创建了一个2D平台游戏风格的游戏,其中一些部分由我自己编程的物理引擎模拟。问题是游戏在某些点上从预期的60 fps减慢到大约30 fps。游戏循环看起来像这样:

@Override
public void run() {

    init();

    long startTime;
    long elapsedTime;
    long waitTime;

    while(running) {

        startTime = System.nanoTime();

        update();
        long updateTime = (System.nanoTime() - startTime) / 1000000;
        draw();
        long drawTime = (System.nanoTime() - startTime) / 1000000;
        drawToScreen();
        long drawscreenTime = (System.nanoTime() - startTime) / 1000000;

        elapsedTime = System.nanoTime() - startTime;
        waitTime = targetTime - elapsedTime / 1000000;
        if(waitTime < 0) {
            waitTime = 0;
        }

        try {
            Thread.sleep(waitTime);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

我正在测量使用updateTime更新游戏逻辑所需的时间以及使用drawTime和drawscreenTime绘制所需的时间。在任何时候(在减速期间!),updateTime为0 ms,drawTime + drawscreenTime大约为10 ms,低于16 ms的最大值(60 fps)。

到目前为止,我发现改变物理对象潜在碰撞的设置可以减少减速。起初我想按区域分隔对象,这样程序就不需要用每个对象检查每个对象。例如,代替100x100 = 10000个对象,只有33x33 + 33x33 + 33x33 = 3267个对象。

按区域分隔如下:

private ArrayList<PhysicalObject> objects;
private ArrayList<ArrayList<PhysicalObject>> zones;

for(int i = 0; i < numberOfZones; i++) {
        zones.get(i).clear();
    }

    for(PhysicalObject object : objects) {
        for(int zone : object.getSimulationZones()) {
            zones.get(zone).add(object);
        }
    }

    for(ArrayList<PhysicalObject> list : zones) {

        for(PhysicalObject object1 : list) {
            for(PhysicalObject object2 : list) {

            collision stuff happens

            }
        }
    }
}

&#34;直言不讳&#34;用每个其他对象来chekcing每个对象的方法如下:

private ArrayList<PhysicalObject> objects;

for(PhysicalObject object1 : objects) {
    for(PhysicalObject object2 : objects) {

        collision stuff happens
    }
}

现在正如你所预料的那样,在查看updateTime时,直接的方法会变慢,但是当我使用这种方法时,减速的重要性要小得多。 我不知道这是怎么回事,因为做一个游戏循环所需的时间似乎与减速无关,但是当我改变在游戏循环中运行的代码时,减速是不同的。

起初我认为Thread.sleep()可能有错,因为我听说它有时不可靠,所以我尝试使用Java.util.Timer。但是当我使用16毫秒(60 fps)的延迟时,fps会以30 fps的速度上下跳跃。

如果有人可以帮助我,我真的很感激。 如果你需要更多代码,我可以发布更多,但由于游戏代码已经相当大,我认为最好从小做起,而不是更多地淹没我的问题。

修改

似乎绘制游戏级别也会对减速产生影响。但是,当有更多图像要绘制时,它不会减慢速度,而是在图像较少时减慢速度。但同样重要的是:即使减速正在减少,当有更多东西需要绘制时,drawTime也会增加。绘制关卡的代码如下所示:

public void draw(Graphics2D g2d) {

    for(int row = drawStartRow; row < drawStartRow + rowsToDraw; row++) {

        if(row >= numRows) {
            break;
        }

        for(int col = drawStartCol; col < drawStartCol + colsToDraw; col++) 
{

            if(col >= numCols) {
                break;
            }

            //0 stands for no tile to draw
            if(map[row][col] == 0) {
                continue;
            }

            int rc = map[row][col];
            int r = rc / numTilesAcross;
            int c = rc % numTilesAcross;

            g2d.drawImage(tiles[r][c].getImage(), (int)x + col * tileSize, (int)y + row * tileSize, null);
        }
    }
}

数组中的图像是通过构造函数中的BufferedImage.getSubImage()生成的。

编辑2:

我终于能够通过改变我关卡的绘图方法来摆脱减速。我现在不是遍历每个点并绘制相应的图像,而是首先迭代不同的图像然后(对于每个图像)遍历斑点并绘制它们(如果它们属于斑点)。

总的来说,我的循环次数是数字时间更长,但减速消失了。原因似乎是我现在正在绘制每个图像,因为它需要绘制,然后继续下一个图像。但我不明白这对我的整体帧率有多大影响,即使绘制所需的时间不是更改?

1 个答案:

答案 0 :(得分:0)

根据drawImage的规格: https://docs.oracle.com/javase/7/docs/api/java/awt/Graphics2D.html#drawImage(java.awt.Image,%20java.awt.geom.AffineTransform,%20java.awt.image.ImageObserver)

绘图可以异步完成,这意味着函数返回时不会渲染图像。通过使用Thread.sleep阻塞线程,可能会减慢渲染速度。您可以通过检查返回值来快速测试以检查图像是否完全呈现。