I'm working on a game which requires me to dynamically generate cards with text on them . To achieve this I am attempting to render a generic card background and some text to a frame buffer then create a TextureRegion from this for use as a Sprite.
My current attempt creates some rather...unexpected results:
The large, colorful image above is what the sprite returned by the below function looks like. The image being rendered is actually the full spritesheet that the texture atlas is loading a sprite from.
The second image (which is the expected result) is the content of the PNG screenshot generated from the pixmap towards the end of the function.
I can confirm that the TextureRegion generated in the function is being used because changing the parameters of fboRegion.flip() does affect the resulting sprite.
private Sprite generateCard(String text, TextureAtlas atlas){
//Create and configure font
BitmapFont font = new BitmapFont();
font.setColor(Color.RED);
//Create a SpriteBatch (Temporary, need to pass this in later)
SpriteBatch sb = new SpriteBatch();
//Create sprite from texture atlas
Sprite sprite = atlas.createSprite("back", 3);
//Create FrameBuffer
FrameBuffer fbo = new FrameBuffer(Pixmap.Format.RGBA8888, Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), false);
//Extract Texture from FrameBuffer
TextureRegion fboRegion = new TextureRegion(fbo.getColorBufferTexture());
//Flip the TextureRegion
fboRegion.flip(false, true);
//Begin using the FrameBuffer (disable drawing to the screen?)
fbo.begin();
//Clear the FrameBuffer with transparent black
Gdx.gl.glClearColor(0f, 0f, 0f, 0f);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);
sb.begin();
//Draw card background
sb.draw(sprite, 0,0, sprite.getWidth(), sprite.getHeight());
//Draw card text
font.draw(sb, text, 20, 100);
sb.end();
//Take "Screenshot" of the FrameBuffer
Pixmap pm = ScreenUtils.getFrameBufferPixmap(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
PixmapIO.writePNG(new FileHandle("screenshot.png"), pm);
fbo.end();
sb.dispose();
fbo.dispose();
return new Sprite(fboRegion);
}
If anyone has any suggestions I'd greatly appreciate the help. I feel like something is just happening in the wrong order but I can't for the life of me see where the FrameBuffer could be getting the Image it is rendering from or why the returned sprite has the wrong image but dumping the FrameBuffer to a PNG gives the the right image.
So after a fair bit of extra experimentation I've found out the above code is working exactly as intended. I have managed to track the issue down to some other code which is taking the dimensions and position of the sprite but rendering a different texture (hence the flipping when I changed the texture region).
Thanks to those that checked out my question.
Related
So here is my issue. I have a 800x800 libgdx game and I have created a 800x800 .png using gimp. I add it and draw it but the image now seems to be extremely larger than expected. For instance, if I have a ocean .png, all that renders is a dark blue screen. Seems like it is accepting my image but I am doing something else wrong. Any help would be awesome. Code is below. The player and enemy both render fine and on top of the blue.
private Texture img;
private TextureRegion textureRegion;
float drawingWidth,drawingHeight;
//Constructor
public GameScreen(Game game) {
this.game = game;
img = new Texture("tester2.png");
img.setWrap(Texture.TextureWrap.Repeat, Texture.TextureWrap.ClampToEdge);
int width=Gdx.graphics.getWidth();
textureRegion=new TextureRegion(img,0,0,width,img.getHeight());
drawingWidth=width;
drawingHeight=Gdx.graphics.getHeight();
Gdx.app.log(ID, "GameScreen is loaded! " + drawingWidth + " " + drawingHeight);
}
#Override
public void render(float deltaTime) {
//buffer screen
Gdx.gl20.glClearColor((11f / 255.0f), (11f / 255.0f), (11f / 255.0f), 1);
Gdx.gl20.glClear(GL20.GL_COLOR_BUFFER_BIT);
sb.begin();
sb.setProjectionMatrix(camera.combined);
update(deltaTime);
sb.draw(textureRegion,0,0,drawingWidth,drawingHeight);
sb.draw(img, 0, 0);
player.render(sb);
enemy.render(sb);
sb.end();
}
From my testing it seems like your camera's viewport is improperly configured. If you are using an OrthographicCamera then you want to use OrthographicCamera.setToOrtho() to set the viewport. Right now the camera is set to display a 2x2 pixel corner of your image. HOVEVER, your example is not replicable and I don't know how you set up your SpriteBatch or your Camera, or anything for that matter so I may be off.
P.S. why are you drawing img and texture region when they are the same? img will just put the image in the bottom left corner, textureRegion will repeat a few times across the screen.
This problem seemed very obvious for me to solve, but whatever I try, it doesn't work. What I'm trying to do is to incorporate a mini-version of my PlayScreen in a ScrollPane as a tutorial where you can read text and try it out immediately.
Because I didn't find any better solution to add this to the Table inside the ScrollPane, I edited the draw() method of the PlayScreen to take the ScrollPane.getScrollPercentY() and offset the camera of the PlayScreen accordingly.
What I want to do now is to only render only part of the viewport that would be normally visible in the real game. Subsequently, I want to be able to control the size and position of this "window".
I also want to be able to resize and move the content, while cutting off the edges that are not visible to the camera. This is what I tried inside the PlayScreenDraw:
public void draw(final float yOffset,
final int xTiles,
final int yTiles) {
view.getCamera().position.y = yTiles / 2f - yOffset * yTiles / HEIGHT; // HEIGHT = 800
view.getCamera().position.x = xTiles / 2f;
view.setWorldSize(xTiles, yTiles); //Do i even need to change the world size?
b.setProjectionMatrix(view.getCamera().combined);
b.begin();
...
b.end();
view.update(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
}
What this gives me, in terms of the picture above, is this
How do I need to change the viewport and/or the camera? Btw., this is how i set the two up:
cam = new OrthographicCamera();
cam.setToOrtho(false, WIDTH, HEIGHT); // WIDTH = 8, HEIGHT = 16
batch.setProjectionMatrix(cam.combined);
view = new FitViewport(WIDTH, HEIGHT, cam);
The Pixmap class can help you achieve what you want since you stated that you wanted to "cut off" the parts outside of the green selection box.
You need to render what the camera sees to an FBO and then get the pixmap from the FBO itself.
Framebuffer Objects are OpenGL Objects, which allow for the creation of user-defined Framebuffers. With them, one can render to non-Default Framebuffer locations, and thus render without disturbing the main screen.
-- OpenGL wiki
// Construct an FBO and keep a reference to it. Remember to dispose of it.
FrameBuffer fbo = new FrameBuffer(Format.RGBA8888, width, height, false);
public void render() {
//Start rendering to the fbo.
fbo.begin();
//From the camera's perspective.
batch.setProjectionMatrix(camera.combined);
batch.begin();
//Draw whatever you want to draw with the camera.
batch.end();
// Finished drawing, get pixmap.
Pixmap pixmap = ScreenUtils.getFrameBufferPixmap(0, 0, width, height);
//Stop drawing to your fbo.
fbo.end();
}
After getting the pixmap you can iterate through the pixels and set the alpha of the pixels outside your green selection window to 0 making them invisible or "cutting them off"
I am quite new to programming so bear with me here...
I am making a 2d basic game just to practice programming in android studio and can't get my sprite to the correct position on the screen. Also when I draw the sprite it appears stretched and the quality is very poor. Any help is appreciated!
public class MyGdxGame extends ApplicationAdapter {
SpriteBatch batch;
Texture background;
Texture ball;
#Override
public void create () {
batch = new SpriteBatch();
background = new Texture("gamebackground.png");
ball = new Texture("ball2.png");
}
#Override
public void render () {
batch.begin();
batch.draw(background, 0,0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
batch.draw(ball, 0,0, Gdx.graphics.getWidth() / 2, Gdx.graphics.getHeight() / 2);
batch.end();
}
You need to keep the original width/height ratio:
instead of scaling it to half the screen size, define your scaling like that:
float scaleFactor = 2.0f;
batch.draw(ball, 0,0, ball.getWidth()*scaleFactor, ball.getHeight*scaleFactor);
If your image is "blurry", and you want the individual pixels to stay crisp, try loading the texture like that:
ball = new Texture("ball2.png");
ball.setFilter(TextureFilter.Nearest, TextureFilter.Nearest);
This prevents (default) linear interpolation when scaling the texture.
I am trying to draw a bunch of tiles (10,000 sprites) for a minimap. It lags on android when drawing individually, so I am trying to use a framebuffer. For some reason, I can't get anything drawn to the screen with the buffer. I will show the relevant code.
buffer = new FrameBuffer(Pixmap.Format.RGBA8888, Main.VIRTUAL_WORLD_WIDTH, Main.VIRTUAL_WORLD_HEIGHT, false);
OrthographicCamera cam = new OrthographicCamera(Main.VIRTUAL_WORLD_WIDTH, Main.VIRTUAL_WORLD_HEIGHT);
buffer.begin();
batch.begin();
batch.setProjectionMatrix(cam.combined);
for(Tile[] tiles : world.level.getGrid()){
for(Tile tile : tiles){
tile.getSprite().draw(batch);
}
}
batch.end();
buffer.end();
tiles = new Sprite(buffer.getColorBufferTexture());
The above code creates the framebuffer in the create method.
And this renders
batch.setProjectionMatrix(camera.combined);
batch.begin();
tiles.draw(batch);
batch.end();
Note, The position of the tiles sprite is 0, 0. I have tried changing all kids of stuff with this code, but can never get it to draw on the screen. The actual tiles aren't a problem, they all function correctly. My camera is setup correctly, so are my viewports.
I am using Libgdx.
I want to simulate fog in my game using pixmap, but I have a problem during generating the "fogless" circle. First, I make a pixmap, filled with black (it is transparent a little bit). After filling I want to draw a filled circle onto it, but the result is not that I expected.
this.pixmap = new Pixmap(640, 640, Format.LuminanceAlpha);
Pixmap.setBlending(Blending.None); // disable Blending
this.pixmap.setColor(0, 0, 0, 0.9f);
this.pixmap.fill();
//this.pixmap.setColor(0, 0, 0, 0);
this.pixmap.fillCircle(200, 200, 100);
this.pixmapTexture = new Texture(pixmap, Format.LuminanceAlpha, false);
In the procedure render()
public void render() {
mapRenderer.render();
batch.begin();
batch.draw(pixmapTexture, 0, 0);
batch.end();
}
If I use Format. Alpha when creating the Pixmap and Texture, I neither see the more translucent circle.
Here is my problem:
Problem
Could somebody help me? What should I do, what should I init before to draw a full transparent circle? Thanks.
UPDATE
I have found the answer for my problem. I have to disable blending to avoid the problem.
Now my code:
FrameBuffer fbo = new FrameBuffer(Format.RGBA8888, 620, 620, false);
Texture tex = EnemyOnRadar.assetManager.get("data/sugar.png", Texture.class);
batch.begin();
// others
batch.end();
fbo.begin();
batch.setColor(1,1,1,0.7f);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.begin();
batch.draw( tex, 100, 100);
batch.end();
fbo.end();
But I don't see the circle (it's a png image, represents transparent bg, white filled circle).
I am not sure if this works for you but i just share it:
You could use FrameBuffers and do the following:
Draw everything you want to draw on screen.
End your SpriteBatch and begin your FrameBuffer, begin the SpriteBatch again.
Draw the Fog, which fills the whole "screen" (FrameBuffer) with a black, non transparent color.
Draw the "Fogless" circle as a white circle, at the position you want to delete the fog.
Set the FrameBuffers alpha channel (transparancy) to 0.7 or something like that.
End the SpriteBatch and the FrameBuffer to draw it to screen.
What happens? You draw the normal scene, without fog. You create a "virtual screen", fill it with black and overdraw the black with a white circle. Now you set a transparacy to this "virtual screen" and overdraw your real screen with it. The part of the screen, which is under the white circle seems to be bright, while the black rest makes your scene darker.
Something to read: 2D Fire effect with libgdx, more or less the same as fog.
My question to this: Libgdx lighting without box2d
EDIT: another Tutorial.
Let me know if it helps!
EDIT: Some Pseudocode:
In create:
fbo = new FrameBuffer(Format.RGBA8888, width, height, false);
In render:
fbo.begin();
glClearColor(0f, 0f, 0f, 1f); // Set the clear color to black, non transparent
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); // Clear the "virtual screen" with the clear color
spriteBatch.begin(); // Start the SpriteBatch
// Draw the filled circles somehow // Draw your Circle Texture as a white, not transparent Texture
spriteBatch.end(); // End the spritebatch
fbo.end(); // End the FrameBuffer
spriteBatch.begin(); // start the spriteBatch, which now draws to the real screen
// draw your textures, sprites, whatever
spriteBatch.setColor(1f, 1f, 1f, 0.7f); // Sets a global alpha to the SpriteBatch, maybe it applies alo to the stuff you have allready drawn. If so just call spriteBatch.end() before and than spriteBatch.begin() again.
spriteBatch.draw(fbo, 0, 0); // draws the FBO to the screen.
spriteBatch.end();
tell me if it works