本文是一篇在android上使用2D物理引擎的入门教程。
2D物理引擎能增强游戏世界中物体如多边形(箱子,三角形,多边形)的动作的真实感从而提高游戏质量。这个引擎通过用户设定的参数如重力,密度,摩擦,弹性等参数计算碰撞,角度,力和动力等。
引擎
有很多开源的2d物理引擎,其中最著名的有Box2D和Chipmunk。这里我们将用Box2D,因为他有更好的性能。很幸运,我们有java版的Box2D库叫做JBox2D,JBox2D用processing库来处理图像显示,而我们不会在android上用。
文档和导引
·
· Box2D 用户手册 描述了怎样入手这个物理库,解析了基本的原理还包括一些示例源码(强烈建议阅读)
·
Box2D 类参考
· JBox2D Wiki 说明了java版和c++版的区别。
导入库文件
让我们把jar文件导入到Eclipse中的当前project中
1. 下载 jbox2d-2.0.1-library-only.jar把它另存为
jbox2d.jar
2. 在Eclipse中新建一个文件夹
/lib/
3. 右键单击/lib, 选择
Import
4. 选择
General / File System
5. 选择jbox2d.jar的目录
6. 把jbox2d.jar导入进来
7. 右键单击该工程选择
“Properties”
8. 点击“Java Build Path” 选择“Libraries” 标签
9. 点击“Add JARs…” 选择
jbox2d.jar
行了,现在我们就可以使用Box2D了,我们还可以引用库文件,如上图所示。
物理Hello World
让我们依据Box2D用户手册快速写一个hello world程序,做一下几件事情:
初始化一个世界(world)
添加一个地面(ground box )
创建几个动态物体(球)
模拟这个世界。
这段代码还没有在屏幕上画任何东西,他只是计算了物理行为打印了一些关于最近添加的元素的日志信息(位置和角度)。
以下代码只是一个管理物理世界的类,它可以被任何activity实现,update()函数必须被阶段性的调用。
复制代码
- import org.jbox2d.collision.AABB;
import org.jbox2d.collision.CircleDef; import org.jbox2d.collision.PolygonDef; import org.jbox2d.common.Vec2; import org.jbox2d.dynamics.Body; import org.jbox2d.dynamics.BodyDef; import org.jbox2d.dynamics.World; import android.util.Log; public class PhysicsWorld { public int targetFPS = 40; public int timeStep = (1000 / targetFPS); public int iterations = 5; private Body[] bodies; private int count = 0; private AABB worldAABB; private World world; private BodyDef groundBodyDef; private PolygonDef groundShapeDef; public void create() { // Step 1: Create Physics World Boundaries worldAABB = new AABB(); worldAABB.lowerBound.set(new Vec2((float) -100.0, (float) -100.0)); worldAABB.upperBound.set(new Vec2((float) 100.0, (float) 100.0)); // Step 2: Create Physics World with Gravity Vec2 gravity = new Vec2((float) 0.0, (float) -10.0); boolean doSleep = true; world = new World(worldAABB, gravity, doSleep); // Step 3: Create Ground Box groundBodyDef = new BodyDef(); groundBodyDef.position.set(new Vec2((float) 0.0, (float) -10.0)); Body groundBody = world.createBody(groundBodyDef); groundShapeDef = new PolygonDef(); groundShapeDef.setAsBox((float) 50.0, (float) 10.0); groundBody.createShape(groundShapeDef); } public void addBall() { // Create Dynamic Body BodyDef bodyDef = new BodyDef(); bodyDef.position.set((float) 6.0+count, (float) 24.0); bodies[count] = world.createBody(bodyDef); // Create Shape with Properties CircleDef circle = new CircleDef(); circle.radius = (float) 1.8; circle.density = (float) 1.0; // Assign shape to Body bodies[count].createShape(circle); bodies[count].setMassFromShapes(); // Increase Counter count += 1; } public void update() { // Update Physics World world.step(timeStep, iterations); // Print info of latest body if (count > 0) { Vec2 position = bodies[count].getPosition(); float angle = bodies[count].getAngle(); Log.v("Physics Test", "Pos: (" + position.x + ", " + position.y + "), Angle: " + angle); } } } 在一个Activity中应用它 在一个Activity中实现一个PhysicsWorld类是非常容易的事情,如下所示: [CODE=java] import android.app.Activity; import android.os.Bundle; import android.os.Handler; public class Physics extends Activity { PhysicsWorld mWorld; private Handler mHandler; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mWorld = new PhysicsWorld(); mWorld.create() // Add 50 Balls for (int i=0; i<50; i++) { mWorld.addBall(); } // Start Regular Update mHandler = new Handler(); mHandler.post(update)); } @Override protected void onPause() { super.onPause(); mHandler.removeCallbacks(update); } private Runnable update = new Runnable() { public void run() { mWorld.update(); mHandler.postDelayed(update, (long) (mWorld.timeStep*1000)); } }; }
|