java2d javafx_javafx做游戏之Jbox2d(1)

Jbox2D介绍:

JBox2D是开源的物理引擎Box2D的Java版本,可以直接用于Android。由于JBox2D的图形渲染使用的是Processing库,因此在Android平台上使用JBox2D时,图形渲染工作只能自行开发。该引擎能够根据开发人员设定的参数,如重力、密度、摩擦系数和弹性系数等,自动地进行2D刚体物理运动的全方位模拟。每种物理引擎都有其独特的概念,在学习开源的物理引擎时,首先需要弄明白的就是其基本概念。因此,本节主要为读者复习一下物理学中的一些基本概念,并介绍JBox2D中的一些常用类与概念。

游戏是对真实世界的仿真,其中用到了许多物理学知识,如密度、质量、质心、摩擦力、扭矩以及碰撞(恢复)系数等。接下来,本小节将简要介绍用JBox2D开发游戏时经常用到的一些物理学概念。

密度

物理学中密度指的是单位体积的质量,符号为"ρ",常用单位为kg/m^3。其是物质的一种基本特性,不随物体的质量、体积的改变而改变,同种物质的密度相同。

质量

质量指的是物体中所含物质的量,即物体惯性的大小,国际单位是kg。同一物体的质量通常是一个常量,不因高度、经度或者纬度的改变而变化。但是根据爱因斯坦的相对论,同一物体的质量会随着速度的变化而改变。只有运动接近光速才能感觉到这种变化,因此在游戏中一般不考虑速度对质量的影响。

质心

物体(或物体系)的质量中心,是研究物体(或物体系)机械运动的一个重要参考点。当作用力(或合力)通过该点时,物体只作移动而不发生转动;否则在发生移动的同时物体将绕该点转动。

研究质心的运动时,可将物体的质量看作集中于质心。理论上,质心是对物体的质量分布用"加权平均法"求出的平均中心。

摩擦力

当两个互相接触的物体,如果要发生或者已经发生相对运动。就会在接触面上产生一种阻碍该相对运动的力,这种力就称之为摩擦力。其基本情况如下图所示。

7e8ca7dec21efe0ac6f41f66a05e9cc5.png

提示 根据物体是否发生相对运动可以分为静摩擦力与滑动摩擦力,实际开发中可以进行简化,但若要模拟更加真实的效果就需要分别开发。

扭矩

扭矩在物理学中就是力矩的大小,等于力与力臂的乘积,国际单位是Nm(牛米)。在力臂不变的情况下,力越大,扭矩越大。基本情况如下图所示。

2136b5c197ec8bc533ee2c2edbd7e58a.png

恢复系数

两物体碰撞后的总动能与碰撞前的总动能之间的比称之为恢复系数,其取值范围为0~1。如果恢复系数为 1,则碰撞为完全弹性碰撞,满足机械能守恒;如果恢复系数小于1并且大于0,则为非完全弹性碰撞,不满足机械能守恒,这种情况是最常见的;如果恢复系数为0,则为完全非弹性碰撞,两个物体会粘在一起。

看效果图:

66f7b679df6c15b46596e52b1fd61d6a.png

javafx和jbox2d组合:

1.坐标系对应

在真实物理环境中坐标系为向右x轴为正方向,向上为y轴正方向。如下图:

ce75c5a3daaa693d1c7828c5c3bec018.png

在fx界面中向右x轴为正方向,向下为y轴正方向。如下图:

4ffb60440d9084359c0f81aaa5d7d211.png

从图中可以看出,两个坐标系中x轴方向完全一致,但y轴方向完全相反,因此需要做坐标变换。

2.类设计(jbox2d版本为2.0.1)

PhysicalObject类设计:

这是物理对象实现的基类,包含World和Body两个重要对象属性

World对象是表示物理世界环境,Body对象表示物理世界中的刚体。

核心代码如下:

public abstract class PhysicalObject extendsParent {protectedWorld world;private boolean shouldCreate = true;private boolean shouldDestroy = false;private boolean destroyed = false;protectedBody body;public abstract voidcreatePhysicsObject();public abstract voidupdate();public voidcreatePhysicsObject(World world) {this.world =world;

createPhysicsObject();

}}

Ball类设计:

Ball类继承PhysicalObject对象,具体代码如下:

注意createPhysicsObject方法,因为球是原形,所以使用CircleDef 来描述球

public class Ball extendsPhysicalObject {public int radius = 3;private DoubleProperty xPos = new SimpleDoubleProperty(50);private DoubleProperty yPos = new SimpleDoubleProperty(6);private DoubleProperty angle = new SimpleDoubleProperty(0);private Image ball = new Image(this.getClass().getResourceAsStream("Ball.png"));public ImageView iv = newImageView(ball);;privateTimeline endAnimator;public Ball(World world, float xPos, floatyPos) {this.world =world;this.xPos.set(xPos);this.yPos.set(yPos);

init();

create();

}private voidinit() {

endAnimator= newTimeline();

KeyFrame frame1= new KeyFrame(Duration.millis(200), newKeyValue(

iv.opacityProperty(),0.1, Interpolator.LINEAR), newKeyValue(

iv.translateYProperty(),-30, Interpolator.LINEAR));

KeyFrame frame2= new KeyFrame(Duration.millis(250),new EventHandler() {

@Overridepublic voidhandle(ActionEvent event) {

setDestroyed(true);

}

});

endAnimator.getKeyFrames().addAll(frame1, frame2);

}private voidcreate() {

iv.xProperty().bind(xPos.multiply(10).subtract(ball.getWidth() / 2));

iv.yProperty().bind(yPos.multiply(10).subtract(ball.getHeight() / 2));

iv.rotateProperty().bind(angle);

getChildren().add(iv);

}

@Overridepublic voidcreatePhysicsObject() {

CircleDef cd= newCircleDef();

cd.radius=radius;

cd.density= 5.0f;

cd.friction= 0.2f;

cd.restitution= 0.75f;

BodyDef bd= newBodyDef();

bd.position.set(newVec2(xPos.floatValue(), yPos.floatValue()));

body=world.createBody(bd);

body.createShape(cd);

body.setMassFromShapes();

body.setUserData(this);

}

@Overridepublic voidmarkDestroyed() {super.markDestroyed();

endAnimator.playFromStart();

}

@Overridepublic voidupdate() {if(isShouldDestroy()) {if (body != null) {

world.destroyBody(body);

body= null;

}return;

}

xPos.set(body.getPosition().x);

yPos.set(body.getPosition().y);

angle.set(Math.toDegrees(body.getAngle()));

}

}

Bridge类设计:

Bridge类继承PhysicalObject对象,具体代码如下

注意:RevoluteJointDef为旋转关节

一个旋转关节会强制两个物体共享一个锚点,即所谓铰接点。旋转关节只有一个自由度:两个物体的相对旋转。

需深入理解可以参考详细教程。

public class Bridge extendsPhysicalObject {private DoubleProperty xPos = new SimpleDoubleProperty(50);private DoubleProperty yPos = new SimpleDoubleProperty(6);private int width = 10;private Image PLANK_IMAGE = new Image(this.getClass().getResourceAsStream("BridgePiece.png"));publicImageView iv;privateTimeline endAnimator;public Bridge(World world, float xPos, float yPos, intwidth) {this.world =world;this.xPos.set(xPos);this.yPos.set(yPos);this.width =width;

create();

}private voidcreate() {

}

@Overridepublic voidcreatePhysicsObject() {float pw = 1.2f;

PolygonDef sd= newPolygonDef();

sd.setAsBox(pw/ 2f, 0.2f);

sd.density=60f;

sd.friction= 0.2f;int numPlanks =width;

RevoluteJointDef jd= newRevoluteJointDef();

Body prevBody= null;

Body firstBody= null;

Vec2 anchor= null;for (int i = 0; i < numPlanks; i++) {

BodyDef bd= newBodyDef();

bd.position.set(xPos.floatValue()+ 1.5f *i, yPos.floatValue());

Body body=world.createBody(bd);

body.createShape(sd);

getChildren().add(newBridgePiece(PLANK_IMAGE, body));if (prevBody == null) {

firstBody=body;

}else{if (i != numPlanks - 1) {

body.setMassFromShapes();

}

anchor= new Vec2(xPos.floatValue() - pw + 1.5f *i,

yPos.floatValue());

jd.initialize(prevBody, body, anchor);

world.createJoint(jd);

}

prevBody=body;

}

Vec2 anchor1= new Vec2(xPos.floatValue() - pw + 1.5f *numPlanks,

yPos.floatValue());

jd.initialize(prevBody, firstBody, anchor1);

world.createJoint(jd);

}

@Overridepublic voidmarkDestroyed() {super.markDestroyed();

endAnimator.playFromStart();

}

@Overridepublic voidupdate() {for(Node c : getChildren()) {

((BridgePiece) c).update();

}

}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值