`
archy123
  • 浏览: 28744 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

libgdx学习笔记系列(九)了解物理引擎box2D

阅读更多
注意:在1.0正式版中box2d被作为一个扩展独立了出来。因为作者感觉有的开发者不一定用到,这样可以减少核心包的大小,详细情况参考官方介绍:http://www.badlogicgames.com/wordpress/?p=3404 

因为最近工作原因有段时间没写学习笔记了。最近心血来潮,看了看box2D这个东西。这里就简单介绍下Box2D。
Box2D是一个用于模拟2D刚体物体的C++引擎。作者为Erin Catto。Bullet Physics之类咱就先不了解了,这玩意太高级了。
   为什么要提到box2D,前几篇中的模拟物理的操作感觉很是繁琐。Box2D给我们提供了偷懒的机会。libgdx中使用jni封装了box2D,不得不说。libgdx的作者也太有毅力了。


下面我们看看什么是box2d。
box2d官方的使用手册:http://box2d.org/manual.pdf
这里我们使用libgdx的文档中的介绍来一步一步创建一个物理世界。
libgdx文档中关于box2d的部分。
https://github.com/libgdx/libgdx/wiki/box2d#creating-a-world

创建物理世界
World world = new World(new Vector2(0, -10), true); 

解释下参数new Vector2(0, -10)世界中的重力系统,第一个是x水平方向的,第二个是y值垂直方向的。true指的是对象是否可以睡眠。其实也就是文档中介绍的让某些物理世界中的物体睡眠以节约cpu资源。box2d中的物理模拟都是通过cpu进行计算模拟的。
还有需要注意的是物理世界中的单位都是以米,秒等标准单位进行计算的。
调试渲染器
Box2DDebugRenderer debugRenderer = new Box2DDebugRenderer();

这没什么好说的,就是为了调试方便。
world.step(1/60f, 6, 2);

这是为了世界中的物体帧率同步,在render的最后调用。
可以参看这篇文章http://gafferongames.com/game-physics/fix-your-timestep/
物理世界渲染
debugRenderer.render(world, camera.combined);


现在物理世界中什么都没有,box2d世界中的对象称为Body。有人称为刚体。
我们就用body好了,可以用演员的概念来理解box2d的对象。
先看第一种body
Dynamic Bodies
动态的body.
这种body的特性就是参与碰撞,可以进行移动。它适合任何需要移动的对象。
创建一个动态的body
// First we create a body definition
BodyDef bodyDef = new BodyDef();
// We set our body to dynamic, for something like ground which doesn't move we would set it to StaticBody
bodyDef.type = BodyType.DynamicBody;
// Set our body's starting position in the world
bodyDef.position.set(100, 300);

// Create our body in the world using our body definition
Body body = world.createBody(bodyDef);

// Create a circle shape and set its radius to 6
CircleShape circle = new CircleShape();
circle.setRadius(6f);

// Create a fixture definition to apply our shape to
FixtureDef fixtureDef = new FixtureDef();
fixtureDef.shape = circle;
fixtureDef.density = 0.5f; 
fixtureDef.friction = 0.4f;
fixtureDef.restitution = 0.6f; // Make it bounce a little bit

// Create our fixture and attach it to the body
Fixture fixture = body.createFixture(fixtureDef);

// Remember to dispose of any shapes after you're done with them!
// BodyDef and FixtureDef don't need disposing, but shapes do.
circle.dispose();

这段代码很好理解。
body由两部分组成:
1.它本身的状态描述(位置,类型,阻尼大小,是否可以休眠等等)。类似于定义对象的属性
2.它的物理状态(形状,密度,质量,摩擦力等物理特性)。这是box2d对此body模拟物理现象的依据。
下面的Static Bodies和Kinematic Bodies大家自己看下就好了。
只介绍下区别。Static Bodies 顾名思义就是静态的body,适合做一些边界和无法破坏的障碍。Kinematic Bodies 这是介于动态和静态之间的。简单理解就是可以移动的静态body。

物理世界如何和我们的游戏世界进行绑定交互呢
body.setUserData(Object);

例如:body.setUserData(girlActor);
直接绑定演员。
然后在循环方法render之前修改演员的状态。
Iterator<Body> bi = world.getBodies();

while (bi.hasNext()){
    Body b = bi.next();

    // Get the body's user data - in this example, our user 
    // data is an instance of the Entity class
    Entity e = (Entity) b.getUserData();

    if (e != null) {
        // Update the entities/sprites position and angle
        e.setPosition(b.getPosition().x, b.getPosition().y);
        // We need to convert our angle from radians to degrees
        e.setRotation(MathUtils.radiansToDegrees * b.getAngle());
    }
}

看出来了吗,这跟前几篇的介绍控制演员动作是一个完全相反的。我们如果使用物理世界,可以直接控制物理世界中的对象,改变对象的状态,位置信息,然后传递给我们的游戏中的演员并修改它的状态,位置等信息。
也就是说,我们直接控制物理世界中的对象,而不是实际的演员,就可以实现前几篇同样的效果。在我们前几篇的示例中,可以更为简单的处理。
girlActor.setPosition(body.getPosition());

这样来更新演员的位置信息。当然这句要放到一个不停执行的方法中。来实现实时刷新。
使用box2d的好处就是,我们不用考虑物理计算了,box2d会给我们自动处理。例如重力影响,碰撞检测,阻力等等。
box2d非常适合模拟一些物理操作比较多的游戏。例如最著名的愤怒的小鸟。重力,弹力,摩擦,碰撞基本都涉及到了。
实际上在我们这个学习示例中倒不是必须使用的。毕竟需要模拟的物理操作不多,只有一个跳起操作。使用box2d是为了接下来把我们上篇的地图跟box2d结合起来使用,来实现障碍物,碰撞检测等方面的东西。
这里只是为了对box2d物理引擎进行下简单的了解。如果想做物理类的游戏就有必要深入研究下了。

修改下我们上篇的代码,这里我把包名变化了下。
资源加载那块感觉还是很麻烦,干脆独立出来好了,新建一个专门负责加载资源的类。
MyAssetManager
package com.me.box2d.common;


import com.badlogic.gdx.assets.AssetManager;
import com.badlogic.gdx.assets.loaders.resolvers.InternalFileHandleResolver;
import com.badlogic.gdx.audio.Sound;
import com.badlogic.gdx.graphics.g2d.Animation;
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.maps.tiled.TiledMap;
import com.badlogic.gdx.maps.tiled.TmxMapLoader;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.physics.box2d.*;

public class MyAssetManager {

    private static final String GIRL_RUN_ATLAS = "data/image/girlRun.atlas";
    private static final String TILEDMAP_TMX = "data/map/map.tmx";

    public static AssetManager assetManager;
    public static TextureAtlas textureAtlas;
    public static TextureRegion[] girlRunFrameLeft;
    public static TextureRegion[] girlRunFrameRight;
    public static Animation animationRight;
    public static Animation animationLeft;
    public static TiledMap map;

    private boolean firstLoad = true;


    public MyAssetManager() {

        assetManager = new AssetManager();
        assetManager.load(GIRL_RUN_ATLAS, TextureAtlas.class);
        assetManager.setLoader(TiledMap.class
                , new TmxMapLoader(new InternalFileHandleResolver()));
        assetManager.load(TILEDMAP_TMX, TiledMap.class);
        girlRunFrameLeft = new TextureRegion[16];
        girlRunFrameRight = new TextureRegion[16];
    }

    public boolean load() {
        if (assetManager.update()) {
            if (firstLoad) {
                textureAtlas = assetManager.get(GIRL_RUN_ATLAS, TextureAtlas.class);
                map = assetManager.get(TILEDMAP_TMX, TiledMap.class);
                createAnimations();
                loadTextures();
                loadSounds();
                loadFonts();
                firstLoad = false;
            }
            return true;
        }
        return false;
    }


    private static void loadTextures() {

    }

    private static void loadSounds() {
    }

    private static void loadFonts() {
    }

    private static void createAnimations() {
        for (int i = 0; i < 16; i++) {
            girlRunFrameRight[i] = textureAtlas.findRegion(String.valueOf(i + 1));
        }

        for (int i = 0; i < 16; i++) {
            girlRunFrameLeft[i] = new TextureRegion(girlRunFrameRight[i]);
            girlRunFrameLeft[i].flip(true, false);
        }

        animationLeft = new Animation(0.06f, girlRunFrameLeft);
        animationRight = new Animation(0.06f, girlRunFrameRight);
    }

    public static void playSound(Sound sound) {
        sound.play(1);
    }


    public static Body getGirlBody(World world) {

        CircleShape girlShape = new CircleShape();
        girlShape.setRadius(1f);

        BodyDef bodyDef = new BodyDef();
        bodyDef.type = BodyDef.BodyType.DynamicBody;
        bodyDef.position.set(new Vector2(2f, 2f));

        Body girlBody = world.createBody(bodyDef);

        FixtureDef fixtureDef = new FixtureDef();
        fixtureDef.friction = 1f;
        fixtureDef.density = 1f;
        fixtureDef.shape = girlShape;

        girlBody.createFixture(fixtureDef);

        girlShape.dispose();
        return girlBody;
    }

}

}



这里增加了个获取演员body的静态方法,为了方便,所以也放到了资源管理里边。
修改下地图文件。


这里除了背景图层,我添加了一个障碍物图层,和一个障碍物对象的对象图层。
对象图层使用矩形工具围绕障碍图层画出一个正方形矩形来框选住狮子。背景图层暂时不让它显示,这是为了方便我们查看效果。

修改我们的World代码
 package com.me.box2d.actor;

import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.physics.box2d.*;
import com.me.box2d.common.MyAssetManager;

/**
 * 我们的游戏世界
 */
public class World {
    //相当于我们游戏世界的大小。只是为了方便控制人物大小,移动速度等
    //手机屏幕划分为10*6方格,具体每个方格大小不知道
    private final float WORLD_WIDTH = 10f;
    private final float WORLD_HEIGHT = 6f;
    //也就是把屏幕分成10*6网格后每个单元格的x,y轴的像素数
    //下面的方法中会根据屏幕大小自动计算出
    private float pixelsX;
    private float pixelsY;

    private int width;
    private int height;
    private GirlActor girlActor;
    //物理世界
    private com.badlogic.gdx.physics.box2d.World box2dWorld;
    private Body girlBody;


    public World() {
        //创建物理世界
        this.box2dWorld =
                new com.badlogic.gdx.physics.box2d.World(new Vector2(0, -9.8f), true);
        //创建演员的body对象
        this.girlBody = MyAssetManager.getGirlBody(this.box2dWorld);

        //创建世界的边界,这个我没放到资源管理里边
      
        BodyDef bodyDef = new BodyDef();
        bodyDef.type = BodyDef.BodyType.StaticBody;
        bodyDef.position.set(0, 0);
        Body worldBounds = box2dWorld.createBody(bodyDef);
        //世界边界是一条线的形状
        EdgeShape edgeShape = new EdgeShape();
        FixtureDef fixtureDef = new FixtureDef();
        fixtureDef.shape = edgeShape;
        //注意是4个边
        edgeShape.set(new Vector2(0f, 0f), new Vector2(28.8f, 0f));
        worldBounds.createFixture(fixtureDef);
        edgeShape.set(new Vector2(0f, 0f), new Vector2(0f, 6f));
        worldBounds.createFixture(fixtureDef);
        edgeShape.set(new Vector2(28.8f, 0f), new Vector2(28.8f, 6f));
        worldBounds.createFixture(fixtureDef);
        edgeShape.set(new Vector2(0f, 6f), new Vector2(28.8f, 6f));
        worldBounds.createFixture(fixtureDef);
        //释放资源
        edgeShape.dispose();

    }

    public com.badlogic.gdx.physics.box2d.World getBox2dWorld() {

        return this.box2dWorld;
    }

    public Body getGirlBody() {
        return this.girlBody;
    }

    public GirlActor getGirlActor() {
        return girlActor;
    }

    public void setGirlActor(GirlActor girlActor) {
        this.girlActor = girlActor;
    }

    //计算出每个方格的像素数
    //例如800*480的屏幕 800/10 480/6  每单位x,y像素为80的方格
    //这样方便我们控制世界中的物体的大小和比例

    public void setPixelsXY(int width, int height) {
        this.width = width;
        this.height = height;
        pixelsX = (float) width / WORLD_WIDTH;
        pixelsY = (float) height / WORLD_HEIGHT;
    }


    /**
     * 屏幕的实际宽度
     *
     * @return width
     */
    public int getWidth() {
        return width;
    }

    /**
     * 屏幕的实际高度
     *
     * @return height
     */
    public int getHeight() {
        return height;
    }

    /**
     * @return 每单元格的像素数
     */
    public float getPixelsX() {
        return this.pixelsX;
    }

    public float getPixelsY() {
        return this.pixelsY;
    }


    public float getWorldWidth() {
        return WORLD_WIDTH;
    }

    public float getWorldHeight() {
        return WORLD_HEIGHT;
    }


}

接下来修改我们view类
package com.me.box2d.view;


import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.maps.tiled.TiledMapRenderer;
import com.badlogic.gdx.maps.tiled.renderers.OrthogonalTiledMapRenderer;
import com.badlogic.gdx.physics.box2d.Box2DDebugRenderer;
import com.badlogic.gdx.utils.Disposable;
import com.me.box2d.actor.GirlActor;
import com.me.box2d.actor.World;
import com.me.box2d.common.MapBodyBuilder;
import com.me.box2d.common.MyAssetManager;

/**
 * view层
 * 主要负责渲染场景,演员
 */
public class WorldView implements Disposable {
    private GirlActor girlActor;
    private SpriteBatch spriteBatch;
    private TextureRegion currentFrame;
    private OrthographicCamera camera;
    private World world;
    //自定义资源管理器专门用来管理资源加载
    private MyAssetManager myAssetManager;
    private Box2DDebugRenderer debugRenderer = new Box2DDebugRenderer();
    private com.badlogic.gdx.physics.box2d.World box2dWorld;
    private boolean first = true;

    /**
     * 构造方法 初始化相关的参数。
     *
     * @param world 游戏世界
     */
    public WorldView(World world) {
        this.world = world;
        box2dWorld = world.getBox2dWorld();
//        box2dWorld.setContactListener(new ListenerClass());

        girlActor = world.getGirlActor();
        spriteBatch = new SpriteBatch();
        currentFrame = new TextureRegion();
        myAssetManager = new MyAssetManager();
        this.camera = new OrthographicCamera(world.getWorldWidth(), world.getWorldHeight());
        this.camera.position.set(world.getWorldWidth() / 2, world.getWorldHeight() / 2, 0);

    }


    /**
     * 演员显示
     */
    public void render(float deltaTime) {

        camera.update();

        //演员走到正中间的时候移动正交相机
        //往回走的时候重置正交相机位置
        if (girlActor.getPosition().x > world.getWorldWidth() / 2
                - girlActor.getBounds().getWidth() / 2) {
            this.camera.position.set(girlActor.getPosition().x
                            + girlActor.getBounds().getWidth() / 2,
                    world.getWorldHeight() / 2, 0
            );
        } else if (girlActor.getPosition().x < world.getWorldWidth() / 2
                - girlActor.getBounds().getWidth() / 2) {
            this.camera.position.set(world.getWorldWidth() / 2,
                    world.getWorldHeight() / 2, 0);
        }

        if (myAssetManager.load()) {

            //执行一次创建
            if (first) {
                //根据地图创建静态body障碍物
                MapBodyBuilder.buildShapes(MyAssetManager.map,
                        box2dWorld, world.getPixelsY());
                first = false;
            }

            spriteBatch.setProjectionMatrix(this.camera.combined);
            //物理世界显示
            debugRenderer.render(box2dWorld, this.camera.combined);
            drawMap();
            spriteBatch.begin();
            drawGirl();
            spriteBatch.end();
            box2dWorld.step(1 / 60f, 6, 2);
        }


    }

    /**
     * Girl的渲染逻辑
     */
    private void drawGirl() {
        //获取演员的当前状态,是站立还是跑动状态
        switch (girlActor.getState()) {
            //站立状态
            case IDLE:
                //根据演员的当前面朝方向获取演员的纹理。因为图片中没有站立的,所以我们取第一个为站立图片使用
                currentFrame = girlActor.isFacingRight() ? MyAssetManager.girlRunFrameRight[0]
                        : MyAssetManager.girlRunFrameLeft[0];
                break;

            //跑动状态,当然是获取跑动动画了
            case RUNING:
                currentFrame = girlActor.isFacingRight()
                        ? MyAssetManager.animationRight.getKeyFrame(girlActor.getStateTime(), true)
                        : MyAssetManager.animationLeft.getKeyFrame(girlActor.getStateTime(), true);
                break;
            default:
                break;
        }

        spriteBatch.draw(currentFrame
                , girlActor.getPosition().x
                , girlActor.getPosition().y
                , girlActor.getBounds().getWidth()
                , girlActor.getBounds().getHeight());
    }

    /**
     * 地图渲染
     */
    private void drawMap() {
        TiledMapRenderer tiledMapRenderer = new OrthogonalTiledMapRenderer(MyAssetManager.map, 0.06f, spriteBatch);
        tiledMapRenderer.setView(this.camera);
        tiledMapRenderer.render();
    }

    /**
     * 资源回收
     */
    @Override
    public void dispose() {
        spriteBatch.dispose();

    }


}


这个也没什么需要解释的。
最重要的就是修改我们的控制类,原来的控制类控制的是演员,现在我们把控制类修改为控制body
package com.me.box2d.control;

import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.physics.box2d.Body;
import com.me.box2d.actor.GirlActor;
import com.me.box2d.actor.World;

import java.util.HashMap;
import java.util.Map;

/**
 * control层,演员的控制
 */
public class GirlBodyControl {

    private GirlActor girlActor;
    private Body girlBody;

    /**
     * 枚举类型的按键
     */
    public enum KEY {
        LEFT, RIGTH, JUMP
    }

    /**
     * 定义个map来存放按键状态。这样就可以支持多按键了。
     * 并且每个按键的状态只能存在一种,这样比较符合实际需要
     */
    private static Map<KEY, Boolean> keys = new HashMap<>();

    static {
        keys.put(KEY.LEFT, false);
        keys.put(KEY.RIGTH, false);
        keys.put(KEY.JUMP, false);
      
    }

    //定义一组改变按键状态的方法
    public void leftDown() {
        keys.put(KEY.LEFT, true);
    }

    public void leftUp() {
        keys.put(KEY.LEFT, false);
    }

    public void rightDown() {
        keys.put(KEY.RIGTH, true);
    }

    public void rigthUp() {
        keys.put(KEY.RIGTH, false);
    }

    public void jumpDown() {
        keys.put(KEY.JUMP, true);
    }

    public void jumpUp() {
        keys.put(KEY.JUMP, false);
    }


    /**
     * 构造器
     *
     * @param world 游戏世界
     */
    public GirlBodyControl(World world) {
        girlActor = world.getGirlActor();
        girlBody = world.getGirlBody();
    }


    /**
     * 不断执行的方法
     * 在MyGame的render方法中调用来不断判断和更新演员状态
     */
    public void update(float deltaTime) {
        state();
        girlActor.setPosition(new Vector2(girlBody.getPosition().x - 1f,
                girlBody.getPosition().y - 1f));
        girlActor.update(deltaTime);
        if (girlBody.getLinearVelocity().y == 0 && (girlActor.getPosition().y < 3)) {
            if (girlActor.getState().equals(GirlActor.State.JUMPING)) {
                girlActor.setState(GirlActor.State.IDLE);
            }
        }

    }

    /**
     * 判断当前按下的按键状态
     * 跳跃和左右方向是可以同时按下的
     */
    private void state() {
        if (keys.get(KEY.JUMP)) {
            if (!girlActor.getState().equals(GirlActor.State.JUMPING)) {
                girlActor.setState(GirlActor.State.JUMPING);
                girlBody.setLinearVelocity((new Vector2(girlBody.getLinearVelocity().x, girlActor.getSpeed_y())));
            }

        }

        if (keys.get(KEY.LEFT)) {

            if (!girlActor.getState().equals(GirlActor.State.JUMPING)) {
                girlActor.setState(GirlActor.State.RUNING);
                girlActor.setFacingRight(false);
                girlBody.setLinearVelocity(new Vector2(-girlActor.getSpeed_x(), girlBody.getLinearVelocity().y));
            } else {
                girlActor.setFacingRight(false);
                girlBody.setLinearVelocity(new Vector2(-girlActor.getSpeed_x(), girlBody.getLinearVelocity().y));

            }
        } else if (keys.get(KEY.RIGTH)) {
            if (!girlActor.getState().equals(GirlActor.State.JUMPING)) {
                girlActor.setState(GirlActor.State.RUNING);
                girlActor.setFacingRight(true);
                girlBody.setLinearVelocity(new Vector2(girlActor.getSpeed_x(), girlBody.getLinearVelocity().y));

            } else {
                girlActor.setFacingRight(true);
                girlBody.setLinearVelocity(new Vector2(girlActor.getSpeed_x(), girlBody.getLinearVelocity().y));

            }
        } else {
            if (!girlActor.getState().equals(GirlActor.State.JUMPING)) {
                girlActor.setState(GirlActor.State.IDLE);
                girlBody.setLinearVelocity(new Vector2(0, girlBody.getLinearVelocity().y));
            }


        }

    }
}


注意把演员类GirlActor中的update方法中的计算坐标的代码注释掉
 public void update(float deltaTime) {
        stateTime += deltaTime;
        //根据时间和速度来运算当前的演员位置信息。
        //这里进行一次拷贝操作,不改变原有的velocity值
        //因为在匀加速运动中,我们需要它作为初始速度值进行计算
//        position.add(velocity.cpy().scl(deltaTime));
        this.bounds.x = position.x;
        this.bounds.y = position.y;

    }

setLinearVelocity();

这其实就是设置一个线性的x,y的速率。和我们原来的没什么不同。
只是需要注意的是不要改变我们没有控制的速率,比如向左走的时候,
girlBody.setLinearVelocity(new Vector2(-girlActor.getSpeed_x(), girlBody.getLinearVelocity().y));

如果演员正好在空中,那么Y的速率我们就要设置为它本身现在Y的速率,不要去改变它。因为现在是box2d在控制速率的计算。我们只改变x的速率就可以了。
 if (girlBody.getLinearVelocity().y == 0 && (girlActor.getPosition().y < 3)) {  
            if (girlActor.getState().equals(GirlActor.State.JUMPING)) {  
                girlActor.setState(GirlActor.State.IDLE);  
            }  
        }  

这段其实就是当人物落地,或者落到狮子的头上的时候,修改为站立状态,因为速率为0的情况有两种,一种就是落到某个物体上,还有就是在跳到最高的那个点的时候,速率会变为0,所以我就直接写了个位置<3来防止获取到第二种状态。还有没有更好的办法。有想到的通知我

最终的动画效果,有点模糊http://shouyou.aipai.com/c14/PD4lKColJy1qJWQqLA.html





  • 大小: 133.2 KB
  • 大小: 90.9 KB
  • 大小: 92.6 KB
分享到:
评论
3 楼 max_eye 2014-06-13  
archy123 写道
max_eye 写道
期待楼主继续更新,我也是刚学习libgdx.觉得你谢的挺不错的.加油

最近工作原因,暂时无法更新,不过下周估计就能继续了。
提前预告下准备使用1.x版本写个flappybird游戏来总结下。多谢关注

哈,期待
2 楼 archy123 2014-05-21  
max_eye 写道
期待楼主继续更新,我也是刚学习libgdx.觉得你谢的挺不错的.加油

最近工作原因,暂时无法更新,不过下周估计就能继续了。
提前预告下准备使用1.x版本写个flappybird游戏来总结下。多谢关注
1 楼 max_eye 2014-05-21  
期待楼主继续更新,我也是刚学习libgdx.觉得你谢的挺不错的.加油

相关推荐

    Libgdx box2d demo

    在这个名为"Libgdx box2d demo"的项目中,我们看到开发者使用Eclipse作为集成开发环境(IDE),加载并运用了Libgdx引擎,同时整合了Box2D物理引擎,创建了一个学习Box2D的实例。这个实例可能是一个基于小球的游戏,...

    使用libgdx中box2d编写的一个简单游戏测试场景1

    而Box2D则是一个物理引擎库,专门用于模拟2D物理效果,如重力、碰撞检测等,使得游戏中的物体运动更加真实。在这个名为“my-gdx-box2d”的项目中,我们将深入探讨如何使用这两个工具构建一个简单的游戏测试场景。 ...

    Libgdx专题系列 box2d

    通过学习和研究这些代码,你可以了解到如何在Libgdx中集成和使用Box2D,例如如何创建和配置Body、Fixture,如何处理物理事件,以及如何通过关节构造复杂的机械结构。此外,你还能掌握如何更新World,使其在每一帧中...

    libgdx使用box2d的demo,很不错

    总之,"libgdx使用box2d的demo"是一个很好的学习资源,它帮助开发者了解如何在LibGDX环境中实现复杂的2D物理效果,这对于开发出更真实、更有趣的游戏至关重要。通过深入研究这个Demo,你将能够掌握一系列实用的技能...

    Node.js-一个GLES2自上而下的赛车游戏构建在libgdx和Box2D之上

    本项目名为"Node.js-一个GLES2自上而下的赛车游戏构建在libgdx和Box2D之上",它巧妙地将Node.js与移动游戏开发框架libgdx和物理引擎Box2D结合,为我们展示了一个独特的游戏开发范例。 首先,让我们深入了解libgdx。...

    一个libgdx下box2d的使用实例

    一个libgdx下box2d的使用实例 包括box2d刚体创建,碰撞已经刚体和texture的绑定

    Libgdx(包含box2d)开发的PC版、Android版Flappy Bird

    在本项目"Libgdx(包含box2d)开发的PC版、Android版Flappy Bird"中,开发者使用了Libgdx来重制经典游戏Flappy Bird,以展示Libgdx的功能和Box2D物理引擎的应用。 首先,我们来了解一下Libgdx。Libgdx是一个用Java...

    Libgdx-Box2D:方块2D

    Box2D是由Ernesto Pons和David Baraff共同开发的2D物理引擎,最初为C++编写。Box2D的主要目标是为游戏开发者提供一个简单、高效的2D物理模拟环境。它能处理碰撞检测、刚体动态、关节连接等多种物理现象,广泛应用于2...

    Java 游戏, 用libgdx引擎.zip

    Java 游戏, 用libgdx引擎Java 游戏, 用libgdx引擎Java 游戏, 用libgdx引擎 Java 游戏, 用libgdx引擎Java 游戏, 用libgdx引擎Java 游戏, 用libgdx引擎 Java 游戏, 用libgdx引擎Java 游戏, 用libgdx引擎Java ...

    Box2D:libgdx的Box2D系列博客源码-源码客

    总之,"Box2D:libgdx的Box2D系列博客源码"是一个宝贵的资源,对于希望掌握libGDX和2D物理模拟的开发者来说,这是一个绝佳的学习材料。通过深入探索和实践,你可以提升游戏开发技能,创造出更具沉浸感和真实感的游戏...

    libgdx学习资料

    - Box2D是libGDX的一个可选扩展,提供了2D物理模拟,如碰撞检测和刚体动力学。 - `Box2DDebugRenderer`可以可视化物理世界,方便调试。 8. **图形渲染**: - 使用`ShapeRenderer`绘制基本形状,如线条、圆和...

    android游戏引擎 libgdx

    6. **Box2D Integration**:LibGDX集成了流行的物理引擎Box2D,使开发者能够轻松地在游戏世界中实现物理模拟,如碰撞检测、重力效果等。 7. **Asset Management**:LibGDX的资源管理器允许开发者方便地加载和管理...

    libgdx引擎开发的游戏

    5. **Box2D Integration**: 虽然Cuboc可能没有直接使用Box2D(libgdx的物理引擎),但libgdx完全支持Box2D,开发者可以创建复杂的物理世界,实现真实感的碰撞检测和物理模拟。 6. **Game States and Screens**: ...

    使用 Artemis Entity Framework、Libgdx 和 Box2D 编写的 简单游戏_java_代码_下载

    3. **Box2D**:这是一款物理模拟引擎,专门用于2D游戏开发。Box2D允许开发者创建真实的物理效果,如重力、碰撞检测和响应。在游戏中,Box2D通常用于处理直升机的移动、旋转、碰撞检测等物理行为,为游戏增加真实感和...

    Libgdx开发丛书之 Learning LibGDX Game Development, 2nd Edition

    6. **Box2D整合**:LibGDX集成了流行的物理引擎Box2D,使得开发者可以轻松实现物理模拟,如碰撞检测和刚体动力学。 7. **文件I/O**和网络通信:LibGDX提供了便捷的文件读写以及网络连接功能,方便游戏存档、更新和...

    libgdx引擎开发的游戏 demo gif图

    6. **Box2D Integration**: LibGDX集成了Box2D物理引擎,用于创建真实的物理效果,如碰撞检测和刚体运动。 7. **Net**: 提供网络通信功能,可以用于在线游戏或者游戏更新。 通过学习和实践LibGDX,开发者可以掌握...

    android游戏开发框架libgdx的使用9.pdf

    Box2D 是一个开源的物理引擎,它可以模拟二维物理世界,常用于游戏开发中。然而,它是用 C++ 编写的,直接使用不方便。在 Android 游戏开发中,使用物理引擎有三个比较好的选择:JBox2D、Havok 和 LibGDX。其中,...

    极品飞车:LibGDX,BOX2D和平铺地图的极品飞车

    极品飞车热Java(赛车模拟)带有LibGDX , BOX2D和平铺地图的NFS产品特点使用LibGDX游戏引擎, Box2D物理引擎和TiledMap开发所有车辆运动变量均根据物理定律进行计算 制动器加速度由下式计算uk * g ,并且g = 10 M/s...

    libgdx UI编辑器 overlap2d

    Libgdx是一个强大的开源游戏开发框架,用于创建跨平台的游戏应用。...在开发游戏时,UI设计是至关重要的部分,而Libgdx 提供了...通过不断地学习和实践,开发者可以充分利用Overlap2D的各项特性,实现更加精美的UI设计。

Global site tag (gtag.js) - Google Analytics