How to get a Box2D Polygon's coordinates? - java

I have a body with just one fixture attached to it. The shape attached to the fixture is a PolygonShape. For rendering the body, I need access to its vertices' coordinates.
This is what I tried:
Vector2 tmpVector = new Vector2();
Fixture f = body.getFixtureList().get(0);
PolygonShape shape = (PolygonShape)f.getShape();
shape.getVertex(3, tmpVector);
shape.getVertex(2, tmpVector);
shape.getVertex(1, tmpVector);
shape.getVertex(0, tmpVector);
It works when the body is not in contact with other bodies.
The problem is that when the body collides with another body, getFixtureList returns more than one fixture and this includes those from other bodies.
How do I solve this problem?
All I need to be able to do is access the vertices' positions of the polygon body on the fly.

You can check if the fixture's body is equal to body with the getBody() method:
Vector2 tmpVector = new Vector2();
Fixture f = body.getFixtureList().get(0);
while (f.getBody() != body)
{
f = f.getNext();
}
if (f != null)
{
PolygonShape shape = (PolygonShape)f.getShape();
// get vertices
}
Of course this work only if you know that body has exactly one fixture with a polygon shape, as it is said in the question. Otherwise you might consider using the userData attribute to store information about the different fixtures.

Related

Libgdx ,can i attach animation in a Body?

im kinda new here, anywho... i am interested in the android gaming app development and i am learning on my own how to do so, using Libgdx as my game-engine and already made a small game not something exciting.
i have recently started to learn how to use the World variable and creating bodies in it, i want to create a class that extends Actor, give it animations (i know how to give animations) and to try and display it on the body, so where ever the body goes, the animation is played on it (basically below the animation is the body that is not displayed ofc)
so my question is : is there a way to give this costume actor into the body so it will play it over the body? (attaching them)
Will appreciate the help!
** NOTE : be aware that my knowledge is still limited, i am a college student for Program Engineering and i am not fully into much depth in java yet (my college not teaching game-engines) **
UPDATE
i have created a costume class, made animations to each action (like herowalk, herosit ... etc...)
i wrote a render method in it :
public void render(SpriteBatch batch) {
float posX = bbody.getPosition().x * PPM;
float posY = bbody.getPosition().y * PPM;
float rotation = (float) Math.toDegrees(bbody.getAngle());
sprite.setPosition(posX,posY);
sprite.setRotation(rotation);
sprite.draw(batch);
}
and created a body, placed it in the middle of my screen and attached the sprite to it using SetUserData() :
BodyDef bdef = new BodyDef();
bdef.position.set(160 / PPM, 200 / PPM);
bdef.type = BodyDef.BodyType.DynamicBody;
PolygonShape shape = new PolygonShape();
shape.setAsBox(5 / PPM, 5 / PPM);
bbody = world.createBody(bdef);
Bodyarray.add(bbody);
FixtureDef fdef = new FixtureDef();
fdef.shape = shape;
fdef.filter.categoryBits = BIT_BOX;
fdef.filter.maskBits = BIT_PLATFORM | BIT_BALL;
bbody.createFixture(fdef);
bbody.setUserData(sprite);
and in my main class where i draw with batch i wrote :
player.sprite.setRegion(player.getAnimationup().getKeyFrame(dt, true));
dt += elapsedTime;
player.render(batch);
to constantly change the animations depends on if the player turns to the right, left, up , down.
the only problem i have is that the sprite it self (the animation works perfectly) is being drawn on the bottom left side of the screen (not on 0,0, it looks like it got the x,y of the body but still away from it) and can see that its attached to it when moving the body (i put controls to control the body movement) and i see the sprite moving with it.
for example im trying to check the coordination of X,Y for both the body and the sprite with Gdx.app.log as usual and both have the SAME exact X and Y. (ofc the sprite has his multiplied by PPM (placed it as 100) since the sprite is not a physical body)
what is causing the wrong location of the sprite?
Welcome to Stack Overflow!
The answer to your question is "Not exactly." Box2D gives you a method called Body#setUserData() which lets you create a reference from the Body to any object (in this case an Animation object, but it is up to you to keep their positions in sync. See the pseudo-code below adapted from the libGDX wiki:
// Create an array to be filled with the bodies
// (better don't create a new one every time though)
Array<Body> bodies = new Array<Body>();
// Now fill the array with all bodies
world.getBodies(bodies);
for (Body b : bodies) {
// Get the body's user data - in this example, our user
// data is an instance of the Entity class
Animation anim = (Animation) b.getUserData();
if (anim != null) {
// Update the entities/sprites position and angle
TextureRegion frame = anim.getKeyFrame( ... );
// Now draw the frame using b.getPosition() and b.getAngle()
}
}
By the way, the libGDX wiki is an excellent resource and reference as you start learning libGDX.

Touch event on a specific area of a box2d body

I have these box2d bodies. I want to check for touch events on the bodies. To be specific, touch on a certain area of the body. Please see the image below, within the body, how can I check if the user touched on the blue area of the body (upper right corner).
I can get the touch coordinates, convert it to world coordinates and check if they overlap with that of the box, but that will trigger even if the box is touched anywhere inside it.
Maybe its too late but i will answer your question for who needs help.
You should create a fixture for the body which defines body's edges and attributes. Than you need to add fixtures to the body as sensor. Code sample would be seems like this.
// create bodydef
BodyDef bdef = new BodyDef();
bdef.type = BodyType.DynamicBody;
bdef.position.set(60 / PPM, 120 / PPM);
bdef.fixedRotation = true;
bdef.linearVelocity.set(1f, 0f);
// create body from bodydef
Body body = world.createBody(bdef);
// create box shape for player collision box
PolygonShape shape = new PolygonShape();
shape.setAsBox(13 / PPM, 13 / PPM);
// create fixturedef for player collision box
FixtureDef fdef = new FixtureDef();
fdef.shape = shape;
fdef.density = 1;
fdef.friction = 0;
// create player collision box fixture
body.createFixture(fdef);
shape.dispose();
// create box shape SENSOR for player
shape = new PolygonShape();
shape.setAsBox(13 / PPM, 3 / PPM, new Vector2(0, -13 / PPM), 0);
// create fixturedef SENSOR for player
fdef.shape = shape;
fdef.isSensor = true;
// create player SENSOR fixture
body.createFixture(fdef).setUserData("SENSOR");;
Have a nice day.
The Body itself has nothing common with Libgdx Input/Output operations - this is what is important to understand. Libgdx is handling touching and gestures by
Listeners mechanism - for example InputListener
Scene2d built-in framework
Then you cannot bind body instance to the listener however you can do this with whole screen (and then calculate somehow if coordinates are in body bounds - then if yes in which part exactly) or you can do this by creating a Scene2d actor instance.
If I were you I would create an Actor (for example rectangle shape) with size of part of body you want to be "touchable". The actor should has attached ClickListener with method that you want to fire on touch. Then in the actor's act() method I would update actor position due to the body position.

How to create a body with Polygon and Rectangle attached together in Libgdx

I am a newbie in Libgdx. I am working on detecting collisions for two bodies. Have created two bodies using "polygonshape" but unfortunately there isn't any method to detect collision among "PolygonShapes" but for "rectangles" .So I came up with an idea of attaching the rectangle at the front of each of the polygons and then detect collision for rectangles but when I run the code, I don't see any rectangles but only polygons.
Here is my code,
public class Player implements Screen, InputProcessor {
private Body polybody;
private Player player;
private World world;
Array<Rectangle> raindrops;
private Body enemybody;
private Sprite polysprite;
public final float width,height;
private Vector2 movement=new Vector2();
private float speed=580;
public Player(World world,float x,float y,float width)
{
this.width=width; //IMP
height=width*2;
BodyDef polygon=new BodyDef();
polygon.type=BodyType.DynamicBody;
polygon.position.set(x,y); //
PolygonShape poly =new PolygonShape();
poly.setAsBox(width/2,height/2); //
FixtureDef polyfixture=new FixtureDef();
polyfixture.shape=poly;
polyfixture.friction=0.8f; //
polyfixture.restitution=0.1f; //
polyfixture.density=3; //
//creating actual body
polybody=world.createBody(polygon);
polybody.createFixture(polyfixture);
//disposing the body
BodyDef rectangle=new BodyDef();
rectangle.type=BodyType.DynamicBody;
Rectangle rect=new Rectangle();
rect.setWidth(50);
rect.setHeight(50);
rect.setPosition(x, y);
enemybody=world.createBody(rectangle);
polysprite=new Sprite(new Texture("img/car.jpg"));
polysprite.setSize(0.5f, 1);
polysprite.setOrigin(polysprite.getWidth()/2, polysprite.getHeight()/2);
polybody.setUserData(polysprite);
poly.dispose();
}
public void update()
{
polybody.applyForceToCenter(movement, true);
enemybody.applyForceToCenter(movement,true);
}
public Body getBody(){
{
return polybody;
}
}
}
Collision Code:
public Player(World world,float x,float y,float width)
{
this.width=width; //IMP
height=width*2;
BodyDef polygon=new BodyDef();
polygon.type=BodyType.DynamicBody;
polygon.position.set(x,y); //
// polygon.fixedRotation=true;
//polygon shape
//Rectangle poly=new Rectangle();
PolygonShape poly =new PolygonShape();
poly.setAsBox(width/2,height/2); //
//fixture defn
polygon.position.set(5,4);
FixtureDef polyfixture=new FixtureDef();
polyfixture.shape=poly;
polyfixture.friction=0.8f; //
polyfixture.restitution=0.1f; //
polyfixture.density=3; //
//creating actual body
polybody=world.createBody(polygon);
polybody.createFixture(polyfixture);
// polybody.applyAngularImpulse(52, true);
//disposing the body
polysprite=new Sprite(new Texture("img/car.jpg"));
polysprite.setSize(2, 3); //size of mario
polysprite.setOrigin(polysprite.getWidth()/2, polysprite.getHeight()/2);
polybody.setUserData(polysprite);
//2nd body
BodyDef polygons=new BodyDef();
polygons.type=BodyType.DynamicBody;
PolygonShape polys=new PolygonShape();
polys.setAsBox(2,2);
FixtureDef polyxfixture=new FixtureDef();
polyxfixture.shape=polys;
polyxfixture.friction=0.8f;
polyxfixture.restitution=0.1f;
polyxfixture.density=3;
polybodys=world.createBody(polygons);
polybodys.createFixture(polyxfixture);
poly.dispose();
}
#Override
public void beginContact(Contact contact) {
// TODO Auto-generated method stub
Fixture fixtureA=contact.getFixtureA();
Fixture fixtureB=contact.getFixtureB();
System.out.println("collides");
}
This is my code. I have created 2 bodies using "polygonshape" and "rectangle" but rectangle isn't created. I can't find what is the mistake. Please help!! Thanks in advance
It seems like you are a bit confused and you are mixing two absolutely independend things:
Box2D, a physics engine, which does all physic calculations
(including collission detection) for you.
The Rectangle, Polygon and the Intersector class of libgdx.
I try to explain what both of them do and why you can't use them together.
The Polygonshape is part of the Box2D engine. It is used to give a Fixture it's shape, which is then used by the collission detection of Box2D.
You can read something about Box2D here.
The Rectangle class is some kind of "Helperclass" in Libgdx, which let you define a Rectangle, with a given position, width and height. It can be used together with the Intersectorclass, which provides some usefull methods for collission detection and other things.
There is also a class caled Polygon. It is, again, a Libgdx class and can't be mixed with the Box2D PolygonShape. The Libgdx Polygon instead can be used with the Intersector class, which provides a method to check for an overlap between 2 Polygons. Polygons are defined by a float[], giving the position of all it's corner points.
That means, that if you want to use the physics engine Box2D, you need to work with the PolygonShape and other shapes, provided by Box2D.
If you instead don't want to use the physics engine and do the collission detection on your own, you can use Rectangle, Polygon and other shapes from Libgdx and you also can use the Intersector for overlap-testing.
EDIT:
If you take a look at this link, there is a section "Contact Listener". There you can see, that the ContactListener provides the methods beginContact (called when two objects start to collide/overlap) and endContact (called when the contact between the two objects ends).
You need to implement those methods and set it as the worlds ContactListener.
Node, that Box2D automatically handles collisions, by seperating the colliding objects (bounce back). If thats not what you want, you shouldset the isSensor-Flag of your FixtureDef. That way, Box2D will notify you, that there is a collision (beginContact gets called) but won't handle it for you.
EDIT 2:
The Contact object you get in your ContactListener-Methods holds 2 Fixtures: FixtrueA and FixtureB.
Thats because in every contact or collision 2 objects have to be involved, so FixtureA is one of them and FixtureB is the ther one.
The reason, why a Contact contains 2 Fixtures instead of 2 Bodys is the following:
Let's say we have a Player, defined by a Body. This Body contains 2 Fixtures: headFixture, a circle repressenting it's head and bodyFixture, a rectangle, repressenting the hitbox of the Players body and feet.
Now, if a Bullet (a Body with one Fixture) hits our Player, it may make a difference, if it hits its body or its head.
So basicly a Body repressents our whole object, the Player, while the Fixtures repressent some parts of it, which are used for the physics-calculation.
If you only want to handle collissions per Body, you can get the Body by calling fixtureA().getBody().

setAngularVelocity rotates really slowly

I am using the basic libgdx box2d to manage physics operations of a game. Everything is working properly, except the rotations: even when I set
anyobject.body.setAngularVelocity(someLargeConstant);
the object rotates really slowly(and almost at the same speed) no matter what the 'someLargeConstant' is. Except when I use small numbers for parameter, it can rotate slower. Thus I think I somehow have a maximum angular velocity constant inside my world object, which should be set to some small value.
(I also had a similar issue with linear velocity before and I solved it by adjusting the pixels/meter scale. So its unlikely that the problem is a scaling issue.)
How can I enable the objects to rotate faster?
Here is the code I use:
private static World world = new World(new Vector2(0, 0), true); //Create a world with no gravity
to create an object I call another class
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
}
and here I just try to make it rotate fast:
tempBall.body.setAngularVelocity(20000);
angularvilocity is used to set the direction of the rotation when it comes to use it with an actionListener as like key or mouse lister , here is an example of use :
case KeyEvent.VK_RIGHT:
ball.setAngularVelocity(-20); // Directly set the angular velocity
case KeyEvent.VK_LEFT:
ball.setAngularVelocity(20); // Directly set the angular velocity
like you can see here the code make the ball body rotate to the right in Key_Right pressed and to the left in Key_Left pressed , and i can play aroud with it's argument to increase or lower the rotation speed and it works pretty well for me , here is my body definition try to apply the same values and it must work with no problem :
private Body createObject(Shape shape, BodyType type, Vec2 position, float orientation, Sprite sprite) throws InvalidSpriteNameException {
for(Sprite s:spriteList) {
if(s.getName().equals(sprite.getName())) {
throw new InvalidSpriteNameException(sprite.getName()+" already used.");
}
}
Body body = null;
FixtureDef fixDef = new FixtureDef();
fixDef.shape = shape;
fixDef.density = 0.1f;
fixDef.isSensor = false;
fixDef.restitution = 0.1f;
BodyDef bodyDef = new BodyDef();
bodyDef.type = type;
bodyDef.angularDamping = 0.1f;
bodyDef.linearDamping = 0.1f;
bodyDef.fixedRotation = false;
bodyDef.gravityScale = 1f;
bodyDef.linearVelocity = new Vec2(0,0);
bodyDef.angularVelocity = 0;
bodyDef.position = new Vec2(position);
bodyDef.angle = orientation;
bodyDef.allowSleep = true;
spriteList.add(sprite); // Save the sprite to the list (sprites must be serialiazed in the PhysicalWorld)
bodyDef.userData = sprite; // Link the body and the sprite
do {
body = jBox2DWorld.createBody(bodyDef);
} while(body== null); // Wait until the object is really created
sprite.linkToBody(body); // Link the body to the sprite (this link is not serialiazed)
body.createFixture(fixDef);
return body;
}
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.

Box2D - Can't destroy multiple fixtures

I'm using box2d along with libgdx on a project I'm working on. I'm having a slight problem destroying a body/the fixtures of a body. Essentially, I want to completely destroy the body, which I do by destroying the fixtures of said body. Everything works perfectly fine with a body with one fixture, but when I use two fixtures, only one fixture get's destroyed, leaving the body intact with the other fixture.
Here's two pictures to demonstrate what I mean:
With both fixtures:
With only one fixture:
Here is how I create the body:
BodyDef bodyDef = new BodyDef();
bodyDef.type = BodyType.DynamicBody;
bodyDef.position.set(level.character.position);
Body body = b2world.createBody(bodyDef);
body.setUserData(level.character);
level.character.body = body;
CircleShape polygonShapeHead = new CircleShape();
origin.x = level.character.circleBoundOrigin.x * 2.0f;
origin.y = level.character.circleBoundOrigin.y * 3.0f;
//polygonShapeHead.setAsBox(level.character.circleBoundOrigin.x,
//level.character.circleBoundOrigin.y, origin, 0);
polygonShapeHead.setPosition(origin);
polygonShapeHead.setRadius(level.character.circleBoundOrigin.x);
FixtureDef fixtureDefHead = new FixtureDef();
fixtureDefHead.shape = polygonShapeHead;
fixtureDefHead.friction = level.character.friction.x;
body.createFixture(fixtureDefHead);
polygonShapeHead.dispose();
PolygonShape polygonShapeBod = new PolygonShape();
origin = level.character.rectBoundOrigin;
polygonShapeBod.setAsBox(level.character.rectBoundOrigin.x,
level.character.rectBoundOrigin.y, origin, 0);
FixtureDef fixtureDefBod = new FixtureDef();
fixtureDefBod.shape = polygonShapeBod;
fixtureDefBod.friction = level.character.friction.x;
body.createFixture(fixtureDefBod);
polygonShapeBod.dispose();
Here is my code for destroying the bodies:
public static void removeSpecifiedBodies() {
for (Body body : bodiesToRemoveList) {
Array<Fixture> fixtures = body.getFixtureList();
for (Fixture fixture : fixtures) {
body.destroyFixture(fixture);
}
}
bodiesToRemoveList.clear();
}
I call this static method after my b2world is stepped. I checked the logging, and the fixtures size is 2, and it is being run twice, but only one fixture is being destroyed. Why is this happening? And what is being destroyed? It runs twice, but I'm only seeing one of them getting destroyed.
Edit: Instead of using that above remove, method, I added
for(Body body : CollisionHandler.bodiesToRemoveList)
b2world.destroyBody(body);
after b2world.step, but it froze everything. :(
GetFixtureList only returns the first fixture. You need to say
var fix = body.GetFixtureList();
while (fix) {
body.DestroyFixture(fix);
fix = fix.next();
}
I was having the same problem using LibGDX with Box2d.
this way solved the problem:
int fixtureCount = body.getFixtureList().size;
for(int i=0;i<fixtureCount;i++){
body.destroyFixture(body.getFixtureList().get(0));
}
body.destroyFixturewill modify( see line 130) fixtureList. Try this:
while (body.getFixtureList().size > 0) {
body.destroyFixture(body.getFixtureList().first());
}

Categories

Resources