简体   繁体   中英

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

在此处输入图片说明

Why dont't you use Box2dlight for your requirement. In my opinion you can use shader for lighting but the effect that you want that can only be achieved by using box2d body and box2dlight.

public class MyGdxGame extends ApplicationAdapter implements InputProcessor{

    SpriteBatch batch;
    OrthographicCamera cam;

    RayHandler rayHandler;
    World world;
    Texture texture;
    PointLight box2d;

    Box2DDebugRenderer renderer;
    Vector3 vector3;
    Array<Body> bodies;

    @Override
    public void create() {

        Pixmap pixmap=new Pixmap(1, 1, Pixmap.Format.RGBA8888);
        pixmap.setColor(Color.WHITE);
        pixmap.fillRectangle(0,0, pixmap.getWidth(), pixmap.getHeight());

        world=new World(new Vector2(0,-9.8f),false);
        rayHandler=new RayHandler(world);

        renderer=new Box2DDebugRenderer();
        bodies=new Array<>();
        vector3=new Vector3();

        batch=new SpriteBatch();
        cam = new OrthographicCamera();
        cam.setToOrtho(true,40,64);

        texture=new Texture(pixmap);
        rayHandler.setAmbientLight(0,0,0,.5f);

        box2d=new PointLight(rayHandler, 100, new Color(1,1,1,1), 25, 10, 10);
        Gdx.input.setInputProcessor(this);


        {
            BodyDef bodyDef = new BodyDef();
            bodyDef.position.set(20, 10);
            bodyDef.type = BodyDef.BodyType.StaticBody;

            PolygonShape p = new PolygonShape();
            p.setAsBox(8, 1.5f);

            FixtureDef fixtureDef = new FixtureDef();
            fixtureDef.shape = p;

            Body body = world.createBody(bodyDef);
            body.createFixture(fixtureDef);

            Sprite sprite=new Sprite(texture);
            sprite.setSize(8*2,1.5f*2);
            body.setUserData(sprite);
        }

        {
            BodyDef bodyDef = new BodyDef();
            bodyDef.position.set(20, 40);
            bodyDef.type = BodyDef.BodyType.StaticBody;

            PolygonShape p = new PolygonShape();
            p.setAsBox(8, 1.5f);

            FixtureDef fixtureDef = new FixtureDef();
            fixtureDef.shape = p;

            Body body = world.createBody(bodyDef);
            body.createFixture(fixtureDef);

            Sprite sprite=new Sprite(texture);
            sprite.setSize(8*2,1.5f*2);

            body.setUserData(sprite);
        }
    }

    @Override
    public void render() {

        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
        Gdx.gl.glClearColor(1,1,1,1);

        world.step(1/60f,4,6);

        renderer.render(world,cam.combined);
        batch.setProjectionMatrix(cam.combined);

        batch.begin();
        world.getBodies(bodies);

        for (Body body:bodies){
            Sprite sprite=(Sprite) body.getUserData();
            sprite.setPosition(body.getPosition().x-sprite.getWidth()/2,body.getPosition().y-sprite.getHeight()/2);
            sprite.draw(batch);
        }

        batch.draw(texture,100,100);
        batch.end();

        rayHandler.setCombinedMatrix(cam);
        rayHandler.updateAndRender();
    }

    @Override
    public void resize(int width, int height) {

    }

    @Override
    public void dispose() {
        batch.dispose();
        rayHandler.dispose();   
    }

    @Override
    public boolean keyDown(int keycode) {
        return false;
    }

    @Override
    public boolean keyUp(int keycode) {
        return false;
    }

    @Override
    public boolean keyTyped(char character) {
        return false;
    }

    @Override
    public boolean touchDown(int screenX, int screenY, int pointer, int button) {
        return false;
    }

    @Override
    public boolean touchUp(int screenX, int screenY, int pointer, int button) {
        return false;
    }

    @Override
    public boolean touchDragged(int screenX, int screenY, int pointer) {

        vector3.set(screenX,screenY,0);
        Vector3 v=cam.unproject(vector3);
        box2d.setPosition(v.x,v.y);
        return false;
    }

    @Override
    public boolean mouseMoved(int screenX, int screenY) {
        return false;
    }

    @Override
    public boolean scrolled(int amount) {
        return false;
    }
}

OUTPUT IS :

在此处输入图片说明

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();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM