gpt4 book ai didi

Java动画内存问题

转载 作者:行者123 更新时间:2023-12-01 10:36:00 25 4
gpt4 key购买 nike

我对这门语言有点陌生,但明年我将攻读学位,其中包括一篇 Java 论文,所以我正在学习这门语言,这样明年我就不会完全无用。

我正在尝试模仿游戏“Flappybird”(这是我首先想到的需要 Java 图形的游戏)。

当我运行代码时,内存快速增加并达到超过 4GB 和 15% CPU 使用率。有人可以解释一下导致此内存泄漏/问题的原因吗?

请随时为我的绘画/图形留下推荐的替代方法。对于当前代码的困惑程度,我深表歉意。

代码:

 import java.awt.Component;
import java.awt.Image;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;


public class Animation {
private Image imgBackgroundBottom, imgBackgroundTop;
private int intFrameHeight;
private int intFrameWidth;

public static void main(String[] args) throws IOException {
new Animation();
}

public Animation() throws IOException{
System.out.println("Program Iniatiated");
JFrame frameAnimation = new JFrame("Animation");
frameAnimation.setResizable(false);
frameAnimation.setSize(310, 650);
frameAnimation.setVisible(true);
int Level = 10;
frameAnimation.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
for (int i = 0; i < frameAnimation.getWidth() + 1; i++) {
if (i == frameAnimation.getWidth()) {
//Level--;
i = 0;
}
frameAnimation.add(new AnimationPane(i));
try {
Thread.sleep(Level);
} catch (InterruptedException e) {
e.printStackTrace();
}
frameAnimation.revalidate();
}
}

import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Timer;
import java.util.concurrent.ThreadLocalRandom;
import java.util.Random;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class AnimationPane extends JPanel {
private BufferedImage imgBackgroundBottom, imgBackgroundTop, imgPipeTop, imgPipeBottom;
private int XPos = 40, YPos = 40;
private int BackgroundTopWidth, BackgroundTopHeight;
private int BackgroundBottomWidth, BackgroundBottomHeight;
private int i = 0;
public static int yPipe1, yPipe2, yPipe3, yPipe4;
public static int xPipe1 = -50, xPipe2 = -50, xPipe3 = -50, xPipe4 = -50;
public static int runAgain = 1, selectPipe = 0;
public AnimationPane(int xValue) {
try {
if (imgBackgroundBottom = null ) {
imgBackgroundBottom = ImageIO.read(new File("resources/BackgroundBottom.png"));
imgBackgroundTop = ImageIO.read(new File("resources/BackgroundTop.png"));
imgPipeTop = ImageIO.read(new File("resources/PipeTop.png"));
imgPipeBottom = ImageIO.read(new File("resources/PipeBottom.png"));
BackgroundTopWidth = imgBackgroundTop.getWidth(null);
BackgroundBottomWidth = imgBackgroundBottom.getWidth(null);
BackgroundTopHeight = imgBackgroundTop.getHeight(null);
BackgroundBottomHeight = imgBackgroundBottom.getHeight(null);
this.setDoubleBuffered(true);
i = xValue;
repaint();
} catch (IOException e) {
e.printStackTrace();
}
}

public void paintComponent(Graphics g){
super.paintComponent(g);
g.drawImage(imgBackgroundTop, 0, 0, getWidth(), BackgroundTopHeight * 2, this);
//Level Difficult can be adjusted by adjusting thread.sleep count AND adjusting max.variance in randomisation.
if (runAgain % 170 == 0) {
selectPipe++;
if (selectPipe % 4 == 0) {
yPipe4 = ThreadLocalRandom.current().nextInt(50, 312 + 1);
xPipe4 = 310;
} else if (selectPipe % 3 == 0){
yPipe3 = ThreadLocalRandom.current().nextInt(50, 312 + 1);
xPipe3 = 310;
} else if (selectPipe % 2 == 0) {
yPipe2 = ThreadLocalRandom.current().nextInt(50, 312 + 1);
xPipe2 = 310;
} else {
yPipe1 = ThreadLocalRandom.current().nextInt(50, 312 + 1);
xPipe1 = 310;
}
}
xPipe1--;
xPipe2--;
xPipe3--;
xPipe4--;
runAgain++;
if (xPipe1 < 310 && xPipe1 > -50) {
g.drawImage(imgPipeTop, xPipe1, yPipe1 - 400, 50, 400, this);
g.drawImage(imgPipeBottom, xPipe1, yPipe1 + 150, 50, 400, this);
}
if (xPipe2 < 310 && xPipe2 > -50) {
g.drawImage(imgPipeTop, xPipe2, yPipe2 - 400, 50, 400, this);
g.drawImage(imgPipeBottom, xPipe2, yPipe2 + 150, 50, 400, this);
}
if (xPipe3 < 310 && xPipe3 > -50) {
g.drawImage(imgPipeTop, xPipe3, yPipe3 - 400, 50, 400, this);
g.drawImage(imgPipeBottom, xPipe3, yPipe3 + 150, 50, 400, this);
}
if (xPipe4 < 310 && xPipe4 > -50) {
g.drawImage(imgPipeTop, xPipe4, yPipe4 - 400, 50, 400, this);
g.drawImage(imgPipeBottom, xPipe4, yPipe4 + 150, 50, 400, this);
}
g.drawImage(imgBackgroundBottom, -i, BackgroundTopHeight * 2, getWidth() * 2, BackgroundBottomHeight * 2, this);
g.drawImage(imgBackgroundBottom, getWidth() - i, BackgroundTopHeight * 2, getWidth() * 2, BackgroundBottomHeight * 2, this);
}

}

我的程序供引用: Reference Image

最佳答案

首先,看一下Concurrency in Swing可能How to use Swing Timers

此外,您的 paint 方法非常危险,绘画是通过将一系列方法调用链接在一起以生成所需结果来完成的,您不应该修改它,除非您非常非常非常确定你在做什么。您应该简单地重写 paintComponent (并调用它的 super 方法),而不是重写 paint

参见Painting in AWT and SwingPerforming Custom Painting了解更多详情

作为一般经验法则,您应该有一个代表游戏当前状态的“模型”(例如玩家位置和您需要跟踪的任何其他值),您将有一个“游戏/主“循环将根据输入和所需的其他逻辑定期更新模型的状态,然后安排绘制更新。

除了绘制模型当前状态所需的逻辑之外,您的绘画不应包含任何逻辑,绘画是为了绘画

让我们看一下代码...

for (int i = 0; i < frameAnimation.getWidth() + 1; i++) {
if (i == frameAnimation.getWidth()) {
//Level--;
i = 0;
}
frameAnimation.add(new AnimationPane(i));
try {
Thread.sleep(Level);
} catch (InterruptedException e) {
e.printStackTrace();
}
frameAnimation.revalidate();
}

这有点奇怪(而且有点危险)。由于 JVM 在启动时调用 main 方法的方式存在偶然性,因此循环并未在事件调度线程的上下文中运行,但您永远不应该做出这些假设。您应该使用 Swing Timer 或另一个 Thread 来运行此循环。

现在有两个主要问题。

  1. 您在循环的每次迭代中添加越来越多的面板
  2. 您正在从 EDT 上下文之外修改 UI 的状态,请参阅第一个链接。 Swing 不是线程安全的,您永远不应该从 EDT 上下文之外修改它的状态。

这似乎是您问题的核心根源

就我个人而言,我会使用一个面板,它能够根据游戏的当前状态简单地绘制需要绘制的内容。请记住,Swing 使用被动渲染引擎,因此可以随时触发绘画事件,这就是我们建议使用 Swing 计时器的原因。

更复杂的方法是使用 BufferStrategyBufferStrategy and BufferCapabilities ,它允许您控制绘画过程(也称为主动绘画),这将允许您在控制绘画过程时使用Thread

您还应该尽可能避免使用 staticstatic 会导致更多的问题,而不仅仅是我们从新开发人员那里看到的任何其他问题,它不是一个跨对象通信机制。

如果您需要共享数据(例如游戏循环和 View 之间的模型),那么您应该将其引用传递给两者

关于Java动画内存问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34733102/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com