setLinearVelocity() not working as expected - java

I've been messing around with jbox2d and was suprised when the x-velocity of a body was affected by the gravity of the world. Here's my code:
//create world
Vec2 gravity = new Vec2(0, 1);
boolean sleep = true;
world = new World(gravity, sleep);
//create wheel
BodyDef wheelBodyDef = new BodyDef();
wheelBodyDef.type = BodyType.DYNAMIC;
wheelBody = world.createBody(wheelBodyDef);
CircleShape circleShape = new CircleShape();
FixtureDef wheelFixtureDef = new FixtureDef();
wheelFixtureDef.shape = circleShape;
Fixture wheelFixture = wheelBody.createFixture(wheelFixtureDef);
wheelBody.setLinearVelocity(new Vec2(50, 0));
The linear velocity only makes a significant difference if I apply it every frame or if I disable gravity. Can anybody figure out what I'm doing wrong?

Box2d does not have support for zero-gravity simulations; that is why you see no difference when you disable gravity. Also you probably see little difference because a gravity of (0, 1) is very weak; try (0, 10).
Also setLinearVelocity is a rayCast function. You are probably looking for applyForce().

If you set linear velocity on a body means that it will move in direction an speed set with the vector. If you disable gravity there is nothing that effects this movement, but with gravity enabled, its movement is influenced by gravity every frame. If you throw an apple in the outerspace it moves infinite in direction of the shoot, but on earth gravity continuously pulls it down again. If you want to move your body straight in the direction you want, than you have to set the linear velocity every frame. watch this tutorials, #2.35 and #2.36, there the proble is nicely explained.
good luck

Related

Jbox2d Issues with positioning platforms

I am working on developing a platformer, and everything's working fine, except, I seem to be unable to position the bodies for the static platforms.
// creating all the bodies
BodyDef bdef = new BodyDef();
bdef.position.set(x, y);
bdef.type = BodyType.STATIC;
Body body = world.createBody(bdef);
PolygonShape shape = new PolygonShape();
shape.setAsBox(width, height);
FixtureDef fdef = new FixtureDef();
fdef.friction = 0.3f;
fdef.shape = shape;
body.createFixture(fdef);
This is general code that's used to create every body in the map. The bodies work fine, but they don't line up with the width nor the coordinates of the map that I've set. I've noticed that I must specify the bottom left point as starting point for it to make body, but what else I am missing? Why bodies tend to be bigger and go past the starting point of X and Y?
Bodies in box2d are made from their center points. When you define it's position, you are setting it's center and when you define it's width/height, you are actually setting half the width/height (i.e. the size ends up double what you intended).

Huge Image when Using Pixel Per Meter on Libgdx Box2d World

hi guys I am trying to implement a box2d world. I have read that box2d uses meters. and You need to convert it from pixels to meters.
I tried to draw an image but do I have to scale down also the image? I think that is a bad I idea to draw the image, the image are very huge and can't figure what to do to make it work with the box2d pixel per meter
public class TestScreen extends ScreenAdapter {
private final Body body;
private int V_WIDTH = 320;
private int V_HEIGHT = 480;
private int PPM = 100;
private SpriteBatch batch;
private OrthographicCamera camera;
private World world;
private Sprite sprite;
Box2DDebugRenderer box2DDebugRenderer;
public TestScreen(){
batch = new SpriteBatch();
camera = new OrthographicCamera();
camera.setToOrtho(false, V_WIDTH / PPM, V_HEIGHT / PPM);
camera.position.set(0,0,0);
world = new World(new Vector2(0,0) , true);
sprite = new Sprite(new Texture("test/player.png"));
box2DDebugRenderer = new Box2DDebugRenderer();
BodyDef bodyDef = new BodyDef();
bodyDef.type = BodyDef.BodyType.KinematicBody;
body = world.createBody(bodyDef);
FixtureDef fixtureDef = new FixtureDef();
PolygonShape shape = new PolygonShape();
shape.setAsBox(sprite.getWidth()/2 / PPM, sprite.getHeight()/2 / PPM);
fixtureDef.shape = shape;
body.createFixture(fixtureDef);
sprite.setPosition(body.getPosition().x - sprite.getWidth() /2 ,body.getPosition().y - sprite.getHeight() / 2 );
}
#Override
public void render(float delta) {
super.render(delta);
camera.position.set( body.getPosition().x, body.getPosition().y , 0);
camera.update();
world.step(1/60.0f, 6, 2);
batch.setProjectionMatrix(camera.combined);
batch.begin();
sprite.draw(batch);
batch.end();
box2DDebugRenderer.render(world, camera.combined);
}
}
with out ppm
with PPm
should I scale down the image? what is the best way to draw the image
You don't need to convert from pixel to meter. As a matter of fact you should forget about pixels. They exist only on your screen and you game logic should not know anything about your screen. That is what a camera or viewport is for, you specify how much of the world to show and if the display should be stretched or blackboxed or whatever. So no pixels, period. They are evil and give you wrong ideas.
Now if you create your own game you can say that a single unit represents 1mm, 34cm or a couple of lightyears. You tell the object responsible for displaying your game how much of these units to display. However you are using Box2D, and Box2D has already filled in the unit for you 1 unit == 1m. It is probably possible to change this or at least create a wrapper class that converts you units to the Box2D unit.
The reason why it is important to keep true to the Box2D unit is the following. If you drop a marble on the ground it seems to be moving faster then the sun in the sky. But believe me, the sun is moving a lot faster but since it is a lot further away it seems to move slowly. Since Box2D is all about movement you should keep true to the unit or things will start to act strange.
Let's just use 1 unit == 1m for now and suddenly everything should become a lot simpler by asking a view questions.
how much of your game world do you want to show in meters?
float width = 20; // 20 meters
//You can calculate on your chosen width or height to maintain aspect ratio
float height = (Gdx.graphics.getHeight() / Gdx.graphics.getWidth()) * width;
camera = new OrthographicCamera(width, height);
//Now the center of the camera is on 0,0 in the game world. It's often more desired and practical to have it's bottom left corner start out on 0,0
//All we need to do is translate it by half it's width and height since that is the offset from it's center point (and that is currently set to 0,0.
camera.translate(camera.viewportWidth / 2, camera.viewportHeight / 2, 0);
camera.update();
How large is our object? Keep in mind that mass, weight and size are completely different things.
Sprite mySprite = new Sprite(myTexture);
//position it somewhere within the bounds of the camera, in the below case the center
//This sprite also gets a size of 1m by 1m
mySprite.setBounds(width / 2, height / 2, 1, 1);
How do we want the SpriteBatch to draw to the screen?
//We tell the SpriteBatch to use out camera settings to draw
spriteBatch.setProjectionMatrix(camera.combined);
//And draw the sprite using this SpriteBatch
mySprite.draw(spriteBatch);
Same counts for the Box2dDebugRenderer implemenation. If you want shapes to show you need to use that combined matrix from your camera again to draw it.
box2DDebugRenderer.render(world, camera.combined);
Of course, when things move around you need to update your sprite position accordingly. You can get this information from the box2d.Body object. But this is beyond the scope of your question.
To finally show you what is going wrong:
camera.setToOrtho(false, V_WIDTH / PPM, V_HEIGHT / PPM);
Your camera shows 320/100 == 3.2f x 480/100 == 4.8f of your game world. Your sprite might be 64x64 pixels. You are not telling anywhere at what size to draw your sprite so it will assume 1 pixel = 1 unit and you set your camera to show 3.2f units in width. We can and should leave pixels out of the equation and just ask what size you want your object to be. Then set the Sprite to that size. Here you see that thinking in pixels just gives you problems.
For a space game where you fly a ship of 100x20 meters in 3th person you probably want your camera viewport to be very large. But for a ant game where your ants are real size you want a very small camera viewport. Do think about physics in real life. Galileo Galilei discovered that objects fall at the same speed, disregarding resistance. So if that ant would drop a sand grain it would look like it would fall very fast because your screen represents much less meters.
For a implementation of a dropping soccer ball look at my answer here. It creates a box2D body and attaches a image to it. I keep the functionality of the ball encapsulated within the Ball() class. (disclaimer: I have just played around a bit with Box2D and I don't know the exact physical behaviors of a soccer ball so I am not stating this is a correct implementation, but it does show how to setup your scene and have a image represent your Box2D body).

Confilicting behavior between dynamic and static bodies in Box2d

I have created Chain shapes (static bodies) all around the perimeter of the game screen whose dimensions are:
(2f*camera.viewportWidth,2f*camera.viewportHeight).
Each chain shape has a density of 5f.
I've also created a Circle Shape (dynamic body) whose
density = 0.5f
friction = 0.25f
restitution =0.2f.
In addition, I've created a polygon shape set as a box shape (dynamic body) which has the same density, restitution and friction as the circle shape.
The world's gravity is (0,-5.8f).
All shapes render appropriately. However, the box shape just keeps falling right through the bottom chain shape which is located at the bottom of the screen. The circle shape doesn't go through, but the box shape does go through. I don't want this to happen. The size of the box shape is
(1.96f*camera.viewportWidth, 1.96f*camera.viewportHeight).
The position of this body(box shape) is set to
(0.02f*camera.viewportWidth, 0.02f*camera.viewportHeight).
I don't know why the box shape just keeps falling through and is not stopped by the bottom chain shape, just like the circle shape is stopped. Can anyone provide any insight?
Also, the reason I am trying to set up my box2d world like this is to eliminate some camera lagging movement when I use camera.translate to move around the world. My idea is to move the box shape by applying linear velocities to its body. Please any thoughts would be appreciated.
You probably did not set filtering on those fixtures. Take a look at the following example
FixtureDef f = new FixtureDef();
f.density = density;
f.friction = friction;
f.restitution = restitution;
now if you want Box2D to handle collisions for you, you should tell it which fiture will collide with which and you are doing it by assigning categoryBits and maskBits like this:
f.filter.categoryBits = categoryBits; //who am I?
f.filter.maskBits = maskBits; //with who I will collide?
Bits should be short type and power of two - you cannot have two bits defined as same value. You can set many maskBits by using logical sum ('|' operator).
public static final short BIT_F1 = 2;
public static final short BIT_F2 = 8;
public static final short BIT_F3 = 32;
FixtureDef f1, f2, f3;
//creating f1, f2, f3...
f1.filter.categoryBits = BIT_F1;
f2.filter.categoryBits = BIT_F2;
f3.filter.categoryBits = BIT_F3;
f1.filter.maskBits = BIT_F1; //now every body having f1 fixture will collide with another f1
f2.filter.maskBits = BIT_F1; //f2 will collide with f1
f3.filter.maskBits = (short)(BIT_F1 | BIT_F2 | BIT_F3); //f3 collides with everything
Please notice that if you want fixture to avoid any collision you can it to be a sensor like:
f.isSensor = sensor;
Here is link to official documentation although it is not very helpful to be honest.

Box2D stopping a dynamic body from moving after collision

I am trying to re-create Pong using LibGDX and Box2D. I have 2 problems, if I fix one it creates another.
My paddles are currently set to Kinematic and are controlled using the up/down keys via a controller class. This works just fine and I can happily play back and forth.
Problem being, my walls are static bodies and my paddles just travel right through them.
Now I can fix this by simple changing the paddle body to a dynamic one, this stops the paddles from going through the walls but then when my ball strikes off a paddle, it goes flying off the X axis and off the screen.
I have tried adding an update method in my controller class as follows:
public void update(float delta){
paddleBodyPosY = paddleBody.getPosition().x;
paddleBodyPosY = paddleBody.getPosition().y;
System.out.println(paddleBodyPosY);
}
The console reports the paddle position being updated every frame, from top to bottom of screen.
So I went back to my GameScreen class and tried all sorts of code in the Render() method like so:
if(playerOnePaddle.paddleBodyPosY < 0){
playerOnePaddle.paddleBody.getPosition().y = 0;
System.out.println("resetting paddle");
}
I have tried LOADS of variations, I can easily break movement by calling paddleBody.setLinearVelocity(0,0) but then it gets stuck like this and it's not movable anymore. Obviously the problem must lie with the fact that I can't set a position using a getter lol.
Any ideas? If you need more snippets ask, I didn't want to overload the question with 100 lines of code you don't need to see :S.
The paddle creation method:
public void createPaddle(World world, float x, float y){
//Define a body for the paddle
BodyDef paddleBodyDef = new BodyDef();
paddleBodyDef.type = BodyType.KinematicBody;
paddleBodyDef.position.set(x, y);
//Define a shape for the paddle
PolygonShape paddleShape = new PolygonShape();
paddleShape.setAsBox(paddleWidth, paddleHeight);
//Define a fixture for the paddle
FixtureDef paddleFixtureDef = new FixtureDef();
paddleFixtureDef.shape = paddleShape;
paddleFixtureDef.density = 0;
//Ensures ball bounces off paddle
//Consistently without losing velocity
paddleFixtureDef.restitution = 1.005f;
//Create the paddles
paddleBody = world.createBody(paddleBodyDef);
paddleFixture = paddleBody.createFixture(paddleFixtureDef);
paddleShape.dispose();
}
Heh, so what I did was.
Set my paddles to dynamic, then set there mass to a stupidly high number so that the a ball would not move them on the x axis, well not enough for the human eye to see at least.
Seems like a cheap fix, if anyone has anything better...that would be great lol

Box2D static body collision performance issue

I'm using JBox2d to perform collision detection in a game project I'm working on.
I represent obstacles in the world with static bodies. Whenever a dynamic body (i.e. a game character) collides with one of these obstacles, there is a very noticeable drop in performance. Fps will drop from ~120 to ~5. This seems to happen more frequently when the corners of the static body are collided with.
When I set the body type of the world obstacles to be dynamic instead of static, with very high density(to prevent the body from moving when it is collided with), this issue disappears... This solution is not ideal for my situation however......
Any ideas as to what could be causing this huge fps drop?
Here's the code I use to create the static bodies:
BodyDef def = new BodyDef();
def.type = BodyType.STATIC; // If this line is commented and the other
//commented lines are uncommented, the issue goes away.
//def.type = BodyType.DYNAMIC;
def.position.set(worldBounds.getCenterX(), worldBounds.getCenterY());
Body staticBody = b2World.createBody(def);
PolygonShape box = new PolygonShape();
box.setAsBox(worldBounds.getWidth() * 0.5f, worldBounds.getHeight() * 0.5f);
FixtureDef fixture = new FixtureDef();
fixture.shape = box;
fixture.friction = 0.3f;
//fixture.density = 1000000000;
staticBody.createFixture(fixture);
//staticBody.setSleepingAllowed(true);
//staticBody.setFixedRotation(true);
I've tried using a CircleShape instead of a PolygonShape, but that doesn't help anything.
Thank you!
this is the code from the game im working on at the moment which works fine. hopefully if you copy and paste, change a few variable names and stuff it might sort your problem. im new to box2d so cant tell you exactly where the problem lies. hope it helps.
//bodydef
BodyDef bodyDef = new BodyDef();
bodyDef.type = BodyType.StaticBody;
bodyDef.position.set(position);
body = world.createBody(bodyDef);
//shape
PolygonShape shape = new PolygonShape();
shape.setAsBox(dimension.x / 2, dimension.y / 2);
//fixture
FixtureDef fixture = new FixtureDef();
fixture.friction = 0.3f;
fixture.shape = shape;
body.createFixture(fixture);
shape.dispose();

Categories