【发布时间】:2017-10-09 20:22:36
【问题描述】:
我正在 libgdx 中制作一个游戏,其中主角身上有一盏灯,而光线没有到达的地方应该是黑暗的,我正在使用 SpriteBash 中的 setBlendFunction 来模拟光线。我的问题是我不知道如何才能使光纹理周围变暗,我可以调整光纹理的大小以适应整个屏幕,但这会很草率并且在代码中不方便。有没有人有任何想法?谢谢你。
这是显示我的问题的游戏图片
【问题讨论】:
我正在 libgdx 中制作一个游戏,其中主角身上有一盏灯,而光线没有到达的地方应该是黑暗的,我正在使用 SpriteBash 中的 setBlendFunction 来模拟光线。我的问题是我不知道如何才能使光纹理周围变暗,我可以调整光纹理的大小以适应整个屏幕,但这会很草率并且在代码中不方便。有没有人有任何想法?谢谢你。
这是显示我的问题的游戏图片
【问题讨论】:
为什么不使用Box2dlight 来满足您的要求。在我看来,您可以使用着色器进行照明,但您想要的效果只能通过使用 box2d body 和 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;
}
}
输出是:
【讨论】:
这通常使用 FrameBuffer 完成。
您希望在resize() 方法中根据需要进行实例化和重新创建,以便它始终与屏幕/窗口的大小相匹配。在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);
}
}
在render(),在你的游戏中绘制任何东西之前,你首先在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();
然后正常绘制你的游戏场景。在绘制之前,不要忘记将混合功能改回您通常使用的功能(默认为 GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA)。最后,在游戏上绘制阴影贴图:
// 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();
【讨论】: