jbox2d使用问题

lbgongfu 发布于 2013/08/08 09:11
阅读 1K+
收藏 0

@小耶果 你好,想跟你请教个问题:

最近一直学习android jbox2d,也试着做了一个练习,但是遇到了一个让我很头疼的问题。是这样的,屏幕上绘制了一个框框,框框里面绘制了一个球,球会自由落体,但是当球碰到下边框的时候并没有弹起,直接穿过去了。查了很多资料,就是找不到答案,请问是怎么回事?

以下是有问题的代码。
不知道在哪里编辑原帖子,所以就在此列出。
//GameView.java 视图类

package com.example.jbox2ddemo;

import java.util.ArrayList;
import java.util.List;

import org.jbox2d.common.Vec2;
import org.jbox2d.dynamics.World;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback;
import android.view.SurfaceView;

public class GameView extends SurfaceView implements Callback {
	private DrawThread drawThread;
	private List<CustomBody> bodyList = new ArrayList<CustomBody>();
	private World world;

	public GameView(Context context) {
		super(context);
		getHolder().addCallback(this);
		world = new World(new Vec2(0f, 10f));
		world.setAllowSleep(true);
		world.setContinuousPhysics(true);
		world.setSubStepping(true);
		world.setWarmStarting(true);
		drawThread = new DrawThread(this, getHolder());
		drawThread.start();
	}
	
	public void addBodys(CustomBody... bodys) {
		for (CustomBody body : bodys) {
			bodyList.add(body);
		}
	}

	public void doDraw(Canvas canvas, Paint paint) {
		canvas.drawColor(Color.BLACK);
		for (CustomBody body : bodyList) {
			body.drawSelf(canvas, paint);
		}
	}
	
	public World getWorld() {
		return world;
	}
	
	@Override
	public void surfaceChanged(SurfaceHolder holder, int format, int width,
			int height) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void surfaceCreated(SurfaceHolder holder) {
		if (!drawThread.isAlive()) {
			drawThread.start();
		}
	}

	@Override
	public void surfaceDestroyed(SurfaceHolder holder) {
		drawThread.setFlag(false);
		drawThread = null;
	}
	
}
//=========
//DrawThread.java 刷频线程

package com.example.jbox2ddemo;

import org.jbox2d.dynamics.World;

import android.graphics.Canvas;
import android.graphics.Paint;
import android.view.SurfaceHolder;

public class DrawThread extends Thread {
	private boolean flag = false;
	private long timeSleep = 20;
	private GameView gameView;
	private SurfaceHolder holder;

	public DrawThread(GameView view, SurfaceHolder holder) {
		flag = true;
		this.gameView = view;
		this.holder = holder;
	}
	
	@Override
	public void run() {
		World world = gameView.getWorld();
		Canvas canvas;
		Paint paint = new Paint();
		paint.setAntiAlias(true);
		while (flag) {
			world.step(Constant.TIME_STEP, Constant.VELOCITY_ITERATIONS, Constant.POSITION_ITERATIONS);
			canvas = holder.lockCanvas();
			if (canvas != null) {
				gameView.doDraw(canvas, paint);
				holder.unlockCanvasAndPost(canvas);
			}
			try {
				Thread.sleep(timeSleep);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}

	public void setFlag(boolean flag) {
		this.flag = flag;
	}
}
==========
MainActivity.java

package com.example.jbox2ddemo;

import org.jbox2d.dynamics.World;

import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.view.Menu;
import android.view.Window;
import android.view.WindowManager;

public class MainActivity extends Activity {
	private GameView gameView;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		requestWindowFeature(Window.FEATURE_NO_TITLE);
		getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
		DisplayMetrics dm = new DisplayMetrics();
		getWindowManager().getDefaultDisplay().getMetrics(dm);
		Constant.SCREEN_WIDTH = dm.widthPixels;
		Constant.SCREEN_HEIGHT = dm.heightPixels;
		
		gameView = new GameView(this);
		World world = gameView.getWorld();
		int span = 20;
		CustomBody ground = Box2dUtil.createRectBody(world, 0, Constant.SCREEN_HEIGHT - span, Constant.SCREEN_WIDTH, span, Color.GREEN, 0f, 0.3f, 0.8f, true);
		CustomBody ball = Box2dUtil.createCircleBody(world, Constant.SCREEN_WIDTH / 2, 30, Color.WHITE, 30, 1f, 0.1f, 0.8f, false);
		gameView.addBodys(ground, ball);
		setContentView(gameView);
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.main, menu);
		return true;
	}

}
//==========
//CustomBody.java 自定义body超类

package com.example.jbox2ddemo;

import org.jbox2d.dynamics.Body;

import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;

public abstract class CustomBody {
	protected Body body;
	protected int color = Color.RED;
	
	public abstract void drawSelf(Canvas canvas, Paint paint);
}
//============
//CircleBody.java// 圆形body

package com.example.jbox2ddemo;

import org.jbox2d.dynamics.Body;

import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Paint.Style;

public class CircleBody extends CustomBody {
	private int radius;
	
	public CircleBody(Body body, int color, int radius) {
		this.body = body;
		this.color = color;
		this.radius = radius;
	}
	
	@Override
	public void drawSelf(Canvas canvas, Paint paint) {
		paint.setStyle(Style.STROKE);
		paint.setStrokeWidth(1);
		paint.setColor(color);
		int x = (int) (body.getPosition().x * Constant.SCALE_FACTOR);
		int y = (int) (body.getPosition().y * Constant.SCALE_FACTOR);
		canvas.drawCircle(x, y, radius, paint);
	}

}
=========
RectBody.java//矩形body

package com.example.jbox2ddemo;

import org.jbox2d.dynamics.Body;

import android.graphics.Canvas;
import android.graphics.Paint;

public class RectBody extends CustomBody {
	private int width;
	private int height;
	
	public RectBody(Body body, int color, int width, int height) {
		this.body = body;
		this.color = color;
		this.width = width;
		this.height = height;
	}
	
	@Override
	public void drawSelf(Canvas canvas, Paint paint) {
		paint.setColor(color);
		int x = (int) (body.getPosition().x * Constant.SCALE_FACTOR);
		int y = (int) (body.getPosition().y * Constant.SCALE_FACTOR);
		canvas.drawRect(x, y, x + width, y + height, paint);
	}

}
========
Box2dUtil.java//用于创建自定义body对象的

package com.example.jbox2ddemo;

import org.jbox2d.collision.shapes.CircleShape;
import org.jbox2d.collision.shapes.PolygonShape;
import org.jbox2d.common.Vec2;
import org.jbox2d.dynamics.Body;
import org.jbox2d.dynamics.BodyDef;
import org.jbox2d.dynamics.BodyType;
import org.jbox2d.dynamics.FixtureDef;
import org.jbox2d.dynamics.World;

public class Box2dUtil {
	public static CircleBody createCircleBody(World world, int x, int y,
			int color, int radius, float density, float friction,
			float restitution, boolean isStatic) {
		BodyDef bodyDef = new BodyDef();
		bodyDef.position = new Vec2(x / Constant.SCALE_FACTOR, y
				/ Constant.SCALE_FACTOR);
		Body body = world.createBody(bodyDef);
		body.setType(isStatic ? BodyType.STATIC : BodyType.DYNAMIC);
		CircleShape shape = new CircleShape();
		shape.m_radius = radius;
		FixtureDef fixtureDef = new FixtureDef();
		fixtureDef.shape = shape;
		fixtureDef.density = density;
		fixtureDef.friction = friction;
		fixtureDef.restitution = restitution;
		body.createFixture(fixtureDef);
		return new CircleBody(body, color, radius);
	}
	
	public static RectBody createRectBody(World world, int x, int y, int width, int height,int color, float density, float friction, float restitution, boolean isStatic) {
		BodyDef bodyDef = new BodyDef();
		bodyDef.position = new Vec2(x / Constant.SCALE_FACTOR, y / Constant.SCALE_FACTOR);
		Body body = world.createBody(bodyDef);
		body.setType(isStatic ? BodyType.STATIC : BodyType.DYNAMIC);
		PolygonShape shape = new PolygonShape();
		shape.setAsBox(width / 2 / Constant.SCALE_FACTOR, height / 2 / Constant.SCALE_FACTOR);
		FixtureDef fixtureDef = new FixtureDef();
		fixtureDef.density = density;
		fixtureDef.friction = friction;
		fixtureDef.restitution = restitution;
		return new RectBody(body, color, width, height);
	}
}
//=========
//Constant.java 常量

package com.example.jbox2ddemo;

public class Constant {
	public static final int SCALE_FACTOR = 10;
	public static final float TIME_STEP = 1f / 60f;
	public static final int VELOCITY_ITERATIONS = 3;
	public static final int POSITION_ITERATIONS = 8;
	public static int SCREEN_WIDTH;
	public static int SCREEN_HEIGHT;
}

加载中
0
小耶果
小耶果

jbox2d是java对box2d的封装,可能例子较少.推荐看C++的子,网上到处都是.像LZ这样的需求自带的例子可以完全达到要求.

这里贴一个其中的test,完全符合LZ的需求预期.代码不长(去除了渲染代码),你可以对比自己的代码看哪里出错

Tumbler()
	{
		b2Body* ground = NULL;
		{
			b2BodyDef bd;
			ground = m_world->CreateBody(&bd);
		}

		{
			b2BodyDef bd;
			bd.type = b2_dynamicBody;
			bd.allowSleep = false;
			bd.position.Set(0.0f, 10.0f);
			b2Body* body = m_world->CreateBody(&bd);

			b2PolygonShape shape;
			shape.SetAsBox(0.5f, 10.0f, b2Vec2( 10.0f, 0.0f), 0.0);
			body->CreateFixture(&shape, 5.0f);
			shape.SetAsBox(0.5f, 10.0f, b2Vec2(-10.0f, 0.0f), 0.0);
			body->CreateFixture(&shape, 5.0f);
			shape.SetAsBox(10.0f, 0.5f, b2Vec2(0.0f, 10.0f), 0.0);
			body->CreateFixture(&shape, 5.0f);
			shape.SetAsBox(10.0f, 0.5f, b2Vec2(0.0f, -10.0f), 0.0);
			body->CreateFixture(&shape, 5.0f);

			b2RevoluteJointDef jd;
			jd.bodyA = ground;
			jd.bodyB = body;
			jd.localAnchorA.Set(0.0f, 10.0f);
			jd.localAnchorB.Set(0.0f, 0.0f);
			jd.referenceAngle = 0.0f;
			jd.motorSpeed = 0.05f * b2_pi;
			jd.maxMotorTorque = 1e8f;
			jd.enableMotor = true;
			m_joint = (b2RevoluteJoint*)m_world->CreateJoint(&jd);
		}

		m_count = 0;
	}

	void Step(Settings* settings)
	{
		Test::Step(settings);

		if (m_count < e_count)
		{
			b2BodyDef bd;
			bd.type = b2_dynamicBody;
			bd.position.Set(0.0f, 10.0f);
			b2Body* body = m_world->CreateBody(&bd);

			b2PolygonShape shape;
			shape.SetAsBox(0.125f, 0.125f);
			body->CreateFixture(&shape, 1.0f);

			++m_count;
		}
	}

	static Test* Create()
	{
		return new Tumbler;
	}

	b2RevoluteJoint* m_joint;
	int32 m_count;

另外再贴一个简单的jbox2d教程:http://download.csdn.net/detail/nono_love_lilith/4131004

简单的概念介绍:

http://blog.csdn.net/jiarusun000/article/details/6947760

http://labs.easymobi.cn/?p=1421

lbgongfu
lbgongfu
我没有c++基础,看起来好吃力啊
lbgongfu
lbgongfu
谢谢。我会认真看的。
0
小耶果
小耶果
package com.ray.test;

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.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;

public class MyBox2d extends Activity {
	
	private final static int RATE = 10;//屏幕到现实世界的比例 10px:1m;
	private AABB worldAABB;//创建 一个管理碰撞的世界
	private World world;
	private float timeStep = 1/60;//模拟的的频率
	private int iterations = 10;//迭代越大,模拟约精确,但性能越低
	private Body body,body2,body3;
	private MyView myView;
	private Handler mHandler;
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().setFlags(WindowManager.LayoutParams. FLAG_FULLSCREEN ,
        WindowManager.LayoutParams. FLAG_FULLSCREEN);
        
        worldAABB = new AABB();
         
       //上下界,以屏幕的左上方为 原点,如果创建的刚体到达屏幕的边缘的话,会停止模拟
        worldAABB.lowerBound.set(-100.0f,-100.0f);
        worldAABB.upperBound.set(100.0f, 100.0f);//注意这里使用的是现实世界的单位
        
        Vec2 gravity = new Vec2(0.0f,10.0f);
        boolean doSleep = true;
        

        world = new World(worldAABB, gravity, doSleep);//创建世界
        
        createBox(160, 470, 160, 10, true);     
        createBox1(160, 150, 160, 10, false);
        
        createCircle(160, 100, 10);
        createCircle1(150, 60, 10);
        timeStep = 1.0f/60.0f;
        iterations = 10;
        
        myView = new MyView(this);
        setContentView(myView);
        mHandler = new Handler();
        mHandler.post(update);
    }
    
    private Runnable update = new Runnable() {
        public void run() {
            	world.step(timeStep, iterations);//开始模拟
            	Vec2 position = body.getPosition();
            	Vec2 position1 = body2.getPosition();
            	Vec2 position2 = body3.getPosition();
            	myView.x=position.x*RATE;
            	myView.y=position.y*RATE;
            	
            	myView.x1=position1.x*RATE; 
            	myView.y1=position1.y*RATE;
            	
            	myView.x2=position2.x*RATE;
            	myView.y2=position2.y*RATE;
                myView.update();
                mHandler.postDelayed(update, (long)timeStep*1000);
        }
    };
    
    public void createBox(float x,float y,float half_width,float half_height,
                     boolean isStatic){ 
    	PolygonDef shape = new PolygonDef();
    	if(isStatic){shape.density = 0;}
    	else{shape.density = 2.0f;}
    	shape.friction = 0.8f;
    	shape.restitution = 0.3f;
    	shape.setAsBox(half_width/RATE, half_height/RATE);
    	
    	BodyDef bodyDef = new BodyDef();
    	bodyDef.position.set(x/RATE, y/RATE);
    	Body body1= world.createBody(bodyDef);
    	body1.createShape(shape);
    	body1.setMassFromShapes();
    }
    
    public void createCircle(float x,float y,float radius){
    	CircleDef shape = new CircleDef();
    	shape.density = 7;
    	shape.friction = 0.2f;
    	shape.radius = radius/RATE;
    	
    	BodyDef bodyDef = new BodyDef();
    	bodyDef.position.set(x/RATE, y/RATE);
    	body2 = world.createBody(bodyDef);
    	body2.createShape(shape);
    	body2.setMassFromShapes();
    }
    
    public void createCircle1(float x,float y,float radius){
    	CircleDef shape = new CircleDef();
    	shape.density = 7;
    	shape.friction = 0.2f;
    	shape.radius = radius/RATE;
    	
    	BodyDef bodyDef = new BodyDef();
    	bodyDef.position.set(x/RATE, y/RATE);
    	body3 = world.createBody(bodyDef);
    	body3.createShape(shape);
    	body3.setMassFromShapes();
    }
    
    public void createBox1(float x,float y,float half_width,float half_height,
                   boolean isStatic){ 
    	PolygonDef shape = new PolygonDef();
    	if(isStatic){shape.density = 0;}
    	else{shape.density = 2.0f;}
    	shape.friction = 0.3f;
    	shape.setAsBox(half_width/RATE, half_height/RATE);
    	
    	BodyDef bodyDef = new BodyDef();
    	bodyDef.position.set(x/RATE, y/RATE);
    	body= world.createBody(bodyDef);
    	body.createShape(shape);
    	body.setMassFromShapes();
    }
    
    class MyView extends View{
    	Canvas canvas;
    	public float x=160,y=150;
    	public float x1=160,y1=100;
    	public float x2=150,y2=60;
		public MyView(Context context) {
			super(context);
		}

		public void drawBox(float x,float y){
			Paint mPaint = new Paint();
			mPaint.setAntiAlias(true);
			mPaint.setColor(Color.RED);
			canvas.drawRect(x-160, y-10, x+160, y+10, mPaint);
		}
		
		public void drawGround(){
			Paint mPaint = new Paint();
			mPaint.setAntiAlias(true);
			mPaint.setColor(Color.BLUE);
			canvas.drawRect(0, 460, 320, 480, mPaint);
		}
		
		public void drawCircle(float x1,float y1){
			Paint mPaint = new Paint();
			mPaint.setAntiAlias(true);
			mPaint.setColor(Color.GREEN);
			canvas.drawCircle(x1, y1, 10, mPaint);
		}
		
		public void update(){
			postInvalidate();
		}
		
		protected void onDraw(Canvas canvas) {
			super.onDraw(canvas);
			this.canvas = canvas;
			drawGround();
			drawBox(x, y);
			drawCircle(x1, y1);
			drawCircle(x2, y2);
		}
		
    	
    }
}
返回顶部
顶部