Render Fog-Of-War on 2d tilemap

939 views Asked by At

I am currently creating a small 2d-game with lwjgl.
I tried to figure out a way of implementing a Fog-Of-War.
I used a black backgound with alpha set to 0.5.
Then I added a Square, to set alpha to 1 for each tile, which is lit, ending up having a black Background with differend Alpha values.

Then I rendered my Background using the blendfunction:

glBlendFunc(GL_ZERO, GL_SRC_ALPHA)

This works well, but now I have a problem with adding a second layer with transparent parts and apply the Fog-Of-War on them, too.

I've read something about FrameBufferObjects, but I don't know how to use them and if they are the right choice.

Later on I want to lit tiles with an texture/Image to give it a smoother look. So these textures may overlap. This is the reason why I chose to first render the Fog-Of-War.

Do you have an idea how to fix this problem?

Thanks to samgak.
Now I try to render a dark square on each dark tile exept the lit tiles. I divided each tile in an 8x8 grid for more details. This is my method:

public static void drawFog() {
    int width = map.getTileWidth()>>3; //Divide by 8
    int height = map.getTileHeight()>>3;

    int mapWidth = map.getWidth() << 3;
    int mapHeight = map.getHeight() << 3;

    //background_x/y is the position of the background in pixel
    int mapStartX = (int) Math.floor(background_x / width); 
    int mapStartY = (int) Math.floor(background_y / height);

    //Multiply each color component with 0.5 to get a darker look
    glBlendFunc(GL_ZERO, GL_SRC_ALPHA);
    glColor4f(0.0f, 0.0f, 0.0f, 0.5f);

    glBegin(GL_QUADS);
    //RENDERED_TILES_X/Y is the amount of tiles to fill the screen
    for(int x = mapStartX; x < (RENDERED_TILES_X<<3) + mapStartX 
                 && x <  mapWidth; x++){
        for(int y = mapStartY; y < (RENDERED_TILES_Y<<3) + mapStartY 
                   && y < mapHeight; y++){
            //visible is an boolean-array for each subtile
            if(!visible[x][y]){
                float tx = (x * width) - background_x;
                float ty = (y * height) - background_y;

                glVertex2f(tx,      ty);
                glVertex2f(tx+width, ty);
                glVertex2f(tx+width, ty+height);
                glVertex2f(tx,      ty+height);

            }
        }
    }
    glEnd();
}

I set the visible array to false except for an small square. It will render fine, but if I move the background the whole screen except the visible square turns black.

1

There are 1 answers

2
samgak On

One approach is to render the Fog-of-War layer last, using an untextured black square rendered over the top of all the other layers after they have been rendered.

Use this blend function:

glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA)

and set the Fog-of-War alpha per-vertex so that when it is 1.0 the black overlay is transparent, and when it is 0.0, it is entirely black. (If you want the alpha to have the opposite meaning, just swap the arguments).

To make it more smooth you can set the alpha per vertex at each of the corners of the square to vary smoothly across it. You could also use a texture with varying alpha values instead of a plain black square, or subdivide the square into 4 or 16 squares to allow finer control.