我试图创建一个与Java中的东方类似的子弹地狱游戏。
我需要一些帮助入门,就像一个例子。我尝试使用JFrame从头开始制作它,但我的主要问题是创建子弹时滞后。
我有一个子弹类,其参数使其从A到B.但是每当程序创建或移除子弹对象(存储在ArrayList中)时,它会冻结一小段时间,但这变成了当有很多子弹时非常明显。
我在这里使用ArrayList是错误的吗?建议使用哪些指南来了解如何正确执行此操作?
这是我的Bullet课程:
import java.awt.Graphics;
public class Bullet
{
double x,y, xend, yend;
int width, height;
int life = 200;
private static final double speed = 8;
double dirX, dirY;
public Bullet(double x, double y, double xend, double yend, int width, int height)
{
this.x=x;
this.y=y;
this.xend = xend;
this.yend = yend;
this.width = width;
this.height = height;
dirX = speed*Math.cos(getAngle());
dirY = speed*Math.sin(getAngle());
}
public double getAngle()
{
double angle = (double) Math.toDegrees(Math.atan2(yend-y, xend - x));
if(angle < 0){
angle += 360;
}
System.out.println(angle);
return Math.toRadians(angle);
}
public void tick()
{
life--;
x+=dirX;
y+=dirY;
}
public void draw (Graphics g)
{
g.fillRect((int) Math.round(this.x),(int) Math.round(this.y),this.width,this.height);
}
}
这是用户创建项目符号时运行的代码。它使用mouseListener作为xend yend坐标 - 找到子弹的目的地。
public void fireNormal(double xend, double yend)
{
Bullet bullet= new Bullet (x,y,xend,yend,5,5);
firedBullets.add(bullet);
}
}
我使用计时器刷新游戏,但由于冻结,它仍然没有达到一致的速度。
答案 0 :(得分:0)
ArrayList.add()
通常应该非常快。有时,当实现必须添加新容量时,它将分配一个新的后备阵列,在继续之前将数据从一个复制到另一个。您可以通过在ArrayList(int initialCapacity)
构造函数中指定合适的初始容量来避免这种情况。
然而,你需要数以万计的参赛作品才能花费足够长的时间来增加明显的游戏延迟。
ArrayList.remove(int index)
必须将删除项目上方的所有条目移到后备阵列中一个插槽。但是,这在CPU级别进行了高度优化,除非你有成千上万的子弹,否则不应再添加明显的游戏延迟。
ArrayList.remove(Object o)
必须依次检查每个元素,并在每个元素上运行equals()
,直到找到目标元素。避免这个!
可能您看到的停顿是由于垃圾收集,这可能是因为您创建了数千个短暂的Bullet
对象。从他们被解雇的那一刻开始,直到他们离开屏幕为止。当它们超出范围时,它们将保留在内存中,直到GC必须清除数千个它们。
您可以通过维护项目符号的对象池来避免这种情况。有些库有对象池实现,或者您可以使用集合来自行创建。
在内存限制严格的环境中(如8位游戏控制台),必须确保游戏在固定内存中运行,这与这些平台上的程序类似。
然而您应该在尝试修复之前证明您的问题,并且为此您需要使用 profiler ,例如VisualVM。这将显示您的执行花费时间的位置,以及它如何使用内存。现代Java中的垃圾收集在大多数情况下表现非常好 - 但不要认为这是问题所在。