Jbox2d實(shí)踐應(yīng)用

開(kāi)門(mén)見(jiàn)山,一針見(jiàn)血~~先來(lái)一張圖片再說(shuō)!

前言

JBox2D是開(kāi)源的物理引擎Box2D的Java版本,可以直接用于Android。由于JBox2D的圖形渲染使用的是Processing庫(kù),因此在Android平臺(tái)上使用JBox2D時(shí),圖形渲染工作只能自行開(kāi)發(fā)。該引擎能夠根據(jù)開(kāi)發(fā)人員設(shè)定的參數(shù),如重力、密度、摩擦系數(shù)和彈性系數(shù)等,自動(dòng)地進(jìn)行2D剛體物理運(yùn)動(dòng)的全方位模擬。

開(kāi)發(fā)前準(zhǔn)備

首先我們得上github上下載對(duì)應(yīng)的jbox2d庫(kù),具體鏈接github.com/jbox2d/jbox2d,我們發(fā)現(xiàn)下載下來(lái)的是zip包,我們可是要的jar包啊。。ok,這里我們就先自行解壓再說(shuō)。解壓完畢發(fā)現(xiàn)它是一個(gè)maven工程,全部是源碼,我擦嘞,這可咋辦,不是gradle結(jié)構(gòu)的。好這里我們就要使用gradle命令把maven工程轉(zhuǎn)成gradle結(jié)構(gòu),這里我們需要自己編譯jar包。

方法一:用gradle編譯maven工程

1.先cmd進(jìn)入到剛下載解壓出來(lái)的jbox2d文件目錄,執(zhí)行maven工程轉(zhuǎn)gradle工程命令 gradle init --type pom

2.接著我們進(jìn)去編譯好的工程目錄,進(jìn)入路徑 jbox2d-master\gradle\wrapper,里面有個(gè)gradle-wrapper.properties文件,在這里,我們打開(kāi)并修改自己gradle已經(jīng)緩存有的版本,這里我修改成distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip,不然是編譯不了的。

3.ok,接下來(lái)我們導(dǎo)入工程。我們需要編譯給我們自己用的jar也是通過(guò)這里的jbox2d-library進(jìn)行編譯的,我們?cè)谟疫叺膅radle選項(xiàng)卡中找到對(duì)應(yīng)的jbox2d-library/Task/build/assemble,雙擊進(jìn)行編譯。如下圖:


心里喜滋滋的準(zhǔn)備生成jar包....居然提示報(bào)錯(cuò)了,關(guān)鍵是沒(méi)有提示報(bào)錯(cuò)的內(nèi)容。這里十分抓狂,github上down下來(lái)的難道沒(méi)有維護(hù)和更新嗎?。。這里我們上去看了看最近都有人在更新,這咋辦....不知道如何下手,很多人都在這里放棄了,不要灰心,我們來(lái)看第四步。

4.我們用命令行看看報(bào)錯(cuò)內(nèi)容。

這里window使用命令是:gradlew :jbox2d-library(模塊名稱(chēng)):assemble(任務(wù))

mac命令為:gradle :jbox2d-library(模塊名稱(chēng)):assemble(任務(wù))

5.好這里可以看到報(bào)的什么錯(cuò),結(jié)果只是一個(gè)簡(jiǎn)單的錯(cuò)誤,包名引用錯(cuò)誤,自行改一下源碼,重新編譯即可打包出jar。

方法二:用maven命令直接編譯maven工程

1.首先在本機(jī)環(huán)境安裝maven :maven.apache.org/download.cgi#,并配置環(huán)境

2.在cmd的命令行的輸入mvn install (注:這里是在jbox2d-master目錄下執(zhí)行的命令)

好吧,maven就兩個(gè)步驟就可以了.......


前方高能預(yù)警~GO!GO!GO!開(kāi)始擼碼

我們來(lái)先了解一下Jbox2d基本概念:

1. 剛體(rigid body)/物體(body)

一塊十分堅(jiān)硬的物質(zhì),它上面的任何兩點(diǎn)之間的距離是完全不變的。它們就像鉆石那樣的堅(jiān)硬。

2. 形狀(shape)

一塊嚴(yán)格依附于物體的 2D碰撞幾何結(jié)構(gòu),形狀具有摩擦和恢復(fù)的材料性質(zhì)。

3.固定裝置(fixture):

fixture綁定一個(gè)形狀到物體,增加材料屬性,例如密度,摩擦,恢復(fù)。

4.約束

一個(gè)約束就是消除物體自由度的物理連接,在2D中,一個(gè)物體有3個(gè)自由度(水平,垂直,旋轉(zhuǎn)),比如秒針,固定后,消除了想x,y的自由度,只剩下旋轉(zhuǎn)一個(gè)自由度

5.世界 world

一個(gè)物理世界就是物體,形狀和約束相互作用的集合。Box2D支持創(chuàng)建多個(gè)世界,但這通常是不必要的。

思路:

1.創(chuàng)建一個(gè)JboxImpl類(lèi),專(zhuān)門(mén)用于管理剛體和世界的創(chuàng)建和邏輯計(jì)算

2.自定義一個(gè)view,這里為了方便直接繼承FrameLayout,并且在真實(shí)屏幕中將JboxImpl中計(jì)算出剛體運(yùn)動(dòng)的坐標(biāo)綁定給真實(shí)的view(也就是這里的image),根據(jù)重力感應(yīng)不停的回調(diào)繪制。

3.MainActivity中做重力感應(yīng)的注冊(cè),回調(diào)的變化傳遞到j(luò)boxView進(jìn)行界面重繪。

JboxView類(lèi)

將屏幕的寬高傳遞給世界

@Override

protected void onSizeChanged(int w, int h, int oldw, int oldh) {

super.onSizeChanged(w, h, oldw, oldh);

jboxImpl.setWorlSize(w,h);

}

初始化世界與創(chuàng)建剛體

@Override

protected void onLayout(boolean changed, int left, int top, int right, int bottom) {

super.onLayout(changed, left, top, right, bottom);

jboxImpl.createWorld();

//子viwe創(chuàng)建tag 設(shè)置body

int childCount = getChildCount();

for (int i =0; i< childCount; i++) {

View view = getChildAt(i);

//body為空時(shí)創(chuàng)建剛體

if (!jboxImpl.isBodyView(view) || changed) {

jboxImpl.creatBody(view);

}

}

}

開(kāi)啟世界與做剛體運(yùn)動(dòng)的view繪制

@Override

protected void onDraw(Canvas canvas) {

jboxImpl.startWorld();

int childCount = getChildCount();

for (int i =0; i< childCount; i++) {

View view = getChildAt(i);

if (jboxImpl.isBodyView(view)) {

view.setX(jboxImpl.getViewX(view));

view.setY(jboxImpl.getViewY(view));

view.setRotation(jboxImpl.getViewRotaion(view));

}

}

invalidate();

}

JboxImpl類(lèi)

創(chuàng)建世界

public void createWorld() {

if (mWorld == null) {

mWorld = new World(new Vec2(0, 10.0f));

//創(chuàng)建左右邊界靜止剛體

updateVertiacalBounds();

//創(chuàng)建上下邊界靜止剛體

updateHorizontalBounds();

}

}

開(kāi)始世界

public void startWorld(){

if (mWorld != null) {

mWorld.step(dt, mVelocityIterations, mPosiontIterations);

}

}

創(chuàng)建世界的上下邊界,這里上下邊界是一個(gè)靜止的剛體

private void updateHorizontalBounds() {

BodyDef bodyDef = new BodyDef();

//創(chuàng)建靜止剛體

bodyDef.type = BodyType.STATIC;

//定義的形狀

PolygonShape box = new PolygonShape();

float boxWidth = switchPositionToBody(mWidth);

//設(shè)置邊界高度為1

float boxHeight = switchPositionToBody(mRatio);

box.setAsBox(boxWidth, boxHeight); //確定為矩形

FixtureDef fixtureDef = new FixtureDef();

fixtureDef.shape = box;

fixtureDef.density = mDesity;

fixtureDef.friction = 0.8f;//摩擦系數(shù)

fixtureDef.restitution = 0.5f; //補(bǔ)償系數(shù)

bodyDef.position.set(0, -boxHeight);

Body topBody = mWorld.createBody(bodyDef); //創(chuàng)建一個(gè)真實(shí)的上邊 body

topBody.createFixture(fixtureDef);

bodyDef.position.set(0, switchPositionToBody(mHeight) + boxHeight);

Body bottomBody = mWorld.createBody(bodyDef);//創(chuàng)建一個(gè)真實(shí)的下邊 body

bottomBody.createFixture(fixtureDef);

}

創(chuàng)建運(yùn)動(dòng)剛體

public void creatBody(View view) {

BodyDef bodyDef = new BodyDef();

bodyDef.setType(BodyType.DYNAMIC);

bodyDef.position.set(switchPositionToBody( view.getX() + (view.getWidth() / 2) )

,switchPositionToBody(view.getY() + (view.getHeight() / 2))? );

Shape shape = null;

Boolean isCircle = (Boolean) view.getTag(R.id.dn_view_circle_tag);

if (isCircle != null && isCircle) {

shape = craeteCircleShape( switchPositionToBody(view.getWidth() / 2) );

} else {

Log.i("kaka","createBody veiw tag is not circle!!!");

return;

}

FixtureDef fixtureDef = new FixtureDef();

fixtureDef.setShape(shape);

fixtureDef.friction = 0.8f;//摩擦系數(shù)

fixtureDef.density = mDesity;

fixtureDef.restitution = 0.5f;//補(bǔ)償系數(shù)

Body body = mWorld.createBody(bodyDef);

body.createFixture(fixtureDef);

view.setTag(R.id.dn_view_body_tag, body);

body.setLinearVelocity(new Vec2(mRandom.nextFloat(), mRandom.nextFloat()));

}

MainActivity類(lèi)

主要實(shí)現(xiàn)SensorEventListener接口

@Override

public void onSensorChanged(SensorEvent event) {

if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {

float x = event.values[0];

float y = event.values[1] * 2.0f;

jboxView.onSensorChanged(-x, y);

}

}


總結(jié):

其實(shí)jbox2d提供的接口運(yùn)用起來(lái)并不是很難,難的物理學(xué)部分計(jì)算都在jbox2d中計(jì)算好了,他會(huì)返回給我們坐標(biāo)值,這里的坐標(biāo)值是世界中的坐標(biāo)值。我們需要將它轉(zhuǎn)化成真實(shí)屏幕的坐標(biāo)值重繪就ok了。一個(gè)view對(duì)應(yīng)世界中的一個(gè)剛體。

代碼地址:github.com/kakaandfigo/Jbox2dProject


好了今天先寫(xiě)到這里。~~~~~~~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容