Libgdx: Dynamically increasing size of Pixmap - libgdx

I am new to Libgdx. I have a requirement where I have multiple balls in a game and I want to increase the ball diameter every time the user touches the ball. I used the method pixmap.drawCircle() to create the ball and every time a user touches the ball, I call a method increaseBallDia() to increase the ball size. Since there is no method to increase the height and width of an existing Pixmap, in increaseBallDia() method, I create a new Pixmap with increased width and height and then draw a ball with incremented diameter.
The problem is that my increaseBallDia() is not working properly and there is no increment to the height and width of the Pixmap. Due to this as the ball diameter increases it covers the entire Pixmap area and appears like a rectangle instead of a circle.
Any pointers on how to solve this would be greatly appreciated.
Following is the relevant code snippet:
public class MyActor extends Actor {
int actorBallDia = 90;
Pixmap pixmap = new Pixmap(actorBallDia, actorBallDia,Pixmap.Format.RGBA8888);
float actorX, actorY;
Texture texture;
public void increaseBallDia() {
actorBallDia = actorBallDia + 5;
int radius = actorBallDia / 2 - 1;
Pixmap pixmap = new Pixmap(actorBallDia, actorBallDia,
Pixmap.Format.RGBA8888);
pixmap.drawCircle(pixmap.getWidth() / 2 , pixmap.getHeight() / 2,
radius);
pixmap.fillCircle(pixmap.getWidth() / 2 , pixmap.getHeight() / 2,
radius);
texture = new Texture(pixmap);
}
public void createYellowBall() {
pixmap.setColor(Color.YELLOW);
int radius = actorBallDia / 2 - 1;
pixmap.drawCircle(pixmap.getWidth() / 2, pixmap.getHeight() / 2,
radius);
pixmap.setColor(Color.YELLOW);
pixmap.fillCircle(pixmap.getWidth() / 2, pixmap.getHeight() / 2,
radius);
texture = new Texture(pixmap);
}
#Override
public void draw(Batch batch, float alpha) {
if (texture != null) {
batch.draw(texture, actorX, actorY);
}
}
public void addTouchListener() {
addListener(new InputListener() {
#Override
public boolean touchDown(InputEvent event, float x, float y,
int pointer, int button) {
MyActor touchedActor = (MyActor) event.getTarget();
touchedActor.actorTouched = true;
return true;
}
#Override
public void touchUp(InputEvent event, float x, float y,
int pointer, int button) {
MyActor touchedActor = (MyActor) event.getTarget();
touchedActor.actorTouched = false;
}
});
}
#Override
public void act(float delta) {
if (actorTouched) {
increaseBallDia();
}
}
Regards,
RG

You should create the pixmap with its biggest possible dimensions. When the ball is meant to be small, just scale it down as you wish.

Related

libgdx isometric tiled map screen to world with viewport

I wanted to create a simple 30x30 isometric tiled map and add a listener to be able to click on the tiles. I looked up a lot of the articles and posts here but none of them helped me.
My issue is, i have a viewport, 30x17, a camera, a stage and a tiled map with tileWidth = 32 and tileHeight = 16 pixels.
Now when i render the tiled map it looks fine.
When i click on stage and try to get the world coordinates i see some really weird coordinates.
This is the code:
private static final float TILE_WIDTH = 32;
private static final float TILE_HEIGHT = 16;
private OrthographicCamera camera;
private Viewport viewport;
private Stage stage;
private IsometricTiledMapRenderer isometricTiledMapRenderer;
private Matrix4 isoTransform;
private Matrix4 invIsotransform;
public void load(AssetManagerLoaderV2 assetManagerLoader) {
assetManagerLoader.load();
init();
camera = new OrthographicCamera();
viewport = new FitViewport(30, 17, camera);
stage = new Stage(viewport);
TiledMap tiledMap = new TiledMapGenerator(assetManagerLoader).generate(30, 30);
isometricTiledMapRenderer = new IsometricTiledMapRenderer(tiledMap, 1/32f);
stage.addListener(new InputListener() {
#Override
public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
System.out.println(screenToCell(x, y));
return true;
}
});
}
#Override
public void show() {
Gdx.input.setInputProcessor(stage);
}
#Override
public void render(float delta) {
DrawUtils.clearScreen();
viewport.apply();
isometricTiledMapRenderer.setView(camera);
isometricTiledMapRenderer.render();
}
#Override
public void resize(int width, int height) {
stage.getViewport().update(width, height, true);
}
#Override
public void pause() {
}
#Override
public void resume() {
}
#Override
public void hide() {
}
#Override
public void dispose() {
isometricTiledMapRenderer.dispose();
stage.dispose();
}
public void init () {
//create the isometric transform
isoTransform = new Matrix4();
isoTransform.idt();
isoTransform.translate(0.0f, 0.25f, 0.0f);
isoTransform.scale((float)(Math.sqrt(2.0) / 2.0), (float)(Math.sqrt(2.0) / 4.0), 1.0f);
isoTransform.rotate(0.0f, 0.0f, 1.0f, -45.0f);
//... and the inverse matrix
invIsotransform = new Matrix4(isoTransform);
invIsotransform.inv();
}
public Vector2 worldToCell(float x, float y) {
float halfTileWidth = TILE_WIDTH * 0.5f;
float halfTileHeight = TILE_HEIGHT * 0.5f;
float row = (1.0f/2) * (x/halfTileWidth + y/halfTileHeight);
float col = (1.0f/2) * (x/halfTileWidth - y/halfTileHeight);
return new Vector2((int)col,(int)row);
}
public Vector2 screenToWorld(float x, float y){
Vector3 touch = new Vector3(x,y,0);
camera.unproject(touch);
touch.mul(invIsotransform);
touch.mul(isoTransform);
return new Vector2(touch.x,touch.y);
}
public Vector2 screenToCell(float x, float y) {
Vector2 world = screenToWorld(x,y);
world.y -= TILE_HEIGHT *0.5f;
return worldToCell(world.x,world.y);
}
Does anyone have an idea how to write worldToCell to get the proper coordinates?
I found the issue, i was missing one step.
This is what touchDown should look like:
#Override
public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
Vector2 newCoords = stage.stageToScreenCoordinates(new Vector2(x, y));
System.out.println(screenToCell(newCoords.x, newCoords.y));
return true;
}
I need to convert stage coordinates to screen coordinates, now this code is working.

Sprite rotation with touch pad

I'am having a issue or just don't know how to make it to work so everything is seen in image.
rotation = lerp(rotation, realRotation, delta / 2);
IMAGE GIF
You want to linearly interpolate ship rotation between a particular angle(set by TouchPad) to original(default) value.
I am trying to achieve your requirement in my code.
public class TestGame1 extends Game {
Stage stage;
Touchpad touchpad;
Image image;
float angle=0;
Texture shipTex;
#Override
public void create() {
stage=new Stage();
image=new Image(shipTex=new Texture("ship1.png"));
image.setPosition(300,300);
image.setSize(100,107);
image.setOrigin(50,53);
Skin skin=new Skin(Gdx.files.internal("skin/uiskin.json"));
touchpad=new Touchpad(10,skin);
touchpad.setPosition(100,100);
Gdx.input.setInputProcessor(stage);
stage.addActor(image);
stage.addActor(touchpad);
}
#Override
public void render() {
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
Gdx.gl.glClearColor(0,0,0,1);
stage.act();
stage.draw();
float knobX=touchpad.getKnobPercentX();
float knobY=touchpad.getKnobPercentY();
if(knobX!=0 && knobY!=0) {
float radAngle = MathUtils.atan2(knobY, knobX);
angle = MathUtils.radiansToDegrees * radAngle;
angle -= 90;
if (angle > 360)
angle -= 360;
}
else
angle=MathUtils.lerpAngleDeg(angle,0,Gdx.graphics.getDeltaTime());
image.setRotation(angle);
}
#Override
public void dispose() {
stage.dispose();
shipTex.dispose();
}
}

Libgdx Box2D create Bodies

in my libgdx tiles 2D jump and run game I want to create Bodies every second at the positin of my cannons, but as far as I am, only one cannon shoots every second.
Can anyone help me how to fix this?
Heres where I create my cannons:
//create cannon bodies/fixtures
cannons = new Array<Cannon>();
for (MapObject object : map.getLayers().get(5).getObjects().getByType(RectangleMapObject.class)) {
recta = ((RectangleMapObject) object).getRectangle();
cannons.add(new Cannon(screen, recta.getX(), recta.getY()));
}
}
public float X() {
return recta.getX();
}
public float Y() {
return recta.getY();
}
Here I add canons( that works for every position) :
private Array<Bullet> bullets;
public Cannon(PlayScreen screen, float x, float y) {
super(screen, x, y);
setBounds(getX(), getY(), getWidth(), getHeight());
}
public Cannon() {
super();
}
#Override
protected void defineTrap() {
b2body = Body.addStatic(b2body, world, 0f, getX(), getY(), 32, x.CANNON_BIT, "cannon");
createBullet();
}
public void createBullet() {
bullets = new Array<Bullet>();
bullets.add(new Bullet(screen, getX(), getY()));
}
Here I add the first bullet(that waoks too for all cannons):
public Bullet(PlayScreen screen, float x, float y) {
super(screen, x, y);
setBounds(getX(), getY(), getWidth(), getHeight());
}
public Bullet() {
}
#Override
public void defineTrap() {
b2body = Body.addDynamic(b2body, world, 0f, getX(), getY(), 8, x.BULLET_BIT, "bullet");
b2body.setLinearVelocity(new Vector2(-1f, 0));
b2body.setGravityScale(0);
}
And here I want every cannon to shoot, but only one does (its my render mehtod):
if (TimeUtils.timeSinceNanos(startTime) > 1000000000) {
bullets = new Array<Bullet>();
bullets.add(new Bullet(this, creator.X(), creator.Y()));
startTime = TimeUtils.nanoTime();
}
I hope you can help me!
You should iterate through all cannons and call some method that can access the private field bullets, I called it addBullet(Screen, float, float). You might to need to do something with creator before addBullet() as I'm unsure what you are doing with it.
if (TimeUtils.timeSinceNanos(startTime) > 1000000000) {
for(int i = 0; i < Cannons.size; i++) {
Cannon cannon = cannons.get(i);
cannon.addBullet(this, creator.X(), creator.Y());
}
startTime = TimeUtils.nanoTime();
}
Then create the addBullet method in the Cannon class.
public void addBullet(Screen screen, float x, float y) {
bullets.add(new Bullet(screen, x, y));
}
As far as I can tell there is no reason to reinitialize the bullet array every time as you have been doing. Just use pop(); or removeIndex(index); to remove the array items that are no longer used. You could add some more methods to the Cannon class
public void removeLastBullet() {
bullets.pop();
}
public void removeBullet(int i) {
bullets.removeIndex(i);
}

render to FrameBuffer not working in combination with ShapeRenderer in a custom Actor (libgdx)

I try to implement a custom Actor which displays contents of a FrameBuffer by extending Image. Inside I'd like to draw using a ShapeRenderer.
public class CustomActor extends Image {
private FrameBuffer frameBuffer = null;
private ShapeRenderer shapeRenderer = new ShapeRenderer();
private int width;
private int height;
public CustomActor() {
width = Gdx.graphics.getWidth();
height = Gdx.graphics.getHeight();
shapeRenderer.setAutoShapeType(true);
}
#Override
public void draw(Batch batch, float parentAlpha) {
if (frameBuffer == null) {
frameBuffer = new FrameBuffer(Pixmap.Format.RGB565, width / 2, height / 2, false);
TextureRegion textureRegion = new TextureRegion(frameBuffer.getColorBufferTexture());
textureRegion.flip(false, true);
setDrawable(new TextureRegionDrawable(textureRegion));
}
frameBuffer.begin();
// render content
Gdx.gl.glClearColor(0, 1, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
shapeRenderer.begin(ShapeRenderer.ShapeType.Filled);
shapeRenderer.setColor(Color.WHITE);
shapeRenderer.rect(0, 0, frameBuffer.getWidth() / 2, frameBuffer.getHeight() / 2);
shapeRenderer.end();
if (frameBuffer != null) {
frameBuffer.end();
}
super.draw(batch, parentAlpha);
}
}
When deleting the ShapeRenderer part I can see the green background in the scene. But as soon as I use the ShapeRenderer the content is black. There is no white rectangle visible.
Any ideas what I am doing wrong?
Just found out that using my own SpriteBatch (with begin() and end()) after the FrameBuffer end() it works. So the problem seems to have to do with the calling order of the FrameBuffers methods and the SpriteBatches methods. Ending the given actor batch before beginning the FrameBuffer and "re"-beginning it to draw the actor is also working (see comment above).

Fix touchDragged logic

What i want:
I want allow the user to drag and drop the actors he puts on the screen
1) An actor (32x32 pixel) can be put in a certain area defined by me (a centered rectangle 5x5, 32 pixel each cell)
2) The actors are snapped to an imaginary grid of the screen when added to the stage.
3) This snap to grid is needed also during the drag and drop
4) An actor can't be moved on another one
5) An actor must be rotated by 90 degrees when the user clicks on it
6) The actor can't be moved outside the bounds
What actually i get:
1) ok
2) ok
3) ok (with bugs)
4) not implemented yet
5) ok (with bugs)
6) not implemented yet
The bugs are:
1) The rotations is applied in any case. I don't want this behavior. I don't want to rotate an actor if the user is just doing drag and drop. (i know that this happens because i put this part of the code in the touchDown method)
2) This is hard to describe with my english, i'll try.
I put an actor and i can move it (when i say "move" i mean drag and drop).
I put a second actor and i can move it.
Now, if i try to move the first actor i put, the second one moves over the first (overlapping to it) and starts moving along with it!
Now the code:
Events in the GameStage
#Override
public boolean touchDown(int screenX, int screenY, int pointer, int button) {
translateScreenToWorldCoordinates(screenX, screenY);
// check if the user clicked or not in the center area
if(!centerArea.contains(touchPoint.x, touchPoint.y)) {
return true;
}
// rotation
Iterator<Square> squareIterator = squares.iterator();
while(squareIterator.hasNext()) {
Square nextSquare = squareIterator.next();
if(nextSquare.getBounds().contains(touchPoint.x, touchPoint.y)) {
nextSquare.rotate();
return true;
}
}
// add an Actor
touchPoint.set(touchPoint.x - Constants.SQUARE_SIZE / 2, touchPoint.y - Constants.SQUARE_SIZE / 2, 0f);
float snapX = Math.round((touchPoint.x / Constants.SQUARE_SIZE)) * Constants.SQUARE_SIZE;
float snapY = Math.round((touchPoint.y / Constants.SQUARE_SIZE)) * Constants.SQUARE_SIZE;
Square square = new Square(snapX, snapY);
squares.add(square);
addActor(square);
return true;
}
public boolean touchDragged(int screenX, int screenY, int pointer) {
Vector3 newTouchPoint = new Vector3(screenX, screenY, 0f);
getCamera().unproject(newTouchPoint.set(screenX, screenY, 0f));
Square next = null;
Iterator<Square> squareIterator = squares.listIterator();
while(squareIterator.hasNext()) {
next = squareIterator.next();
if(next.getBounds().contains(newTouchPoint.x, newTouchPoint.y)) {
next.setX(newTouchPoint.x - Constants.SQUARE_SIZE / 2);
next.setY(newTouchPoint.y - Constants.SQUARE_SIZE / 2);
continue;
}
}
newTouchPoint.set(newTouchPoint.x - Constants.SQUARE_SIZE / 2, newTouchPoint.y - Constants.SQUARE_SIZE / 2, 0f);
float snapX = Math.round((newTouchPoint.x / Constants.SQUARE_SIZE)) * Constants.SQUARE_SIZE;
float snapY = Math.round((newTouchPoint.y / Constants.SQUARE_SIZE)) * Constants.SQUARE_SIZE;
next.setX(snapX);
next.setY(snapY);
return true;
}
private void translateScreenToWorldCoordinates(int x, int y) {
getCamera().unproject(touchPoint.set(x, y, 0f));
}
Actor
public class Square extends GameActor {
private float rotation;
private ShapeRenderer shapeRenderer;
public Square(float x, float y) {
super(x, y);
shapeRenderer = new ShapeRenderer();
}
#Override
protected void initializeSprite() {
texture = new Texture(Gdx.files.internal(Constants.SQUARE_LOCATION));
}
#Override
public void act(float delta) {
super.act(delta);
}
#Override
protected void updateBounds() {
bounds.setPosition(x, y);
}
public void rotate() {
rotation -= 90;
if(rotation <= -360) {
rotation = 0;
}
setRotation(rotation);
}
public void setX(float x) {
this.x = x;
}
public void setY(float y) {
this.y = y;
}
#Override
public void draw(Batch batch, float parentAlpha) {
super.draw(batch, parentAlpha);
/*shapeRenderer.begin(ShapeRenderer.ShapeType.Line);
shapeRenderer.setColor(Color.RED);
shapeRenderer.rect(bounds.getX(), bounds.getY(), Constants.SQUARE_SIZE, Constants.SQUARE_SIZE);
shapeRenderer.end();*/
//batch.begin();
batch.draw(texture, x, y, texture.getWidth() / 2, texture.getHeight() / 2,
texture.getWidth(), texture.getHeight(), 1, 1, rotation, 0, 0, Constants.SQUARE_SIZE, Constants.SQUARE_SIZE, false, false);
}
}
I hope you can help me, i'm new to Libgdx, thank you.
UPDATE
I fixed the rotation bug moving its logic inside the touchUp method.