4

I am currently working on a 2D Java game, and am currently in the process of implementing dynamic lighting, for e.g. torches, light bulbs and the sun. I however, have run into a problem. Numerous attempts with different implementations have not yet provided the desired result, either not being what I was looking, not working as expected or lagging the whole game. I have tried the following implementations:

  • A (BufferedImage) mask created with RadialGradientPaint
  • Asynchronous flood-fill
  • Synchronous flood-fill

The RadialGradientPaint mask did not prove to be what I was looking for, my implementation of it did not handle any elements on the screen, meaning light would "go through" walls.

The second implementation, an asynchronous flood-fill, did not work properly. It only rendered part of the light, and then called it a day, especially with larger lights.

The third implementation, a synchronous flood-fill, does what I want, but because it is running on the main thread, it hangs it in the process:

The code used to create the last image is as follows:

public void lightQueue(int x, int y, float level, boolean isSun){
    float newLevel;

    Queue<LightData> queue = new LinkedList<LightData>();
    queue.add(new LightData(x,y,level));

    while(!queue.isEmpty()){
        LightData d = queue.remove();

        try{
            newLevel = d.level - Level.getBlock(d.x, d.y).getLightBlockAmount();
        }catch(NullPointerException e){
            continue;
        }

        if(newLevel <= Level.getBlock(d.x, d.y).getLightLevel()) continue;

        if(newLevel > 1f){
            Level.getBlock(d.x, d.y).setLightLevel(1f);
        } else {
            Level.getBlock(d.x, d.y).setLightLevel(newLevel);
        }

        queue.add(new LightData(d.x + 1, d.y, newLevel));
        queue.add(new LightData(d.x - 1, d.y, newLevel));
        queue.add(new LightData(d.x, d.y + 1, newLevel));
        queue.add(new LightData(d.x, d.y - 1, newLevel));
    }
}
public void tick(){
    for(Emitter e:emitters){
        e.tick();
    }
    if(Main.tickCount % 20 == 0){
        for(Emitter e:emitters){
             if(e instanceof Sun){
                lightRec((int) e.getLocation().getX(), (int)e.getLocation().getY(), e.lightLevel, true);
            } else if(Level.shouldRender(e.getLocation(), Level.camera)){
                lightRec((int) e.getLocation().getX(), (int)e.getLocation().getY(), e.lightLevel, false);
            }
        }
    }
}

Edit: The rendering of blocks goes as follows:

public void render(Graphics g, Camera c){
    g.drawImage(texture, c.getRelativePixelX(getLocation().getPixelX()), c.getRelativePixelY(getLocation().getPixelY()), null);
    g.setColor(new Color(0f, 0f, 0f, 1f - lightLevel));
    g.fillRect(c.getRelativePixelX(getLocation().getPixelX()), c.getRelativePixelY(getLocation().getPixelY()), getBounds(c).width, getBounds(c).height);
    g.setColor(Color.WHITE);
}

The RelativePixel stuff is only a conversion from the in-game coordinate system to onscreen pixels for proper placement.

This code is being ran twice a second to ensure that the game doesn't instantly freeze. Multiple light sources or light sources brighter than 1f (to increase the radius) will freeze the game.

So my question is, is there a more effective/better way to implement dynamic lighting? If not, is there any way I can improve the current system?

If there is anything unclear please let me know! Thank you

John Kugelman
  • 349,597
  • 67
  • 533
  • 578
  • 1
    Honestly the right way to do this is to use code that somebody else wrote. You can fake 2D with a 3D program, that's the route I'd take. Search for "java opengl library" and use one of the results. The problem is that you'll spend as much time trying to write and debug this 2D code as you would a 3D program, so just going 3D makes sense. – markspace May 04 '15 at 17:10
  • 3
    Is there a reason you're using Java2D and not an OpenGL wrapper like JOGL or LWJGL? The "right" way to do this is to use an existing library. – Kevin Workman May 04 '15 at 17:11
  • @Kevin There are two reasons for that, firstly because this project was a project for computer sciences (which is now handed in though), for which we couldn't use any external libraries, and secondly because I never really thought about that. I was already considering implementing LWJGL for about the last few weeks, but I figured there had to be a way to make it work like this. – KevoSoftworks May 04 '15 at 17:19
  • 2
    @KevoSoftworks I definitely recommend checking out LWJGL, or even better, libGDX. I'm sure it's possible to do in Java2D, but it won't be particularly fast or pretty. I guess I'm not really sure what your question is, sorry! – Kevin Workman May 04 '15 at 17:28
  • @KevinWorkman Thanks for the information, and it is a proper answer to my question =). I will take a look at libGDX and implement it if it's nice to work with. – KevoSoftworks May 04 '15 at 17:35
  • @markspace That is what I will probably do. I have already looked at LWJGL, and I'll implement one library or another into the game. Thanks for your help! – KevoSoftworks May 04 '15 at 17:37
  • @KevoSoftworks You might be particularly interested in [Box2DLights](https://github.com/libgdx/box2dlights), which comes with libGDX. – Kevin Workman May 04 '15 at 17:38
  • You can try [gamedev.stackexchange.com](http://gamedev.stackexchange.com) next time. It's more specific to game-development questions. – ashes999 May 04 '15 at 19:02
  • @KevoSoftworks If you're going to use an OpenGL library, take a look at [JMonkeyEngine](http://jmonkeyengine.org/) I've only read through the docs, but there seems to be a lot of work done for you. Also they use a BSD license: free as in beer. – markspace May 04 '15 at 20:06

1 Answers1

1

i've answered that question for a top-down-view... ...but i'ts the same issue...

use ray-tracing...

Efficient 2D Tile based lighting system

Community
  • 1
  • 1
Martin Frank
  • 3,445
  • 1
  • 27
  • 47
  • Thanks for sharing this! I had taken a look at that post before, but forgot to try it out. I managed to still get reasonable performance with this method, so optimalisation will make it run properly. This really helped me out! – KevoSoftworks May 06 '15 at 21:10
  • thank you very much for acceping this answer! there are certainly many options on how you can increase the performance on the raytracing, although i don't think it is soooooo unperformant.... (worked very good for me - i used it even on mobile devices) – Martin Frank May 07 '15 at 08:22