1
\$\begingroup\$

I'm making a 2D roguelike tile-based game with Java and JavaFX. I'm currently working on adding lighting and darkness to the dungeon, but whenever I try running it, it takes a very long time to load, and it eventually gives an out of memory error.

Here is Lighting.java:

package sample;

import static sample.World.worlds;

public class Lighting {
    public static void calculateLighting(int wn, int skyLighting) {
        Block[][][] world = worlds[wn];
        for (int z = 0; z < worlds[Player.cw][0][0].length; z++) {
            for (int y = 0; y < worlds[Player.cw][0].length; y++) {
                for (int x = 0; x < worlds[Player.cw].length; x++) {
                    Block b = world[x][y][z];
                    b.light = skyLighting;
                    if (b.embID == 1) { //test if a block has a torch attached to it
                        for (int distance = 0; distance <= 15; distance++) {
                            for (int x1 = x - distance; x1 < x + distance; x1++) {
                                for (int y1 = y - distance; y1 < y + distance; y1++) {
                                    for (int z1 = 0; z1 < worlds[Player.cw][0][0].length; z1++) {
                                        try {
                                            world[x1][y1][z1].light += 1;
                                        } catch (ArrayIndexOutOfBoundsException ignored) {

                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        for (int z = 0; z < worlds[Player.cw][0][0].length; z++) {
            for (int y = 0; y < worlds[Player.cw][0].length; y++) {
                for (int x = 0; x < worlds[Player.cw].length; x++) {
                    Block b = world[x][y][z];
                    if (b.light > 15) {
                        b.light = 15;

                        //If your number X falls between A and B, and you would like Y to fall between C and D, you can apply the following linear transform:
                        //Y = (X-A)/(B-A) * (D-C) + C
                        //https://stackoverflow.com/questions/345187/math-mapping-numbers
                        //(worlds[Player.cw][x][y][z].light-0)/(15-0) * (1-0.5) + 0.5
                        if (b.sprite != null) {
                            b.sprite = ImgManip.darken(b.sprite, (worlds[Player.cw][x][y][z].light) / (15d) * (1 - 0.5) + 0.5);
                        }
                    }
                }
            }
        }
    }
}

What this is doing is that it first finds torches in the world, and then increases the brightness of each block around it, depending on how far away the torch is. Then, it takes each block's sprite and makes it darker with the darken() method. This is what is causing it to take so long. When I just comment that out, it performs just fine, but the lighting isn't there.

Here is the darken() method:

public static Image darken(Image image, double amount) {
        PixelReader pixelReader = image.getPixelReader();
        WritableImage writableImage =
                new WritableImage(
                        (int)image.getWidth(),
                        (int)image.getHeight());
        PixelWriter pixelWriter = writableImage.getPixelWriter();

        for(int y=0; y<image.getHeight(); y++){
            for(int x=0; x<image.getWidth(); x++){
                Color color = pixelReader.getColor(x, y);

                color = color.deriveColor(0,-amount/2d,-amount,0);

                pixelWriter.setColor(x, y, color);
            }
        }
        return writableImage;
    }
```
\$\endgroup\$
0
\$\begingroup\$


first of all, if you want to apply effects like lighting to your scene/canvas then PixelWriter is a terrible idea, because of the unevitable O(n^2) created by the nested loop for traversing every pixel. This loop will perform on your CPU since it is located in your Java code and thus performs slow.
This is the reason why "shaders" exists. To perform heavy weight graphical operations on your GPU, which is optimized for transforming pixels. Though shaders are not directly accessible from JavaFX.

The closest thing you have in JavaFX are Effects and blending mechanisms. For your use case you should definetly try to implement your lighting effects with JavaFX Effects Objects or blending. I once had the same issue. Blending on a canvas improved the performance a lot. But there is only so much you can do with JavaFX. It is very limited.

If you don't want to deal with such low level problems all the time, try using FXGL. It might be lightweight framework compared to others, but it is based on JavaFX.

| improve this answer | |
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.