LibGDX float with camera position causing black lines with Tiled map - java

I am creating a top-down shooter game, and whenever I move the camera, or zoom, black likes appear like a grid
I am using Tiled to create the map, and I have the camera following my centered box2d body. I have found that making the camera position equal the position of the box2d body with an int cast results in the black lines disappearing like this:
The problem though, is that because I have the game scaled down, the player will move for a second or two and then when the player reaches the next whole number on either axis, the camera snaps to the player, which is not what I want for the game as it's jarring. The player's movement is granular, but, while rounded, the camera's is not. I do not know if this is a problem with my tile sheet or if it's something I can fix by altering some code. I have tried all different kinds of combinations of padding, and values of spacing and margins. So ultimately, how can I have the camera match the player's position smoothly and not cause the black lines? I'd greatly appreciate any help or recommendations. Thank you in advance!
Where I am type casting the player's float position to an int in game class:
public void cameraUpdate(float delta) {
//timeStep = 60 times a second, velocity iterations = 6, position iterations = 2
world.step(1/60f, 6, 2); //tells game how many times per second for Box2d to make its calculations
cam.position.x = (int)playerOne.b2body.getPosition().x;
cam.position.y = (int)playerOne.b2body.getPosition().y;
cam.update();
}
Majority of player class:
public class PlayerOne extends Sprite implements Disposable{
public World world; // world player will live in
public Body b2body; //creates body for player
private BodyDef bdef = new BodyDef();
private float speed = 1f;
private boolean running;
TextureAtlas textureAtlas;
Sprite sprite;
TextureRegion textureRegion;
private Sound runningSound;
public PlayerOne(World world) {
this.world = world;
definePlayer();
textureAtlas = new TextureAtlas(Gdx.files.internal("sprites/TDPlayer.atlas"));
textureRegion = textureAtlas.findRegion("TDPlayer");
sprite =new Sprite(new Texture("sprites/TDPlayer.png"));
sprite.setOrigin((sprite.getWidth() / 2) / DunGun.PPM, (float) ((sprite.getHeight() / 2) / DunGun.PPM - .08));
runningSound = Gdx.audio.newSound(Gdx.files.internal("sound effects/running.mp3"));
}
public void definePlayer() {
//define player body
bdef.position.set(750 / DunGun.PPM, 400 / DunGun.PPM);
bdef.type = BodyDef.BodyType.DynamicBody;
//create body in the world
b2body = world.createBody(bdef);
FixtureDef fdef = new FixtureDef();
CircleShape shape = new CircleShape();
shape.setRadius(12 / DunGun.PPM);
fdef.shape = shape;
b2body.createFixture(fdef);
}
public void renderSprite(SpriteBatch batch) {
float posX = b2body.getPosition().x;
float posY = b2body.getPosition().y;
float posX2 = (float) (posX - .14);
float posY2 = (float) (posY - .1);
sprite.setSize(32 / DunGun.PPM, 32 / DunGun.PPM);
sprite.setPosition(posX2, posY2);
float mouseX = Level1.mouse_position.x; //grabs cam.unproject x vector value
float mouseY = Level1.mouse_position.y; //grabs cam.unproject y vector value
float angle = MathUtils.atan2(mouseY - getY(), mouseX - getX()) * MathUtils.radDeg; //find the distance between mouse and player
angle = angle - 90; //makes it a full 360 degrees
if (angle < 0) {
angle += 360 ;
}
float angle2 = MathUtils.atan2(mouseY - getY(), mouseX - getX()); //get distance between mouse and player in radians
b2body.setTransform(b2body.getPosition().x, b2body.getPosition().y, angle2); //sets the position of the body to the position of the body and implements rotation
sprite.setRotation(angle); //rotates sprite
sprite.draw(batch); //draws sprite
}
public void handleInput(float delta) {
setPosition(b2body.getPosition().x - getWidth() / 2, b2body.getPosition().y - getHeight() / 2 + (5 / DunGun.PPM));
this.b2body.setLinearVelocity(0, 0);
if(Gdx.input.isKeyPressed(Input.Keys.W)){
this.b2body.setLinearVelocity(0f, speed);
}if(Gdx.input.isKeyPressed(Input.Keys.S)){
this.b2body.setLinearVelocity(0f, -speed);
}if(Gdx.input.isKeyPressed(Input.Keys.A)){
this.b2body.setLinearVelocity(-speed, 0f);
}if(Gdx.input.isKeyPressed(Input.Keys.D)){
this.b2body.setLinearVelocity(speed, 0f);
}if(Gdx.input.isKeyPressed(Input.Keys.W) && Gdx.input.isKeyPressed(Input.Keys.A)){
this.b2body.setLinearVelocity(-speed, speed);
}if(Gdx.input.isKeyPressed(Input.Keys.W) && Gdx.input.isKeyPressed(Input.Keys.D)){
this.b2body.setLinearVelocity(speed, speed);
}
if(Gdx.input.isKeyPressed(Input.Keys.S) && Gdx.input.isKeyPressed(Input.Keys.A)){
this.b2body.setLinearVelocity(-speed, -speed );
}if(Gdx.input.isKeyPressed(Input.Keys.S) && Gdx.input.isKeyPressed(Input.Keys.D)){
this.b2body.setLinearVelocity(speed, -speed);
}
Where I declare the pixels per meter scale:
public class DunGun extends Game{
public SpriteBatch batch;
//Virtual Screen size and Box2D Scale(Pixels Per Meter)
public static final int V_WIDTH = 1500;
public static final int V_HEIGHT = 800;
public static final float PPM = 100; //Pixels Per Meter
Game render and resize methods:
#Override
public void render(float delta) {
cameraUpdate(delta);
playerOne.handleInput(delta);
//clears screen
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
if (Gdx.input.isButtonPressed(Input.Buttons.LEFT)) {
cam.zoom -= .01;
}
if (Gdx.input.isButtonPressed(Input.Buttons.RIGHT)) {
cam.zoom += .01;
}
mapRenderer.render();
b2dr.render(world, cam.combined); //renders the Box2d world
mapRenderer.setView(cam);
//render our game map
//mapRenderer.render(); // renders map
//mapRenderer.render(layerBackround); //renders layer in Tiled that p1 covers
game.batch.setProjectionMatrix(cam.combined); //keeps player sprite from doing weird out of sync movement
mouse_position.set(Gdx.input.getX(), Gdx.input.getY(), 0);
cam.unproject(mouse_position); //gets mouse coordinates within viewport
game.batch.begin(); //starts sprite spriteBatch
playerOne.renderSprite(game.batch);
game.batch.end(); //starts sprite spriteBatch
//mapRenderer.render(layerAfterBackground); //renders layer of Tiled that hides p1
}
#Override
public void resize(int width, int height) {
viewport.update(width, height, true); //updates the viewport camera
}

I solved it by fiddling around with the padding of the tilesets in GDX Texture Packer. I added 5 pixels of padding around the 32x32 tiles. I set the margins to 2, and spacing to 4 in Tiled. I had tried a lot of different combinations of padding/spacing/margins that didn't work which made me think it was a coding problem, but those settings worked, and I didn't have to round the floats.

Related

cannot rotate my sprite in libgdx

so I've been looking at other people's questions and I've tried to apply the answers to my code but I do not seem to find how to do so. All I am trying to do is that when the Sprite moves is going to rotate at the same time. This is where I am calling the rotate function inside my Player class (which extends Sprite):
public void playerMovement(float dt){
if(Gdx.input.isPeripheralAvailable(Input.Peripheral.Accelerometer)) {
float roll = Gdx.input.getRoll();
float pitch = Gdx.input.getPitch();
final float MAX_SPEED = 0.4f;
velocity.x = roll;
velocity.y = pitch;
x = position.x;
y = position.y;
if (Math.abs(velocity.x) > 1) {
x = Math.max(0, Math.min(Gdx.graphics.getWidth(), x + velocity.x * MAX_SPEED));
position.x = x;
position.y = y;
rotate(90 * dt); //NOT WORKING
}
if (Math.abs(velocity.y) > 1) {
y = Math.max(0, Math.min(Gdx.graphics.getHeight(), y + velocity.y * MAX_SPEED));
position.x = x;
position.y = y;
rotate(90* dt); //NOT WORKING
}
}
}
before it used to extend Actor and use setRotate(90 * dt) and it was working fine. I decided to change to Sprite because I did not want to depend on the stage.
here's how I am rendering the player inside my GameScreen:
game.batch.begin();
game.batch.draw(atlas2.findRegion("player"), player.getPosition().x, player.getPosition().y, player.PLAYER_DIMENSION , player.PLAYER_DIMENSION);
game.batch.end();
I tried to use the player.draw(game.batch) function from the Sprite class, yet I did not work because I needed a Texture and the texture I am using is just an AtlasRegion and it did not let my type casted to a Texture
so if there are any suggestions on how to make my Sprite rotate I will appreciate!
Sprite holds the geometry, color, and texture information for drawing 2D sprite. In geometry, it carry sprite position, size, rotation and scale.
By using below method you're only passing position and size of player Sprite.
game.batch.draw(atlas2.findRegion("player"), player.getPosition().x, player.getPosition().y, player.PLAYER_DIMENSION , player.PLAYER_DIMENSION);
Use in this way :
TextureAtlas atlas2=....;
Sprite player=new Sprite(atlas2.findRegion("player"));
and draw by using draw method of Sprite
player.draw(game.batch);
EDIT
public class Player extends Sprite {
public Player(TextureRegion region){ // <- Add this constructor
super(region);
...
}
}
And create object of Player
Player player=new Player(atlas2.findRegion("player");

LibGdx Box2d collison not matching up with sprite

I am making a game as a project for a college class. when my main character (the tree) hits the ground, it stops short of the ground
screenshot 1
and when the player lands on the little platform that gap is even bigger
screenshot 2
my code for creating the body of the character and and ground is this
public static Body createBody(int x, int y, float width, float height, boolean isStatic){
Body body;
BodyDef def = new BodyDef();
if(isStatic){
def.type = BodyDef.BodyType.StaticBody;
}
else {
def.type = BodyDef.BodyType.DynamicBody;
}
def.position.set(x / PPM , y / PPM);
// returns a World object
body = GlobalWorld.getInstance().createBody(def);
PolygonShape shape = new PolygonShape();
shape.setAsBox(width / 2 / PPM, height / 2 / PPM);
body.createFixture(shape, 1.0f);
shape.dispose();
return body;
}
The code for the ground is in it's own class
public class Material {
private Texture image;
private Body body;
private Sprite sprite;
public Material(Texture t, int x, int y, int w, int h){
image = t;
sprite = new Sprite(t);
body = BoxBuilder.createBody(x, y, w, h, true);
body.setUserData("Ground");
}
public void draw(){
// returns a SpriteBatch
SpriteBatch batch = GlobalBatch.getInstance();
sprite.setPosition(body.getPosition().x * PPM, body.getPosition().y * PPM);
batch.begin();
sprite.draw(batch);
batch.end();
}
public void dispose(){
image.dispose();
}
}
the code for drawing the ground
public void draw(){
for(Material m : worldObjects){
m.draw();
}
}
my code for drawing the character
public void create(){
// do stuff
// global vars
body = createBody(0, 480, 313, 260, false);
texture = new Texture("tree.PNG");
sprite = new Sprite(texture);
// do stuff
}
public void render(){
// do stuff
sprite.setPosition(body.getPosition().x*PPM, body.getPosition().y*PPM);
batch.begin()
sprite.draw(batch)
batch.end()
// do stuff
}
and PPM(Pixel per Meter) is
public static final float PPM = 32;
I don't know what is the problem here, I want the character to land on the ground, not land above it. So if someone could tell me what's causing this or point me to a good tutorial for learning more about box2d I'd appreciate it.
When we create body with PolygonShape then body is at the center of that Polygon so when draw with body position it starts drawing from center of PolygonShape so we need to draw at left bottom corner.
In Material class
replace
sprite.setPosition(body.getPosition().x * PPM, body.getPosition().y * PPM);
with
sprite.setPosition(body.getPosition().x*PPM-sprite.getWidth()/2,body.getPosition().y-sprite.getHeight()/2);
sprite.setRotation(body.getAngle()*MathUtils.radDeg);
And for Character draw also change
sprite.setPosition(body.getPosition().x*PPM, body.getPosition().y*PPM);
with
sprite.setPosition(body.getPosition().x*PPM-sprite.getWidth()/2, body.getPosition().y*PPM-sprite.getHeight()/2);
sprite.setRotation(body.getAngle()*MathUtils.radDeg);
As I see in your code you're not setting size of Sprite in Material class as well as for Character so set width and height.
In Material Class
sprite = new Sprite(t);
sprite.setSize(w,h);
And for Character
body = createBody(0, 480, 313, 260, false);
texture = new Texture("tree.PNG");
sprite = new Sprite(texture);
sprite.setSize(313,260);

simple Circle on circle Collision libgdx

made two circles one of radius 8(image 16x16)
and one of radius 20( image 40x40)
i am calling the circle over overlap method and the collsion is just off. It is colliding with a circle that is around the 0,0 point of where ever my image of the ball is. the bullet can go within the ball on the bottom and right sides.
public class MyGame extends ApplicationAdapter {
SpriteBatch batch;
Texture ballImage, bulletImage;
OrthographicCamera cam;
Circle ball;
Array <Circle> bullets;
long lastShot;
#Override
public void create ()
{
System.out.println("game created");
ballImage = new Texture(Gdx.files.internal("ball.png"));
bulletImage = new Texture(Gdx.files.internal("bullet.png"));
cam = new OrthographicCamera();
cam.setToOrtho(true,320,480);//true starts top right false starts top left
batch = new SpriteBatch();
ball = new Circle();
ball.radius=20;
ball.x=320/2-ball.radius; // half screen size - half image
ball.y=480/2-ball.radius;
bullets = new Array<Circle>();
spawnBullet();
/*
batch.draw(bulletImage,bullet.x,bullet.y);
bullet.x++;
bullet.y++; */
}
public void spawnBullet()
{
Circle bullet = new Circle();
bullet.radius=8;
bullet.x=0;
bullet.y=0;
bullets.add(bullet);
lastShot = TimeUtils.nanoTime();
}
#Override
public void render ()
{
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
cam.update();
batch.setProjectionMatrix(cam.combined);
batch.begin();
batch.draw(ballImage,ball.x,ball.y);
for(Circle bullet: bullets)
{
batch.draw(bulletImage, bullet.x, bullet.y);
}
batch.end();
if(Gdx.input.isTouched())
{
Vector3 pos = new Vector3();
pos.set(Gdx.input.getX(), Gdx.input.getY(),0);
cam.unproject(pos);
ball.y = pos.y - ball.radius;
ball.x = pos.x - ball.radius ;
}
//if(TimeUtils.nanoTime()-lastShot >1000000000) one second
//spawnBullet();
Iterator<Circle> i = bullets.iterator();
while(i.hasNext())
{
Circle bullet = i.next();
bullet.x++;
bullet.y++;
if(bullet.overlaps(ball))
{
System.out.println("overlap");
i.remove();
}
}
}
}
If your bullet and the ball are 2 circles, like you said you don't need an overlap method.
It is simple: 2 circles collide, if their distance is smaller then the sum of their radiuses.
To calculate the distance you need to make a squareroot. This is a pretty expensive calculation, so it would be better to use squared distance and squared sum of radiuses:
float xD = ball.x - bullet.x; // delta x
float yD = ball.y - bullet.y; // delta y
float sqDist = xD * xD + yD * yD; // square distance
boolean collision = sqDist <= (ball.radius+bullet.radius) * (ball.radius+bullet.radius);
Thats it.
Also in your cam.setToOrtho you wrote a cooment:
//true starts top right false starts top left
Thats wrong, it is top left or bottom left. By default it is bottom left, because this is the way a coordinate system works normaly. The top left is, because the monitor addresses pixels starting from top left = pixel 1.
EDIT: this should be the problem: The coordinates you give the batch.draw method are the left lower corner of the Texture by default, if you are using the "y = Down"-System it should be the top left corner (you have to try i am not sure).
The Circles position instead is its center.
To solve the problem you need to adjust the position like this (for "y = Up"-System):
batch.draw(bulletImage, bullet.x - bullet.radius, bullet.y - bullet.radius);
It is possible, that the same formula works also for the "y = Down"-System but i am not sure

libgdx vector2: shooting ball at an angle

I'm using Libgdx: I have a sprite that is supposed to shoot a ball when touching the screen. The touchPoint should define the direction of the ball. I can't figure out how to rotate and shoot in the correct direction.
public void update(float deltaTime) {
double angle = Math.toRadians(Math.atan2(position.y, position.x));
position.x = (float)Math.cos(angle) * position.x - (float)Math.sin(angle) * position.y;
position.y = (float)Math.sin(angle) * position.x + (float)Math.cos(angle) * position.y;
}
The ball takes off, but shoots in the wrong direction. Is there a way using Vector2.rotate function instead?
I'd do something like this, assuming you are shooting the ball from its current position (or any known position really) toward the touched position:
public class Snippet extends ApplicationAdapter {
ShapeRenderer renderer;
OrthographicCamera camera;
Ball ball = new Ball();
#Override
public void create () {
renderer = new ShapeRenderer();
camera = new OrthographicCamera();
camera.setToOrtho(false);
}
#Override
public void render () {
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
ball.update(Gdx.graphics.getDeltaTime());
renderer.setProjectionMatrix(camera.combined);
renderer.begin(ShapeType.Line);
renderer.setColor(1.0f, 1.0f, 1.0f, 1.0f);
renderer.circle(ball.position.x, ball.position.y, ball.radius);
// Show the travel path of the ball if we were to click at the current location.
if (Gdx.app.getType() == ApplicationType.Desktop || Gdx.app.getType() == ApplicationType.WebGL) {
renderer.setColor(0.2f, 0.2f, 0.2f, 1.0f);
renderer.line(ball.position.x, ball.position.y, Gdx.input.getX(), Gdx.graphics.getHeight()- Gdx.input.getY());
}
renderer.end();
if (Gdx.input.justTouched()) {
// Invert the the y to accommodate difference in coordinate systems
ball.shootToward(Gdx.input.getX(), Gdx.graphics.getHeight()- Gdx.input.getY());
}
}
class Ball {
public float speedMax = 350;
public float radius = 10;
public Vector2 position = new Vector2();
public Vector2 velocity = new Vector2();
/** Shoot the ball toward the designated position */
public void shootToward(float targetX, float targetY) {
/*
* Get the normalized direction vector from our position to the target. Then scale that value to our desired speed. In
* this particular example, we are using the distance of the target from the current position to determine how fast we
* will shoot the ball, and limiting to a maximum speed. We will apply velocity in the update method.
*/
velocity.set(targetX - position.x, targetY - position.y).nor().scl(Math.min(position.dst(targetX, targetY), speedMax));
}
public void update(float deltaTime) {
position.add(velocity.x * deltaTime, velocity.y * deltaTime);
velocity.scl(1 - (0.98f * deltaTime)); // Linear dampening, otherwise the ball will keep going at the original velocity forever
}
}
public static void main(String[] args) {
new LwjglApplication(new Snippet2());
}
}

Body moving without any force applied? (Box2d)

So I am making a game in box 2d. In one part I need a ball which has a constant bounce height. I set the ball's restitution to 1 and am applying no force on it whatsoever (except gravity of course). Now this ball, on every bounce, bounces a bit higher everytime till it goes out of the top edge of the screen. What is wrong with this code?
public class Ball implements ApplicationListener {
World world ;
Box2DDebugRenderer debugRenderer;
OrthographicCamera camera;
static final float BOX_STEP=1/60f;
static final int BOX_VELOCITY_ITERATIONS=8;
static final int BOX_POSITION_ITERATIONS=3;
static final float WORLD_TO_BOX=0.01f;
static final float BOX_WORLD_TO=100f;
Rectangle ball;
Body body;
/* (non-Javadoc)
* #see com.badlogic.gdx.ApplicationListener#create()
*/
#Override
public void create() {
world = new World(new Vector2(0, -10), true);
camera = new OrthographicCamera();
camera.viewportHeight = 480;
camera.viewportWidth = 800;
camera.position.set(camera.viewportWidth * .5f, camera.viewportHeight * .5f, 0f);
camera.update();
//Ground body
BodyDef groundBodyDef =new BodyDef();
groundBodyDef.position.set(new Vector2(0, 10 * WORLD_TO_BOX));
Body groundBody = world.createBody(groundBodyDef);
PolygonShape groundBox = new PolygonShape();
float w = (camera.viewportWidth * 2) * WORLD_TO_BOX;
float h = 10.0f * WORLD_TO_BOX;
groundBox.setAsBox(w,h);
groundBody.createFixture(groundBox, 0.0f);
String a="gb";
groundBody.setUserData(a);
//Dynamic Body
BodyDef bodyDef = new BodyDef();
bodyDef.type = BodyType.DynamicBody;
float posX = (camera.viewportWidth / 8) * WORLD_TO_BOX;
float posY = (camera.viewportHeight / 2) * WORLD_TO_BOX;
bodyDef.position.set(posX, posY);
body = world.createBody(bodyDef);
// create a Rectangle to logically represent the ball
CircleShape dynamicCircle = new CircleShape();
dynamicCircle.setRadius(1f);
FixtureDef fixtureDef = new FixtureDef();
fixtureDef.shape = dynamicCircle;
fixtureDef.density = 1.0f;
fixtureDef.friction = 0.0f;
fixtureDef.restitution =1f;
body.createFixture(fixtureDef);
debugRenderer = new Box2DDebugRenderer();
}
#Override
public void dispose() {
}
#Override
public void render() {
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
debugProjection.set(camera.combined);
debugProjection.scl(BOX_WORLD_TO);
debugRenderer.render(world, debugProjection);
world.step(BOX_STEP, BOX_VELOCITY_ITERATIONS, BOX_POSITION_ITERATIONS);
}
#Override
public void resize(int width, int height) {
}
#Override
public void pause() {
}
#Override
public void resume() {
}
}
This may be caused by numerical instability. Repeatedly calculating positions of your ball inevitably introduces tiny numerical errors (because a float can only hold a limited number of digits). These may grow and add up from iteration to iteration, bounce to bounce.
You can try using restitution 0.9999999 or something. But chances are that there is no restitution value which gives desired results.
Try to actively compensate for the numerical instability e.g. by controlling the ball's position and/or velocity in situations in which you can calculate values non-iteratively. (I do not know Box2D. Maybe when the ball hits the ground you can reset its speed or something.)
Ok I solved it by setting the restitution to 0 and applying an upward force of 5N on each contact. As halfbit said, the problem is that because box2d uses float, the position calculations are not precise which causes minor changes in height on every bounce.
If I have done the math right for the calculations, your sphere has a radius of 1m, and your box as dimensions of 16m x 0.1m.
In Box2d, everything needs to be on the scale of 0.1m to 10m. The reason your bodies may be numerically unstable is because the ratio of the width to height is greater than the normal sizes of objects. While you may get some stability by changing the restitution, I think you will always be on the "hairy edge" with these dimensions.
Try changing the dimensions of your objects so the width is 8 and the height is 0.1.

Categories

Resources