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

作者:w93223010 时间:2023-09-26 16:01:57 

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

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

一、JBox2D简介

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

二、示例

1.小球弹跳进阶版

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

(1)常量类Constant


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物理仿真对象进行了封装。


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


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


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


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


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


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


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


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程序设计有所帮助。

标签:Android,游戏,引擎
0
投稿

猜你喜欢

  • jar包手动添加到本地maven仓库的步骤详解

    2023-11-23 05:09:37
  • java 装饰模式(Decorator Pattern)详解及实例代码

    2023-09-07 03:13:08
  • 在Android app中实现九(n)宫格图片连续滑动效果

    2022-10-14 21:09:23
  • Flutter实现切换应用时隐藏应用预览

    2021-07-20 21:05:46
  • IntellJ IDEA神器使用技巧(小结)

    2023-08-08 22:01:44
  • java实现简单的猜数字小游戏

    2023-11-11 12:55:40
  • Java快速批量移动文件的实现方法

    2021-06-15 16:58:56
  • 全面解析Java支持的数据类型及Java的常量和变量类型

    2022-03-25 16:54:10
  • Java实现五子棋游戏的完整代码

    2022-07-01 15:32:34
  • SpringMVC使用MultipartFile实现文件上传

    2021-07-01 03:50:22
  • MyBatis-Plus 集成动态多数据源的实现示例

    2023-06-26 17:56:35
  • spring boot如何指定启动端口

    2021-06-27 19:52:14
  • 深入同步访问共享的可变数据分析

    2023-05-08 00:16:49
  • Android编程获取网络连接方式及判断手机卡所属运营商的方法

    2023-09-18 21:54:14
  • 通过openOffice将office文件转成pdf

    2021-12-29 21:35:32
  • Java 在PDF中添加骑缝章示例解析

    2023-11-24 22:41:35
  • Java中对象的比较操作实例分析

    2023-03-05 03:58:09
  • Java实现的具有GUI的校园导航系统的完整代码

    2022-06-28 03:43:56
  • c# 进程和线程的区别与联系

    2023-05-04 23:18:36
  • SpringBoot 整合 Shiro 密码登录与邮件验证码登录功能(多 Realm 认证)

    2023-06-23 02:45:28
  • asp之家 软件编程 m.aspxhome.com