Android游戏开发学习之引擎用法实例详解
作者:w93223010 发布时间:2023-09-26 16:01:57
标签:Android,游戏,引擎
本文实例讲述了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程序设计有所帮助。
0
投稿
猜你喜欢
- 注:如果没有 root 权限也是可以试试,一般情况下,都需要 root 权限,才能连接成功。1.需要确保你的开发 PC 和 Android
- transferTo(File file)的路径问题今天看到layui的文件上传的控件,就尝试了一下。简单创建了一个SpringMVC项目。
- 在网上翻阅了很多关于ProgressBar滚动效果,但是始终没有找到适合项目中的这种效果,故自己写这篇文章,记录一下写作过程,给大家做一个参
- 在servlet3.0标准之前,是每一个请求对应一个线程。如果此时一个线程出现了高延迟,就会产生阻塞问题,从而导致整个服务出现严重的性能情况
- 闲话不多说,直接上图。给大家讲讲我的编程思想吧。第一部分:沉浸式状态栏(API-Level 19, Android4.4 KitKat 之后
- 一、流程图二、Token1、token是一种客户端认证机制,是一个经过加密的字符串,安全性强,支持跨域2、用户第一次登录,服务器通过数据库校
- 前言Spring 的 JDBC Templet 是 Spring 对 JDBC 使用的一个基本的封装。他主要是帮助程序员实现了数据库连接的管
- 1.理解装箱简单地说,装箱就是将一个值类型的数据存储在一个引用类型的变量中。假设你一个方法中创建了一个 int 类型的本地变量,你要将这个值
- 可重入锁,从字面来理解,就是可以重复进入的锁。可重入锁,也叫做递归锁,指的是同一线程外层函数获得锁之后,内层递归函数仍然有获取该锁的代码,但
- 目录查查询指定列查询所有列条件查询子查询根据业务逻辑添加条件连接查询增新增一条批量新增删改主要演示DynamicSql风格代码如何使用,基本
- 起因unity程序build到pc上,拿到其他人的机器上结果有些功能不正常,看log里面大概是Fallback handler could
- DataGridView:显示数据表后台数据绑定:List<xxx> list = new List<xxx>();
- Thread dumps(线程转储)能帮助我们判断 CPU 峰值、死锁、内存异常、应用反应迟钝、响应时间变长和其他系统问题。一些在线的分析工
- 控制json序列化/反序列化1. @JsonIgnoreProperties的用法@JsonIgnoreProperties(value =
- 本文实例为大家分享了Java实现点击按钮弹出新窗体的功能,旧窗体不进行操作分析:对于自定义窗体来说,最简单直接的做法就是让新窗体继承java
- Maven是个很好用的管理工具,不经能够管理jar,还能实现打包。这里讲解Maven 本地打包,服务器打包,可以全部交给jenkins去完成
- 最近做了一个项目其中有需求,要实现自动登录功能,通过查阅相关资料,打算用session监听来做,下面给大家列出了配置 * 的方法:1.在项目
- 配置详情pom.xmldependency> <groupId>com.baomidou<
- 1.服务配置中心1.1 服务配置中心介绍首先我们来看一下,微服务架构下关于配置文件的一些问题:1.配置文件相对分散。在一个微服务架构下,配置
- 前言MongoDB是一款由C++编写的高性能、开源、无模式的常用非关系型数据库产品,是非关系数据库当 * 能最丰富、最像关系数据库的数据库。它