Java中的轻量级图像修改

问题描述 投票:0回答:1

作为我的 CS 项目,我正在创建一个完整的东方风格的子弹躲避游戏,其中涉及在 JPanel 上的正确坐标上渲染数千个子弹图像。幸运的是,JVM 可以容纳数以万计的 bufferedImage,而不会出现任何明显的帧丢失,所以我没想到会遇到这个巨大的障碍:旋转图像。

我最初想要实现的是旋转敌人子弹的BufferedImage;我在其他 Stack Overflow 问题上使用了小样本的旋转方法,效果很好。当我尝试旋转子弹对象的 ArrayList 中的数千个子弹精灵时,问题出现了。数以万计的新 BufferedImage 和 Graphics2D 创建在运行时完全停止了 JVM。

我研究了与 Java 图像旋转相关的所有问题,以找到一种不会导致严重丢帧或彻底的堆空间问题的轻量级方法。然而,这些方法都至少包含某种形式的对象创建或操作,而程序根本无法接受。

我确实尝试自己制作一个轻量级的轮换方法,牺牲了两周的时间和至少七个智商点。尽管如此,在没有对计算机科学更内在的理解的情况下,我能得到的“最佳”性能就是这种方法,修改现场图像:

public Bullet(... , double deg, ... , BufferedImage shape /*actual bullet sprite*/, String tag, BufferedImage emp /*empty bufferedimage to act as a template to modify image then redraw*/ ) throws IOException
    {
        rotor = emp;
        img = shape;
        rotate(deg);
        setDeg(deg);
        this.deg = deg;
        ...
    }
public void rotate(double angle) { //tried AffineTransform and image Op and everything but all the same...
        Graphics2D g = rotor.createGraphics();
        g.setBackground(new Color(255, 255, 255, 0));
        g.clearRect(0,0, rotor.getWidth(), rotor.getHeight());
        g.rotate(Math.toRadians(angle), img.getWidth() / 2, img.getHeight() / 2);
        g.drawImage(img, null, img.getWidth() - rotor.getWidth(), img.getHeight() - rotor.getHeight());
        g.dispose();
        img = rotor;
}

尽管如此,由于需要渲染如此多的子弹(至少 10,000 个),该方法并没有带来任何创新性的差异。有什么方法可以使图像旋转尽可能轻,以免给渲染添加相关的权重(并希望将项目从注定的厄运中拯救出来)?

如果不旋转,刀看起来很不对劲。请帮忙:c

java image performance swing rotation
1个回答
0
投票

考虑在游戏初始化期间预先计算和存储旋转图像,以有效地旋转。这种方法最大限度地减少了实时计算负载以提高性能。以下是实现此方法的方法:

预计算阶段:

以固定间隔(例如,每 1 度)预先计算每个子弹精灵的旋转版本。 将这些预先旋转的图像存储在数组或地图中,其中每个索引/键代表一个旋转角度。 实施示例:

// Precompute rotated images
BufferedImage[] preRotatedImages = new BufferedImage[360];
for (int i = 0; i < 360; i++) {
    preRotatedImages[i] = rotateImage(originalImage, i);
}

// Rotate function
private BufferedImage rotateImage(BufferedImage img, int angle) {
    int w = img.getWidth();
    int h = img.getHeight();
    int newW = (int) Math.ceil(Math.sqrt(w * w + h * h));
    BufferedImage rotated = new BufferedImage(newW, newW, BufferedImage.TYPE_INT_ARGB);
    Graphics2D g2d = rotated.createGraphics();
    g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
    g2d.rotate(Math.toRadians(angle), newW / 2, newW / 2);
    g2d.drawImage(img, (newW - w) / 2, (newW - h) / 2, null);
    g2d.dispose();
    return rotated;
}

// During gameplay, fetch pre-rotated images
public void render(Graphics g, int angle, int x, int y) {
    g.drawImage(preRotatedImages[angle % 360], x, y, null);
}

优化:

正如 @Abra 建议的那样,仅旋转和存储可见项目符号的图像,从而减少内存使用。 使用具有 Java 内置功能的硬件加速图像绘制。 此方法通过利用预先计算的资源来减少运行时开销,即使屏幕上有数千个子弹,也能确保更流畅的游戏体验。测试内存使用情况和性能,看看这种方法是否适合您。

© www.soinside.com 2019 - 2024. All rights reserved.