服务器之家:专注于服务器技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - Android - Android游戏开发学习之引擎用法实例详解

Android游戏开发学习之引擎用法实例详解

2021-04-04 16:05w93223010 Android

这篇文章主要介绍了Android游戏开发学习之引擎用法,较为详细的分析了Android游戏开发中所常用的JBox2D引擎功能及相关使用技巧,具有一定参考借鉴价值,需要的朋友可以参考下

本文实例讲述了Android游戏开发学习之引擎用法。分享给大家供大家参考。具体如下:

汽车引擎是汽车的心脏,其决定了汽车的性能和稳定性,是人们在购车时相当关注的。而游戏中的物理引擎就如汽车的引擎一样,占据了非常重要的位置。一款好的物理引擎可以非常真实地模拟现实世界,使得游戏更加逼真,提供更好的娱乐体验。

一、JBox2D简介

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

二、示例

1.小球弹跳进阶版

在第1节中小球的下落、碰撞、弹起都是用代码来维护的,下面使用物理引擎来实现,并且加入了刚体之间的碰撞。

(1)常量类Constant

?
1
2
3
4
5
6
7
8
9
package box2d.bheap;
public class Constant {
  public static final float RATE=10; //屏幕与现实世界的比例
  public static final boolean DRAW_THREAD_FLAG=true; //绘制线程工作标识位
  public static final float TIME_STEP=2.0f/60.0f; //模拟的频率
  public static final int ITERA=10; //迭代次数
  public static int SCREEN_WIDTH; //屏幕宽度
  public static int SCREEN_HEIGHT; //屏幕高度
}

(2)抽象类MyBody

该类为自定义的抽象类,是所有自定义刚体类的基类。由于JBox2D中的刚体类对象仅具有物理仿真计算的功能,并没有提供Android平台下的绘制功能,直接使用不是很方便。因此,这里定义了MyBody对自定义刚体的绘制及JBox2D物理仿真对象进行了封装。

?
1
2
3
4
5
6
7
8
9
package box2d.bheap;
import org.jbox2d.dynamics.Body;
import android.graphics.Canvas;
import android.graphics.Paint;
public abstract class MyBody {
  Body body; //JBox2D物理引擎中的刚体 
  int color; //刚体的颜色
  public abstract void drawSelf(Canvas canvas,Paint paint); //绘制的方法
}

(3)圆形刚体类MyCircleColor

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package box2d.bheap;
import org.jbox2d.dynamics.Body;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import static box2d.bheap.Constant.*; //静态导入
public class MyCircleColor extends MyBody {
  float radius; //圆形半径
  public MyCircleColor(Body body,float radius,int color) {
    this.body=body;
    this.radius=radius;
    this.color=color;
  }
  @Override
  public void drawSelf(Canvas canvas, Paint paint) {
    paint.setColor(color&0xCFFFFFF); //设置颜色
    float x=body.getPosition().x*RATE;
    float y=body.getPosition().y*RATE;
    canvas.drawCircle(x, y, radius, paint); //画圆
    paint.setStyle(Style.STROKE); //设置空心无填充
    paint.setStrokeWidth(1);
    paint.setColor(color); //画边
    canvas.drawCircle(x, y, radius, paint);
    paint.reset(); //恢复画笔设置
  }
}

(4)矩形刚体类MyRectColor

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package box2d.bheap;
import static box2d.bheap.Constant.RATE;
import org.jbox2d.dynamics.Body;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
public class MyRectColor extends MyBody {
  float halfWidth;//半宽
  float halfHeight;//半高
  public MyRectColor(Body body,float halfWidth,float halfHeight,int color)
  {
    this.body=body;
    this.halfWidth=halfWidth;
    this.halfHeight=halfHeight;   
    this.color=color;
  }
  public void drawSelf(Canvas canvas,Paint paint)
  {     
    paint.setColor(color&0x8CFFFFFF); 
    float x=body.getPosition().x*RATE;
    float y=body.getPosition().y*RATE;
    float angle=body.getAngle();
    canvas.save();
    Matrix m1=new Matrix();
    m1.setRotate((float)Math.toDegrees(angle),x, y);
    canvas.setMatrix(m1);
    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();   
    canvas.restore();
  }
}

(5)生成刚体形状的工具类Box2DUtil

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
package box2d.bheap;
import static box2d.bheap.Constant.RATE;
import org.jbox2d.collision.CircleDef;
import org.jbox2d.collision.PolygonDef;
import org.jbox2d.dynamics.Body;
import org.jbox2d.dynamics.BodyDef;
import org.jbox2d.dynamics.World;
public class Box2DUtil {
  /**
   * 创建矩形物体(颜色)
   */
  public static MyRectColor createBox (
      float x,
      float y,
      float halfWidth,
      float halfHeight,
      boolean isStatic, //是否为静止的
      World world,
      int color
  ) {
    PolygonDef shape=new PolygonDef(); //创建多边形描述对象
    if(isStatic) {
      shape.density=0;
    } else {
      shape.density=1.0f;
    }
    shape.friction=0.0f; //设置摩擦系数
    shape.restitution=0.6f; //设置能量损失率
    shape.setAsBox(halfWidth/RATE, halfHeight/RATE);
    BodyDef bodyDef=new BodyDef(); //创建刚体描述对象
    bodyDef.position.set(x/RATE,y/RATE); //设置位置
    Body bodyTemp=world.createBody(bodyDef); //在世界中创建刚体
    bodyTemp.createShape(shape); //指定刚体形状
    bodyTemp.setMassFromShapes(); //设置物体质量
    return new MyRectColor(bodyTemp, halfWidth, halfHeight, color);
  }
  /**
   * 创建圆形物体(颜色)
   */
  public static MyCircleColor createCircle (
      float x,
      float y,
      float radius,
      World world,
      int color
  ) {
    CircleDef shape=new CircleDef(); //创建圆描述对象
    shape.density=2; //设置密度
    shape.friction=0.0f; //设置摩擦系数
    shape.restitution=0.95f; //设置能量损失率
    shape.radius=radius/RATE;//设置半径
    BodyDef bodyDef=new BodyDef(); //创建刚体描述对象
    bodyDef.position.set(x/RATE,y/RATE); //设置位置
    Body bodyTemp=world.createBody(bodyDef); //在世界中创建刚体
    bodyTemp.createShape(shape); //指定刚体形状
    bodyTemp.setMassFromShapes(); //设置物体质量
    return new MyCircleColor(bodyTemp, radius, color);
  }
}

(6)颜色工具类ColorUtil

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
package box2d.bheap;
public class ColorUtil {
  static int[][] result= 
    {
      {56,225,254},  
      {41,246,239},
      {34,244,197},
      {44,241,161},
      {65,239,106},
      {45,238,59},
      {73,244,51},  
      {99,233,58},
      {129,243,34},
      {142,245,44},
      {187,243,32},
      {232,250,28},
      {242,230,46},
      {248,196,51},
      {244,125,31},
      {247,88,46},
      {249,70,40},
      {249,70,40},
      {248,48,48},
      {250,30,30},
      {252,15,15},
      {255,0,0}, 
    };
    public static int getColor(int index)
    {
      int[] rgb=result[index%result.length];
      int result=0xff000000;
      result=result|(rgb[0]<<16);
      result=result|(rgb[1]<<8);
      result=result|(rgb[2]);
      return result;
    }
}

(7)主控制类MyBox2dActivity

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
package box2d.bheap;   
import java.util.ArrayList;
import java.util.Random;
import org.jbox2d.collision.AABB;  
import org.jbox2d.common.Vec2;  
import org.jbox2d.dynamics.World;   
import android.app.Activity;  
import android.content.pm.ActivityInfo;
import android.os.Bundle;  
import android.util.DisplayMetrics;
import android.view.Window;  
import android.view.WindowManager; 
import static box2d.bheap.Constant.*;
public class MyBox2dActivity extends Activity 
{  
  AABB worldAABB;//创建 一个管理碰撞的世界  
  World world;
  Random random=new Random();
  //物体列表
  ArrayList<MyBody> bl=new ArrayList<MyBody>();
  public void onCreate(Bundle savedInstanceState) 
  {  
    super.onCreate(savedInstanceState);
    //设置为全屏
    requestWindowFeature(Window.FEATURE_NO_TITLE);  
    getWindow().setFlags(WindowManager.LayoutParams. FLAG_FULLSCREEN ,  
    WindowManager.LayoutParams. FLAG_FULLSCREEN); 
    //设置为横屏模式
    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
    //获取屏幕尺寸
    DisplayMetrics dm=new DisplayMetrics();
    getWindowManager().getDefaultDisplay().getMetrics(dm); 
    if(dm.widthPixels<dm.heightPixels)
    {
       SCREEN_WIDTH=dm.widthPixels;
       SCREEN_HEIGHT=dm.heightPixels;
    }
    else
    {
      SCREEN_WIDTH=dm.heightPixels;
      SCREEN_HEIGHT=dm.widthPixels;  
    }
    worldAABB = new AABB();  
    //上下界,以屏幕的左上方为 原点,如果创建的刚体到达屏幕的边缘的话,会停止模拟  
    worldAABB.lowerBound.set(-100.0f,-100.0f);
    worldAABB.upperBound.set(100.0f, 100.0f);//注意这里使用的是现实世界的单位  
    Vec2 gravity = new Vec2(0.0f,10.0f);
    boolean doSleep = true;
    //创建世界 
    world = new World(worldAABB, gravity, doSleep);     
    //创建4边
    final int kd=40;//宽度或高度
    MyRectColor mrc=Box2DUtil.createBox(kd/4, SCREEN_HEIGHT/2, kd/4, SCREEN_HEIGHT/2, true,world,0xFFe6e4FF);
    bl.add(mrc);
    mrc=Box2DUtil.createBox(SCREEN_WIDTH-kd/4, SCREEN_HEIGHT/2, kd/4, SCREEN_HEIGHT/2, true,world,0xFFe6e4FF);
    bl.add(mrc);
    mrc=Box2DUtil.createBox(SCREEN_WIDTH/2, kd/4, SCREEN_WIDTH/2, kd/4, true,world,0xFFe6e4FF);
    bl.add(mrc);
    mrc=Box2DUtil.createBox(SCREEN_WIDTH/2, SCREEN_HEIGHT-kd/4, SCREEN_WIDTH/2, kd/4, true,world,0xFFe6e4FF);
    bl.add(mrc);
    //创建砖块
    //砖块间距 行间距为20   模块宽度为10 最多一行为9块
    final int bs=20;
    final int bw=(int)((SCREEN_WIDTH-2*kd-11*bs)/18);
    //============================================================
    for(int i=2;i<10;i++)
    {
      if((i%2)==0)
      {
        //左侧蓝木块
        for(int j=0;j<9-i;j++)
        {
          mrc=Box2DUtil.createBox
          (
            kd/2+bs+bw/2+i*(kd+5)/2+j*(kd+5)+3,
            SCREEN_HEIGHT+bw-i*(bw+kd)/2,
            bw/2,
            kd/2,
            false,
            world,
            ColorUtil.getColor(Math.abs(random.nextInt()))
          );
          bl.add(mrc);
        }
        //右侧蓝木块
        for(int j=0;j<9-i;j++)
        {
          mrc=Box2DUtil.createBox
          (
            3*kd/2+bs-bw/2+i*(kd+5)/2+j*(kd+5)-3,
            SCREEN_HEIGHT+bw-i*(bw+kd)/2,
            bw/2,
            kd/2,
            false,
            world,
            ColorUtil.getColor(Math.abs(random.nextInt()))
          );
          bl.add(mrc);
        }
      }  
      if((i%2)!=0)
      {
        for(int j=0;j<10-i;j++)
        {
          mrc=Box2DUtil.createBox
          (
            kd/2+bs+kd/2+(i-1)*(kd+5)/2+j*(kd+5),
            SCREEN_HEIGHT-(kd-bw)/2-(i-1)*(bw+kd)/2,
            kd/2,
            bw/2,
            false,
            world,
            ColorUtil.getColor(Math.abs(random.nextInt()))
          );
          bl.add(mrc);
        }
      }
    }
    mrc=Box2DUtil.createBox
    (
      5*kd+bs+20,
      SCREEN_HEIGHT-(kd+bw)*4-kd,
      bw/2,
      kd/2,
      false,
      world,
      ColorUtil.getColor(Math.abs(random.nextInt()))
    );
    bl.add(mrc);
    //创建球
    MyCircleColor ball=Box2DUtil.createCircle(SCREEN_WIDTH/2-24, kd, kd/2, world,ColorUtil.getColor(Math.abs(random.nextInt())));
    bl.add(ball);
    ball.body.setLinearVelocity(new Vec2(0,50));
    GameView gv= new GameView(this);
    setContentView(gv);
  }
}

(8)显示界面类GameView

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
package box2d.bheap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback;
import android.view.SurfaceView;
public class GameView extends SurfaceView implements Callback{
  MyBox2dActivity activity;
  Paint paint;
  DrawThread dt;
  public GameView(MyBox2dActivity activity) {
    super(activity);
    this.activity=activity;
    this.getHolder().addCallback(this); 
    paint =new Paint();
    paint.setAntiAlias(true);
    dt=new DrawThread(this);
    dt.start();
  }
  public void onDraw(Canvas canvas) {
    if(canvas==null) {
      return ;
    }
    canvas.drawARGB(255, 255, 255, 255); //设置背景颜色白色
    for (MyBody mb : activity.bl) {
      mb.drawSelf(canvas, paint);
    }
  }
  @Override
  public void surfaceChanged(SurfaceHolder holder, int format, int width,
      int height) {
  }
  @Override
  public void surfaceCreated(SurfaceHolder holder) {
        repaint();
  }
  @Override
  public void surfaceDestroyed(SurfaceHolder holder) {
  }
  public void repaint() {
    SurfaceHolder holder=this.getHolder();
    Canvas canvas=holder.lockCanvas();
    try {
      synchronized(holder){
        onDraw(canvas);
      }
    } catch(Exception e){
      e.printStackTrace();
    } finally {
      if(canvas!=null) {
        holder.unlockCanvasAndPost(canvas); 
      }
    }
  }
}

(9)绘制线程类DrawThread

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package box2d.bheap;
import static box2d.bheap.Constant.*;
//绘制线程
public class DrawThread extends Thread
{
  GameView gv;
  public DrawThread(GameView gv)
  {
    this.gv=gv;
  }
  @Override
  public void run()
  {
    while(DRAW_THREAD_FLAG)
    {
      gv.activity.world.step(TIME_STEP, ITERA);//开始模拟
      gv.repaint();
      try
      {
        Thread.sleep(20);
      } catch (InterruptedException e) 
      {
        e.printStackTrace();
      }
    }
  }
}

希望本文所述对大家的jsp程序设计有所帮助。

延伸 · 阅读

精彩推荐