Imprecise Box2d coordinates using LibGDX - android

I am using LibGDX and Box2d to build my first Android game. Yay!
But I am having some serious problems with Box2d.
I have a simple stage with a rectangular Box2d body at the bottom representing the ground, and two other rectangular Box2d bodies both at the left and right representing the walls.
A Screenshot
Another Screenshot
I also have a box. This box can be touched and it moves using applyLinearImpulse, like if it was kicked. It is a DynamicBody.
What happens is that in my draw() code of the Box object, the Box2d body of the Box object is giving me a wrong value for the X axis. The value for the Y axis is fine.
Those blue "dots" on the screenshots are small textures that I printed on the box edges that body.getPosition() give me. Note how in one screenshot the dots are aligned with the actual DebugRenderer rectangle and in the other they are not.
This is what is happening: when the box moves, the alignment is lost in the movement.
The collision between the box, the ground and the walls occur precisely considering the area that the DebugRenderer renders. But body.getPosition() and fixture.testPoint() considers that area inside those blue dots.
So, somehow, Box2d is "maintaining" these two areas for the same body.
I thought that this could be some kind of "loss of precision" between my conversions of pixels and meters (I am scaling by 100 times) but the Y axis uses the same technique and it's fine.
So, I thought that I might be missing something.
Edit 1
I am converting from Box coordinates to World coordinates. If you see the blue debug sprites in the screenshots, they form the box almost perfectly.
public static final float WORLD_TO_BOX = 0.01f;
public static final float BOX_TO_WORLD = 100f;
The box render code:
public void draw(Batch batch, float alpha) {
x = (body.getPosition().x - width/2) * TheBox.BOX_TO_WORLD;
y = (body.getPosition().y - height/2) * TheBox.BOX_TO_WORLD;
float xend = (body.getPosition().x + width/2) * TheBox.BOX_TO_WORLD;
float yend = (body.getPosition().y + height/2) * TheBox.BOX_TO_WORLD;
batch.draw(texture, x, y);
batch.draw(texture, x, yend);
batch.draw(texture, xend, yend);
batch.draw(texture, xend, y);
}
Edit 2
I am starting to suspect the camera. I got the DebugRenderer and a scene2d Stage. Here is the code:
My screen resolution (Nexus 5, and it's portrait):
public static final int SCREEN_WIDTH = 1080;
public static final int SCREEN_HEIGHT = 1920;
At the startup:
// ...
stage = new Stage(SCREEN_WIDTH, SCREEN_HEIGHT, true);
camera = new OrthographicCamera();
camera.setToOrtho(false, SCREEN_WIDTH, SCREEN_HEIGHT);
debugMatrix = camera.combined.cpy();
debugMatrix.scale(BOX_TO_WORLD, BOX_TO_WORLD, 1.0f);
debugRenderer = new Box2DDebugRenderer();
// ...
Now, the render() code:
public void render() {
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
camera.update();
world.step(1/45f, 6, 6);
world.clearForces();
stage.act(Gdx.graphics.getDeltaTime());
stage.draw();
debugRenderer.render(world, debugMatrix);
}

Looks like the answer to that one was fairly simple:
stage.setCamera(camera);
I was not setting the OrthographicCamera to the stage, so the stage was using some kind of default camera that wasn't aligned with my stuff.
It had nothing to do with Box2d in the end. Box2d was returning healthy values, but theses values were corresponding to wrong places in my screen because of the wrong stage resolution.

Related

Libgdx - box2d polygonshape doesn't fit its sprite

I have a body with a polygonshape created using .setasbox but when I run my game the box is a bit bigger than my sprite.
I know setasbox uses half height and half width, I used my scaling constant to convert meters to pixels and I know the sprite has the origin of the axis on the bottom left as well. Despite of that I still have a box with a width a bit larger than the sprite and this gap is the same however I change the size of the box...
This is the code I use to create my box (160 is the constant to scale meters to pixels):
public Block(World w, float halfWidth, float halfHeight, Vector2 position, Texture tex){
world = w;
bodyd = new BodyDef();
bodyd.type = BodyDef.BodyType.KinematicBody;
bodyd.gravityScale = 0;
shape = new PolygonShape();
shape.setAsBox(halfWidth, halfHeight);
fixtured = new FixtureDef();
fixtured.shape = shape;
fixtured.density = DENS;
fixtured.friction = FRIC;
fixtured.restitution = REST;
bodyd.position.set(new Vector2(position.x, position.y));
body = world.createBody(bodyd);
fixture = body.createFixture(fixtured);
body.setUserData(this);
texture = tex;
sprite = new Sprite(texture);
sprite.setSize(halfWidth * 2 * 160, halfHeight*2*160);
sprite.setPosition((body.getPosition().x - halfWidth) * 160, (body.getPosition().y - halfHeight) * 160);
}
can you try using Box2DSprite? its very easy..
https://bitbucket.org/dermetfan/libgdx-utils/wiki/net.dermetfan.gdx.graphics.g2d.Box2DSprite
http://www.java-gaming.org/index.php?topic=29843.0
I don't see anything wrong with your code
did you consider that the size that you put for your sprite is the size of the full sprite not the size of the block inside your sprite
I think this is why your brick sprite is smaller than your brick physic :
unless the your brick has the full size of the sprite then may be the problem is related to something else
hope that was helpful !

How to find out if game sprite is moving smoothly?

I'm making a simple jumping game for android using libgdx and box2d and I cannot figure out how to make sprites move really smooth. I have checked several articles regarding timestep fixing and synchronizing renderer and physics emulation, but none of the suggested ways really helped (http://gafferongames.com/game-physics/fix-your-timestep/).
Finally I decided to run the most simple test setting box2d world step equal to the framerate (which in case of stable fps should provide the best performance), but still movement is not totally smooth. I have tested on PC and on Android device, with stable 60-61 FPS. Here is pseudocode:
In render:
world.step(Gdx.graphics.getDeltaTime(), 6, 2);
stage.act();
stage.draw();
Stage basically has just one actor with act and draw overriden:
#Override
public void draw(Batch batch, float arg1) {
float x = this.getX() - width/2;
float y = this.getY() - height/2;
batch.draw(sprite, x, y, width, height);
}
#Override
public void act (float delta) {
...
//get body position
position = body.getPosition();
this.setPosition(position.x, position.y);
}
Actor has box2d body attached to it, there is no gravity and body's velocity is set constant:
BodyDef bodyDef = new BodyDef();
bodyDef.type = BodyType.DynamicBody;
bodyDef.position.set(world_position);
bodyDef.linearDamping = 0f;
bodyDef.angularDamping = 0f;
bodyDef.fixedRotation = true;
bodyDef.gravityScale = 0f;
...fixure added to the body
body.setLinearVelocity(0, -2f);
Camera is not moving, the case seems to be dead simple and yet sprite does not move exactly perfect. (Though it still looks smoother then when using time accumulator and interpolation)
Is it possible to achive absolutely smooth movement at all? Is there some mistake in my approach?
I have checked some similar games on the same android device - it seems that objects are moving absolutely smooth, but maybe it just seems so, because too many things happen on the screen and I don't have time to notice.
Any advice would be appreciated.
After further testing and researched I have figured out the problem - it was related not to FPS, but to pixel rounding. Box2d bodies have float coordinates - after converting them to round pixel values animation bemace much smoother.
How about to use CCPhysicsSprite instead of change position of sprite by time? You can use a batch, too. Just
sprite = [CCPhysicsSprite spriteWithTexture:batch.texture];
[batch addChild:sprite];
CCPhysicsSprite class
Example:
#import "CCPhysicsSprite.h"
CCPhysicsSprite *sprite = [CCPhysicsSprite spriteWithFile:#"sprite.png"];
[self addChild:sprite];
b2BodyDef bodyDef;
bodyDef.type = b2_dynamicBody;
bodyDef.position.Set(300/PTM_RATIO, 200/PTM_RATIO);
body = world->CreateBody(&bodyDef);
b2CircleShape circleShape;
circleShape.m_radius = 0.3;
b2FixtureDef fixtureDef;
fixtureDef.shape = &circleShape;
fixtureDef.density = 1;
fixtureDef.friction = 0.3f;
body->CreateFixture(&fixtureDef);
[sprite setPTMRatio:PTM_RATIO];
[sprite setB2Body:body];
[sprite setPosition: ccp(300, 200)];

Converting Camera Coordinates to Custom View Coordinates

I am trying to make a simple face detection app consisting of a SurfaceView (essentially a camera preview) and a custom View (for drawing purposes) stacked on top. The two views are essentially the same size, stacked on one another in a RelativeLayout. When a person's face is detected, I want to draw a white rectangle on the custom View around their face.
The Camera.Face.rect object returns the face bound coordinates using the coordinate system explained here and the custom View uses the coordinate system described in the answer to this question. Some sort of conversion is needed before I can use it to draw on the canvas.
Therefore, I wrote an additional method ScaleFacetoView() in my custom view class (below) I redraw the custom view every time a face is detected by overriding the OnFaceDetection() method. The result is the white box appears correctly when a face is in the center. The problem I noticed is that it does not correct track my face when it moves to other parts of the screen.
Namely, if I move my face:
Up - the box goes left
Down - the box goes right
Right - the box goes upwards
Left - the box goes down
I seem to have incorrectly mapped the values when scaling the coordinates. Android docs provide this method of converting using a matrix, but it is rather confusing and I have no idea what it is doing. Can anyone provide some code on the correct way of converting Camera.Face coordinates to View coordinates?
Here's the code for my ScaleFacetoView() method.
public void ScaleFacetoView(Face[] data, int width, int height, TextView a){
//Extract data from the face object and accounts for the 1000 value offset
mLeft = data[0].rect.left + 1000;
mRight = data[0].rect.right + 1000;
mTop = data[0].rect.top + 1000;
mBottom = data[0].rect.bottom + 1000;
//Compute the scale factors
float xScaleFactor = 1;
float yScaleFactor = 1;
if (height > width){
xScaleFactor = (float) width/2000.0f;
yScaleFactor = (float) height/2000.0f;
}
else if (height < width){
xScaleFactor = (float) height/2000.0f;
yScaleFactor = (float) width/2000.0f;
}
//Scale the face parameters
mLeft = mLeft * xScaleFactor; //X-coordinate
mRight = mRight * xScaleFactor; //X-coordinate
mTop = mTop * yScaleFactor; //Y-coordinate
mBottom = mBottom * yScaleFactor; //Y-coordinate
}
As mentioned above, I call the custom view like so:
#Override
public void onFaceDetection(Face[] arg0, Camera arg1) {
if(arg0.length == 1){
//Get aspect ratio of the screen
View parent = (View) mRectangleView.getParent();
int width = parent.getWidth();
int height = parent.getHeight();
//Modify xy values in the view object
mRectangleView.ScaleFacetoView(arg0, width, height);
mRectangleView.setInvalidate();
//Toast.makeText( cc ,"Redrew the face.", Toast.LENGTH_SHORT).show();
mRectangleView.setVisibility(View.VISIBLE);
//rest of code
Using the explanation Kenny gave I manage to do the following.
This example works using the front facing camera.
RectF rectF = new RectF(face.rect);
Matrix matrix = new Matrix();
matrix.setScale(1, 1);
matrix.postScale(view.getWidth() / 2000f, view.getHeight() / 2000f);
matrix.postTranslate(view.getWidth() / 2f, view.getHeight() / 2f);
matrix.mapRect(rectF);
The returned Rectangle by the matrix has all the right coordinates to draw into the canvas.
If you are using the back camera I think is just a matter of changing the scale to:
matrix.setScale(-1, 1);
But I haven't tried that.
The Camera.Face class returns the face bound coordinates using the image frame that the phone would save into its internal storage, rather than using the image displayed in the Camera Preview. In my case, the images were saved in a different manner from the camera, resulting in a incorrect mapping. I had to manually account for the discrepancy by taking the coordinates, rotating it counter clockwise 90 degrees and flipping it on the y-axis prior to scaling it to the canvas used for the custom view.
EDIT:
It would also appear that you can't change the way the face bound coordinates are returned by modifying the camera capture orientation using the Camera.Parameters.setRotation(int) method either.

Chase player with camera in AndEngine and limit world's bounds

Using AndEngine for Android, I would like to have my scene look like this:
The red box is the world which must be limited to a given size, say 2000px*450px.
The blue box is the Camera, which is limited as well (as usual), for example to 750px*450px.
For the whole scene, I have a background image that is exactly 450px high. So my Camera can be scaled to whatever size is appropriate, but the background must exactly fit to the height. The width of the Camera may be variable.
The player (circle) must always be in the center (horizontally) but may not leave the world's boundaries.
To achieve this, I've tried adding two types of sizes:
camera size (CAMERA_WIDTH, CAMERA_HEIGHT)
world size (WORLD_WIDTH, WORLD_HEIGHT)
And this function was to add boundaries to the world so that the physics engine prevents the player from leaving those boundaries:
private void createWorldBoundaries() {
Body body;
final Rectangle wall_top = new Rectangle(0, WORLD_HEIGHT-5, WORLD_WIDTH, 10, mVertexManager);
final Rectangle wall_bottom = new Rectangle(0, 5, WORLD_WIDTH, 10, mVertexManager);
final Rectangle wall_left = new Rectangle(5, 0, 10, WORLD_HEIGHT, mVertexManager);
final Rectangle wall_right = new Rectangle(WORLD_WIDTH-5, 0, 10, WORLD_HEIGHT, mVertexManager);
body = PhysicsFactory.createBoxBody(mPhysicsWorld, wall_top, BodyType.StaticBody, new PhysicsFactory.createFixtureDef(0.0f, 0.5f, 0.5f));
wall_top.setUserData(body);
body = PhysicsFactory.createBoxBody(mPhysicsWorld, wall_bottom, BodyType.StaticBody, new PhysicsFactory.createFixtureDef(0.0f, 0.5f, 0.5f));
wall_bottom.setUserData(body);
body = PhysicsFactory.createBoxBody(mPhysicsWorld, wall_left, BodyType.StaticBody, new PhysicsFactory.createFixtureDef(0.0f, 0.5f, 0.5f));
wall_left.setUserData(body);
body = PhysicsFactory.createBoxBody(mPhysicsWorld, wall_right, BodyType.StaticBody, new PhysicsFactory.createFixtureDef(0.0f, 0.5f, 0.5f));
wall_right.setUserData(body);
attachChild(wall_top);
attachChild(wall_bottom);
attachChild(wall_left);
attachChild(wall_right);
}
But this is not working, unfortunately. (see edit)
Setting the camera to chase the player has the wrong result for me: The player does really stay in the center of the screen all time, but I want the player only to stay in the center horizontally, not vertically.
What am I doing wrong and what can I change? And the basic question is: How can I make the world wider than the camera view, while the height is equal to the camera view. The result should be that you can horizontally walk through your world (moving camera) and you can always see the full height.
Edit:
As you define the coordinates of the Rectangle's center and not its top-left corner, you have to do it like this, it seems:
final Rectangle wall_top = new Rectangle(WORLD_WIDTH/2, WORLD_HEIGHT-1, WORLD_WIDTH, 2, mVertexManager);
final Rectangle wall_bottom = new Rectangle(WORLD_WIDTH/2, FIELD_BASELINE_Y+1, WORLD_WIDTH, 2, mVertexManager);
final Rectangle wall_left = new Rectangle(1, WORLD_HEIGHT/2, 2, WORLD_HEIGHT, mVertexManager);
final Rectangle wall_right = new Rectangle(WORLD_WIDTH-1, WORLD_HEIGHT/2, 2, WORLD_HEIGHT, mVertexManager);
However, I had found the other solution in several tutorials. Are these authors not testing their code before writing the tutorials or did the behaviour change from GLES1 to GLES2 or with any recent version?
i think your question about the world boundaries is self answered, isn't it?
PhysicsWorld Boundaries
for further research you can download nicolas' AndEngine Examples App from the Play Store and look up the different examples here (GLES_2, didn't look for AnchorCenter yet): https://github.com/nicolasgramlich/AndEngineExamples/tree/GLES2/src/org/andengine/examples
Taken from the PhysicsExample, the code for the rectangles should look like this, if the bounds are set to the camera bounds. in your case, you can extend width like you want (3 times CAMERA_WIDTH?)
final Rectangle ground = new Rectangle(0, CAMERA_HEIGHT - 2, WORLD_WIDTH, 2, vertexBufferObjectManager);
final Rectangle roof = new Rectangle(0, 0, WORLD_WIDTH, 2, vertexBufferObjectManager);
final Rectangle left = new Rectangle(0, 0, 2, CAMERA_HEIGHT, vertexBufferObjectManager);
final Rectangle right = new Rectangle(WORLD_WIDTH - 2, 0, 2, CAMERA_HEIGHT, vertexBufferObjectManager);
Camera following player
for the Camera to follow your player, you can lookup the code of the BoundCameraExample https://github.com/nicolasgramlich/AndEngineExamples/blob/GLES2/src/org/andengine/examples/BoundCameraExample.java
the interesting part for you should be the addFace method at the bottom
private void addFace(final float pX, final float pY) {
final FixtureDef objectFixtureDef = PhysicsFactory.createFixtureDef(1, 0.5f, 0.5f);
final AnimatedSprite face = new AnimatedSprite(pX, pY, this.mBoxFaceTextureRegion, this.getVertexBufferObjectManager()).animate(100);
final Body body = PhysicsFactory.createBoxBody(this.mPhysicsWorld, face, BodyType.DynamicBody, objectFixtureDef);
this.mScene.attachChild(face);
this.mPhysicsWorld.registerPhysicsConnector(new PhysicsConnector(face, body, true, true));
this.mBoundChaseCamera.setChaseEntity(face);
}
this method creates a physics body + sprite for "your player" (in this case, a boxed face) and sets the sprite as a chaseEntity for the camera to follow. Since the camera has bounds, that it can't exceed and your camera will have the height of your PhysicWorld boundaries, you can use this to let your camera follow the player in x, but not in y direction.
if you (i don't know why) don't want to use these boundaries, you can overwrite the onUpdate method of your Sprite and re-locate your camera only in x-direction, instead of xy coords
face.registerUpdateHandler(new IUpdateHandler() {
#Override
public void onUpdate(final float pSecondsElapsed) {
float[] coord = face.getSceneCenterCoordinates();
this.mBoundChaseCamera.setCenter(sceneCenterCoordinates[0], CAMERA_Y_POSITION);
}
}
where the CAMERA_Y_POSITION is a static final field with the y-position.
I hope this answers your question(s). :-)
edit: oops, i forgot to mention, how to achieve the camera to be bound and i will edit the world width above:
this.mBoundChaseCamera.setBounds(0, 0,
WORLD_WIDTH, CAMERA_HEIGHT);
all settings are like your image given (except the exact position of the face, that has to be given to the addFace(px, py))
Edit: Difference between scene boundaries in Andengine GLES2 vs GLES2-AnchorCenter
As far as i understood the question, i thought you would use GLES2, i thought of the (older) default GLES2 branch of AndEngine and posted the boundaries. As you found out yourself before and stated in the comments, you use another approach to set the rectangles - where you need to set the rectangles center as pX and pY. The reason for this is in fact, that with the AnchorCenter branch, you won't set the upper left position of an entity anymore and instead use it's center position.

How to make a cylinder in renderscript

I have been trying to make a cylinder in renderscript. This is the code I've tried:
public Mesh cylinder(){
float radius=1.25f, halfLength=5;
int slices=16;
Mesh.TriangleMeshBuilder mbo= new TriangleMeshBuilder(mRSGL,3, Mesh.TriangleMeshBuilder.TEXTURE_0);
for(int i=0; i<slices; i++) {
float theta = (float) (((float)i)*2.0*Math.PI);
float nextTheta = (float) (((float)i+1)*2.0*Math.PI);
/*vertex at middle of end*/
mbo.addVertex(0.0f, halfLength, 0.0f);
/*vertices at edges of circle*/
mbo.addVertex((float)(radius*Math.cos(theta)), halfLength, (float)(radius*Math.sin(theta)));
mbo.addVertex((float)(radius*Math.cos(nextTheta)), halfLength, (float)(radius*Math.sin(nextTheta)));
/* the same vertices at the bottom of the cylinder*/
mbo.addVertex((float)(radius*Math.cos(nextTheta)), -halfLength, (float)(radius*Math.sin(nextTheta)));
mbo.addVertex((float)(radius*Math.cos(theta)), halfLength, (float)(radius*Math.sin(theta)));
mbo.addVertex(0.0f, -halfLength, 0.0f);
mbo.addTriangle(0, 1, 2);
mbo.addTriangle(3, 4, 5);
}
return mbo.create(true);
}
But this code gives me a rectangle of length 5. Any ideas where I'm going wrong?
You actually have a few problems here. First, your angles are always equal to multiples of 2pi. You need to divide by the number of sectors when you calculate your angles. Additionally in this step you have an unnecessary explicit type conversion, java will handle the conversion of integer to double for you.
Second, you are constantly adding the same two triangles to the mesh and not adding any triangles for the side of the cylinder, just the two end faces. In your loop when calling addTriangle() you should use indices, for example addTriangle(n, n+1, n+2).
Finally, you were missing a negative sign when you created your 4th vertex, so it was actually at halfLength, not -halfLength.
Try this:
public Mesh cylinder(){
float radius=1.25f, halfLength=5;
int slices=16;
Mesh.TriangleMeshBuilder mbo= new TriangleMeshBuilder(mRSGL,3, Mesh.TriangleMeshBuilder.TEXTURE_0);
/*vertex at middle of end*/
mbo.addVertex(0.0f, halfLength, 0.0f);
mbo.addVertex(0.0f, -halfLength, 0.0f);
for(int i=0; i<slices; i++) {
float theta = (float) (i*2.0*Math.PI / slices);
float nextTheta = (float) ((i+1)*2.0*Math.PI / slices);
/*vertices at edges of circle*/
mbo.addVertex((float)(radius*Math.cos(theta)), halfLength, (float)(radius*Math.sin(theta)));
mbo.addVertex((float)(radius*Math.cos(nextTheta)), halfLength, (float)(radius*Math.sin(nextTheta)));
/* the same vertices at the bottom of the cylinder*/
mbo.addVertex((float)(radius*Math.cos(nextTheta)), -halfLength, (float)(radius*Math.sin(nextTheta)));
mbo.addVertex((float)(radius*Math.cos(theta)), -halfLength, (float)(radius*Math.sin(theta)));
/*Add the faces for the ends, ordered for back face culling*/
mbo.addTriangle(4*i+3, 4*i+2, 0);
//The offsets here are to adjust for the first two indices being the center points. The sector number (i) is multiplied by 4 because the way you are building this mesh, there are 4 vertices added with each sector
mbo.addTriangle(4*i+5, 4*i+4, 1);
/*Add the faces for the side*/
mbo.addTriangle(4*i+2, 4*i+4, 4*i+5);
mbo.addTriangle(4*i+4, 4*i+2, 4*i+3);
}
return mbo.create(true);
}
I have also added a slight optimization where the vertices for the centers of the circles are created only once, thus saving memory. The order of indices here is for back face culling. Reverse it if you want front face. Should your needs require a more efficient method eventually, allocation builders allow for using trifans and tristrips, but for a mesh of this complexity the ease of triangle meshes is merited. I have run this code on my own system to verify that it works.

Categories

Resources