Box2d setAngularVelocity do not work for high speeds - java

I am using Box2d for a game, and although I use large constants to set angular velocity, the fastest speed I can get is 1 revolution at 3.86 seconds.
I had checked my source code in the following thread and everything is the same with what I have been suggested from both users in here and in tutorials:
setAngularVelocity rotates really slowly
However than I noticed the following unresolved thread:
http://www.reddit.com/r/libgdx/comments/1qr2m3/the_strangest_libgdxbox2d_behaviour/
and noticed that might actually be the problem. Here is my dispose method
public void dispose() {
//Get Rid of Everything!
Assets.Clear();
GameEngine.Clear();
BallMap.clear();
PlayerMap.clear();
shapeRenderer.dispose();
debugRenderer.dispose();
world.dispose();
batch.dispose();
font.dispose();
}
They are all reinitialized on the beginning as follows:
this.game = game;
this.cameraWidth = cameraWidth*pixelRatio;
this.cameraHeight = cameraHeight*pixelRatio;
batch = new SpriteBatch();
shapeRenderer = new ShapeRenderer();
stateTime = 0F;
Scores = new Integer[]{0, 0};
debugRenderer = new Box2DDebugRenderer();
world = new World(new Vector2(0, 0), true); //Create a world with no gravity
GameEngine.setContactListener(world);
I navigate through screens with the following code:
public void create () {
scene_menu = new MainMenuScreen(this, cameraWidth, cameraHeight);
setScreen(scene_menu);
}
public void swtogame(){
scene_menu.dispose();
scene_game = new MatchScreen(this, cameraWidth, cameraHeight);
setScreen(scene_game);
}
public void swtomenu(){
scene_game.dispose();
scene_menu = new MainMenuScreen(this, cameraWidth, cameraHeight);
setScreen(scene_menu);
}
the way i initialize objects:
public Object(World world, short category, short mask, float x, float y, float radius, Sprite image,
float maxSpeed, float frictionStrength, float linearDamping, float angularDamping, boolean movable,
float elasticity, float mass){
this.world = world;
this.category = category;
this.mask = mask;
// We set our body type
this.bodyDef = new BodyDef();
if(movable==true){bodyDef.type = BodyType.DynamicBody;}else{bodyDef.type = BodyType.StaticBody;}
// Set body's starting position in the world
bodyDef.position.set(x, y);
bodyDef.linearDamping = linearDamping;
bodyDef.angularDamping = angularDamping;
// Create our body in the world using our body definition
this.body = world.createBody(bodyDef);
// Create a circle shape and set its radius
CircleShape circle = new CircleShape();
circle.setRadius(radius);
// Create a fixture definition to apply our shape to
fixtureDef = new FixtureDef();
fixtureDef.shape = circle;
fixtureDef.density = (float) (mass/(Math.PI*radius*radius));
fixtureDef.friction = frictionStrength;
fixtureDef.restitution = elasticity;
fixtureDef.filter.categoryBits = category;
fixtureDef.filter.maskBits = mask;
// Create our fixture and attach it to the body
this.fixture = body.createFixture(fixtureDef);
// BodyDef and FixtureDef don't need disposing, but shapes do.
circle.dispose();
... unrelated functions after that
}
Am I disposing correctly? Is this a bug? Is there any way to get around it and use the setAngularVelocity properly?

Because you haven't shown much code, I can I'm not 100% sure that I'm right, but I think that you are hitting the built in maximum movement limit of 2.0 units per time step. This means that at a typical framerate of 60Hz a body covering 2 units per timestep is moving at 120 m/s or 432 km/h (270 mph). Unfortunately it seems that there is no direct way to change this limit in Java, because this limit seems to be defined in the native C++ librarys.
But I think that the real problem is that you have a wrong scale. Box2D uses MKS (meters, kilograms, and seconds). And you may have used pixels instead of meters. The FAQ of Box2D suggests to use
objects [that are] between 0.1 - 10 meters
otherwise you can get strange situations.
See http://www.iforce2d.net/b2dtut/gotchas#speedlimit
and https://code.google.com/p/box2d/wiki/FAQ

I just found the problem, and it was pretty simple. Im just going to post this here for future googlers:
Object was actually rotating properly, the problem was in my drawing method, I didn't use conversion between radians to degrees in my batch.draw, and it interpreted everything in radians. I know such an amateur mistake! Thanks a lot for your time.

Related

Box2D. Trying to understand how much force is needed

I'm trying to understand the amount of force i need to move my object. This is how my world is setup and the physics step is done
private void setupWorld() {
mWorld = new World(new Vector2(0f, -9.8f), true);
BodyDef bodyDef = new BodyDef();
bodyDef.type = BodyDef.BodyType.DynamicBody;
bodyDef.position.set(x, y);
body = world.createBody(bodyDef);
PolygonShape box=new PolygonShape();
box.setAsBox(1,1);
FixtureDef fixtureDef = new FixtureDef();
fixtureDef.shape = box;
fixtureDef.density = 1f;
fixtureDef.friction = 0.0f;
fixtureDef.restitution = 0.0f;
Fixture fixture = body.createFixture(fixtureDef);
box.dispose();
}
private void doPhysicsStep(float deltaTime) {
float frameTime = Math.min(deltaTime, 0.25f);
accumulator += frameTime;
while (accumulator >= TIME_STEP) {
body.applyForceToCenter(new Vector2(0, 10f), true);
world.step(TIME_STEP, VELOCITY_ITERATIONS, POSITION_ITERATIONS);
accumulator -= (TIME_STEP);
}
}
So i've got a 1x1 box with a density 1. Gravity is set at -9.8 and i'm expecting that when I apply an amount of force to my box that is greater than the gravity (in this example i've set it to 10) that the box should start moving up.
But the box doesn't move. I have to set the force to about 80 (i.e. body.applyForceToCenter(new Vector2(0, 80f), true);) before it starts to move the box.
I've considered that this is due to my time step (which i've currently set to 1/60f), but if anything taking that into account would reduce the force I'm applying in each step.
Can someone explain what i'm miscalculating here?
Your box has a mass of 4, not 1, because in method setAsBox(float hx, float hy) hx means half of desired width, and hy means half of desired height. So if you want to have a box 1 x 1 you will call setAsBox(0.5F, 0.5F).
But this doesn't explain why you need a force of 80 to move it, because force of 50 should be enough to make a difference.
Fg = m * g = 9.8 * 4 = 39.2
On my test project on object of mass 4 even the force of 40 is noticeable when applied programmatically (the delay of application start and pressing the button is significant so I avoid it).

LibGDX Box2D: Cannot get Fixture to render

I have been recently trying to get back into LibGDX's version of Box2D, and I looked back at a demo I created a few months back, and my code looks fine, and from my Google search results, my code is fine, but for the life of me, I cannot get the Fixture to render.
Here is my (Minimalist example) code, and for the life of me, I cannot get it to work Note: I built a wrapper around the LibGDX Game class, should be self-explanatory:
public class TestBox2D extends EGGame {
int width;
int height;
static final Vector2 ZERO_GRAVITY = new Vector2(0f, 0f);
OrthographicCamera camera;
World world;
Body body;
Box2DDebugRenderer box2dDebugRenderer;
RayHandler rayHandler;
... // Removed Constructor, nothing special here.
#Override
protected void init() {
width = Gdx.graphics.getWidth() / 2;
height = Gdx.graphics.getHeight() / 2;
camera = new OrthographicCamera(width, height);
camera.position.set(width / 2, height / 2, 0);
camera.update();
world = new World(ZERO_GRAVITY, true);
box2dDebugRenderer = new Box2DDebugRenderer();
rayHandler = new RayHandler(world);
rayHandler.setCombinedMatrix(camera.combined);
// creating Body
BodyDef bodyDef = new BodyDef();
bodyDef.type = BodyDef.BodyType.StaticBody;
bodyDef.position.set(width/2, height/2);
body = world.createBody(bodyDef);
CircleShape shape = new CircleShape();
shape.setRadius(1f);
FixtureDef fixtureDef = new FixtureDef();
fixtureDef.shape = shape;
body.createFixture(fixtureDef);
}
#Override
protected void updateGame() {
world.step(1f / 30f, 6, 2);
rayHandler.update();
}
#Override
protected void renderGame() {
box2dDebugRenderer.render(world, camera.combined);
rayHandler.render();
}
#Override
public void dispose() {
world.dispose();
}
... // Removed main method, nothing special here.
}
Note that world.getBodyCount(); and world.getFixtureCount(); both return 1.
Probable causes of problem.
Check if you have called render on fixtures in either RayHandler class or Box2DDebugRenderer class.
You have not set the position of the circle shape. It might be lying on the edge and remain out of camera bounds.
Check your units. Radius of circle might be relatively so small that it would be invisible, or it might be so large that it might be covering entire screen.
Hope this helps.
You can try the following, one of the things mention Tanmay Patil, it resizes body:
Example:
Varible Class:
long time = 0;
float testSize = 0;
Call in your render method:
time += System.nanoTime();
if (time >= 100000000){
time = 0;
testSize += (0.1f);
body.getFixtureList().first().getShape().setRadius(testSize);
}
if not notice any change, try the opposite:
time += System.nanoTime();
if (time >= 100000000){
time = 0;
testSize -= (0.1f);
body.getFixtureList().first().getShape().setRadius(testSize);
}
Edit:
On the other hand, this does not affect the question, but you can call dispose here if you want:
.////////////
CircleShape shape = new CircleShape();
shape.setRadius(1f);
FixtureDef fixtureDef = new FixtureDef();
fixtureDef.shape = shape;
body.createFixture(fixtureDef);
shape.dispose();
}
Fixed.
The issue was that I was attempting to call RayHandler#render() after Box2DDebugRenderer.render(...) while the RayHandler didn't have any Light objects (Adding a PointLight allowed it to render), but whatever the reason for it is, it's weird, but calling the RayHandler#render() first allows it to work. This might be a bug in LibGDX that I will report.

LibGDX Box2D player is stumbling

I'm trying to program a simple 2D platformer, and I want the player to go over some platforms. Unfortunately, my player stumbles after some platforms for no reason:
And that's clearly not what I want. The only thing I can imagine is that the boxes aren't the same height for some reason... But how to fix that? Here's some of my code:
createPlatform...
public static Body createPlatform(World world, int x, int y) {
BodyDef bodyDef = new BodyDef();
bodyDef.type = BodyDef.BodyType.StaticBody;
bodyDef.position.set(new Vector2(x, y));
PolygonShape shape = new PolygonShape();
shape.setAsBox(1, 1);
Body body = world.createBody(bodyDef);
body.createFixture(shape, Constants.GROUND_DENSITY);
body.resetMassData();
PlatformUserData userData = new PlatformUserData(1, 1, Constants.GROUND_IMAGE_PATH);
body.setUserData(userData);
shape.dispose();
return body;
}
Runner.java - act()
#Override
public void act(float delta) {
super.act(delta);
body.setLinearVelocity(new Vector2(10f,0));
}
When you have the ground made of multiple sections, the collision detection framework might detect the edge of the next block, like it was a little bit highrt than the previous. This is a computation error which happens with every sliding object sometimes. This is why they often set the player's shape to be an ellipse, and freeze the rotation of the object.
The problem is that the player fictions against the ground so velocity is greater than the friction support so the body stumbs.
You have to put:
body.setFixedRotation(true);
Or go down the value of the friction.

Drawing rotated bodies using JBox2D and JavaFX

I'm doing some initial experiments for a CS course, where I'm trying to use JBox2D as a physics library and drawing using JavaFX. I have had some luck draw circles that fall from the top of the screen, but now I have issues doing the same with rectangles (or any other shape).
I'm able to both draw and simulate, but I cannot figure out how to rotate the drawn nodes in JavaFX using values from the Body objects.
Here's my code for the bodies using JBox2D:
#Override
public Body createBody() {
BodyDef bd = new BodyDef();
bd.type = BodyType.DYNAMIC;
bd.position.set(centerX, centerY);
PolygonShape ps = new PolygonShape();
ps.setAsBox(2.0f,4.0f);
FixtureDef fd = new FixtureDef();
fd.shape = ps;
fd.density = 0.9f;
fd.friction = 0.3f;
fd.restitution = 0.5f;
Body b = PhysicalScene.world.createBody(bd);
b.createFixture(fd);
return b;
}
}
This is drawn using nodes in JavaFX - as written here:
#Override
public Node create() {
Rectangle r = new Rectangle();
r.setHeight(20);
r.setWidth(40);
r.setStroke(Color.RED);
r.setLayoutX(Physics.toPixelX(centerX));
r.setLayoutY(Physics.toPixelY(centerY));
// THIS IS WHAT I'M MISSING
// r.setRotate(/* some value from Body */);
return r;
}
The code isn't pretty, but I hope you get the idea. I am able to rotate the nodes by inserting arguments in the method, but do not know how to get these values from the Body objects themselves.
I hope you can help, thanks!

Shaky unstable JBox2D bodies

Edit 2: http://youtu.be/KiCzUZ69gpA - as you can see in this video, the shaking effect is amplified when I also render some text for each body. Observe how the ground body (blue) shakes violently when each body has some text rendered near it, and how it does not when text rendering is commented out. This has to be connected!
Edit: I've made two important additions to the original question: I've added my rendering functions, and the camera (translation) methods, and I think that the error is actually there, not in JBox2D.
I'm trying to simulate and render a lot of random bodies (2-20) connected with RevoluteJoints. One body can be connected to multiple others, and there are no separate constructions, i.e. all the bodies are interconnected.
However, when watching the live rendering, it is very shaky and unstable. By that I mean that bodies' positions (or maybe angles) seem to be randomly fluctuating for no apparent reason, making the simulation look unstable.
Here's a video of what I'm observing:
http://youtu.be/xql-ypso1ZU
Notice the middle square and the rotating rectangle. The middle square is shifting its position back and forth slightly at seemingly random intervals, and the rotating rectangle is very jittery (take a look at the point it is rotating about).
What could this effect be due? Is it some known issue with (J)Box2D, or is it an issue with my rendering system? I think that I have somehow misconfigured the physics engine, but also some floating point math in the rendering system could be the culprit.
Here's how I'm creating the bodies and the joints:
private Body setPart(Part part) {
// body definition
BodyDef bd = new BodyDef();
bd.position.set(0f, -10f);
bd.angle = 0f;
bd.type = BodyType.DYNAMIC;
// define shape of the body.
PolygonShape Shape = new PolygonShape();
Shape.setAsBox(part.width / 2, part.height / 2);
// define fixture of the body.
FixtureDef fd = new FixtureDef();
Filter filter = new Filter();
filter.groupIndex = -1;
fd.filter = filter;
fd.shape = Shape;
fd.density = 0.5f;
fd.friction = 0.3f;
fd.restitution = 0.5f;
// create the body and add fixture to it
Body body = world.createBody(bd);
body.createFixture(fd);
body.setUserData(new PartUserData());
return body;
}
private void setJoint(PartJoint partJoint) {
Body bodyOne = partToBody.get(partJoint.partOne);
Body bodyTwo = partToBody.get(partJoint.partTwo);
RevoluteJointDef jointDef = new RevoluteJointDef();
jointDef.bodyA = bodyOne;
jointDef.bodyB = bodyTwo;
jointDef.localAnchorA = partJoint.partOne
.getAnchor(partJoint.percentOne);
jointDef.localAnchorB = partJoint.partTwo
.getAnchor(partJoint.percentTwo);
// rotation
jointDef.lowerAngle = GeomUtil.circle(partJoint.rotateFrom);
jointDef.upperAngle = GeomUtil.circle(partJoint.rotateTo);
jointDef.enableLimit = true;
jointDef.maxMotorTorque = 10.0f; // TODO limit maximum torque
jointDef.motorSpeed = GeomUtil.circle(partJoint.angularVelocity);
jointDef.enableMotor = true;
world.createJoint(jointDef);
}
The time step is 0.01f.
Here is how I draw bodies:
private void drawBody(Body body) {
// setup the transforms
Vector position = camera.translate(body.getPosition());
currentGraphics.translate(position.x, position.y);
currentGraphics.rotate(body.getAngle());
// do the actual rendering
for (Fixture fixture = body.getFixtureList(); fixture != null; fixture = fixture
.getNext()) {
PolygonShape shape = (PolygonShape) fixture.getShape();
if (body.getUserData() instanceof PartUserData) {
fillShape(shape, partFillColor);
currentGraphics.setStroke(partOutlineStroke);
outlineShape(shape, partOutlineColor);
} else {
fillShape(shape, groundFillColor);
outlineShape(shape, groundOutlineColor);
}
}
// clean up
currentGraphics.rotate(-body.getAngle());
currentGraphics.translate(-position.x, -position.y);
currentGraphics.setColor(defaultColor);
currentGraphics.setStroke(defaultStroke);
}
I think that the issue might be the way I'm handling rendering of all the bodies.
This is the algorithm for each body:
1. Translate the Graphics2D object to its position
2. Rotate it by body.getAngle()
3. Render the body
4. Rotate the graphics back
5. Translate the graphics back
Could it be that amongst all these transforms something goes wrong?
When I removed the calls to camera's methods, the effect seems to have been reduced. These are the relevant camera methods:
public Vector translate(Vec2 worldPosition) {
Vector point = new Vector();
point.x = (int) (worldPosition.x * pixelsPerMeter) - position.x;
point.y = (int) (worldPosition.y * pixelsPerMeter) - position.y;
point.x = (int) (point.x * zoom);
point.y = (int) (point.y * zoom);
point.x += renderer.getWidth() / 2;
point.y += renderer.getHeight() / 2;
return point;
}
public Vector translateRelative(Vec2 worldPosition) {
Vector point = new Vector();
point.x = (int) (worldPosition.x * pixelsPerMeter);
point.y = (int) (worldPosition.y * pixelsPerMeter);
point.x = (int) (point.x * zoom);
point.y = (int) (point.y * zoom);
return point;
}
But what part of them would cause an issue?
tl;dr: I've found a solution, but haven't identified the exact problem. Quite sure it's with my translation methods.
It seems that I have identified the scope of the problem and the solution, but I am still not sure what exactly is causing this behavior.
In those translation formulas I posted in the question, all JBox2D vectors are multiplied by a scale called pixelsPerMeter. When I set this scale to a low value, the shaking effect occurs (it's also important to note that there is another factor as well, called zoom, which is usually greater for a lower pixelsPerMeter).
So, it could be that when multiplying by a relatively low pixelsPerMeter, I have to multiply with a higher zoom factor, and since I'm converting to ints in both steps, there could be some errors in the floating point math or something. Please see the translation methods I've posted in the question.
Here's a video that demonstrates this: (to be uploaded)
Notice that when I set the pixelsPerMeter to 250, shaking seems to be gone, while when I set it to 25, it's quite visible.
Your solution was the correct one. You are not supposed to use pixel units for the Box2D physics engine :)
http://box2d.org/2011/12/pixels/
and
https://code.google.com/p/box2d/wiki/FAQ#How_do_I_convert_pixels_to_meters?

Categories