Java awt 性能焦虑

发布于 2024-10-02 18:41:46 字数 1807 浏览 0 评论 0原文

有一个程序可以在屏幕上同时生成数百或数千个移动粒子。显示数百个后,速度就会变慢。使用 netbeans profiler 分析性能,大约 80% 的时间花在 jpanel 的 Paint 方法上……所以算法优化似乎不太可能产生明显的差异。对此有什么可以做的吗?或者是时候考虑一​​个新平台了?绘制方法看起来像这样:

public void paintComponent(Graphics g) {
    super.paintComponent(g);
    setBackground(Color.WHITE);

    for (int i = 0; i < gameLogic.getParticleArrSize(); i++) {
        g.setColor(gameLogic.getParticleColor(i));
        g.fillOval(gameLogic.getParticleXCoor(i),
                gameLogic.getParticleYCoor(i),
                gameLogic.getParticleSize(i),
                gameLogic.getParticleSize(i));
    }
    g.setColor(gameLogic.getCurrPartColor());
    g.fillOval(mouseX - mouseOvalRadius, mouseY - mouseOvalRadius,
            mouseOvalSize, mouseOvalSize);
    g.setColor(gameLogic.getCursorColor());
    g.fillOval(mouseX - 19, mouseY - 19, 38, 38);

    for (int i = 0; i < gameLogic.getBombArrSize(); i++) {
        g.setColor(Color.RED);
        g.fillOval(gameLogic.getBombXCoor(i) - 6,
                gameLogic.getBombYCoor(i) - 6,
                gameLogic.getBombSize(i),
                gameLogic.getBombSize(i));
    }
    for (int i = 0; i < gameLogic.getPowerUpParticleArrSize(); i++) {
        g.setColor(gameLogic.getPowerUpParticleColor(i));
        g.fillOval(gameLogic.getPowerUpParticleXCoor(i),
                gameLogic.getPowerUpParticleYCoor(i),
                gameLogic.getPowerUpParticleSize(i),
                gameLogic.getPowerUpParticleSize(i));
    }
    for (int i = 0; i < gameLogic.getBlackArrSize(); i++) {
        g.setColor(Color.BLACK);
        g.fillOval(gameLogic.getBlackParticleXCoor(i),
                gameLogic.getBlackParticleYCoor(i),
                gameLogic.getBlackParticleSize(i),
                gameLogic.getBlackParticleSize(i));
    }
}

There is a program that generates hundreds or thousands of moving particles onscreen at once. After several hundred are displayed, slowdown occurs. Performance was analyzed using netbeans profiler and about 80% of the time was spend in the jpanel's paint method...so algorithm optimization seems unlikely to make a noticeable difference. Is there anything that can be done about this or is it time to think about a new platform? The paint method looks something like this:

public void paintComponent(Graphics g) {
    super.paintComponent(g);
    setBackground(Color.WHITE);

    for (int i = 0; i < gameLogic.getParticleArrSize(); i++) {
        g.setColor(gameLogic.getParticleColor(i));
        g.fillOval(gameLogic.getParticleXCoor(i),
                gameLogic.getParticleYCoor(i),
                gameLogic.getParticleSize(i),
                gameLogic.getParticleSize(i));
    }
    g.setColor(gameLogic.getCurrPartColor());
    g.fillOval(mouseX - mouseOvalRadius, mouseY - mouseOvalRadius,
            mouseOvalSize, mouseOvalSize);
    g.setColor(gameLogic.getCursorColor());
    g.fillOval(mouseX - 19, mouseY - 19, 38, 38);

    for (int i = 0; i < gameLogic.getBombArrSize(); i++) {
        g.setColor(Color.RED);
        g.fillOval(gameLogic.getBombXCoor(i) - 6,
                gameLogic.getBombYCoor(i) - 6,
                gameLogic.getBombSize(i),
                gameLogic.getBombSize(i));
    }
    for (int i = 0; i < gameLogic.getPowerUpParticleArrSize(); i++) {
        g.setColor(gameLogic.getPowerUpParticleColor(i));
        g.fillOval(gameLogic.getPowerUpParticleXCoor(i),
                gameLogic.getPowerUpParticleYCoor(i),
                gameLogic.getPowerUpParticleSize(i),
                gameLogic.getPowerUpParticleSize(i));
    }
    for (int i = 0; i < gameLogic.getBlackArrSize(); i++) {
        g.setColor(Color.BLACK);
        g.fillOval(gameLogic.getBlackParticleXCoor(i),
                gameLogic.getBlackParticleYCoor(i),
                gameLogic.getBlackParticleSize(i),
                gameLogic.getBlackParticleSize(i));
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

尾戒 2024-10-09 18:41:46

什么时候触发repaint()?是否在某个时间间隔上设置了计时器?我创建了一个动画库,并且能够顺利地为 40 个项目制作动画。您可能有更多对象,但我会首先查看时间间隔。

编辑
好的,这是我的建议。首先,您需要弄清楚绘图中的哪个功能占用了最多的时间。看来您经常调用 fillOval 。我的建议是使用以下内容创建一次形状:new RoundRectangle2D.Double()。然后使用 AffineTransformation 来移动形状。我很想知道其他人有什么建议,所以我会回来查看。

When are you triggering repaint()? Is it set on a timer on some time interval? I created an animation lib and I was able to animate 40 items smoothly. You probably have many more objects but I would look at the time interval first.

Edit:
Ok so here is my suggestion. First you need to figure out which function in paint is taking the most amount of time. It seems like you are calling fillOval a lot. My suggestion would be to create the shape once using something like: new RoundRectangle2D.Double(). And then use AffineTransformation to move around the shapes instead. I am curious to know what other suggest, so I will check back.

嘴硬脾气大 2024-10-09 18:41:46

尝试探索 Graphics2D 库。任何形状的填充算法,即使是像椭圆形这样简单的形状,都是昂贵的。创建形状、填充它然后将其复制到其他位置要快得多。 2D 库还支持各种缩放变换等。

这与 Daniel Viona 的 sprite 建议非常相似。精灵的存在是有原因的 - 它们是绘制许多简单小对象的快速方法!

如果我有时间,我会尝试画 1000 个小物体 - 介意了解这些物体的尺寸范围吗?就几个像素?我猜能量提升和炸弹相对较少,只有粒子会伤害你,对吧......

Try exploring the Graphics2D library. The fill algorithm for any shape, even something as simple as an oval, is expensive. It is far faster to create a shape, fill it then copy it to other locations. The 2D library also supports various transforms for scaling etc.

This is very similar to Daniel Viona's sprite suggestion. Sprites exist for a reason - they are a fast way to draw many small simple objects!

If I get some time I will try to draw 1000's of small objects - care to give an idea of the size range these objects will have? Just a few pixels? I am guessing the power ups and bombs are relative few, it is only the particles that are hurting you right...

兰花执着 2024-10-09 18:41:46

大约80%的时间花在了jpanel的paint方法上

,因为绝大多数处理都是单线程的,这意味着在现代机器上至少有一个 CPU 核心几乎完全被浪费了。如今,大多数计算机至少有双核,甚至更多。有几种方法可以让您利用这一点:

  • 如果您 80% 的时间都花在一种方法上,请确保剩余的 20% 不必等待绘画完成。在等待最后一帧绘制完成的同时,提前计算下一帧。
  • 您的绘制方法也可以分为多个线程。在多个线程之间共享相同的 Graphics 对象并不安全,但您可以让不同的线程渲染不同的图像,然后在最后将它们合成在一起。
    • 例如,让一个线程获取粒子的前半部分并直接渲染到后缓冲区。第二个线程获取剩余的粒子并将它们渲染为图像。一旦它们都完成,将图像传输到后台缓冲区,合并两个图像。

作为奖励...如果您确实想要性能,请考虑 JOGL。请参阅此处的示例:

about 80% of the time was spend in the jpanel's paint method

Since the vast majority of your processing is single-threaded, that means at least one CPU core is being almost entirely wasted on modern machines. Most computers have at least dual-cores these days, if not more. There are a couple ways for you to take advantage of this:

  • If 80% of your time is spent in one method, make sure that the remaining 20% doesn't have to wait for the painting to complete. Compute the next frame in advance while waiting for the last one to finish drawing.
  • Your paint method can also be split up into multiple threads. It's not safe to share the same Graphics object between multiple threads, but you can have different threads rendering to different images then composite them together at the end.
    • For example, have one thread take the first half of the particles and render directly to the backbuffer. A second thread takes the remaining particles and renders them to an image. Once they both complete, blit the image to your backbuffer, combining the two images.

As a bonus note... If you really want performance, consider JOGL. Look here for an example:

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文