Why does wheel movement in Box2d doesn't cause car to move? - android

I'm working on moving vehicle based on Box 2d physics for my Android game (Java + LibGDX). When I thought I have everything up and running my, my car with two wheels stands on the ground but when I rotate the wheels The car does not move.
That's my Game class:
public class MyGdxGame implements ApplicationListener {
World world = new World(new Vector2(0, -10), true);
Box2DDebugRenderer debugRenderer;
OrthographicCamera camera;
static final float BOX_STEP=1/60f;
static final int BOX_VELOCITY_ITERATIONS=6;
static final int BOX_POSITION_ITERATIONS=2;
static final int WIDTH=256;
static final int HEIGHT=169;
Hero hero;
MovableBox box;
#Override
public void create() {
camera = new OrthographicCamera();
camera.viewportHeight = HEIGHT;
camera.viewportWidth = WIDTH;
camera.position.set(camera.viewportWidth * .5f, camera.viewportHeight * .5f, 0f);
camera.update();
Vector2[] anArray;
anArray = new Vector2[4];
anArray[0]= new Vector2(-30,0);
anArray[1]= new Vector2(55,55);
anArray[2]= new Vector2(110,55);
anArray[3]= new Vector2(195,0);
//Ground body
BodyDef groundBodyDef =new BodyDef();
groundBodyDef.position.set(new Vector2(-8-13-20-20-10, -44));
Body groundBody = world.createBody(groundBodyDef);
PolygonShape groundBox = new PolygonShape();
groundBox.set(anArray);
//groundBox.setAsBox((camera.viewportWidth) * 2, 10.0f);
groundBody.createFixture(groundBox, 0.0f);
//Ground body
BodyDef groundBodyDef2 =new BodyDef();
groundBodyDef2.position.set(new Vector2(13*11-4-7-8-13-20-20-10, -44));
Body groundBody2 = world.createBody(groundBodyDef2);
PolygonShape groundBox2 = new PolygonShape();
groundBox2.set(anArray);
//groundBox.setAsBox((camera.viewportWidth) * 2, 10.0f);
groundBody2.createFixture(groundBox2, 0.0f);
hero = new Hero();
hero.create(world, 0, 0);
box.create(world, WIDTH / 4 * 3, HEIGHT / 2);
boxes.add(box);
debugRenderer = new Box2DDebugRenderer();
}
private void update(){
hero.update();
for(MovableBox b : boxes) {
b.update();
}
}
#Override
public void dispose() {
}
#Override
public void render() {
update();
camera.position.set(hero.getPos(), 0f);
camera.update();
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
debugRenderer.render(world, camera.combined);
world.step(BOX_STEP, BOX_VELOCITY_ITERATIONS, BOX_POSITION_ITERATIONS);
}
#Override
public void resize(int width, int height) {
}
#Override
public void pause() {
}
#Override
public void resume() {
}
And Hero class (which should be called a car actually)
Body body;
Body wheel, wheel2;
public void create(World world, int posx, int posy){
BodyDef bodyDef = new BodyDef();
bodyDef.type = BodyDef.BodyType.DynamicBody;
bodyDef.position.set(posx, posy);
body = world.createBody(bodyDef);
PolygonShape dynamicCircle = new PolygonShape();
dynamicCircle.setAsBox(8, 3);
FixtureDef fixtureDef = new FixtureDef();
fixtureDef.shape = dynamicCircle;
fixtureDef.density = 4.0f;
fixtureDef.restitution = 0.1f;
fixtureDef.friction=0.95f;
body.createFixture(fixtureDef);
BodyDef bodyDef2 = new BodyDef();
bodyDef2.type = BodyDef.BodyType.DynamicBody;
wheel = world.createBody(bodyDef2);
CircleShape dynamicCircle2 = new CircleShape();
dynamicCircle2.setRadius(2);
FixtureDef fixtureDef2 = new FixtureDef();
fixtureDef2.shape = dynamicCircle2;
fixtureDef2.density = 4;
fixtureDef2.friction=3.0f;
fixtureDef2.restitution=0.1f;
wheel.createFixture(fixtureDef2);
wheel2 = world.createBody(bodyDef2);
wheel2.createFixture(fixtureDef2);
RevoluteJointDef revoluteJointDef = new RevoluteJointDef();
revoluteJointDef.bodyA = body;
revoluteJointDef.bodyB = wheel;
revoluteJointDef.localAnchorA.add(-8,-6);
world.createJoint(revoluteJointDef);
RevoluteJointDef revoluteJointDef2 = new RevoluteJointDef();
revoluteJointDef2.bodyA = body;
revoluteJointDef2.bodyB = wheel2;
revoluteJointDef2.localAnchorA.add(8,-6);
world.createJoint(revoluteJointDef2);
}
public Vector2 getPos(){
return body.getPosition();
}
public void update(){
if(Gdx.input.isTouched())
{
if(Gdx.input.getX()<600){
wheel.setTransform(wheel.getPosition().x,wheel.getPosition().y,wheel.getAngle()+0.1f);
wheel2.setTransform(wheel2.getPosition().x,wheel2.getPosition().y, wheel2. getAngle() + 0.1f);
}
else{
wheel.setTransform(wheel.getPosition().x,wheel.getPosition().y,wheel.getAngle()-0.1f);
wheel2.setTransform(wheel2.getPosition().x,wheel2.getPosition().y,wheel2.getAngle()-0.1f);
}
}
}

Well I think there are two things you need to consider.
First of all I think if you want your physics engine to "force" the car to move on wheels spin, you probably should look into damping parameters of BodyDef (linearDamping and angularDamping). Setting those for ground and car wheels might help you move your car on wheels spin.
The second thing is that you really need to analyze if it's the proper approach. Maybe you should think about simulating movement of your car by moving the body of your car itself and spinning your wheels. I think this approach should give you more control on the car movement.

Related

harpoon as the pang game in libgdx

I am using Scene2D.
This is my Shoot Actor
public class ActorDisparo extends Actor {
private TextureRegion textureDisparo = new TextureRegion();
private World world;
public static Body body;
//private Fixture fixture;
private FixtureDef fdef;
private String userData;
private float anchoDisparo, altoDisparo;
private float positionX,positionY;
private static float porcentajeDeancho = 0,anchoMediano = 0, anchoPequeno = 0, anchoDiminuto = 0;
private TextureRegion arponRegion = new TextureRegion();
public ActorDisparo(World world, TextureRegion disparo, Vector2 position, float anchoDisparo, float altoDisparo, float fuerzaX, float fuerzaY, String userData){
this.textureDisparo = disparo;
this.world = world;
this.anchoDisparo = anchoDisparo;
this.altoDisparo = altoDisparo;
this.userData = userData;
BodyDef bodyDef = new BodyDef();
bodyDef.position.set(position);
bodyDef.type = BodyDef.BodyType.DynamicBody;
body = world.createBody(bodyDef);
PolygonShape shapeDisparo = new PolygonShape();
shapeDisparo.setAsBox((anchoDisparo/2)/2,altoDisparo/2);
fdef = new FixtureDef();
fdef.shape = shapeDisparo;
//fdef.restitution = 0.70f;
fdef.filter.categoryBits = BolasGame.DISPARO_BIT;
fdef.filter.maskBits = BolasGame.BOLAROJA_BIT |
BolasGame.TECHO_BIT;
body.createFixture(fdef).setUserData(userData);
shapeDisparo.dispose();
body.setGravityScale(0f);
body.applyLinearImpulse(fuerzaX,fuerzaY,position.x,position.y,true);
setSize( anchoDisparo *BolasGame.MetrosAPixels ,altoDisparo*BolasGame.MetrosAPixels);
//setBounds(0, 0, getWidth(), getHeight());
}
public float getPositionX() {
return getPositionX();
}
public float getPositionY() {
return getPositionY();
}
#Override
public void act(float delta) {
super.act(delta);
}
#Override
public void draw(Batch batch, float parentAlpha) {
super.draw(batch, parentAlpha);
setPosition( (body.getPosition().x * BolasGame.MetrosAPixels) - getWidth()/2, (body.getPosition().y * BolasGame.MetrosAPixels) - getHeight()/2);
batch.draw(textureDisparo,getX(),getY(),getWidth(),getHeight());
}
public void detach(){
world.destroyBody(body);
remove();
}
}
and this is the call to shoot class
if(Gdx.input.justTouched() && hasdisparado == false){
hasdisparado =true;
touch = new Vector3(Gdx.input.getX(), Gdx.input.getY(), 0);
stage.getCamera().unproject(touch);
arponRegion = new TextureRegion(textureDisparo, 0, 0, 20, 40);
actorDisparo = new ActorDisparo(world,arponRegion,new Vector2(touch.x/BolasGame.MetrosAPixels,touch.y/BolasGame.MetrosAPixels ),20/BolasGame.MetrosAPixels,40/BolasGame.MetrosAPixels,0,2f,BolasGame.USERDATA_DISPARO);
stage.addActor(actorDisparo);
}
this creates a shot like a bullet but I need since I touched the screen until it is destroyed is continuous like the harpoon of game pang
the textureregion the charge of a texture whose dimensions are 446x20
textureDisparo = new Texture("gfx/disparo.png");
I have no idea how to do this because you have to repeat the image and body in box2d for collisions.
I totally lost
if someone can give me an idea would appreciate
Thank you
(Sorry for my English, I'm learning now)

My box2d body drops way too slow

I tried almost everything but nothing works.
If you run it you will see a square falling down very slow.
I'm a beginner so explain it not too complicated.
Any questions about this code dylan.missu#gmail.com
Here is my code:
#Override
public void show() {
camera = new OrthographicCamera();
debugRenderer = new Box2DDebugRenderer();
BodyDef bodyDef = new BodyDef();
bodyDef.type = BodyDef.BodyType.DynamicBody;
bodyDef.position.set(100,100);
body = world.createBody(bodyDef);
PolygonShape shape = new PolygonShape();
shape.setAsBox(Gdx.graphics.getHeight()/6,Gdx.graphics.getHeight()/6);
FixtureDef fixtureDef = new FixtureDef();
fixtureDef.shape = shape;
fixtureDef.density = 1f;
fixtureDef.restitution = 2;
Fixture fixture = body.createFixture(fixtureDef);
}
private void line(float X, float Y, float w, float h)
{
BodyDef bodyDef = new BodyDef();
bodyDef.type=BodyDef.BodyType.StaticBody;
bodyDef.position.set(X,Y);
PolygonShape polygonShape=new PolygonShape();
polygonShape.setAsBox(w,h);
FixtureDef fixtureDef = new FixtureDef();
fixtureDef.shape=polygonShape;
fixtureDef.restitution=0.4f;
fixtureDef.friction=0.5f;
Body theFloor=world.createBody(bodyDef);
theFloor.createFixture(fixtureDef);
}
private void wall(float A)
{
// is there a better way of doing this?
line(0,Gdx.graphics.getHeight()/2-A,Gdx.graphics.getWidth()/2-A,0);
line(Gdx.graphics.getWidth()/2-A,0,0,Gdx.graphics.getHeight()/2-A);
line(0,-Gdx.graphics.getHeight()/2+A,Gdx.graphics.getWidth()/2-A,0);
line(-Gdx.graphics.getWidth()/2+A,0,0,Gdx.graphics.getHeight()/2-A);
}
#Override
public void render(float delta) {
world.step(1 / 5f, 6, 2);
OrthographicCamera camera = new OrthographicCamera(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
processAccelerometer();
wall(1);
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
debugRenderer.render(world, camera.combined);
}
#Override
public void dispose() {
world.dispose();
debugRenderer.dispose();
}
private void processAccelerometer() {
float y = Gdx.input.getAccelerometerY();
float x = Gdx.input.getAccelerometerX();
if (prevAccelX != x || prevAccelY != y) {
world.setGravity(new Vector2(y, -x));
prevAccelX = x;
prevAccelY = y;
}
}
#Override
public void hide()
{
// TODO: Implement this method
}
#Override
public void resize(int p1, int p2)
{
// TODO: Implement this method
}
#Override
public void resume()
{
// TODO: Implement this method
}
#Override
public void pause()
{
// TODO: Implement this method
}
#Override
public void render()
{
// TODO: Implement this method
}
}
In Box2D you have to take into account that 1 pixel = 1 meter. So, basically, everything you simulate in Box2D will be HUGE by default. And Box2D simulations are not accurate for huge distances, huge masses, huge speeds...
So all you have to do is convert your viewport with a conversion factor, so you'll just look at small entities, that will be easier to simulate.
For example, let's say you want 100 pixel = 1 meter, you'll put that code when you create your game screen :
WORLD_TO_BOX = 1/100f;
BOX_TO_WORLD = 1/WORLD_TO_BOX;
//Creation of the camera with your factor 100
camera = new OrthographicCamera();
camera.viewportHeight = Gdx.graphics.getHeight() * WORLD_TO_BOX;
camera.viewportWidth = Gdx.graphics.getWidth() * WORLD_TO_BOX;
camera.position.set(camera.viewportWidth/2, camera.viewportHeight/2, 0f);
camera.update();
Then, you'll create your boxes in term of camera.viewportWidth and camera.viewportHeight, instead of Gdx.graphics.getWidth() and Gdx.graphics.getHeight()
I your case you'll have :
PolygonShape shape = new PolygonShape();
shape.setAsBox(camera.viewportHeight/6,camera.viewportHeight/6);
You can see in my code, there is also a BOX_TO_WORLD conversion factor. It will be used when you want to render graphics over your box2D bodies.
For that, look at the answer of this question.

Newton's cradle on andengine, box2d

i'm trying to create something like Newton's cradle. But when one ball hits another, all balls move simultaneously in same direction. How can I decide this problem? Should i create another physical options of balls in createFixtureDef? Or I need to use some specific algorithm to transfer impuls between balls?
public class MainActivity extends SimpleBaseGameActivity implements IAccelerationListener,
IOnAreaTouchListener
{
private static final int CAMERA_WIDTH = 720;
private static final int CAMERA_HEIGHT = 480;
private BitmapTextureAtlas mBitmapTextureAtlas;
final String TAG = "States";
private Scene mScene;
protected ITiledTextureRegion mBoxFaceTextureRegion;
protected ITiledTextureRegion mCircleFaceTextureRegion;
protected PhysicsWorld mPhysicsWorld;
#Override
public EngineOptions onCreateEngineOptions() {
final Camera camera = new Camera(0, 0, CAMERA_WIDTH, CAMERA_HEIGHT);
return new EngineOptions(true, ScreenOrientation.LANDSCAPE_FIXED,
new RatioResolutionPolicy(CAMERA_WIDTH, CAMERA_HEIGHT), camera);
}
#Override
protected void onCreateResources() {
BitmapTextureAtlasTextureRegionFactory.setAssetBasePath("gfx/");
this.mBitmapTextureAtlas = new BitmapTextureAtlas(this.getTextureManager(), 64, 64, TextureOptions.BILINEAR);
this.mBoxFaceTextureRegion = BitmapTextureAtlasTextureRegionFactory.createTiledFromAsset(this.mBitmapTextureAtlas, this, "face_box_tiled.png", 0, 0, 2, 1); // 64x32
this.mCircleFaceTextureRegion = BitmapTextureAtlasTextureRegionFactory.createTiledFromAsset(this.mBitmapTextureAtlas, this, "face_circle_tiled.png", 0, 32, 2, 1); // 64x32
this.mBitmapTextureAtlas.load();
}
#Override
protected Scene onCreateScene() {
this.mEngine.registerUpdateHandler(new FPSLogger());
this.mScene = new Scene();
this.mScene.setBackground(new Background(0, 0, 0));
//this.mScene.setOnSceneTouchListener(this);
this.mPhysicsWorld = new PhysicsWorld(new Vector2(0, SensorManager.GRAVITY_EARTH), false);
this.initJoints(mScene);
this.mScene.registerUpdateHandler(this.mPhysicsWorld);
this.mScene.setOnAreaTouchListener(this);
return this.mScene;
}
private void initJoints(final Scene pScene) {
final float centerY = CAMERA_HEIGHT / 2;
final float spriteWidth = this.mBoxFaceTextureRegion.getWidth();
final float spriteHeight = this.mBoxFaceTextureRegion.getHeight();
final FixtureDef objectFixtureDef = PhysicsFactory.createFixtureDef(30, 0.2f, 0.2f);
for(int i = 0; i < 10; i++) {
final float anchorFaceX = 100 + i * spriteWidth ;
final float anchorFaceY = centerY;
final AnimatedSprite anchorFace = new AnimatedSprite(anchorFaceX, anchorFaceY,
this.mBoxFaceTextureRegion, this.getVertexBufferObjectManager());
final Body anchorBody = PhysicsFactory.createBoxBody(this.mPhysicsWorld,
anchorFace, BodyType.StaticBody,
objectFixtureDef);
final AnimatedSprite movingFace = new AnimatedSprite(anchorFaceX, anchorFaceY + 150,
this.mCircleFaceTextureRegion, this.getVertexBufferObjectManager()) ;
// movingFace.setScale(1.2f);
final Body movingBody = PhysicsFactory.createCircleBody(this.mPhysicsWorld,
movingFace, BodyType.DynamicBody, objectFixtureDef);
movingFace.setUserData(movingBody);
// anchorFace.setScale(1.2f);
anchorFace.animate(200);
anchorFace.animate(200);
final Line connectionLine = new Line(anchorFaceX + spriteWidth / 2,
anchorFaceY + spriteHeight / 2,
anchorFaceX + spriteWidth / 2,
anchorFaceY + spriteHeight / 2,
this.getVertexBufferObjectManager());
pScene.registerTouchArea(movingFace);
pScene.attachChild(connectionLine);
pScene.attachChild(anchorFace);
pScene.attachChild(movingFace);
this.mPhysicsWorld.registerPhysicsConnector(new PhysicsConnector(anchorFace,
anchorBody, true, true){
#Override
public void onUpdate(final float pSecondsElapsed) {
super.onUpdate(pSecondsElapsed);
final Vector2 movingBodyWorldCenter = movingBody.getWorldCenter();
connectionLine.setPosition(connectionLine.getX1(), connectionLine.getY1(),
movingBodyWorldCenter.x * PhysicsConstants.PIXEL_TO_METER_RATIO_DEFAULT,
movingBodyWorldCenter.y * PhysicsConstants.PIXEL_TO_METER_RATIO_DEFAULT);
}
});
this.mPhysicsWorld.registerPhysicsConnector(new PhysicsConnector(movingFace, movingBody, true, true));
final RevoluteJointDef revoluteJointDef = new RevoluteJointDef();
revoluteJointDef.initialize(anchorBody, movingBody, anchorBody.getWorldCenter());
this.mPhysicsWorld.createJoint(revoluteJointDef);
}
}
#Override
public void onAccelerationAccuracyChanged(final AccelerationData pAccelerationData) {
}
#Override
public void onAccelerationChanged(final AccelerationData pAccelerationData) {
final Vector2 gravity = Vector2Pool.obtain(pAccelerationData.getX(), pAccelerationData.getY());
this.mPhysicsWorld.setGravity(gravity);
Vector2Pool.recycle(gravity);
}
public boolean onAreaTouched( final TouchEvent pSceneTouchEvent,
final ITouchArea pTouchArea,final float pTouchAreaLocalX,
final float pTouchAreaLocalY) {
if(pSceneTouchEvent.isActionMove())
{
float touchX = pSceneTouchEvent.getX();
float touchY = pSceneTouchEvent.getY();
Log.d(TAG, "move to in X" +touchX + "n Y " +touchY);
final AnimatedSprite anchorFace = (AnimatedSprite) pTouchArea;
final Body tochedBody = (Body)anchorFace.getUserData();
//move sprite to xy
final float x = pSceneTouchEvent.getX();
final float y = pSceneTouchEvent.getY();
final float widthD2 = anchorFace.getWidth() / 2;
final float heightD2 = anchorFace.getHeight() / 2;
final float angle = tochedBody.getAngle(); // keeps the body angle
final Vector2 v2 = Vector2Pool.obtain((x + widthD2) / 32, (y + heightD2) / 32);
tochedBody.setTransform(v2, angle);
Vector2Pool.recycle(v2);
return true;
}
return false;
}
}
Unfortunately Box2D is not really suitable for this.
In my experience, you can get one or two swing-thrus to work as long as the balls are not touching each other to start with. That is, each ball starts with a very small gap between it and the neighbor on each side. This means that when they collide each collision is solved using just two balls at a time, for a total of 4 separate collisions for the impact to travel to the other side (for 5 balls), instead of solving all 5 balls as a single 'island'.
Trouble is, the positioning needs to be very precise, and after a few swings the balls stray from that, so that you end up with collisions involving more than two balls at a time. I only ever saw at most 2-3 swings work as desired...

jbox2d on Android - circle not applied gravity and other staff

I am doing simple application that should put circle on Canvas when the user taps the screen and then put that circle in the PhysicalWorld I have defined.
I draw the circle in "onDraw" method, but when it is created its position does not change (seems like the gravity and staff are not applied) and the circle is static (stays on the position where it's created).
can you check this code and tell me if I am doing anything wrong:
[update]
public class PhysicsWorld extends SurfaceView implements SurfaceHolder.Callback {
private AABB worldAABB;
private World world;
private PolygonDef groundShapeDef;
public int W_width, W_height;
private static final String TAG = PhysicsWorld.class.getSimpleName();
protected static final int GUIUPDATEIDENTIFIER = 0x231;
public int targetFPS = 40;
public float timeStep = (10.0f/targetFPS);
public int iterations = 5 ;
private int count=0;
private Body[] theBodies ;
private Paint paint;
private float radius = 20;
private MyThread mMyThread;
public PhysicsWorld(Context context) {
super(context);
}
public PhysicsWorld(Context context, AttributeSet set) {
super(context, set);
getHolder().addCallback(this);
W_width = 500;
W_height = 700;
worldAABB = new AABB();
Vec2 min = new Vec2(-50, -50);
Vec2 max = new Vec2(W_width+50, W_height+50);
worldAABB.lowerBound.set(min);
worldAABB.upperBound.set(max);
Vec2 gravity = new Vec2((float) 10.0, (float) 9.8);
boolean doSleep = false;
world = new World(worldAABB, gravity, doSleep);
BodyDef groundBodyDef = new BodyDef();
groundBodyDef.position.set(new Vec2((float) 0.0, (float) -10.0));
Body groundBody = world.createBody(groundBodyDef);
groundShapeDef = new PolygonDef();
groundShapeDef.setAsBox(W_width, 10);
groundBody.createShape(groundShapeDef);
// up :
groundBodyDef = new BodyDef();
groundBodyDef.position.set(new Vec2((float) 0.0, (float) (W_height + 10.0)));
groundBody = world.createBody(groundBodyDef);
groundShapeDef = new PolygonDef();
groundShapeDef.setAsBox(W_width, 10);
groundBody.createShape(groundShapeDef);
// left :
groundBodyDef = new BodyDef();
groundBodyDef.position.set(new Vec2(-10, (float) 0.0));
groundBody = world.createBody(groundBodyDef);
groundShapeDef = new PolygonDef();
groundShapeDef.setAsBox(10, W_height);
groundBody.createShape(groundShapeDef);
// right :
groundBodyDef = new BodyDef();
groundBodyDef.position.set(new Vec2((float) W_width + 10, (float) 0.0));
groundBody = world.createBody(groundBodyDef);
groundShapeDef = new PolygonDef();
groundShapeDef.setAsBox(10, W_height);
groundBody.createShape(groundShapeDef);
theBodies = new Body[50];
paint = new Paint();
paint.setStyle(Style.FILL);
paint.setColor(Color.RED);
paint.setAntiAlias(true);
// setWillNotDraw(false);
}
public void addBall(int x, int y) {
BodyDef bodyDef = new BodyDef();
bodyDef.position.set(x, y);
Log.d(TAG,"Ball Created At: " + Integer.toString(x) + "," + Integer.toString(y));
theBodies[count] = world.createBody(bodyDef);
CircleDef circle = new CircleDef();
circle.radius = radius;
circle.density = (float) 1.0;
circle.restitution = 0.5f;
theBodies[count].createShape(circle);
theBodies[count].setMassFromShapes();
count+=1;
}
public void update() {
world.step(timeStep, iterations);
postInvalidate();
}
#Override
protected void onDraw(Canvas canvas) {
paint = new Paint();
paint.setStyle(Style.FILL);
paint.setColor(Color.RED);
for (int j = 0; j < count; j++) {
canvas.drawCircle(theBodies[j].getPosition().x, W_height - theBodies[j].getPosition().y, radius, paint);
Log.v(TAG + " x: ", String.valueOf(theBodies[j].getPosition().x));
Log.v(TAG + " y:", String.valueOf(W_height - theBodies[j].getPosition().y));
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
addBall((int)event.getX(),(int)event.getY());
}
return true;
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format,
int width, int height) {
// TODO Auto-generated method stub
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
mMyThread = new MyThread(holder, this);
mMyThread.setFlag(true);
mMyThread.start();
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
// TODO Auto-generated method stub
}
}
My experience with box2D is in C++ and iPhone, but it seems your forgetting to make the Ball dynamic.
I've kinda guessed at the solution as I don't know the exact syntax for JBox2D (Please edit if anyone knows actual code)
bodyDef.type = BodyDef.dynamicBody;
I've had a look at the documentation on google code and I think you should use world.createDynamicBody(bodyDef);

jBox2d android drawing dynamic bodies

I started off with the tutorial here and added drawing code for a view (covering the entire screen). The scene appears static and not dynamic even though I'm calling world.step(,). How does one make the scene dynamic and is my drawing the right implementation or is there a better way (using jBox2d functions)?
private class PhysicsView extends View {
Paint mPaint;
public PhysicsView(Context context) {
super(context);
mPaint = new Paint();
mPaint.setColor(Color.BLUE);
mPaint.setStyle(Style.FILL_AND_STROKE);
}
#Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
synchronized (canvas) {
Body[] b = mWorld.bodies;
for (int i = 0; i < b.length; i++) {
if (b[i] != null) {
Float mass = b[i].getMass();
Vec2 v = b[i].getPosition();
canvas.drawCircle(v.x, v.y, 15, mPaint);
}
}
Paint p2 = new Paint(mPaint);
p2.setColor(Color.GREEN);
Vec2 base = mWorld.groundBody.getPosition();
canvas.drawRect(new RectF((float) base.x - 25.0f,
(float) base.y - 10.0f, (float) base.x + 25.0f,
(float) base.y + 10.0f), p2);
canvas.drawLine(0.0f, 0.0f,
mWorld.world.getWorldAABB().upperBound.x, mWorld.world
.getWorldAABB().upperBound.y, p2);
}
}
}
public class PhysicsWorld {
public int targetFPS = 40;
public int timeStep = (1000 / targetFPS);
public int iterations = 5;
public Body[] bodies = new Body[50];
public Body groundBody;
private int count = 0;
private AABB worldAABB;
public World world;
private BodyDef groundBodyDef;
private PolygonDef groundShapeDef;
private Vec2 screenDimensions;
public void create(Vec2 dimens) {
screenDimensions = dimens;
worldAABB = new AABB();
worldAABB.lowerBound.set(new Vec2((float) -1*dimens.x, (float) -1*dimens.y));
worldAABB.upperBound.set(new Vec2((float) dimens.x, (float) dimens.y));
Vec2 gravity = new Vec2((float) 0.0, (float) 0.0);
boolean doSleep = true;
world = new World(worldAABB, gravity, doSleep);
groundBodyDef = new BodyDef();
groundBodyDef.position.set(new Vec2((float) dimens.x/2, (float) dimens.y - 10.0f));
groundBody = world.createBody(groundBodyDef);
groundBody.m_mass = 200.0f;
groundShapeDef = new PolygonDef();
groundShapeDef.setAsBox((float) 50.0, (float) 10.0);
groundShapeDef.density = 1.0f;
groundShapeDef.friction = 0.3f;
groundBody.createShape(groundShapeDef);
}
public void addBall() {
float x = (float) Math.random() * screenDimensions.x;
float y = (float) Math.random() * screenDimensions.y;
BodyDef bodyDef = new BodyDef();
bodyDef.position.set(new Vec2((float) x, (float) y));
bodyDef.massData.mass = 20.0f;
bodies[count] = world.createBody(bodyDef);
bodies[count].m_type = Body.e_dynamicType;
bodies[count].m_linearVelocity = new Vec2(1.0f, 2.0f);
CircleDef circle = new CircleDef();
circle.radius = (float) 1.8;
circle.density = (float) 1.0;
circle.type = ShapeType.CIRCLE_SHAPE;
bodies[count].createShape(circle);
count++;
}
public void update() {
world.step(timeStep, iterations);
}
public void changeGravity(Vec2 gravity) {
world.setGravity(gravity);
}
}
There are a number of issues with your code....but this answer is probably way too late to be of any help anyways.
Firstly, world.createBody() seems to have been deprecated. Now you have to explicitly call world.createDynamicBody() in the latest version of the Android Box2D jar that I have.
Anyways...my version goes something like this...not perfect but at least its dynamic.
package com.box2D;
import java.util.ArrayList;
import org.jbox2d.collision.AABB;
import org.jbox2d.collision.CircleDef;
import org.jbox2d.collision.PolygonDef;
import org.jbox2d.common.Vec2;
import org.jbox2d.dynamics.Body;
import org.jbox2d.dynamics.BodyDef;
import org.jbox2d.dynamics.World;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.Log;
public class PhysicsWorld
{
public float timeStep = 1;
public int iterations = 1;
private ArrayList<Body> bodies;
private int count = 0;
private AABB worldAABB;
private World world;
private BodyDef groundBodyDef;
private PolygonDef boxShapeDef;
//a paint
private Paint paint;
public void create()
{
//create the paint
paint = new Paint();
paint.setColor(0xFFFFFF);
// Step 1: Create Physics World Boundaries
worldAABB = new AABB();
worldAABB.lowerBound.set(new Vec2((float) -100.0, (float) -100.0));
worldAABB.upperBound.set(new Vec2((float) 100.0, (float) 300.0));
// Step 2: Create Physics World with Gravity
Vec2 gravity = new Vec2((float) 0.0, (float)10.0);
boolean doSleep = true;
world = new World(worldAABB, gravity, doSleep);
bodies = new ArrayList<Body>();
// Step 3: Create Ground Box
groundBodyDef = new BodyDef();
groundBodyDef.position.set(new Vec2((float) 0.0, (float) 300.0));
Body groundBody = world.createDynamicBody(groundBodyDef);
boxShapeDef = new PolygonDef();
boxShapeDef.setAsBox((float) 50.0, (float) 10.0);
groundBody.createShape(boxShapeDef);
}
public void addBall()
{
// Create Dynamic Body
BodyDef bodyDef = new BodyDef();
bodyDef.position.set((float)16.0+(count * 10), (float)24.0);
Body newBody = world.createDynamicBody(bodyDef);
// Create Shape with Properties
CircleDef circle = new CircleDef();
circle.radius = (float)5;
circle.density = (float)1.0;
// Assign shape to Body
newBody.createShape(circle);
newBody.setMassFromShapes();
newBody.m_userData = "Circle";
bodies.add(newBody);
// Increase Counter
count += 1;
}
public void addBox()
{
// Create Dynamic Body
BodyDef bodyDef = new BodyDef();
bodyDef.position.set((float)36.0+(count * 10), (float)24.0);
Body newBody = world.createDynamicBody(bodyDef);
// Create Shape with Properties
boxShapeDef = new PolygonDef();
boxShapeDef.setAsBox((float) 50.0, (float) 10.0);
// Assign shape to Body
newBody.createShape(boxShapeDef);
newBody.setMassFromShapes();
newBody.m_userData = "Box";
bodies.add(newBody);
// Increase Counter
count += 1;
}
/*
*
*
* Physics Update
*/
private Vec2 position;
private float angle;
public void Update(Canvas canvas)
{
// Update Physics World
world.step(timeStep/5, 1);
// Print info of latest body
for (Body i : bodies)
{
position = i.getPosition();
angle = i.getAngle();
if(i.m_userData == "Circle")
canvas.drawCircle(position.x, position.y, 5,paint );
if(i.m_userData == "Box")
canvas.drawRect((float)(position.x -5), (float)(position.y - 5), (float)(position.x + 5), (float)(position.y + 5), paint );
Log.v("Physics Test", "Pos: (" + position.x + ", " + position.y + "), Angle: " + angle);
}
}
}
In response to this part of your question:
"is my drawing the right implementation or is there a better way"
This is from the Box2D website:
What units does Box2D use?
Box2D is tuned for meters-kilograms-seconds (MKS). Your moving objects should be between 0.1 - 10 meters. Do not use pixels as units! You will get a jittery simulation.
How do I convert pixels to meters?
Suppose you have a sprite for a character that is 100x100 pixels. You decide to use a scaling factor that is 0.01. This will make the character physics box 1m x 1m. So go make a physics box that is 1x1. Now suppose the character starts out at pixel coordinate (345,679). So position the physics box at (3.45,6.79). Now simulate the physics world. Suppose the character physics box moves to (2.31,4.98), so move your character sprite to pixel coordinates (231,498). Now the only tricky part is choosing a scaling factor. This really depends on your game. You should try to get your moving objects in the range 0.1 - 10 meters, with 1 meter being the sweet spot.
...
What are the biggest mistakes made by new users?
Using pixels for length instead of meters.
...
Source: http://code.google.com/p/box2d/wiki/FAQ
public class PhysicsWorld extends View{
protected static final int GUIUPDATEIDENTIFIER = 0x231;
public int targetFPS = 40;
public float timeStep = 10.0f / targetFPS;
public int iterations = 5;
private Body[] bodies;
private int count = 0;
private AABB worldAABB;
public World world;
private PolygonDef groundShapeDef;
public int World_W,World_H;
private Paint paint;
private float radius=10;
public PhysicsWorld(Context context,int W,int H) {
super(context);
World_W=W;
World_H=H;
// Step 1: Create Physics World Boundaries
worldAABB = new AABB();
Vec2 min = new Vec2(-50, -50);
Vec2 max = new Vec2(World_W + 50, World_H + 50);
worldAABB.lowerBound.set(min);
worldAABB.upperBound.set(max);
// Step 2: Create Physics World with Gravity
Vec2 gravity = new Vec2((float) 0.0, (float) -10.0);
boolean doSleep = true;
world = new World(worldAABB, gravity, doSleep);
// Step 3:
//Create Ground Box :
BodyDef bodyDef = new BodyDef();
bodyDef.position.set(new Vec2((float) 0.0, (float) -10.0));
Body groundBody = world.createBody(bodyDef);
groundShapeDef = new PolygonDef();
groundShapeDef.setAsBox((float) World_W, (float) 10);
groundBody.createShape(groundShapeDef);
// up :
bodyDef = new BodyDef();
bodyDef.position.set(new Vec2((float) 0.0, (float) (World_H+10.0) ));
groundBody = world.createBody(bodyDef);
groundShapeDef = new PolygonDef();
groundShapeDef.setAsBox((float) World_W, (float) 10);
groundBody.createShape(groundShapeDef);
// left :
bodyDef = new BodyDef();
bodyDef.position.set(new Vec2((float) -10, (float) 0.0 ));
groundBody = world.createBody(bodyDef);
groundShapeDef = new PolygonDef();
groundShapeDef.setAsBox((float)10, (float) World_H);
groundBody.createShape(groundShapeDef);
// right :
bodyDef = new BodyDef();
bodyDef.position.set(new Vec2((float) World_W+10, (float) 0.0 ));
groundBody = world.createBody(bodyDef);
groundShapeDef = new PolygonDef();
groundShapeDef.setAsBox((float)10, (float) World_H);
groundBody.createShape(groundShapeDef);
//
// step 4: initialize
bodies=new Body[50];
//
paint=new Paint();
paint.setStyle(Style.FILL_AND_STROKE);
paint.setColor(Color.CYAN);
}
public void addBall() {
// Create Dynamic Body
BodyDef bodyDef = new BodyDef();
Random rnd = new Random();
bodyDef.position.set((float) radius*2+rnd.nextInt( (int)(World_W-radius*4) ), (float)2*radius+ rnd.nextInt( (int)(World_H-radius*4) ));
bodies[count] = world.createBody(bodyDef);
// Create Shape with Properties
CircleDef circle = new CircleDef();
circle.radius = (float) radius;
circle.density = (float) 1.0;
circle.friction = 0.1f;
circle.restitution=0.5f;
// Assign shape to Body
bodies[count].createShape(circle);
bodies[count].setMassFromShapes();
// Increase Counter
count += 1;
}
public void addBox() {
BodyDef bodyDef = new BodyDef();
Random rnd = new Random();
bodyDef.position.set((float)2*count+rnd.nextInt( (int)(World_W-4*count) ), (float)2*count+rnd.nextInt( (int)(World_H-count*4) ));
bodies[count] = world.createBody(bodyDef);
// Create Shape with Properties
PolygonDef boxShapeDef = new PolygonDef();
boxShapeDef.setAsBox((float) 10.0, (float) 10.0);
boxShapeDef.density = 1.0f; // A density of 0 will create a fixed Body that doesn't move
boxShapeDef.friction = 0.1f; // How much friction
boxShapeDef.restitution = 0.5f; // How bouncy is this Shape?
// Assign shape to Body
bodies[count].createShape(boxShapeDef);
bodies[count].setMassFromShapes();
bodies[count].m_userData = "Box";
count += 1;
}
public void update() {
world.step(timeStep/5, 1);
postInvalidate();
}
protected void onDraw(Canvas canvas) {
for(int j = 0;j<count;j++)
{
canvas.drawRect((float)(bodies[j].getPosition().x -10), (float)(bodies[j].getPosition().y - 10), (float)(bodies[j].getPosition().x+ 10), (float)(bodies[j].getPosition().y + 10), paint );
canvas.drawCircle(bodies[j].getPosition().x,World_H- bodies[j].getPosition().y, radius, paint);
}
}

Categories

Resources