天天看點

JBox2D學習 - 小球碰撞

 Android 交流群 110687406       
JBox2D學習 - 小球碰撞

使用引擎版本:jbox2d-library-2.1.2.jar

封裝好的JBOX2D引擎,專門适合android平台使用

點選下載下傳

注意:下載下傳這個封裝好的不需要slfj庫支援,效率更高

之前在jbox2d 官網下載下傳的2.1.2一直跑不起來,發現jar包有問題,後來在官網發文章,jbox2d作者非常耐心的解答了我的問題,終于用上2.1.2的jbox2d了哇,

非常感謝老外的開源精神

JBox2D學習 - 小球碰撞

,做出這麼好的實體引擎,完全免費

jbox2d官網:http://code.google.com/p/jbox2d/

現在奉上我學習jbox2d做的demo,這個demo類似與testbed 裡的 varying restitution

baseview.java:

package com.tszy.testjbox2d212;

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;
import org.jbox2d.dynamics.joints.MouseJoint;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.view.View;


public class BaseView extends View implements Runnable{
	public static final float RATE = 30.0f;		//比例尺
	public static final int DEF_FPS = 30;	//預設重新整理頻率
	 
	private Thread thread;
	
	protected World world;
	protected Paint paint;
	protected Matrix matrix;
	protected BodyDef bd;
	protected MouseJoint mouseJoint;
	
	public boolean a = true;
	public Body m_groundBody;
	
	
	public BaseView(Context context) {
		super(context);
		// TODO Auto-generated constructor stub
		bd = new BodyDef();
		
		paint = new Paint(Paint.ANTI_ALIAS_FLAG);// 無鋸齒
		paint.setStyle(Style.FILL);
		matrix = new Matrix();
		
		
		Vec2 gravity = new Vec2(0, 10f);
        world = new World(gravity, true);
        
        BodyDef bodyDef = new BodyDef();
        m_groundBody = world.createBody(bodyDef);
		
		thread = new Thread(this);
		thread.start();
	}

	
	/**
	 * 建立矩形
	 * @param world 所在世界
	 * @param x, y 中心點位置
	 * @param w, h 尺寸
	 * @param friction 摩擦力
	 * @param restitution 恢複力
	 * @param isStatic 靜态否
	 * @return 對象
	 */
	public Body createPolygon(float x, float y, float w, float h, 
			float friction, float restitution,
			boolean isStatic) {
		//建立多邊形皮膚
		PolygonShape shape = new PolygonShape();
		shape.setAsBox(w/2/RATE, h/2/RATE);
		
		FixtureDef fd = new FixtureDef();
		fd.shape = shape;
		fd.density =  1.0f;	//設定密度
		fd.friction = friction;			//設定摩擦力
		fd.restitution = restitution;	//設定多邊形的恢複力
		
		//設定剛體初始坐标
		bd.type = isStatic? BodyType.STATIC : BodyType.DYNAMIC;
		bd.position.set(x/RATE, y/RATE);
		
		//建立物體
		Body body = world.createBody(bd);	//實體世界建立物體
		
		//此方法改變了
		//body.createShape(pDef);	//為body添加皮膚
		body.createFixture(fd);
		
		return body;
	}
	
	public Body createPolygon(float x, float y, float w, float h, 
			boolean isStatic) {
		return createPolygon(x, y, w, h, 0.3f, 0.5f, isStatic);
	}
	
	/**
	 * 建立圓形
	 * @param world 所在世界
	 * @param x, y 圓心位置 
	 * @param r 半徑
	 * @param friction 摩擦力
	 * @param restitution 恢複力
	 * @param isStatic 靜态否
	 * @return 對象
	 */
	public Body createCircle(float x, float y, float r,
			float friction, float restitution,
			boolean isStatic) {
		//建立圓形皮膚
		CircleShape shape = new CircleShape();
		shape.m_radius = r/RATE;
		
		FixtureDef fd = new FixtureDef();
		fd.shape = shape;
		fd.density = 1.0f;
		fd.friction = friction;
		fd.restitution = restitution;
		
		//建立剛體
		bd.type = isStatic? BodyType.STATIC : BodyType.DYNAMIC;
		bd.position.set((x+r)/RATE, (y+r)/RATE);
		
		//建立一個body
		Body body = world.createBody(bd);
		body.createFixture(fd);
		
		return body;
	}
	
	
	public Vec2 screen2world(Vec2 p) {
		p.x /= RATE;
		p.y /= RATE;
		
		return p;
	}
	
	public Vec2 world2screen(Vec2 p){
		p.x *= RATE;
		p.y *= RATE;
		
		return p;
	}
	
	public Vec2 screen2world2(Vec2 p) {
		return new Vec2(p.x/RATE, p.y/RATE);
	}
	public Vec2 world2screen2(Vec2 p){
		return new Vec2(p.x*RATE, p.y*RATE);
	}
	
	private void drawFPS(Canvas canvas) {
		paint.setColor(0xffffffff);
		paint.setAntiAlias(true);
		if (USETIME > 0)
			canvas.drawText("FPS:" + (USETIME>0? 1000/USETIME : 33), 3,
					3 + paint.getTextSize(), paint);
	}
	
	@Override
	protected void onDraw(Canvas canvas) {
		// TODO Auto-generated method stub
		drawFPS(canvas);
		super.onDraw(canvas);
	}
	
	private long USETIME;
	@Override
	public void run() {
		// TODO Auto-generated method stub
		long t1, t2;
		
		while (a) {
			//模拟世界 
			//速度模拟頻率,位置模拟頻率
			world.step(1.0f/30.0f, 3, 8);
			
			t1 = System.currentTimeMillis();
			postInvalidate();
			t2 = System.currentTimeMillis();
			USETIME = t2 - t1;

			//正常休眠
			if (USETIME < 33) {
				try {
					Thread.sleep(33 - USETIME);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
	}
}
           

View.java

package com.tszy.testjbox2d212;

import org.jbox2d.callbacks.QueryCallback;
import org.jbox2d.collision.AABB;
import org.jbox2d.common.Vec2;
import org.jbox2d.dynamics.Body;
import org.jbox2d.dynamics.BodyType;
import org.jbox2d.dynamics.Fixture;
import org.jbox2d.dynamics.joints.MouseJoint;
import org.jbox2d.dynamics.joints.MouseJointDef;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.view.MotionEvent;


public class View6 extends BaseView {
	private static final float R = 15.0f;
	
	public View6(Context context) {
		super(context);
		// TODO Auto-generated constructor stub
		create();
	}

	private void create() {
		// 地闆
		Body body = null;
		
		body = createPolygon(10+460/2, 305, 460, 10, true);

		// 球
		float restitution[] = new float[]{0.0f, 0.1f, 0.3f, 0.5f, 0.75f, 0.9f, 1.0f};
		for (int i = 0; i < restitution.length; i++) {
			body = createCircle(80 + i * 40, 40, R, 0.3f, restitution[i], false);
		}
	}
	
	@Override
	protected void onDraw(Canvas canvas) {
		// TODO Auto-generated method stub
		canvas.drawColor(0xff000000);
		
		//地闆
		paint.setColor(0xff00ff00);
		paint.setAntiAlias(false); //消除畫筆鋸齒
		paint.setStyle(Paint.Style.STROKE);
		Rect r = new Rect(10, 300, 470, 310);
		canvas.drawRect(r, paint);
		r = null;
		
		//球
		//得到body連結清單表頭
		Body  body = world.getBodyList();
		for(int i=1; i<world.getBodyCount(); i++){
			if(body.getType() != BodyType.DYNAMIC){	//不是動态的物體
				continue;
			}
			drawBall(canvas, body);
			
			body = body.m_next;
		}
		
		//if(mouseJoint != null)
			drawLine(canvas);
		
		super.onDraw(canvas);
	}
	
	private void drawLine(Canvas canvas){
		if(curBody==null || !isMoving) return;

		paint.setAntiAlias(false); //消除畫筆鋸齒
		paint.setColor(Color.GREEN);
		paint.setStyle(Paint.Style.STROKE);
		
		Vec2 d = world2screen2(curBody.getPosition());
		Vec2 d2 = world2screen2(p);
		canvas.drawLine(d.x, d.y, d2.x, d2.y, paint);
	}
	
	private void drawBall(Canvas canvas, Body ball){
		//得到的body的質點坐标
		Vec2 p = world2screen2(ball.getPosition());
		
		//canvas.save();
		//擷取球的旋轉角度
		float degrees = (float) ((ball.getAngle()*180/Math.PI) % 360);
		
		matrix.reset();
		canvas.save();	//儲存不需要繪制的區域
		if (degrees != 0)
			matrix.preRotate(degrees, p.x, p.y);	//設定矩陣旋轉角度
		canvas.setMatrix(matrix);
		
		//填充
		paint.setColor(0x80ffbbff);
		paint.setStyle(Paint.Style.FILL);
		canvas.drawCircle(p.x, p.y, R, paint);
		
		//輪廓
		paint.setAntiAlias(true);
		paint.setColor(0xffffbbff);
		paint.setStyle(Paint.Style.STROKE);
		canvas.drawCircle(p.x, p.y, R, paint);
		//paint.setAntiAlias(false);
		
		//角度
		paint.setColor(0xff00ff00);
		paint.setStyle(Paint.Style.FILL);
		canvas.drawLine(p.x, p.y, p.x, p.y-R, paint);
		
		canvas.restore();
	}
	
	private boolean isMoving;
	private Body curBody;
	private Vec2 p;
	private final AABB queryAABB = new AABB();
    private final TestQueryCallback callback = new TestQueryCallback();
     
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		// TODO Auto-generated method stub
		p = screen2world(new Vec2(event.getX(), event.getY()));
		
		switch (event.getAction()) {
			case MotionEvent.ACTION_DOWN :{
				isMoving = true;
				
				if (mouseJoint != null) {
					return true;
				}
				
				queryAABB.lowerBound.set(p.x - .001f, p.y - .001f);
                queryAABB.upperBound.set(p.x + .001f, p.y + .001f);
                callback.point.set(p);
                callback.fixture = null;
                world.queryAABB(callback, queryAABB);
                
                if(callback.fixture != null){
                        curBody = callback.fixture.getBody();
                        MouseJointDef def = new MouseJointDef();
                        def.bodyA = m_groundBody;
                        def.bodyB = curBody;
                        def.target.set(p);
                        def.maxForce = 1000f * curBody.getMass();
                        mouseJoint = (MouseJoint) world.createJoint(def);
                        curBody.setAwake(true);
                }
			}
			
			case MotionEvent.ACTION_MOVE : {
				if (mouseJoint != null) {
		            mouseJoint.setTarget(p);
		        }
				
				return true;
			}

			case MotionEvent.ACTION_UP : {
				isMoving = false;
				
				if (mouseJoint != null) {
		            world.destroyJoint(mouseJoint);
		            mouseJoint = null;
		        }
				
				return true;
			}
		}

		return super.onTouchEvent(event);
	}
	
	class TestQueryCallback implements QueryCallback {
		public final Vec2 point;
		public Fixture fixture;

		public TestQueryCallback() {
			point = new Vec2();
			fixture = null;
		}

		/**
		 * @see org.jbox2d.callbacks.QueryCallback#reportFixture(org.jbox2d.dynamics.Fixture)
		 */
		public boolean reportFixture(Fixture argFixture) {
			Body body = argFixture.getBody();
			if (body.getType() == BodyType.DYNAMIC) {
				boolean inside = argFixture.testPoint(point);
				if (inside) {
					fixture = argFixture;

					return false;
				}
			}

			return true;
		}
	}
}
           

jbox2d庫,這兩個都需要

jbox2d-library-2.1.2.jar

slf4j-api-1.6.3.jar

繼續閱讀