Search code examples
javalibgdxtextures

How to draw around a texture in LibGDX?


I'm making a game in libgdx where the main character has a light on him and where the light doesn't reach it should be dark, I'm using the setBlendFunction from SpriteBash to emulate the light. My problem is I don't know how I can make all around the light texture dark, I could size the light texture to fit the whole screen but that would be sloppy and an inconveniente in code. Does anyone have any ideas? Thanks you.

Here is a picture of the game showing my problem

enter image description here


Solution

  • This is typically done with a FrameBuffer.

    You want to instantiate and recreate as necessary in the resize() method so it always matches the size of the screen/window. In resize():

    if (frameBuffer != null && (frameBuffer.getWidth() != width || frameBuffer.getHeight() != height)){
        frameBuffer.dispose();
        frameBuffer = null;
    }
    if (frameBuffer == null){
        try {
            frameBuffer = new FrameBuffer(Pixmap.Format.RGBA8888, width, height, false);
        } catch (GdxRuntimeException e){ // device doesn't support 8888
            frameBuffer = new FrameBuffer(Pixmap.Format.RGB565, width, height, false);
        }
    }
    

    And in render(), before drawing anything in your game, you first draw the shadow map on the frameBuffer:

    frameBuffer.begin();
    Gdx.gl.glClearColor(/* ... */); // This will be your ambient color, a dark color, like gray
    Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
    
    spriteBatch.setProjectionMatrix(camera.combined); // same camera as your game scene
    spriteBatch.setBlendFunction(GL20.GL_ONE, GL20.GL_ONE); //additive blending
    spriteBatch.begin();
    
    // draw light sprites, such as a white circle where your character is standing
    
    spriteBatch.end();
    frameBuffer.end();
    

    Then draw your game scene normally. Don't forget to change your blend function back to what you normally use (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA by default) before drawing that. And finally, draw the shadow map over the game:

    // Use identity matrix so you don't have to worry about lining up the frame buffer texture
    spriteBatch.setProjectionMatrix(spriteBatch.getProjectionMatrix().idt());
    
    // Set multiplicative blending for shadows
    spriteBatch.setBlendFunction(GL20.GL_ZERO, GL20.GL_SRC_COLOR); 
    
    spriteBatch.begin();
    spriteBatch.draw(frameBuffer.getColorBufferTexture(), -1, 1, 2, -2); //dimensions for full screen with identity matrix
    spriteBatch.end();