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) ba开发者_如何学Gose.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);
}
}
精彩评论