5

对于我的大学作业,我必须制作一个可联网的 pacman 版本。我想我最好先制作一个 pacman 的本地副本来解决这个问题,然后将此功能扩展为网络游戏。

我不得不说我对 java GUI 开发和在 java 中利用这些特性还比较陌生。

我已经开始关注上面关于 java 中的游戏开发的链接和一个 pacman 游戏的例子。

我决定将迷宫表示为一个 int 数组,其中不同的值意味着不同的事物。然而,当主游戏循环中的绘制方法运行时,我正在用这种方法重新绘制整个迷宫。

    for (int i : theGame.getMaze())
    {
        if (i == 4)
        {
            g.setColor(mazeWallColour);
            g.fillRect(curX, curY, cellSize, cellSize);
            curX += 25;
        }
        else
        {
            curX += cellSize;
        }

        index++;


        // Move to new row
        if (index == 25)
        {
            index = 0;
            curX = 10;
            curY += cellSize;
        }
    }

然而,这为我提供了不到 1fps 的速度。尽管我注意到上面链接的示例在每次调用paint方法时都使用类似的重绘方式,并且我相信在不可见的图像上会这样做(有点像双缓冲[我使用了像第一个链接一样的 BufferStrategy解释]) 重新绘制迷宫的更好方法是什么?

任何与此有关的指针/建议都会很有用。

感谢您的时间。

http://pastebin.com/m25052d5a - 用于主要游戏类。

编辑:我刚刚注意到在尝试查看哪些代码需要这么长时间才能执行之后发生了一些非常奇怪的事情。

在我添加的 paintClear(Graphics g) 方法中

ocean = sprites.getSprite("oceano.gif");
g.setPaint(new TexturePaint(ocean, new Rectangle(0,t,ocean.getWidth(),ocean.getHeight())));
g.fillRect(10, 10,getWidth() - 20,getHeight() - 110);

这使整个事情顺利进行 - 但是当我删除这些行时,整个事情变慢了?是什么原因造成的?

更新代码

4

10 回答 10

4

首先,我建议您使用命名常量,而不是在代码中使用随机幻数,并考虑为您的单元格类型使用枚举。虽然它不会让你的代码运行得更快,但它肯定会让它更容易理解。此外,“i”通常用作计数器,而不是返回值。您可能应该调用它cellType或类似的名称。我还建议您为舞台地图使用 2D 数组,因为它使许多事情变得更容易,无论是逻辑上还是概念上。

也就是说,这里有一些事情可以尝试:

拉出setColor()循环并执行一次。编译器可能能够进行循环不变的提升,从而为您执行此操作(并且可能会),但从概念上讲,您可能无论如何都应该这样做,因为您似乎希望所有的墙壁都是一种颜色。

尝试调用drawRect()而不是,fillRect()看看是否会更快。我不认为它会,但它值得一试,即使它看起来更丑陋。同样,您可以尝试创建一个Image然后绘制它。这样做的好处是很容易告诉您的 Graphics 对象在您的图像上实现转换。此外,请考虑完全取消它,并确保它对性能造成重大影响。

此外,通常您不需要为其 Graphics 对象询问父级并直接在其上实现绘画。相反,您应该重写它的paintComponent()方法并只使用给您的 Graphics(可能像您一样调用辅助方法)。Swing 组件默认是双缓冲的,所以你不需要自己实现;只需让摆动对象完成其工作,并让您知道何时绘画。

此外,您最终会重新绘制整个屏幕,这有点矫枉过正。如果您调用repaint(Rectangle),Swing 可以选择仅重绘板上明确标记为脏的部分。当您更新其中一个精灵时,仅在精灵的旧位置和新位置区域调用 repaint(r)。当你完成一个关卡并需要一个新的棋盘时,你可以调用 repaint()(不带参数)来重绘整个地图。

您还应该查看Sun 的教程以获取有关 Swing 效率的一些技巧。

于 2009-01-15T00:07:04.767 回答
4

我仍然认为自己是 Java 的初学者,但我最近使用您提到的一些技术开发了一个带有动态地图和编辑器的 Frogger 式游戏,我很乐意提供一些帮助。

如前所述,枚举是要走的路。我将我的地图设置为二维数组并为每种不同类型设置一个枚举,在我的地图类中编写一个方法来获取一个图像并将地图中的每个正方形划分为我的枚举中的每个值。

可以在Coke and Code上找到帮助我进行映射的教程。如果您需要任何源代码,所有源代码都在那里,尽管您似乎对自己正在做的事情有很好的掌握。如果您仍然需要帮助,我总是可以拖出一些源代码。

于 2009-01-15T01:05:01.153 回答
3

您上面列出的代码不能成为 1fps 问题的根源......我的代码做得比这要快得多。

您能否对该代码进行基准测试并确保它是问题的根源?

于 2009-01-15T00:00:26.260 回答
3

看起来您对 Thread.sleep 的调用没有达到您的预期,但我认为这不是您麻烦的根源。你有:

Thread.sleep(Math.max(0, startTime - System.currentTimeMillis()));

startTime 将始终小于 System.currentTimeMillis(),因此 startTime - System.currentTimeMillis() 将始终为负数,因此您的睡眠时间将始终为 0 毫秒。它与您展示的示例不同,因为该示例在进行计算之前将 startTime 增加了 40 毫秒。它正在计算睡眠时间以将绘图时间填充到 40 毫秒。

无论如何,回到你的问题。我建议通过测量来确定您的时间都花在了哪里。在你知道什么是慢之前,优化是没有意义的。您已经知道如何使用 System.currentTimeMillis()。尝试使用它来衡量所有时间都在哪里。都是花在画墙上吗?


编辑 - 我看到这被标记为已接受,所以我应该推断当你修复睡眠时间时问题就消失了吗?我没有很多 Java GUI 经验,但我可以推测您的代码可能正在耗尽其他重要线程。通过将您的线程设置为具有最高优先级并且只调用 sleep(0),您几乎可以保证您的进程中没有其他线程可以做任何事情。这是Raymond Chen 博客中的一篇文章,解释了原因。

于 2009-01-15T01:17:35.903 回答
2

我不是游戏开发者,但那个帧率似乎很慢。

我不太确定您的代码是如何工作的,但是提高渲染性能的一种可能性是找到那些变化不大的显示部分(例如迷宫的墙壁)并避免重新创建它们每一帧。

创建一个包含常量元素(迷宫?背景)的 BufferedImage,然后首先为每一帧重新绘制它。在这个缓冲图像的顶部,绘制可变元素(PacMan、ghosts、dots 等)。

Romain Guy 的优秀著作Filthy Rich Clients中讨论了这种技术以及许多其他 Java2D 性能技巧。

于 2009-01-14T23:58:53.910 回答
2

只是为了让您不必担心它是 Java,我在一个频谱分析器(就像一个 o-scope)上工作,其中整个 GUI 部分(跟踪、菜单、按钮和滚轮处理)都是用 Java 完成的。当我到达那里时它获得了 1fps,当我离开时它是 12-20。那有很多处理正在进行,并且在一个非常慢的处理器上运行。

只查看需要更新的 GUI 的更新部分。通常,您可以重绘整个屏幕,但只需将剪辑区域设置为真正更新的部分。

小心内部循环——它们是速度杀手。

尽量避免分配和释放大量对象。我不是说不要使用对象,我是说不要为每个像素创建一个 :)

祝你好运

于 2009-01-15T00:05:06.750 回答
1

哇,对于刚学习 Java 的人来说,这是一个相当棘手的问题。

我的建议?从对象的角度思考。你能在没有模仿游戏本身行为的用户界面的情况下编写一些东西吗?一旦你开始工作,你就可以专注于用户界面的特殊问题。是的,从网络版之前的本地版本开始。

我不是游戏玩家。我想知道 Java2D API 会提供什么让您的生活更美好?

你有多少时间来完成它?

于 2009-01-14T23:23:09.910 回答
1

这听起来很明显,但您的性能问题是因为您正在重绘整个迷宫,这不需要完成,而是您只需要重绘迷宫的更改部分。

我之前处理这个问题的方法是将迷宫的更新与实际重绘分离到不同的线程中(有点像线程 MVC)。每次更改迷宫中的单元格时,您都会将其标记为“脏”,您的重绘线程将不时检查以仅重绘脏单元格。

对不起,非常笼统的建议

于 2009-01-14T23:58:16.983 回答
1

默认情况下,Java/Swing 双缓冲区。如果您使用的是 Swing,则不需要像其他答案所建议的那样单独进行双重缓冲。

我同意艾伦的观点,你列出的代码不能是 1fps 的原因。我编写了效率极低的 Java/Swing 动画代码,运行速度比您描述的要快得多。进行更多测试以缩小速度缓慢的原因。

于 2009-01-15T00:42:05.990 回答
1

如果可能,您应该保留迷宫的图像,并在一次库调用中绘制它。它可能也不需要全分辨率——如果你想要块状的 8 位感觉,我希望图形库会非常乐意提供 8 ^)

此外,正如其他人所提到的,您可以通过仅重绘那些需要更新的屏幕部分来节省时间。这可能很烦人,但它可以让您显着提高帧速率。在进行所需的努力之前,请务必进行一些实验以确保是这种情况!

于 2009-01-15T01:45:23.570 回答