Jbox2d实践应用

开门见山,一针见血~~先来一张图片再说!

前言

JBox2D是开源的物理引擎Box2D的Java版本,可以直接用于Android。由于JBox2D的图形渲染使用的是Processing库,因此在Android平台上使用JBox2D时,图形渲染工作只能自行开发。该引擎能够根据开发人员设定的参数,如重力、密度、摩擦系数和弹性系数等,自动地进行2D刚体物理运动的全方位模拟。

开发前准备

首先我们得上github上下载对应的jbox2d库,具体链接github.com/jbox2d/jbox2d,我们发现下载下来的是zip包,我们可是要的jar包啊。。ok,这里我们就先自行解压再说。解压完毕发现它是一个maven工程,全部是源码,我擦嘞,这可咋办,不是gradle结构的。好这里我们就要使用gradle命令把maven工程转成gradle结构,这里我们需要自己编译jar包。

方法一:用gradle编译maven工程

1.先cmd进入到刚下载解压出来的jbox2d文件目录,执行maven工程转gradle工程命令 gradle init --type pom

2.接着我们进去编译好的工程目录,进入路径 jbox2d-master\gradle\wrapper,里面有个gradle-wrapper.properties文件,在这里,我们打开并修改自己gradle已经缓存有的版本,这里我修改成distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip,不然是编译不了的。

3.ok,接下来我们导入工程。我们需要编译给我们自己用的jar也是通过这里的jbox2d-library进行编译的,我们在右边的gradle选项卡中找到对应的jbox2d-library/Task/build/assemble,双击进行编译。如下图:


心里喜滋滋的准备生成jar包....居然提示报错了,关键是没有提示报错的内容。这里十分抓狂,github上down下来的难道没有维护和更新吗?。。这里我们上去看了看最近都有人在更新,这咋办....不知道如何下手,很多人都在这里放弃了,不要灰心,我们来看第四步。

4.我们用命令行看看报错内容。

这里window使用命令是:gradlew :jbox2d-library(模块名称):assemble(任务)

mac命令为:gradle :jbox2d-library(模块名称):assemble(任务)

5.好这里可以看到报的什么错,结果只是一个简单的错误,包名引用错误,自行改一下源码,重新编译即可打包出jar。

方法二:用maven命令直接编译maven工程

1.首先在本机环境安装maven :maven.apache.org/download.cgi#,并配置环境

2.在cmd的命令行的输入mvn install (注:这里是在jbox2d-master目录下执行的命令)

好吧,maven就两个步骤就可以了.......


前方高能预警~GO!GO!GO!开始撸码

我们来先了解一下Jbox2d基本概念:

1. 刚体(rigid body)/物体(body)

一块十分坚硬的物质,它上面的任何两点之间的距离是完全不变的。它们就像钻石那样的坚硬。

2. 形状(shape)

一块严格依附于物体的 2D碰撞几何结构,形状具有摩擦和恢复的材料性质。

3.固定装置(fixture):

fixture绑定一个形状到物体,增加材料属性,例如密度,摩擦,恢复。

4.约束

一个约束就是消除物体自由度的物理连接,在2D中,一个物体有3个自由度(水平,垂直,旋转),比如秒针,固定后,消除了想x,y的自由度,只剩下旋转一个自由度

5.世界 world

一个物理世界就是物体,形状和约束相互作用的集合。Box2D支持创建多个世界,但这通常是不必要的。

思路:

1.创建一个JboxImpl类,专门用于管理刚体和世界的创建和逻辑计算

2.自定义一个view,这里为了方便直接继承FrameLayout,并且在真实屏幕中将JboxImpl中计算出刚体运动的坐标绑定给真实的view(也就是这里的image),根据重力感应不停的回调绘制。

3.MainActivity中做重力感应的注册,回调的变化传递到jboxView进行界面重绘。

JboxView类

将屏幕的宽高传递给世界

@Override

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

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

jboxImpl.setWorlSize(w,h);

}

初始化世界与创建刚体

@Override

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

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

jboxImpl.createWorld();

//子viwe创建tag 设置body

int childCount = getChildCount();

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

View view = getChildAt(i);

//body为空时创建刚体

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

jboxImpl.creatBody(view);

}

}

}

开启世界与做刚体运动的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类

创建世界

public void createWorld() {

if (mWorld == null) {

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

//创建左右边界静止刚体

updateVertiacalBounds();

//创建上下边界静止刚体

updateHorizontalBounds();

}

}

开始世界

public void startWorld(){

if (mWorld != null) {

mWorld.step(dt, mVelocityIterations, mPosiontIterations);

}

}

创建世界的上下边界,这里上下边界是一个静止的刚体

private void updateHorizontalBounds() {

BodyDef bodyDef = new BodyDef();

//创建静止刚体

bodyDef.type = BodyType.STATIC;

//定义的形状

PolygonShape box = new PolygonShape();

float boxWidth = switchPositionToBody(mWidth);

//设置边界高度为1

float boxHeight = switchPositionToBody(mRatio);

box.setAsBox(boxWidth, boxHeight); //确定为矩形

FixtureDef fixtureDef = new FixtureDef();

fixtureDef.shape = box;

fixtureDef.density = mDesity;

fixtureDef.friction = 0.8f;//摩擦系数

fixtureDef.restitution = 0.5f; //补偿系数

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

Body topBody = mWorld.createBody(bodyDef); //创建一个真实的上边 body

topBody.createFixture(fixtureDef);

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

Body bottomBody = mWorld.createBody(bodyDef);//创建一个真实的下边 body

bottomBody.createFixture(fixtureDef);

}

创建运动刚体

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;//摩擦系数

fixtureDef.density = mDesity;

fixtureDef.restitution = 0.5f;//补偿系数

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类

主要实现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);

}

}


总结:

其实jbox2d提供的接口运用起来并不是很难,难的物理学部分计算都在jbox2d中计算好了,他会返回给我们坐标值,这里的坐标值是世界中的坐标值。我们需要将它转化成真实屏幕的坐标值重绘就ok了。一个view对应世界中的一个刚体。

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


好了今天先写到这里。~~~~~~~

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,378评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,356评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,702评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,259评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,263评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,036评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,349评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,979评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,469评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,938评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,059评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,703评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,257评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,262评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,485评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,501评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,792评论 2 345

推荐阅读更多精彩内容