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.
Related
I am trying to make ball bouncing between 4 walls using the JBox2D library in Java. The code above is the code I use to create and the ball in the world.
// Creating the Body Definition
BodyDef bodyDef = new BodyDef();
// Set position to Body Definition
bodyDef.position.set(x, y);
// Setting body type to body definition
bodyDef.type = bodyType;
// Creating CircleShape object
CircleShape circleShape = new CircleShape();
// Setting radius to CircleShape
circleShape.m_radius = radius;
/ /Creating Fixture Definition object
FixtureDef fixtureDef = new FixtureDef();
// Setting circleShape as shape of fixture definition
fixtureDef.shape = circleShape;
// This defines the heaviness of the body with respect to its area
fixtureDef.density = density;
// This defines how bodies slide when they come in contact with each other.
// Friction value can be set between 0 and 1. Lower value means more slippery bodies.
fixtureDef.friction = friction;
// This define how bouncy is the body.
// Restitution values can be set between 0 and 1.
// Here higher value means more bouncy body.
fixtureDef.restitution = restitution;
// "Uploading" the ball into the world
Body body = world.createBody(bodyDef);
// Setting fixtureDef as body's fixture
body.createFixture(fixtureDef);
And this is the code I used to make a wall. For example the right wall.
// Creating the Body Definition
BodyDef bodyDef = new BodyDef();
// Set position to Body Definition
bodyDef.position.set(850f, 0f);
// Setting body type as static
bodyDef.type = BodyType.STATIC;
// Creating CircleShape object
PolygonShape polygonShape = new PolygonShape();
// Set polygon shape as a box
polygonShape.setAsBox(1f - 44,1000);
// Creating Fixture Definition object
FixtureDef fixtureDef = new FixtureDef();
// Setting circleShape as shape of fixture definition
fixtureDef.shape = polygonShape;
fixtureDef.friction = 0f;
// "Uploading" the ball into the world
Body body = world.createBody(bodyDef);
// Setting fixtureDef as body's fixture
body.createFixture(fixtureDef);
The ball starts to move vertically or horizontally when it collides with another body. The circle goes fine until it collides with another body. As some other posts said, I tried setting the ball's friction to 0 but that didn't work for me.
These are the values I use for the ball:
tileFixture.density = 1f;
tileFixture.friction = 1f;
tileFixture.restitution = 10000f;
I found my mistake. The problem is in the value of the restitution. The value is a lot so JBox2D makes move horizontally or vertically. I changed the value of restitution to 1f and now it works great.
I've been looking at some other threads, and despite every thing I have tried, the shapes I have created in box2d are not rendering. It is very bizarre, and I hope that you guys can provide a solution.
public class worldRender {
fighterGame game;
PlayScreen renderGame;
private Viewport gamePort = new StretchViewport(1020 / game.PPM,760 / game.PPM);
World world = new World(new Vector2(0,-10), true);
Box2DDebugRenderer b2dr = new Box2DDebugRenderer();
private OrthographicCamera gameCam = new OrthographicCamera();
BodyDef bDef = new BodyDef();
public Body b2body;
FixtureDef fixtureDef = new FixtureDef();
ShapeRenderer shapeRender;
public worldRender() {
gameCam = new OrthographicCamera(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
gameCam.position.set(1020/2, 760/2, 0);
}
public worldRender(float dt) {
gameCam.update();
world.step(1/60f, 6, 2);
b2dr.render(world, gameCam.combined);
bodyRender();
}
public void bodyRender() {
BodyDef bdef = new BodyDef();
bdef.position.set(0.0f / game.PPM,4.0f / game.PPM);
bdef.type = BodyDef.BodyType.DynamicBody;
b2body = world.createBody(bdef);
FixtureDef fdef = new FixtureDef();
fdef.friction = 0.25f;
CircleShape shape = new CircleShape();
shape.setRadius(5);
fdef.shape = shape;
fdef.density = 1.0f;
b2body.createFixture(fdef);
}
}
I'm going to list off a few solutions because not everything is clear in the snippet:
Are you sure the worldRender() method is being run
If you are using Game and Screen make sure your game render() method calls super() otherwise your Screen render() method will not be run;
As mentioned before is the value of PPM correct/what is it?
Does this draw:
// First we create a body definition
BodyDef bodyDef = new BodyDef();
bodyDef.type = BodyType.StaticBody;
// Set our body's starting position in the world
bodyDef.position.set(50, 50);
// Create our body in the world using our body definition
Body body = world.createBody(bodyDef);
// Create a circle shape and set its radius to 6
CircleShape circle = new CircleShape();
circle.setRadius(10f);
// Create a fixture definition to apply our shape to
FixtureDef fixtureDef = new FixtureDef();
fixtureDef.shape = circle;
// Create our fixture and attach it to the body
Fixture fixture = body.createFixture(fixtureDef);
// Remember to dispose of any shapes after you're done with them!
// BodyDef and FixtureDef don't need disposing, but shapes do.
circle.dispose();
This should draw a circle of radius 10 at x=10,y=10 (make sure those points are in your view port.
I would suggest cleaning up your code a bit, and studying some more tutorials, that will probably solve your problems. But let's give you some hints to get you on the way:
I somehow suspect you are creating a worldRender object every frame. Java is a garbage collected language, doing so will severly impact your performance. Persist as many objects as possible. In my bigger games, i create next to 0 objects each render and game logic tick. Aim for that.
Finally, what will probably solve your problem: the camera you use to render your box2ddebugrenderer ("dbrndr") has screen pixels as units. The dbrndr uses meters as render units. You need to give the dbrndr its own camera in meters. Your current method will draw a 10pixel wide circle at 0 / 4 pixels in the bottom left corner.
Do you create your world with gravity? if yes, the circle instantly falls out of your screen...Yes you do.
You might actually even see your circle for a splitsecond in the lower left corner after starting... given that you render before you do box2d logic.
Please dispose() all objects that you create, otherwise the memory they occupy is not free'd afterwards.
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.
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().
I have a texture of a circle, which gets drawn to a new position when a touch drag occurs. It isn’t set up as a body.
I have made a physics map using Aurelien Ribon's Physics Body Editor Loader GUI to the circle's upper and lower part, and I’d like to draw that mask over the texture’s position, and to its new position when a drag occurs.
How can I do this? In my create method I initialize the variables, the mask gets drawn to the texture’s initial position, but when I move it the mask stays at the circle’s initial position.
Here's my code:
Create() method:
//... rest of the method ommited for clarity
karika = gameWorld.getKarika();
World world = new World(new Vector2(0, 0), false);
Box2DDebugRenderer renderer = new Box2DDebugRenderer();
BodyEditorLoader karikaLoader = new BodyEditorLoader(Gdx.files.internal("data/collision-masks/karika.json"));
BodyDef karikaDef = new BodyDef();
karikaDef.type = BodyType.DynamicBody;
karikaDef.position.set(karika.getPosition().x, karika.getPosition().y);
karikaDef.angle = karika.getRotation();
Body karikaBody = world.createBody(karikaDef);
FixtureDef karikaFixture = new FixtureDef();
karikaFixture.density = 0.5f;
karikaFixture.friction = 0.8f;
karikaFixture.restitution = 0.6f;
karikaLoader.attachFixture(karikaBody, "karika", karikaFixture, karika.getWidth());
Vector2 karikaBodyOrigin = karikaLoader.getOrigin("karika", karika.getWidth()).cpy();
//rest of the method ommited for clarity
My render() method:
//...
batch.begin();
batch.draw(karikaTexture, karika.getPosition().x, karika.getPosition().y, karika.getWidth() / 2, karika.getHeight() / 2, karika.getWidth(), karika.getHeight(), 1, 1, karika.getRotation(), 0, 0, karikaTexture.getWidth(), karikaTexture.getHeight(), false, false);
batch.end();
renderer.render(world, cam.combined);
world.step(1 / 60f, 6, 2);
//...
The texture that is being drawn in the render method is my circle's texture. As said before, I haven't set that up as a body, only the collision mask.
What I'd like to do, is attach the mask to the texture, and keep up with it's position, for example when I drag the circle, the mask should stay on the circle.
Look into the DebugRenderer. It works very well, and does precisely what you're asking.
Here's how to use it.
debugRenderer.render(this.world, camera.combined);
And here's a more thorough tutorial.
I recommend you assign your circle's position using physics object's position rather than trying to assign the physics object to your texture's position.
In your code, it looks like you create your karikaBody using the current position of karika, but the karikaBody position is never being updated after that. So your "collision mask" (your physics body) position never changes.