http://pimentoso.blogspot.com/2013/01/meter-and-pixel-units-in-box2d-game.html

需翻墙

——————————————————————————————————————————————————————————————————

Meter and pixel units in a box2d game - LibGDX

I often see posts on the LibGDX forum from users confused about converting game units to pixel units, while coding box2d+scene2d games. I'm writing this short article to present my approach on this matter, which actually doesn't involve any unit conversion. It's all done by different cameras with different viewports.

As you know, box2d wants its bodies sized in meters. "But hey my character is 200 pixels big, I'll make it 200 meters and use a 1:1 conversion" you can't. The box2d manual says that the physics simulation starts to go freaky with dynamic bodies bigger than a truck. So stick with real-size dimensions.

The key is to have 2 different stages with different viewports. In the following example I'll use a stage to represent the box2d world, which will be the "game stage" and will have a viewport of about 3x6 meters; then I'll use another stage on top of the other one, aka "GUI stage", which will be used to render the GUI and will have a viewport of 1024x600 pixels. This way you get a meter-sized game with pixel-exact GUI.

Game Screen - this class is our main game screen. It contains the GUI stage.

 public class GameScreen implements Screen {  

     // this is actually my tablet resolution in landscape mode. I'm using it for making the GUI pixel-exact.
public static float SCREEN_WIDTH = 1024;
public static float SCREEN_HEIGHT = 600; private GameWorld world; // contains the game world's bodies and actors.
private GameRenderer renderer; // our custom game renderer.
private Stage stage; // stage that holds the GUI. Pixel-exact size.
private OrthographicCamera guiCam; // camera for the GUI. It's the stage default camera. @Override
public final void show() { this.stage = new Stage(); // create the GUI stage
this.stage.setViewport(SCREEN_WIDTH, SCREEN_HEIGHT, false); // set the GUI stage viewport to the pixel size world = new GameWorld();
renderer = new GameRenderer(world); // add GUI actors to stage, labels, meters, buttons etc.
Label labelStatus = new Label("TOUCH TO START", Assets.skin);
labelStatus.setPosition(GenericScreen.SCREEN_WIDTH/2-500, GenericScreen.SCREEN_HEIGHT/2);
labelStatus.setWidth(1000);
labelStatus.setAlignment(Align.center);
labelStatus.setFontScale(2);
stage.addActor(labelStatus);
// add other GUI elements here
} @Override
public void render(float delta) { guiCam = (OrthographicCamera) stage.getCamera();
guiCam.position.set(SCREEN_WIDTH/2, SCREEN_HEIGHT/2, 0); Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
Gdx.gl.glEnable(GL10.GL_TEXTURE_2D);
guiCam.update(); world.update(delta); // update the box2d world
stage.act(delta); // update GUI renderer.render(); // draw the box2d world
stage.draw(); // draw the GUI
}
}

Game World - our container for the box2d world and other game elements. It also contains the game stage.

 public class GameWorld {  

     // here we set up the actual viewport size of the game in meters.
public static float UNIT_WIDTH = GameScreen.SCREEN_WIDTH/160; // 6.4 meters width
public static float UNIT_HEIGHT = GameScreen.SCREEN_HEIGHT/160; // 3.75 meters height public static final Vector2 GRAVITY = new Vector2(0, -9.8f); public final Stage stage; // stage containing game actors (not GUI, but actual game elements)
public World box2dWorld; // box2d world
public Bob bob; // our playing character public GameWorld() { box2dWorld = new World(GRAVITY, true);
stage = new Stage(); // create the game stage
stage.setViewport(UNIT_WIDTH, UNIT_HEIGHT, false); // set the game stage viewport to the meters size createWorld();
} private void createWorld() { // create box2d bodies and the respective actors here.
bob = new Bob(this);
stage.addActor(bob);
// add more game elements here
} public void update(float delta) { // perform game logic here
box2dWorld.step(delta, 3, 3); // update box2d world
stage.act(delta); // update game stage
}
}

Bob - our character. It extends Image which is a subclass of Actor, and contains a reference to the box2d body (in this case a circle). Its texture is resized to the game meter units, but it will be rendered using the game stage camera, so even if the texture is scaled to 0.8x0.8, it will be quite big since the viewport is 6x3 meters.

 public class Bob extends Image {  

     public static final float RADIUS = 0.4f; // bob is a ball with 0.8m diameter
public final Body body; // bob's box2d body public Bob(GameWorld world) { // bob is an Image, so we load the graphics from the assetmanager
Texture tex = Assets.manager.get("characters.png", Texture.class);
this.setDrawable(new TextureRegionDrawable(new TextureRegion(tex, 0, 256, 128, 128))); // generate bob's box2d body
CircleShape circle = new CircleShape();
circle.setRadius(RADIUS); BodyDef bodyDef = new BodyDef();
bodyDef.type = BodyType.DynamicBody;
bodyDef.position.x = 2f;
bodyDef.position.y = 2f;
bodyDef.linearDamping = 0.1f;
bodyDef.angularDamping = 0.5f; this.body = world.box2dWorld.createBody(bodyDef);
this.body.setUserData(ElementType.BOB); Fixture fix = body.createFixture(circle, 50);
fix.setDensity(1);
fix.setFriction(1f);
fix.setRestitution(0.8f);
fix.setFilterData(filter); circle.dispose(); // generate bob's actor
this.setPosition(body.getPosition().x-RADIUS, body.getPosition().y-RADIUS); // set the actor position at the box2d body position
this.setSize(RADIUS*2, RADIUS*2); // scale actor to body's size
this.setScaling(Scaling.stretch); // stretch the texture
this.setAlign(Align.center);
} @Override
public void act(float delta) {
// here we override Actor's act() method to make the actor follow the box2d body
super.act(delta);
setOrigin(RADIUS, RADIUS);
setRotation(MathUtils.radiansToDegrees * body.getAngle());
setPosition(body.getPosition().x-RADIUS, body.getPosition().y-RADIUS);
}
}

Game Renderer - a custom renderer used to draw the game world. It just positions the camera each frame and draws the game stage. Very simple.

 public class GameRenderer
{
GameWorld world;
OrthographicCamera camera;
Box2DDebugRenderer renderer; public GameRenderer(GameWorld world)
{
this.world = world;
this.renderer = new Box2DDebugRenderer(); // we obtain a reference to the game stage camera. The camera is scaled to box2d meter units
this.camera = (OrthographicCamera) world.stage.getCamera(); // center the camera on bob (optional)
camera.position.x = world.bob.body.getPosition().x;
camera.position.y = world.bob.body.getPosition().y;
} public void render()
{
// have the camera follow bob
camera.position.x = world.bob.body.getPosition().x;
camera.position.y = world.bob.body.getPosition().y; Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT); // box2d debug renderering (optional)
camera.update();
renderer.render(world.box2dWorld, camera.combined); // game stage rendering
world.stage.draw();
}
}

Meter and pixel units in a box2d game - LibGDX的更多相关文章

  1. poi导出excel

    Java使用poi组件导出excel报表,能导出excel报表的还可以使用jxl组件,但jxl想对于poi功能有限,jxl应该不能载excel插入浮动层图片,poi能很好的实现输出excel各种功能, ...

  2. 导出(Excel格式)

    poi导出,需要的poi jar包: 步骤一.两个工具类: 1.ExcelUtil.java package util; import java.awt.Color; import java.io.F ...

  3. C# 水印透明度图片

    /// <summary> /// 在一张图片的指定位置处加入一张具有水印效果的图片 /// </summary> /// <param name="Sourc ...

  4. 创建支持多种屏幕尺寸的Android应用

    Android涉及各种各样的支持不同屏幕尺寸和密度的设备.对于应用程序,Android系统通过设备和句柄提供了统一的开发环境,大部分工作是校正每一个应用程序的用户界面到它显示的屏上.与此同时,系统提供 ...

  5. 2dtoolkit获取sprite像素大小的方法

    获取sprite像素的方法 Vector2 GetPixelSize(tk2dSpriteDefinition def){ ].x; ].y; // Calculate dimensions in p ...

  6. StereoBM::disp12MaxDiff Crash the Release

    Initializing "cv::StereoBM bm.state->disp12MaxDiff" should be careful, inappropriate va ...

  7. Android用户界面布局(layouts)

    Android用户界面布局(layouts) 备注:view理解为视图 一个布局定义了用户界面的可视结构,比如activity的UI或是APP widget的UI,我们可以用下面两种方式来声明布局: ...

  8. Html代码Font-Size中px与pt的区别

    一个是设备坐标,一个是逻辑坐标,两者是不同的. px是个相对单位,一般像素的参考值为:在一个像素密度是90 pdi的显示器上,正常人从距离显示器28英寸处看一个像素的视角应该不小于0.0227度. 1 ...

  9. Google Map 自定义 infowindow

    最近做的东西用到了infowindow,不过google提供的样式太难看了,于是想改变一下样式.看了一下好像infowindow的样式不太好改. 查了半天资料,看到一个infobox,感觉真的挺好用. ...

随机推荐

  1. automake连载---关于两个文件configure.in和Makefile.am的编写

    http://blog.csdn.net/shanzhizi/article/details/30251763 automake主要通过编辑Makefile.am来控制它的行为,下面就常用的三个Mak ...

  2. Win7如何更改网络位置,如何加入或创建家庭组

    1 打开网络和共享中心,点击连接上网的哪一个网络,点击把公用网络改为家庭网络   2 依次执行下一步     3 如果是加入一个家庭组,则输入家庭组的密码,否则将得到一个家庭组的密码   4 加入成功 ...

  3. ionic中ionicView的生命周期

    ionicView的生命周期的事件调用在每个ionicView的controller中使用$scope.$on('$ionicView.enter', function() {});调用. 1.$ i ...

  4. 两种方法连接MySql数据库

    .用MySQLDriverCS连接MySQL数据库 先下载和安装MySQLDriverCS,在安装文件夹下面找到MySQLDriver.dll,然后将MySQLDriver.dll添加引用到项目中. ...

  5. Hadoop的改进实验(中文分词词频统计及英文词频统计)(4/4)

    声明: 1)本文由我bitpeach原创撰写,转载时请注明出处,侵权必究. 2)本小实验工作环境为Windows系统下的百度云(联网),和Ubuntu系统的hadoop1-2-1(自己提前配好).如不 ...

  6. js实现回放拖拽轨迹-------Day48

    今天有点小高兴,csdn博客浏览量过万了,在过去还从来没有过这么高的浏览量呢.不得不说.太多时候还是有些矫情.可看到这些鼓舞还是忍不住高兴啊,至少,这样让我有一种行内人员的感觉,吾道不孤啊. 闲话不多 ...

  7. Java提高合集(转载)

    转载自:http://www.cnblogs.com/pony1223/p/7643842.html Java提高十五:容器元素比较Comparable&Comparator深入分析 JAVA ...

  8. ISP封了80和8080端口

    今天用自己的电脑做服务器,绑定了域名,路由映射什么的都做了,但是80和8080端口在外网怎么都访问不了,只在内网可以访问. 最后看有人说联通封了80和8080端口,真是遗憾,谨记于此,以后有时间了再来 ...

  9. 从MVC和三层架构说到ssh整合开发-下

    这章主要讲整合开发,直接从实战讲起,对与ssh的单方面了解,请继续等待我的兴许文章. 解说不到位的地方欢迎大家指正:联系方式rlovep.com 具体请看源码凝视: 全部代码下载(csdn):链接 G ...

  10. mongodb的基本语法(一)

    一.数据库常用命令 1.Help查看命令提示 help db.help(); db.yourColl.help(); db.youColl.find().help(); rs.help(); 2.切换 ...