在上一篇文章中,我给出了几张游戏的图片,相信大家已经迫不及待想要知道这个是如何实现的吧,OK,下面我从最基础的部分开始讲。
创建世界
在使用JBox2D物理引擎时,我们需要先创建一个world,在这个world下,我们可以创建出我们想要的刚体,既然是创建一个world,那么就需要给这个world定下world的尺寸大小。
下面先看看代码吧:
public class MainActivity extends Activity implements View.OnClickListener{
//屏幕到现实世界的比例 10px:1m;这里要注意,当我们根据android当中的坐标去定义刚体的位置时,
// 我们需要将坐标除以这个比例获得世界当中的长度,用这个长度来进行定义。
private final static int RATE = 10;
//创建一个坐标系统
private AABB worldAABB;
//创建一个世界
public static World world;
...
public void createWorld(){
//创建这个世界的坐标范围,并且设定上下限,这里应该是按世界的长度来算的,
//也就是说这个范围是足够大的,我们只能在这个范围内创建刚体
worldAABB = new AABB();
//第一个参数为左边界参数,第二个参数为上边界参数,按世界的长度来算
worldAABB.lowerBound.set(-200.0f, -200.0f);
//第一个参数为右边界参数,第二个参数为下边界参数,按世界的长度来算
worldAABB.upperBound.set(200f, 300.0f);
//向量,用来标示当前世界的重力方向,第一个参数为水平方向,
//负数为做,正数为右。第二个参数表示垂直方向
Vec2 gravity = new Vec2(0.0f, 10.0f);
//标示 是否睡眠
boolean doSleep = true;
//创建世界
world = new World(worldAABB, gravity, doSleep);
...
}
...
}
代码中的注释写的很详尽了,我也不多作解释了。
创建边界
虽然已经创建好了世界,不过如果不给世界创建边界的话,刚体会掉出世界外哦,一旦掉出世界,刚体便不会再遵循原本世界的法则(重力等),小伙伴们可以尝试一下。
创建边界前,我们先理解下什么是边界。边界,就是一个能够拦住刚体掉出世界的刚体,简单的来说,边界就是世界中的墙壁,用墙壁将世界中的刚体围起来,这样就不会掉出世界了。
理解了什么是边界后就好办了,我们可以通过创建4个刚体(上边界、下边界、左边界、右边界)来作为边界。
创建刚体类MyBody
在创建刚体时,我们选择面向对象的方法,所以我们先创建一个刚体根类——Mybody类
public abstract class MyBody {//自定义刚体根类
Body body;//JBox2D物理引擎中的刚体
int color; //刚体的颜色
boolean isLive = true; //是否绘制
boolean isDeleted = false; //是否被删除
public abstract void drawSelf(Canvas canvas, Paint paint); //绘制的方法
}
当然,这个类中没有什么具体的实现方法,代码中的drawSelf方法在稍后会讲到。
创建刚体类MyRectColor
有了刚体根类,下面我们来创建一个矩形刚体的类
public class MyRectColor extends MyBody
{//自定义的矩形类
float halfWidth; //半宽
float halfHeight; //半高
boolean isObstacle; //是否为敌人
boolean isBottom;//是否为底边
boolean isTop;//是否为上边
boolean isLeft;//是否为左边界
boolean isRight;//是否为右边界
int level;//敌人的等级
...
public MyRectColor(Body body, float halfWidth, float halfHeight, int color,
boolean isObstacle,boolean isBottom,boolean isTop,
boolean isLeft,boolean isRight,int level) {
//以下为初始化成员变量
this.body = body;
this.halfWidth = halfWidth;
this.halfHeight = halfHeight;
this.color = color;
this.isObstacle = isObstacle;
this.isBottom = isBottom;
this.isTop = isTop;
this.isLeft = isLeft;
this.isRight = isRight;
this.level = level;
...
}
public void drawSelf(Canvas canvas, Paint paint) {//重写的绘制方法
if (!isLive) {
return;
}//如果isLive为false则返回
float x = body.getPosition().x * RATE;//获取刚体的x坐标
float y = body.getPosition().y * RATE;//获取刚体的y坐标
canvas.drawRect(x - halfWidth, y - halfHeight, x + halfWidth, y + halfHeight, paint);
paint.setStyle(Paint.Style.STROKE);//设置画笔样式
paint.setStrokeWidth(1);//设置画笔宽度
paint.setColor(color);//设置颜色
canvas.drawRect(x - halfWidth, y - halfHeight, x + halfWidth, y + halfHeight, paint);//绘制边
paint.reset();//恢复画笔设置
...
}
}
到这里MyRectColor类也已经创建好,这个类继承MyBody类的,看到这里想必也知道drawSelf函数的作用了,即用画笔将刚体画在画布上呈现给用户,对于canvas的使用这里就不做说明了。
在drawSelf函数中,通过body.getPosition().x获取到的坐标为世界中的坐标,要乘以RATE才会得到实际坐标,所以千万不要忘记乘以RATE!!
创建createBox函数
有了MyRectColor类,现在我们需要将其创建出来,所以需要自己再创建一个创建MyRectColor刚体的函数
public MyRectColor createBox( //创建矩形物体(颜色)
float x, //x坐标
float y, //y坐标
float halfWidth, //半宽
float halfHeight, //半高
boolean isObstacle, //是否为敌人
boolean isBottom,//是否为下边界
boolean isTop,//是否为上边界
boolean isLeft,//是否为左边界
boolean isRight,//是否为右边界
World world, //世界
int color,//颜色
int level,//敌人等级
boolean isSensor)//是否产生碰撞反应
{
PolygonDef shape = new PolygonDef(); //创建多边形描述对象
if (!isObstacle) { //判断isStatic是否为true
shape.density = 0; //密度为0
} else {
shape.density = 100.0f; //密度为1.0f
}
shape.friction = 0.5f;//设置摩擦系数
shape.restitution = 1.0f; //设置能量损失率
shape.isSensor = isSensor;//设置是否产生碰撞反应
shape.setAsBox(halfWidth / RATE, halfHeight / RATE);
BodyDef bodyDef = new BodyDef(); //创建刚体描述对象
bodyDef.position.set(x / RATE, y / RATE); //设置位置
Body bodyTemp;//定义一个bodyTemp
while ((bodyTemp = world.createBody(bodyDef)) == null) ; //在世界中创建刚体
bodyTemp.createShape(shape); //指定刚体形状
bodyTemp.setMassFromShapes(); //设置物体质量
return new MyRectColor(bodyTemp, halfWidth, halfHeight, color,
isObstacle, isBottom,isTop,isLeft,isRight,level);
}
通过isObstacle的值判断创建的是否是边界,是边界的话将其密度设置为0,学过物理的话就应该明白密度为0的物体以为没有质量,没有质量意味着运动状态不会被改变,所以设置为0的目的在于将边界定死在我们设置的位置上,不会因为受力而改变位置。
要注意的是,创建刚体时,使用坐标为刚体的中心坐标,创建矩形时,使用的长度为矩形的半长半宽。其中isSensor这个值决定了此刚体是否产生碰撞反应,若设置为true,则在碰到其他刚体时,不会发生碰撞,而是直接穿过刚体,这个值默认为false。
创建边界
前期的准备工作都已经做好,现在就让我们创建出世界的边界吧
public ArrayList<MyBody> bl = new ArrayList<MyBody>();
...
public void createWorld(){
//创建一个上边界
MyRectColor TopBorder = createBox(SCREEN_WIDTH/2,-350,SCREEN_WIDTH/2,1,
false,false,true,false,false, world,Color.CYAN,0,false);
//创建一个下边界
MyRectColor BottomBorder = createBox(SCREEN_WIDTH/2,SCREEN_HEIGHT+140,SCREEN_WIDTH/2,1,
false,true,false,false,false, world,Color.CYAN,0,false);
//创建一个左边界
MyRectColor LeftBorder = createBox(-1,SCREEN_HEIGHT/2,1,SCREEN_HEIGHT/2,
false,false,false,true,false,world,Color.CYAN,0,false);
//创建一个右边界
MyRectColor RightBorder = createBox(SCREEN_WIDTH+1,SCREEN_HEIGHT/2,1,SCREEN_HEIGHT/2,
false,false,false,false,true,world,Color.CYAN,0,false);
bl.add(TopBorder);
bl.add(BottomBorder);
bl.add(LeftBorder);
bl.add(RightBorder);
...
}
...
bl变量是用于存储所建立的刚体类的,方便我们之后的刚体遍历。
OK,这样就成功的建立出了世界的边界,成功的将世界围起来啦。当然,只是这样,程序是不能开始模拟这个世界的,因为现在只是创建好了一个地形,但却没有让世界开始运转,不过不要着急,我会在下篇文章中详细告诉大家的^_^~