以下是一个基于 Android 和 JBox2D 的简单小游戏开发示例,实现一个小球在屏幕上弹跳的效果:
1. 添加 JBox2D 依赖
在项目的 build.gradle
文件中添加 JBox2D 的依赖:
dependencies {
implementation 'org.jbox2d:jbox2d-library:2.3.1'
}
2. 创建物理世界和刚体
创建一个类 JBoxImpl
,用于封装 JBox2D 的逻辑:
import org.jbox2d.collision.shapes.CircleShape;
import org.jbox2d.collision.shapes.EdgeShape;
import org.jbox2d.common.Vec2;
import org.jbox2d.dynamics.*;
public class JBoxImpl {
private World world;
private float widthWorld = 10f; // 世界宽度
private float heightWorld = 10f; // 世界高度
private float ratioForBox2dToScreen; // 屏幕与世界的比例
public JBoxImpl() {
world = new World(new Vec2(0f, -10f)); // 重力向下
}
public void onSizeChanged(int width, int height) {
ratioForBox2dToScreen = width / widthWorld;
initEdges(width, height);
}
private void initEdges(int width, int height) {
// 创建边界
float widthScreen = width;
float heightScreen = height;
float widthWorld = widthScreen / ratioForBox2dToScreen;
float heightWorld = heightScreen / ratioForBox2dToScreen;
BodyDef bodyDef = new BodyDef();
bodyDef.type = BodyType.STATIC;
EdgeShape edgeShape = new EdgeShape();
FixtureDef fixtureDef = new FixtureDef();
fixtureDef.shape = edgeShape;
fixtureDef.density = 1f;
fixtureDef.restitution = 1f; // 完全弹性碰撞
// 创建四个边界
Body groundBody = world.createBody(bodyDef);
edgeShape.set(new Vec2(0, 0), new Vec2(widthWorld, 0));
groundBody.createFixture(fixtureDef);
edgeShape.set(new Vec2(widthWorld, 0), new Vec2(widthWorld, heightWorld));
groundBody.createFixture(fixtureDef);
edgeShape.set(new Vec2(widthWorld, heightWorld), new Vec2(0, heightWorld));
groundBody.createFixture(fixtureDef);
edgeShape.set(new Vec2(0, heightWorld), new Vec2(0, 0));
groundBody.createFixture(fixtureDef);
}
public Body createBall(float x, float y, float radius) {
BodyDef bodyDef = new BodyDef();
bodyDef.type = BodyType.DYNAMIC;
bodyDef.position.set(x / ratioForBox2dToScreen, y / ratioForBox2dToScreen);
CircleShape circleShape = new CircleShape();
circleShape.m_radius = radius / ratioForBox2dToScreen;
FixtureDef fixtureDef = new FixtureDef();
fixtureDef.shape = circleShape;
fixtureDef.density = 1f;
fixtureDef.restitution = 1f; // 完全弹性碰撞
Body ballBody = world.createBody(bodyDef);
ballBody.createFixture(fixtureDef);
return ballBody;
}
public void step() {
world.step(1f / 60f, 8, 3); // 更新物理世界
}
public World getWorld() {
return world;
}
public float getRatioForBox2dToScreen() {
return ratioForBox2dToScreen;
}
}
3. 创建自定义 View 进行绘制
创建一个自定义 View
,用于绘制小球:
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;
public class JBoxView extends View {
private JBoxImpl jBoxImpl;
private Paint paint;
public JBoxView(Context context, AttributeSet attrs) {
super(context, attrs);
jBoxImpl = new JBoxImpl();
paint = new Paint();
paint.setColor(0xFFFF0000); // 红色
paint.setStyle(Paint.Style.FILL);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
jBoxImpl.onSizeChanged(w, h);
jBoxImpl.createBall(w / 2, h / 2, 50); // 创建一个小球
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
jBoxImpl.step(); // 更新物理世界
for (Body body = jBoxImpl.getWorld().getBodyList(); body != null; body = body.getNext()) {
if (body.getType() == BodyType.DYNAMIC) {
float x = body.getPosition().x * jBoxImpl.getRatioForBox2dToScreen();
float y = body.getPosition().y * jBoxImpl.getRatioForBox2dToScreen();
float radius = ((CircleShape) body.getFixtureList().get(0).getShape()).m_radius * jBoxImpl.getRatioForBox2dToScreen();
canvas.drawCircle(x, y, radius, paint);
}
}
invalidate(); // 重绘
}
}
4. 在布局中使用自定义 View
在布局文件中添加自定义 JBoxView
:
<com.example.jbox2dgame.JBoxView
android:layout_width="match_parent"
android:layout_height="match_parent" />
5. 运行效果
运行程序后,你将看到一个小球在屏幕上弹跳。