java - “HOW DOOM FIRE WAS DONE” –重新实现会产生噪音动画的火灾动画

标签 java animation

(注意:在此问题的末尾提供了一个最小,完整和可验证的示例)

摘要


背景,目标与问题
我对作者的解释和出处的理解(可能是错误的?)-请注意:我必须向您解释,因为我的错误可能来自对执行方法的错误理解或代表我的错误实现。
我做了什么
预期结果,实际结果和问题
最小,完整和可验证的示例


背景,目标与问题

我根据http://fabiensanglard.net/doom_fire_psx/研究了著名的DOOM游戏的动画,其中包括生火。

作者代码的完整版本为:https://github.com/fabiensanglard/DoomFirePSX/blob/master/flames.html

我以这个实现结束了,但是我得到的结果是噪声的动画(这就是问题所在)。确实,在此动画的结尾,我得到了以下结果:

enter image description here



我对作者的解释和出处的理解(可能是错误的?)

第一种方法:实施主要原理,并简化火灾(因为已替换为简单的颜色渐变)


设置精确填充的颜色集:此颜色集定义了看起来像火的渐变。从白色到黑色共有36种颜色,其中有黄色,橙色和红色。此集不包含任何重复项。
第一次在画布像素上进行迭代。此处的目标是将所有像素着色为黑色(即:该组的最后一种颜色)。
在画布上第二次迭代。这次,我们必须将底部第一行像素的像素涂成白色(即:该组的第一色)。
再次在画布上进行迭代,但仅从第二个底线(包括)进行迭代,而不是从第一个底线(因此将其排除在外)。对于每个迭代像素,我们以这种方式修改其颜色:我们采用其直接下方像素的颜色,我们在所有颜色中找到该颜色的索引,然后向该索引加1:我们获得另一个索引,称为i2,找到索引为i2的颜色,然后将此颜色应用于此迭代像素。


执行完成后,将有多个渐变,每个渐变包含36行(36种颜色)。

使它看起来真的像火。

当然,由http://fabiensanglard.net/doom_fire_psx/解释的程序还远远不止于此:它使用伪随机两次,得到的东西看起来不像是简单的渐变,但看起来像是火。

这个想法如下。对于要迭代的像素:

我们得到位于下方的像素的颜色索引。然后,我们在颜色集中获得该颜色,其索引是该索引+一个随机数,其中包含一个轻微的偏移(如果我没有记错的话,最大为2个正方形)。因此,我们可以模拟颗粒温度变化的加速度。

并且,此外,我们认为位于要迭代的像素左侧一点的像素。 “一点” =根据芯片号1的相同随机数。正是该像素位于左侧一点,将分配在芯片N°1中恢复的颜色。因此,我们可以模拟火焰左侧的水平位移。

因此,我们看到这是一个三角形的工作(因为我们将像素进行迭代,一个像素在下面,另一个像素在左边)。

伪随机模型用于模拟粒子温度变化加速度

生成一个随机数,其中包含0到3之间的一个随机数,并在此处使用:

firePixels[src - FIRE_WIDTH ] = pixel - (rand & 1);

因此,要施加的颜色略有变化。

伪随机模型用于模拟火焰左侧的水平位移。

除了我们刚刚看到的以外,还使用了每行像素的伪随机数。

在此重复使用相同的随机数:

var dst = src - rand + 1; firePixels[dst - FIRE_WIDTH ] = pixel - (rand & 1);

在此,水平方向略微移位。



我做了什么

以上所有说明均已实现,但是我的程序输出了不好的结果。所以:


我不是很了解这个想法,
否则我执行得不好。


您可以在下面找到实现的源。

预期结果,实际结果和问题

我希望有几个垂直渐变(每个从下到上)。 “多个”是因为画布的高度大于渐变颜色的数量,并且因为我使用模数来选择要应用的颜色。这些渐变必须类似于诅咒(http://fabiensanglard.net/doom_fire_psx/)的渐变。

实际结果是:我得到了一些声音。

我的问题是:为什么不起作用?我想我该怎么做。也许我忘记了实施中的某些内容,但是呢?

我的问题是:为什么不起作用?我想我该怎么做。也许我忘记了实施中的某些内容,但是呢?

最小,完整和可验证的示例

Launcher.java

import java.util.ArrayList;

public class Launcher {

    public static void main(String args[]) {
        int width = 800, height = 800;
        Gui gui = new Gui(width, height);
        gui.setUp("DOOM-like fire");
        gui.setVisible(true);

        Colors colors = new FireColors(new ArrayList<>());
        gui.colorize(colors.getLastColor(), -1, -1);  // Setting black anywhere
        gui.colorize(colors.getColorAtIndex(0), -1, height - 1);  // Setting white, in a lower line

        new ThreadPainter(0, colors, gui, width, height).schedulePainting();
    }

}


Gui.java

import java.awt.*;
import javax.swing.*;
import java.awt.image.BufferedImage;

class Gui extends JFrame {

    private JPanel panel;
    private BufferedImage buffered_image;

    Gui(int width, int height) {
        buffered_image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        panel = new JPanel() {
            public void paintComponent(Graphics graphics) {
                super.paintComponent(graphics);
                graphics.drawImage(buffered_image, 0, 0, null);
            }
        };
    }

    void setUp(String title) {
        setTitle(title);
        setLayout(null);
        setSize(buffered_image.getWidth(), buffered_image.getHeight());
        setContentPane(panel);
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    }

    void colorize(Color color, int x_parameter, int y_parameter) {
        for(int y = (y_parameter == -1 ? 0 : y_parameter); y <= (y_parameter == -1 ? this.getHeight() - 1 : y_parameter); y++) {
            for(int x = (x_parameter == -1 ? 0 : x_parameter); x <= (x_parameter== -1 ? this.getWidth() - 1 : x_parameter); x++) {
                buffered_image.setRGB(x, y, color.getRGB());
            }
        }
        panel.repaint();
    }

    int getRGBAtCoordinates(int x, int y) {
        return buffered_image.getRGB(x, y);
    }

}


ThreadPainter.java

import java.util.Timer;
import java.util.TimerTask;

class ThreadPainter extends Timer {
    private Gui gui;
    private Colors colors;
    private int delay;
    private int height;
    private int width;

    ThreadPainter(int delay, Colors colors, Gui gui, int width, int height) {
        this.colors = colors;
        this.gui = gui;
        this.delay = delay;
        this.width = width;
        this.height = height;
    }

    void schedulePainting() {
        this.schedule(new TimerTask() {
            @Override
            public void run() {
                try {
                    int number_of_colored_portions = height / colors.getSize();
                    // int locking_changement_of_color = 0;
                    for(int y = height - 2; y >= 0; y--) {

                        //if(locking_changement_of_color == number_of_colored_portions) {
                            //locking_changement_of_color = 0;
                        /*} else {
                            index_of_color_to_apply = index_of_found_color;
                        }*/

                        for(int x = 0; x < width; x++) {
                            int rand = (int) Math.round(Math.random() * 3.0) & 3;
                            int below_pixel_rgb = gui.getRGBAtCoordinates(x, y + 1);
                            int index_of_found_color = colors.getIndexOfColor(below_pixel_rgb);
                            int index_of_color_to_apply = (index_of_found_color + (rand & 1)) % colors.getSize();

                            int x_copy = x - rand + 1;
                            if(x_copy <= 0) {
                                x_copy = 0;
                            } else if(x_copy >= width) {
                                x_copy = width - 1;
                            }
                            gui.colorize(colors.getColorAtIndex(index_of_color_to_apply), x_copy, y);
                        }

                        //locking_changement_of_color++;
                        //Thread.sleep(10);
                    }
                } catch(Exception e) {
                    System.err.println("Exception: " + e.getMessage());
                }
            }
        }, this.delay);
    }

}


Colors.java

import java.awt.Color;
import java.util.List;

abstract class Colors {
    List<Color> colors;

    Color getColorAtIndex(int index) {
        return colors.get(index);
    }

    int getIndexOfColor(int rgb) throws Exception {
        for (int x = 0; x < colors.size(); x++) {
            if(colors.get(x).getRGB() == rgb) {
                return x;
            }
        }
        throw new Exception("Color not found in the list!");
    }

    int getSize() {
        return colors.size();
    }

    Color getLastColor() {
        return colors.get(colors.size() - 1);
    }
}


FireColors.java

import java.awt.Color;
import java.util.List;

class FireColors extends Colors {

    FireColors(List<Color> colors) {

        this.colors = colors;

        this.colors.add(new Color(255, 255, 255));
        this.colors.add(new Color(239, 239, 199));
        this.colors.add(new Color(223, 223, 159));
        this.colors.add(new Color(207, 207, 111));
        this.colors.add(new Color(183, 183, 55));
        this.colors.add(new Color(183, 183, 47));
        this.colors.add(new Color(183, 175, 47));
        this.colors.add(new Color(191, 175, 47));
        this.colors.add(new Color(191, 167, 39));
        this.colors.add(new Color(191, 167, 39));
        this.colors.add(new Color(191, 159, 31));
        this.colors.add(new Color(191, 159, 31));
        this.colors.add(new Color(199, 151, 31));
        this.colors.add(new Color(199, 143, 23));
        this.colors.add(new Color(199, 135, 23));
        this.colors.add(new Color(207, 135, 23));
        this.colors.add(new Color(207, 127, 15));
        this.colors.add(new Color(207, 119, 15));
        this.colors.add(new Color(207, 111, 15));
        this.colors.add(new Color(215, 103, 15));
        this.colors.add(new Color(215, 95, 7));
        this.colors.add(new Color(223, 87, 7));
        this.colors.add(new Color(223, 87, 7));
        this.colors.add(new Color(223, 79, 7));
        this.colors.add(new Color(199, 71, 7));
        this.colors.add(new Color(191, 71, 7));
        this.colors.add(new Color(175, 63, 7));
        this.colors.add(new Color(159, 47, 7));
        this.colors.add(new Color(143, 39, 7));
        this.colors.add(new Color(119, 31, 7));
        this.colors.add(new Color(103, 31, 7));
        this.colors.add(new Color(87, 23, 7));
        this.colors.add(new Color(71, 15, 7));
        this.colors.add(new Color(47, 15, 7));
        this.colors.add(new Color(7, 7, 7));

    }

}

最佳答案

有很多小问题,因此这里是带注释的固定版本,供您理解(为了简化起见,我将类组合到一个文件中):

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.WindowConstants;

public class Launcher {
    private static class Gui extends JFrame {
        final int width;
        final int height;
        final JPanel panel;
        final BufferedImage buffered_image;

        Gui(final String title, final int width, final int height) {
            this.width = width;
            this.height = height;
            this.buffered_image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
            this.panel = new JPanel() {
                @Override
                public void paintComponent(final Graphics graphics) {
                    super.paintComponent(graphics);
                    graphics.drawImage(Gui.this.buffered_image, 0, 0, null);
                }
            };
            this.setTitle(title);
            this.setContentPane(this.panel);
            this.setSize(width, height);
            this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
            this.setVisible(true);
        }

        void colorize(final Color color, final int x, final int y) {
            if ((x < 0) || (x >= this.width) || (y < 0) || (y >= this.height))
                return;
            this.buffered_image.setRGB(x, y, color.getRGB());
        }

        int getRGBAtCoordinates(final int x, final int y) {
            return this.buffered_image.getRGB(x, y);
        }
    }

    public static void main(final String args[]) {
        final List<Color> colors = new ArrayList<>();
        colors.add(new Color(0, 0, 0)); // black
        colors.add(new Color(7, 7, 7));
        colors.add(new Color(47, 15, 7));
        colors.add(new Color(71, 15, 7));
        colors.add(new Color(87, 23, 7));
        colors.add(new Color(103, 31, 7));
        colors.add(new Color(119, 31, 7));
        colors.add(new Color(143, 39, 7));
        colors.add(new Color(159, 47, 7));
        colors.add(new Color(175, 63, 7));
        colors.add(new Color(191, 71, 7));
        colors.add(new Color(199, 71, 7));
        colors.add(new Color(223, 79, 7));
        colors.add(new Color(223, 87, 7));
        colors.add(new Color(223, 87, 7));
        colors.add(new Color(215, 95, 7));
        colors.add(new Color(215, 103, 15));
        colors.add(new Color(207, 111, 15));
        colors.add(new Color(207, 119, 15));
        colors.add(new Color(207, 127, 15));
        colors.add(new Color(207, 135, 23));
        colors.add(new Color(199, 135, 23));
        colors.add(new Color(199, 143, 23));
        colors.add(new Color(199, 151, 31));
        colors.add(new Color(191, 159, 31));
        colors.add(new Color(191, 159, 31));
        colors.add(new Color(191, 167, 39));
        colors.add(new Color(191, 167, 39));
        colors.add(new Color(191, 175, 47));
        colors.add(new Color(183, 175, 47));
        colors.add(new Color(183, 183, 47));
        colors.add(new Color(183, 183, 55));
        colors.add(new Color(207, 207, 111));
        colors.add(new Color(223, 223, 159));
        colors.add(new Color(239, 239, 199));
        colors.add(new Color(255, 255, 255)); // white

        final Gui gui = new Gui("DOOM-like fire", 800, 800);

        final Color black = colors.get(0);
        final Color white = colors.get(colors.size() - 1);
        final Dimension dim = gui.getContentPane().getSize(); // get actual size, without title/borders
        for (int y = 0; y < dim.height; y++) {
            final Color clr = y < (dim.height - 1) ? black : white;
            for (int x = 0; x < dim.width; x++)
                gui.colorize(clr, x, y);
        }

        new Timer().schedule(new TimerTask() {
            final Random rnd = new Random();

            Color getColorAtIndex(final int index) {
                if (index < 0)
                    return colors.get(0); // minimal color is black
                return colors.get(index);
            }

            int getIndexOfColor(final int rgb) {
                for (int x = 0; x < colors.size(); x++)
                    if (colors.get(x).getRGB() == rgb)
                        return x;
                throw new RuntimeException("Color not found in the list!");
            }

            @Override
            public void run() {
                for (int x = 0; x < dim.width; x++) {
                    for (int y = 1; y < dim.height; y++) {
                        final int new_index = this.getIndexOfColor(gui.getRGBAtCoordinates(x, y)) - this.rnd.nextInt(2);
                        final int new_x = (x - this.rnd.nextInt(3)) + 1;
                        gui.colorize(this.getColorAtIndex(new_index), new_x, y - 1);
                    }
                }
                gui.repaint();
            }
        }, 0, 40); // start immediately and repeat every 40ms
    }
}

关于java - “HOW DOOM FIRE WAS DONE” –重新实现会产生噪音动画的火灾动画,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54010139/

相关文章:

java - 贾斯珀报告 : continue on same while performing batch export

java - 用于对支持插件的系统进行编程的资源

javascript - 无法为 matter.js 设置动画

javascript - 使用 -webkit-animation 时 webkitTransitionEnd 不触发

android - 在 android 中显示大型预渲染动画的首选方法是什么?

c# - 如何将 Windows 任务栏从 "show"切换/切换到 "auto-hide"(反之亦然)?

javascript - Jquery 树形图

java - IntelliJ IDEA 显示找不到插件

java - android访问扩展customListAdapter的成员变量

java - 使用 Apache POI 从 Excel 电子表格获取的单元格值打印与 Java 字符串相同的值,但 IF 语句没有说它们是相同的?