简单的Java2D应用程序中的可怕性能

时间:2022-05-06 21:54:07

I've just finished my entry for the 14th Ludum Dare 48-hours game making competition yesterday, and decided to do it in java using java2d for the graphics.

我刚刚参加了第14届Ludum Dare 48小时游戏制作比赛,并决定在java中使用java2d进行图形处理。

I'm not that familiar with the API and haven't done a lot of graphics programming, but my game is quite small (only a dozen or so very small moving object) so I assumed I could program it naively and still encounter no performance problems.

我对API并不熟悉并没有做过很多图形编程,但是我的游戏很小(只有十几个非常小的移动物体)所以我认为我可以天真地编程并且仍然没有遇到任何性能问题。

Needless to say, I was wrong. The game performs alright most of the time but once there are a bit too many 'enemies' moving around on the screen or the resolution is cranked up too high it start getting visibly slower.

不用说,我错了。游戏在大多数时间内表现不错,但是一旦有太多“敌人”在屏幕上移动或者分辨率过高,它开始明显变慢。

I've determined the performance bottleneck to be the screen drawing functions, when those are commented out the game is very fast.

我已经确定了屏幕绘图功能的性能瓶颈,当这些功能被评论出来时游戏速度非常快。

Could someone give me a heads up on what I might be doing wrong here? The (very short) source code is located here with most of it the Main class, with the usual suspects being the draw() function that is called in the inner game loop.

有人可以告诉我这里我可能做错了什么吗? (非常短的)源代码位于此处,其中大部分是Main类,通常的嫌疑人是在内部游戏循环中调用的draw()函数。

I already use a BufferStrategy to update the screen, so that shouldn't be the problem unless I'm doing it wrong.

我已经使用BufferStrategy来更新屏幕,所以这不应该是问题,除非我做错了。

Thanks in advance, Ido.

提前谢谢,Ido。

4 个解决方案

#1


7  

A few observations, although I don't think any of them will help much.

一些观察,虽然我认为它们中的任何一个都没有多大帮助。

The main thing is that you're painting off of the AWT thread. Override paintComponent() and instead call repaint() on the object. This can cause all sorts of problems otherwise.

最重要的是你正在绘制AWT线程。覆盖paintComponent(),而是在对象上调用repaint()。否则会导致各种问题。

You recreate colors every frame. This may or may not be one of those things that you want to cache. I don't think though that having a constant for your colors is likely to screw up GCing and will make things easier to keep straight when you want to reuse colors later.

您可以每帧重新创建颜色。这可能是也可能不是您要缓存的内容之一。我不认为虽然你的颜色有一个常数可能会搞砸GCing,并且当你想在以后重复使用颜色时会更容易保持直线。

You redraw the entire window every frame. You just need to repaint the sections that changed.

您每帧重绘整个窗口。您只需要重新绘制已更改的部分。

You don't need to draw the background. Set the background color and let the parent take care of everything.

您不需要绘制背景。设置背景颜色,让父母照顾好一切。

As a design thing, the bodies should be in charge of drawing themselves. Their owner should notify them that they need to be drawn rather than drawing them.

作为一种设计,身体应该负责自己画画。他们的主人应该通知他们需要绘制而不是绘制它们。

The bodies recreate their state every time. Consider having them store it between times and mutate them as needed. You may be spending a lot of time doing trig calculations in the drawCircleBody()

身体每次都重建他们的状态。考虑让它们在不同时间存储它们并根据需要改变它们。您可能花了很多时间在drawCircleBody()中进行trig计算

Something to consider is setting up a timer rather than using a sleep in a while loop. This will get you a more consistent frame rate, but you need to make sure that you can actually meet your obligations (or coalesce multiple frames into one if you miss a deadline) or you'll end up creating too many threads.

要考虑的是设置计时器而不是在while循环中使用sleep。这将为您提供更加一致的帧速率,但您需要确保您实际上可以履行您的义务(或者如果您错过截止日期,将多个帧合并为一个),或者您最终会创建太多的线程。

Consider using a SwingWorker to do the calculations, then update the state in the done() method, finishing by calling repaint().

考虑使用SwingWorker进行计算,然后在done()方法中更新状态,通过调用repaint()来完成。

These are just a few things. You should experiment to see what works and what doesn't. It's been a while since I've done Java graphics drawing.

这些只是一些事情。你应该试验看哪些有效,哪些无效。自从我完成Java图形绘制以来已经有一段时间了。

#2


6  

Your code isn't following the single threading rule:

您的代码不遵循单线程规则:

http://java.sun.com/products/jfc/tsc/articles/threads/threads1.html

http://java.sun.com/products/jfc/tsc/articles/threads/threads1.html

I'm not sure if this will cause the specific performance problems that you are seeing, but it stands out as a big potential problem, imo.

我不确定这是否会导致你所看到的具体性能问题,但它是一个很大的潜在问题,imo。

#3


6  

Well, just from a brief look at your draw() function, it seems that you're declaring a number of new objects (especially in drawPolygonBody). Try to reuse objects instead of declaring a new ones each time.

好吧,只是简单地看一下你的draw()函数,你似乎在宣告一些新的对象(特别是在drawPolygonBody中)。尝试重用对象,而不是每次都声明一个新对象。

EDIT: instanceof has overhead. It would be a better idea to extend Body to have a draw(Graphics g) function that draws itself. eg:

编辑:instanceof有开销。将Body扩展为具有绘制自身的绘制(Graphics g)函数将是一个更好的主意。例如:

public class Circle extends Body
{
    // override
    public void draw(Graphics g)
    {
        ...
    }
}

...

void drawBody(Body body) 
{
    body.draw();
}

#4


4  

Have you tried profiling it to see where in the drawing functions the bottleneck is?

您是否尝试过分析它以查看绘图功能中瓶颈的位置?

It's hard to say much just by looking at it, but I'm wondering why you're both drawing and filling the polygon in drawPolygonBody.
Also, in drawBoxBody, you're drawing four lines separately instead of just calling drawRect().

通过观察很难说很多,但我想知道你为什么要在drawPolygonBody中绘制和填充多边形。另外,在drawBoxBody中,您分别绘制了四行而不是仅调用drawRect()。

#1


7  

A few observations, although I don't think any of them will help much.

一些观察,虽然我认为它们中的任何一个都没有多大帮助。

The main thing is that you're painting off of the AWT thread. Override paintComponent() and instead call repaint() on the object. This can cause all sorts of problems otherwise.

最重要的是你正在绘制AWT线程。覆盖paintComponent(),而是在对象上调用repaint()。否则会导致各种问题。

You recreate colors every frame. This may or may not be one of those things that you want to cache. I don't think though that having a constant for your colors is likely to screw up GCing and will make things easier to keep straight when you want to reuse colors later.

您可以每帧重新创建颜色。这可能是也可能不是您要缓存的内容之一。我不认为虽然你的颜色有一个常数可能会搞砸GCing,并且当你想在以后重复使用颜色时会更容易保持直线。

You redraw the entire window every frame. You just need to repaint the sections that changed.

您每帧重绘整个窗口。您只需要重新绘制已更改的部分。

You don't need to draw the background. Set the background color and let the parent take care of everything.

您不需要绘制背景。设置背景颜色,让父母照顾好一切。

As a design thing, the bodies should be in charge of drawing themselves. Their owner should notify them that they need to be drawn rather than drawing them.

作为一种设计,身体应该负责自己画画。他们的主人应该通知他们需要绘制而不是绘制它们。

The bodies recreate their state every time. Consider having them store it between times and mutate them as needed. You may be spending a lot of time doing trig calculations in the drawCircleBody()

身体每次都重建他们的状态。考虑让它们在不同时间存储它们并根据需要改变它们。您可能花了很多时间在drawCircleBody()中进行trig计算

Something to consider is setting up a timer rather than using a sleep in a while loop. This will get you a more consistent frame rate, but you need to make sure that you can actually meet your obligations (or coalesce multiple frames into one if you miss a deadline) or you'll end up creating too many threads.

要考虑的是设置计时器而不是在while循环中使用sleep。这将为您提供更加一致的帧速率,但您需要确保您实际上可以履行您的义务(或者如果您错过截止日期,将多个帧合并为一个),或者您最终会创建太多的线程。

Consider using a SwingWorker to do the calculations, then update the state in the done() method, finishing by calling repaint().

考虑使用SwingWorker进行计算,然后在done()方法中更新状态,通过调用repaint()来完成。

These are just a few things. You should experiment to see what works and what doesn't. It's been a while since I've done Java graphics drawing.

这些只是一些事情。你应该试验看哪些有效,哪些无效。自从我完成Java图形绘制以来已经有一段时间了。

#2


6  

Your code isn't following the single threading rule:

您的代码不遵循单线程规则:

http://java.sun.com/products/jfc/tsc/articles/threads/threads1.html

http://java.sun.com/products/jfc/tsc/articles/threads/threads1.html

I'm not sure if this will cause the specific performance problems that you are seeing, but it stands out as a big potential problem, imo.

我不确定这是否会导致你所看到的具体性能问题,但它是一个很大的潜在问题,imo。

#3


6  

Well, just from a brief look at your draw() function, it seems that you're declaring a number of new objects (especially in drawPolygonBody). Try to reuse objects instead of declaring a new ones each time.

好吧,只是简单地看一下你的draw()函数,你似乎在宣告一些新的对象(特别是在drawPolygonBody中)。尝试重用对象,而不是每次都声明一个新对象。

EDIT: instanceof has overhead. It would be a better idea to extend Body to have a draw(Graphics g) function that draws itself. eg:

编辑:instanceof有开销。将Body扩展为具有绘制自身的绘制(Graphics g)函数将是一个更好的主意。例如:

public class Circle extends Body
{
    // override
    public void draw(Graphics g)
    {
        ...
    }
}

...

void drawBody(Body body) 
{
    body.draw();
}

#4


4  

Have you tried profiling it to see where in the drawing functions the bottleneck is?

您是否尝试过分析它以查看绘图功能中瓶颈的位置?

It's hard to say much just by looking at it, but I'm wondering why you're both drawing and filling the polygon in drawPolygonBody.
Also, in drawBoxBody, you're drawing four lines separately instead of just calling drawRect().

通过观察很难说很多,但我想知道你为什么要在drawPolygonBody中绘制和填充多边形。另外,在drawBoxBody中,您分别绘制了四行而不是仅调用drawRect()。