Sprite rotation with touch pad - libgdx

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

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.

RayHandler doesn't goes with Box2D world

I have a difficult situation.
I'm making a 2D game and I'm on the step
of integrating box2Dlights part.
But when i'm rendering my RayHandler, I have a black screen.
Here is another image, where I don't render my lights. There is no lights now.
I need to have collision of Box2D and Box2Dlights mixed together.
Please note:
All my boxes are made in units, equal to 1, so that one room is 16 squares length.
All entire world is zoomed by setToOrtho((16 - 1.875f) / Gdx.graphics.getHeight()), where 16 is tile size.
If I scaled my tile size, I would like to have this stuff work.
All code is complicated so I send the only GameScreen and GameMap classes for now:
#Override
public void show() {
InstanceVars inst = InstanceVars.getInstance();
inst.world = new World(new Vector2(0, 0f), true);
inst.engine = new Engine();
inst.handler = new RayHandler(inst.world);
LevelCreator creator = new LevelCreator("level_def.cfg");
try {
gameWorld = creator.createNewLevel();
gameWorld.start();
} catch (FileCorruptedException e) {
e.printStackTrace();
}
}
#Override
public void render(float delta) {
gameWorld.render();
}
#Override
public void resize(int width, int height) {
gameWorld.resize(width, height);
}
#Override
public void dispose() {
gameWorld.dispose();
InstanceVars.getInstance().dispose();
}
for the GameScreen.java
and
private World physWorld = InstanceVars.getInstance().world;
private Box2DDebugRenderer physRender = new Box2DDebugRenderer();
private OrthographicCamera cam = new OrthographicCamera();
private RayHandler lights = new RayHandler(physWorld);
private PlayerController controls;
private float STD_ZOOM = ((float) CELL_SIZE + 16) / Gdx.graphics.getHeight();
private Body playerBody;
public GameMap() {
cam.zoom = STD_ZOOM;
}
public void start() {
GameObject player = (GameObject) getProperties().get("ent_player");
playerBody = player.getComponent(PhysicsComponent.class).getBody();
controls = new PlayerController();
Gdx.input.setInputProcessor(controls);
physWorld.setContactListener(new CollisionInteractor(InstanceVars.getInstance().engine));
PointLight light = new PointLight(lights, 1000, Color.GOLDENROD, 500, playerBody.getPosition().x, playerBody.getPosition().y);
}
public void render() {
updatePlayer();
physWorld.step(1/60f, 8, 2);
updateCamera();
physRender.render(physWorld, cam.combined);
// lights.updateAndRender();
}
private void updatePlayer() {
if (controls.up) playerBody.setLinearVelocity(playerBody.getLinearVelocity().x, -controls.speed);
else playerBody.setLinearVelocity(playerBody.getLinearVelocity().x, controls.down ? controls.speed : 0);
if (controls.down) playerBody.setLinearVelocity(playerBody.getLinearVelocity().x, controls.speed);
else playerBody.setLinearVelocity(playerBody.getLinearVelocity().x, controls.up ? -controls.speed : 0);
if (controls.left) playerBody.setLinearVelocity(-controls.speed, playerBody.getLinearVelocity().y);
else playerBody.setLinearVelocity(controls.right ? controls.speed : 0, playerBody.getLinearVelocity().y);
if (controls.right) playerBody.setLinearVelocity(controls.speed, playerBody.getLinearVelocity().y);
else playerBody.setLinearVelocity(controls.left ? -controls.speed : 0, playerBody.getLinearVelocity().y);
}
public void resize(float width, float height) {
STD_ZOOM = ((float) CELL_SIZE - 1.875f) / Gdx.graphics.getHeight();
cam.setToOrtho(true, width, height);
}
private void updateCamera() {
cam.position.set(playerBody.getPosition(), 0);
cam.update();
}
public void dispose() {
super.dispose();
physWorld.dispose();
physRender.dispose();
}
for GameMap.java.
If you need more details, don't be afraid to ask.
I cannot solve the problem on my own.

Box2d body leaves trail

I am trying to shoot a bullet that is a box2d body with linear impulse applied. Everything is fine except that it appears to leave trails and the movement is not smooth. Here's an image of how it is appearing ..this is one bullet .. but is leaving trail while moving ...
This is a single bullet ..rest are just trails that were not cleared. Here is the render method of screen ,
public void render(float delta) {
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
frameTime = Math.min(delta, 0.25f);
accumulator += frameTime;
while (accumulator >= TIME_STEP) {
world.step(TIME_STEP, 6, 2);
accumulator -= TIME_STEP;
}
stage.act();
stage.draw();
}
Here's the bullet actor
public class Bullet extends Actor {
Sprite bulltetSprite = new Sprite(new Texture(Gdx.files.internal("bullet1.png")));
float x, y;
Body body;
public Bullet(Body b) {
this.body = b;
}
#Override
public void act(float delta) {
x = body.getPosition().x * Constants.PPM;
y = body.getPosition().y * Constants.PPM;
super.act(delta);
}
#Override
public void draw(Batch batch, float parentAlpha) {
super.draw(batch,parentAlpha);
batch.draw(bulltetSprite, x - Constants.BULLET_WIDTH / 2, y - Constants.BULLET_HEIGHT / 2, Constants.BULLET_WIDTH, Constants.BULLET_HEIGHT);
}
}
What am I missing here, so the bullet with move smoothly ...
Edit: The trails appear even when I am not using sprites and just rendering with Box2dDebugRenderer.
Edit 2 : It appears it has to do with the physics. The density I was using for the bullet was way too low .. after setting the density to higher value it seems to work fine now.

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

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.