Pixmaps or Textures for dynamicalliy colored graphics in LibGdx? - libgdx

I was trying to create a dynamic array containing sprites, that created from pixmap textures. I want to give randomly different colors to this array elements also.
None is working.
Then I tried to create a single pixmap. That also shows same behavior.
I created a pixmap in show() like this:
pixmap = new Pixmap(128, 128, Format.RGBA8888);
Pixmap.setBlending(Pixmap.Blending.None);
pixmap.setColor(128, 0, 0, 1f);
pixmap.fillCircle(64, 64, 64);
texture = new Texture(pixmap);
pixmap.dispose();
in render()
sprite = new Sprite(texture);
sprite.setPosition(b.getX()-sprite.getWidth()/2, b.getY()-sprite.getHeight()/2);
sprite.draw(batch);
Whenever I give an rgb color code, it gives either some different colors or black as output. Tried hex code also.
What wrong I did here?
Previousely I used pixmaps as overlay and single texture etc. But did not go deep in to it and tried.
Here, I planned to draw filled circles with pixmap, instead of using graphics. Because my game elements are very simple filled circles and more than 10 colors I should implement.
These circle objects will be generated dynamically throughout the game.
Now I am wondering what I planned to do will be effective with pixmaps. No exapmples I found on net.
Is it possible to create dynamic array with different colored objects?
Or using graphics is the better option compared to pixmaps?
It would be very helpful if I get suggestions from experienced persons.

r,g,b,a values should be in range from 0f to 1f. And it's bad to create new sprites in render(), since it's called every frame.
I'll try to answer your questions with this small code sample (left comments in the code):
public class MyGdxGame extends ApplicationAdapter {
SpriteBatch spriteBatch;
Pixmap pixmap;
Texture texture;
Array<Sprite> sprites = new Array<Sprite>();
#Override
public void create() {
spriteBatch = new SpriteBatch();
// you should use only one Pixmap object and one Texture object
pixmap = new Pixmap(128, 128, Pixmap.Format.RGBA8888);
pixmap.setBlending(Pixmap.Blending.None);
pixmap.setColor(Color.WHITE);
pixmap.fillCircle(64, 64, 64);
texture = new Texture(pixmap);
pixmap.dispose();
// generate sprites with different colors
// r,g,b,a values should be in range from 0f to 1f
addCircleSprite(128f / 255f, 0f, 0f, 1f);
addCircleSprite(0.4f, 0.2f, 0.5f, 1f);
addCircleSprite(0.6f, 0f, 1f, 1f);
addCircleSprite(0.3f, 0.8f, 1f, 1f);
addCircleSprite(0.1f, 1f, 1f, 1f);
}
void addCircleSprite(float r, float g, float b, float a) {
// every sprite references on the same Texture object
Sprite sprite = new Sprite(texture);
sprite.setColor(r, g, b, a);
// I just set random positions, but you should handle them differently of course
sprite.setCenter(
MathUtils.random(Gdx.graphics.getWidth()),
MathUtils.random(Gdx.graphics.getHeight()));
sprites.add(sprite);
}
#Override
public void render() {
Gdx.gl.glClearColor(0f, 0f, 0f, 1f);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
spriteBatch.begin();
for (Sprite sprite : sprites) {
sprite.draw(spriteBatch);
}
spriteBatch.end();
}
#Override
public void dispose() {
texture.dispose();
}
}
also read this Q/A. I guess you could load your Texture object from .png file with white circle:
texture = new Texture("whiteCircle.png");
but creating Pixmap circle with only 64 pixels in radius (and then creating a Texture from it) is ok too, shouldn't make much difference.

setColor() takes r, g, b, a parameters to convert it to rgba8888 format -
public void setColor (float r, float g, float b, float a) {
color = Color.rgba8888(r, g, b, a);
}
So set r, g, b and alpha component as floats in the range [0,1].
use
pixmap.setColor(128f/255, 0, 0, 1f);
instead of
pixmap.setColor(128, 0, 0, 1f);
If you want to use hex then -
Color color = new Color(0x000000a6) //(Black with 65% alpha).

Related

The depth buffer is ignored depending the X/Y position using an orthographic projection

Using libgdx, I want to discard occluded sprites using a depth buffer. To do so I use the provided Decal and DecalBatch with an OrthographicCamera and I set the z position manually.
Depending my sprite position on the x and y axes, the depth buffer works or not as expected.
red square z = 98
green square z = 10
The square are 50% transparent so I can see if the depth test occurred as expected.
Here the test code:
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.backends.lwjgl.LwjglApplication;
import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration;
import com.badlogic.gdx.graphics.*;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.graphics.g3d.decals.CameraGroupStrategy;
import com.badlogic.gdx.graphics.g3d.decals.Decal;
import com.badlogic.gdx.graphics.g3d.decals.DecalBatch;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.utils.Array;
import fr.t4c.ui.GdxTest;
public class DecalTest extends GdxTest {
DecalBatch batch;
Array<Decal> decals = new Array<Decal>();
OrthographicCamera camera;
OrthoCamController controller;
FPSLogger logger = new FPSLogger();
Decal redDecal;
Decal greenDecal;
public void create() {
camera = new OrthographicCamera(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
//camera.near = 1;
camera.position.set(600, 600, 100);
camera.near = 1;
camera.far = 100;
controller = new OrthoCamController(camera);
Gdx.input.setInputProcessor(controller);
batch = new DecalBatch(new CameraGroupStrategy(camera));
TextureRegion[] textures = {
new TextureRegion(new Texture(Gdx.files.internal("src/test/resources/redsquare.png"))),
new TextureRegion(new Texture(Gdx.files.internal("src/test/resources/greensquare.png")
))};
redDecal = Decal.newDecal(textures[0], true);
redDecal.setPosition(600, 600, 98f);
decals.add(redDecal);
greenDecal = Decal.newDecal(textures[1], true);
greenDecal.setPosition(630, 632f, 10f);
decals.add(greenDecal);
Decal decal = Decal.newDecal(textures[0], true);
decal.setPosition(400, 500, 98f);
decals.add(decal);
decal = Decal.newDecal(textures[1], true);
decal.setPosition(430f, 532f, 10f);
decals.add(decal);
}
public void render() {
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);
Gdx.gl.glEnable(GL20.GL_DEPTH_TEST);
Gdx.gl.glDepthFunc(GL20.GL_LEQUAL);
camera.update();
for (int i = 0; i < decals.size; i++) {
Decal decal = decals.get(i);
batch.add(decal);
}
batch.flush();
}
#Override
public void dispose() {
batch.dispose();
}
public static void main(String[] args) {
LwjglApplicationConfiguration cfg = new LwjglApplicationConfiguration();
cfg.useGL30 = false;
cfg.width = 640;
cfg.height = 480;
cfg.resizable = false;
cfg.foregroundFPS = 0; // Setting to 0 disables foreground fps
// throttling
cfg.backgroundFPS = 0; // Setting to 0 disables background fps
new LwjglApplication(new DecalTest(), cfg);
}
}
It is a depth buffer precision problem, the orientation of the camera that messed up the calcul or something else?
Edit:
I expect the sprites being occluded if they are behind another. So in my example the red square should occlude the green part he is in front of.
The left bottom squares have the right behaviour but the upper right squares does not. The things is red squares have the same Z value and green squares have the same Z value too(different than the red squares Z of course). So the only things that made the square couples different is their x and y position, which should not impact the depth test.
So, what I want is a consistent depth test behaviour that occluded hided texture as we see whith the bottom left squares no matter their x and y position.
According to the comment, I added information about what I expect.
Decal and DecalBatch rely on GroupStrategy for depth sorting, NOT the camera. Additionally, these strategies sort depth EITHER by the distance from the camera OR by only the Z axis, which would required for a perspective camera i.e. a decal that is closer and should occlude as measured by Z, might be further as measured by distance from camera.
i.e. (x,y,z)
Camera 0,0,1.
Decal A 1,1,0 (Z distance 1, vector distance 1.73)
Decal B 0,0,-0.1 (Z distance 1.1, vector distance 1.1)
The depth strategy you chose for the above decals could either consider A or B first.
The most common recommended GroupStrategy is CameraGroupStrategy, but this does not sort by Z, but uses camera distance. If you intialise DecalBatch instead with SimpleOrthoGroupStrategy then depth will be sorted purely by Z, here is depth sort for it, you can look at the other group strategies and see its purely absolute distance.
class Comparator implements java.util.Comparator<Decal> {
#Override
public int compare (Decal a, Decal b) {
if (a.getZ() == b.getZ()) return 0;
return a.getZ() - b.getZ() < 0 ? -1 : 1;
}
}

Two stages with different viewports, how to remove blackbars between them

I have two stages, one for the background image (using FillViewport to stretch the image)
Another one use Fitviewport to display game objects.
How do I remove the blackbars to display the background of the first stage ?
I tried Extendviewport for second stages but it will show the gap at the right for 1280x720 devices (how could I split the gap to left ?)
public LoginScreen(final MyGame gam) {
game = gam;
stageBG = new Stage(new FillViewport(800, 480));
textureBackground = new Texture(Gdx.files.internal("background.png"));
stageBG.addActor(new Image(textureBackground));
stage = new Stage(new ExtendViewport(640, 480, 1280, 720));
table = new Table();
textureLoginArea = new Texture(Gdx.files.internal("login-area.png"));
textureGirlGreen = new Texture(Gdx.files.internal("girl-green.png"));
Gdx.input.setInputProcessor(stage);
table.setBounds(415, 15, 374, 459);
table.setBackground(new TextureRegionDrawable(new TextureRegion(textureLoginArea)));
stage.addActor(table);
}
#Override
public void render(float v) {
stageBG.act(Gdx.graphics.getDeltaTime());
stageBG.draw();
stage.act(Gdx.graphics.getDeltaTime());
stage.getBatch().begin();
stage.getBatch().draw(textureGirlGreen, 120, 0);
stage.getBatch().end();
stage.draw();
}
#Override
public void resize(int width, int height) {
stageBG.getViewport().update(width, height, true);
stage.getViewport().update(width, height, true);
}
I think you should avoid using two stages with different viewports. You will get into more trouble. If you want a background image with an login overlay you should just use scene2d. Or just use two stages with the same viewport and scale your overlay manually.
However you could use frame buffers with blending to overdraw the black bars.

TextureRegion in ArrayList Won't draw to screen

I'm having some issues drawing TextureRegions with a spriteBatch in LibGDX.
So I have a main class that hosts the game logic.
In the constructor, I have:
atlas = new TextureAtlas(Gdx.files.internal("sheet.txt") );
this.loadTileGFX();
the loadTileGFX() method does this:
roseFrames = new ArrayList<AtlasRegion>();
roseFrames.add(atlas.findRegion("Dirt", 0));
roseFrames.add(atlas.findRegion("Dirt", 1));
roseFrames.add(atlas.findRegion("Dirt", 2));
roseFrames.add(atlas.findRegion("Dirt", 3));
Then I pass the arrayList of AtlasRegions into the object:
///in the main class
rsoe = new RoseSquare(roseFrames, st, col, row, tileWidth);
//in the constructor for the object to draw
this.textureRegions = roseFrames;
Then every render() loop I call:
batch.begin();
rose.draw(batch);
batch.end()
The rose.draw() method looks like this:
public void draw(SpriteBatch batch){
batch.draw(this.textureRegions.get(1), rect.x, rect.y, rect.width, rect.height);
}
But the thing is, this doesn't draw anything to the screen.
BUT HERE'S THE THING.
If I change the code to be:
public void draw(SpriteBatch batch){
batch.draw(new TextureAtlas(Gdx.files.internal("sheet.txt")).findRegion("Dirt", 0)), rect.x, rect.y, rect.width, rect.height);
}
Then it draws correctly.
Can anybody shed some light on what error I might have?
Keep in ming I don't get any errors with the "nothing drawn" code.
Also, I can trace the details of this.textureRegions.get(1), and they all are correct....
Thanks.
If you need to draw an array of something that has textures you can do like this:
batch.begin();
for (Ground ground : groundArray){
batch.draw(ground.getTextureRegion(), ground.x, ground.y);
}
batch.end();
As you see i am drawing the TextureRegion here.
You can check related classes and other information in my answers HERE and HERE
Answering drew's comment:
public TextureRegion customGetTextureRegion(int i){
switch(i){
case 1: return atlas.findRegion("dirt1"); break;
case 2: return atlas.findRegion("dirt2"); break;
case 3: return atlas.findRegion("dirt3"); break;
}
}
I have found a solution to my own problem.
I was also drawing some debug ShapeRenderer stuff.
The issue seemed to be that libGDX didn't like a SpriteBatch and a ShapeRenderer to be "on" at the same time:
//LibGDX Doesn't like this:
spriteBatch.begin();
shapeRenderer.begin(ShapeType.Line);
shapeRenderer.drawRect(x, y, width, height);
shapeRenderer.end();
sprtieBatch.draw(texRegion, x, y, width, height);
spriteBatch.end();
It prefers:
//LibGDX likes this:
shapeRenderer.begin(ShapeType.Line);
shapeRenderer.drawRect(x, y, width, height);
shapeRenderer.end();
spriteBatch.begin();
sprtieBatch.draw(texRegion, x, y, width, height);
spriteBatch.end();
Thanks for your responses everyone.

loading regions of textureatlas in libgdx loads the entire file

I managed to pack a textureatlas with images i have and it works properly in that it creates the .pack file and the .png file. The issue is when i load the texture atlas and try to assign AtlasRegions. it loads the entire atlas instead of only the image i want. here is a mockup code i used to test it.
#Override
public void create() {
camera = new OrthographicCamera(800, 480);
batch = new SpriteBatch();
test = new TextureAtlas(Gdx.files.internal("polytest.png"));
sprite = test.findRegion("hero");
texture = new Texture(Gdx.files.internal("data/libgdx.png"));
texture.setFilter(TextureFilter.Linear, TextureFilter.Linear);
}
#Override
public void render() {
Gdx.gl.glClearColor(1, 1, 1, 1);
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
batch.setProjectionMatrix(camera.combined);
batch.begin();
batch.draw(sprite.getTexture(), 10, 10);
batch.end();
}
this renders the entire atlas instead of only the image called "hero" in the atlas. Why does this happen?
Thanks in advance.
When you do.-
batch.draw(sprite.getTexture(), 10, 10);
you're actually telling libgdx to render the whole Texture. What you need is to draw just the TextureRegion.-
batch.draw(sprite, 10, 10);

Libgdx: screen resize and ClickListener (libgdx)

I develope a 2D game and use OrthographicCamera and Viewport to resize virtaul board to real display size. I add images to stage and use ClickListener to detect clicks. It works fine, but when I change resolution it works incorrent(can't detect correct actor, I think the problem with new and original x and y). Is there any way to fix this?
You will need to translate the screen coordinates to world coordinates.
Your camera can do that. You can do both ways, cam.project(...) and cam.unproject(...)
Or if you are already using Actors, don't initialize a camera yourself, but use a Stage. Create a Stage and add the actors to it. The Stage will then do coordinate translation for you.
Once me too suffered from this problem but at end i got the working solution, for drawing anything using SpriteBatch or Stage in libgdx. Using orthogrphic camera we can do this.
first choose one constant resolution which is best for game. Here i have taken 1280*720(landscape).
class ScreenTest implements Screen{
final float appWidth = 1280, screenWidth = Gdx.graphics.getWidth();
final float appHeight = 720, screenHeight = Gdx.graphics.getHeight();
OrthographicCamera camera;
SpriteBatch batch;
Stage stage;
Texture img1;
Image img2;
public ScreenTest(){
camera = new OrthographicCamera();
camera.setToOrtho(false, appWidth, appHeight);
batch = new SpriteBatch();
batch.setProjectionMatrix(camera.combined);
img1 = new Texture("your_image1.png");
img2 = new Image(new Texture("your_image2.png"));
img2.setPosition(0, 0); // drawing from (0,0)
stage = new Stage(new StretchViewport(appWidth, appHeight, camera));
stage.addActor(img2);
}
#Override
public void render(float delta) {
Gdx.gl.glClearColor(1, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.begin();
batch.draw(img, 0, 0);
batch.end();
stage.act();
stage.act(delta);
stage.draw();
// Also You can get touch input according to your Screen.
if (Gdx.input.isTouched()) {
System.out.println(" X " + Gdx.input.getX() * (appWidth / screenWidth));
System.out.println(" Y " + Gdx.input.getY() * (appHeight / screenHeight));
}
}
//
:
:
//
}
run this code in Any type of resolution it will going to adjust in that resolution without any disturbance.
I just think Stage is easy to use.
If there are some wrong,i consider you should check your code:
public Actor hit(float x, float y)