zoukankan      html  css  js  c++  java
  • cocos2d_x_05_Box2D物理引擎

    一、认识Box2D

    帮助文档,共69页



    二、创建一个物理世界
    先导入主头文件

    #include <Box2D/Box2D.h>








    三、物理世界一览

    像素转成米 的比例因子 就是32












    三、运动的物体
    刚体的类型有三种:动态的、静态的、漂浮的(不受重力影响)

    结构体b2BodyDef,构造刚体时,必须指定的、定义一个刚体所需的參数

    cocos2d的像素和box2d的世界 长度转换
    当box2d中世界长度为10米 为最佳模拟

    b2FixtureDef

    一个 b2FixtureDef 是依附在刚体 身上的物理特质的属性 

    一个刚体 有多个 b2FixtureDef

    每个 b2FixtureDef 又有形状shape、密度、摩擦系数等成员属性


    加入一个刚体的三步曲:
    通过world创建一个body (參数是一个结构体b2BodyDef)
    为body设置Fixture属性 (參数是一个b2FixtureDef结构体)
    创建一个精灵,并将其绑定到body的UserData


    glview->setDesignResolutionSize
    (480,320,ResolutionPolicy::SHOW_ALL)表示:
    游戏编写时,依照480*320的屏幕分辨率来的;
    当执行在不同的屏幕分辨率下时,
    会依据实际的屏幕分辨率 与 编写时的分辨率 的缩放比例因子,进行图像绘制
    ResolutionPolicy::SHOW_ALL表示完整显示 界面上的全部元素
    即:宽高等比缩放,但缩放比例取宽比和高比之中小的那一个。



    四、漂浮的物体 b2_kinematicBody

    创建一个漂浮的物体,不受重力影响,向右漂浮动

    addRectBody(1,5,b2_kinematicBody);

    #pragma mark - 加入一个刚体
    // 加入一个精巧的或运动的Rect刚体,通过參数type指定,x和y是世界坐标中的位置
    void Box2DScene::addRectBody(float x, float y, b2BodyType body_type)
    {
        // 1.1 结构体b2BodyDef
        // 每个刚体都有自身的 固有的 必须的 b2BodyDef属性
        b2BodyDef def;
        // 在世界坐标中 的位置:第x米,第y米处
        def.position = b2Vec2(x, y);
        // 设置【b2BodyDef】的 类型 (运动的或精巧的或漂浮的)
        def.type = body_type;
        
        // 设置【b2BodyDef】的 线速度 y = 10 ,表示物体向上飞
        if(body_type == b2_dynamicBody){
            // 动态物体  自由落体
            def.linearVelocity = b2Vec2(0, 9.8);
        }else{
            // 漂浮物体  向右飘动
            def.linearVelocity = b2Vec2(1, 0);
        }
        // 设置【b2BodyDef】的 子弹效应 (防止碰撞检測时 由于速度 太快,而失效;如本应反弹,结果陷入地板内)
        // def.bullet = true;
        
        // 1.2 通过调用world的方法,创建一个Body物体
        // 參数 是一个 b2BodyDef,它是构造一个刚体必须的、固有的东东
        // 由于,每个刚体都有自身的 b2BodyDef属性
        b2Body* body = world->CreateBody(&def);
        // *************************************************
        // 2.1 形状分为 圆和多边形
        b2PolygonShape shape;
        shape.SetAsBox(0.5, 0.5);
        // 2.2 一个刚体 有多个 b2FixtureDef
        // 一个 b2FixtureDef 是依附在刚体 身上的物理物质的属性
        // 每个 b2FixtureDef 又有形状shape、密度、摩擦系数等成员属性
        b2FixtureDef fixtureDef;
        // 每个 b2FixtureDef都有一个成员shape
        fixtureDef.shape = &shape;
        // 密度
        fixtureDef.density = 1;
        // 摩擦系数
        fixtureDef.friction = 0.3;
        // 为刚体 加入一个 b2FixtureDef
        body->CreateFixture(&fixtureDef);
        // *************************************************
        // 3、创建并加入一个 cocos2d 的精灵
        auto s = Sprite::create();
        // 0.5是物理世界中的精灵大小 单位是 米
        // 即在物理世界中,精灵 是一个1米 * 1米的方块
        s->setTextureRect(Rect(0, 0, 0.5*2*RATIO, 0.5*2*RATIO));
        // 加入到图层Layer
        addChild(s);
        // *************************************************
        // 4、绑定 cocos2d界面上的精灵
        body->SetUserData(s);
        
    }


    五、精巧的物体 如地板
    #pragma mark - 加入一个地板
    void Box2DScene::addGroundBody()
    {
        // 1.1 结构体b2BodyDef
        // 每一个刚体都有自身的 固有的 必须的 b2BodyDef属性
        b2BodyDef def;
        // 在世界坐标中 的位置:第x米,第y米处  这个是在
        log("宽:%f",winSize.width);
        // 位置
        def.position = b2Vec2(480/RATIO,0);
        // 设置【b2BodyDef】的 类型 (运动的或精巧的或漂浮的)
        def.type = b2_staticBody;
        // 1.2 通过调用world的方法,创建一个Body物体
        // 參数 是一个 b2BodyDef,它是构造一个刚体必须的、固有的东东
        // 由于,每一个刚体都有自身的 b2BodyDef属性
        groundBody = world->CreateBody(&def);
        // *************************************************
        // 2.1 形状分为 圆和多边
        b2PolygonShape groundShape;
        // 尺寸: 在物理世界中的 半长和 半宽 多少米
        groundShape.SetAsBox(480/RATIO, 0.5);
        // 2.2 一个刚体 有多个 b2FixtureDef
        // 一个 b2FixtureDef 是依附在刚体 身上的物理物质的属性
        // 每一个 b2FixtureDef 又有形状shape、密度、摩擦系数等成员属性
        b2FixtureDef fixureDef;
        // 形状
        fixureDef.shape = &groundShape;
        // 密度
        fixureDef.density = 1;
        // 摩擦系数
        fixureDef.friction = 0.3;
        groundBody->CreateFixture(&fixureDef);
    }


    六、物体间的碰撞检測






    首先, 设置碰撞检測 的侦听者 为当前Layer

    world->SetContactListener(this);

    让场景继承b2ContactListener(实现接口)
    实现接口中的方法:

        virtual void BeginContact(b2Contact* contact);


    b2Contact类中有一个方法,能够得到刚体:

    contact->GetFixtureA()->GetBody()


    接口中的方法,固定写法




    完整代码
    //
    //  Box2DScene.h
    //  01_cocos2d-x
    //
    //  Created by beyond on 14-10-5.
    //
    //
    
    #ifndef ___1_cocos2d_x__Box2DScene__
    #define ___1_cocos2d_x__Box2DScene__
    
    
    #include "cocos2d.h"
    // 1、导入物理世界 主头文件
    #include <Box2D/Box2D.h>
    
    USING_NS_CC;
    // 注意 这儿,继承的是 Layer
    // 要想进行碰撞检測,必须 实现接口
    class Box2DScene : public cocos2d::Layer,public b2ContactListener
    {
    private:
        // 2、成员变量:物理世界,參数 指定x和y的重力方向
        b2World *world;
        // 由于 要碰撞检測,所以
        b2Body *groundBody;
        
        // 屏幕尺寸
        Size winSize;
    
    public:
        // c++里面没有id类型, 所以 返回类的实例对象的 指针
        static cocos2d::Scene* createScene();
        // 下面是 不同点:cocos2d-x的 'init' 方法 返回 bool
        // 而cocos2d-iphone 返回 'id' 类型
        virtual bool init();
        // 宏 自己主动实现 "静态的 create()方法"
        CREATE_FUNC(Box2DScene);
        
        // 4、在时钟方法里,模拟世界的执行 step
        virtual void update(float dt);
        
        // 5、加入一个精巧的或运动的Rect刚体,通过參数type指定,x和y是世界坐标中的位置
        void addRectBody(float x,float y,b2BodyType body_type);
        // 6、加入一个地板
        void addGroundBody();
        
        // 7、碰撞检測
        // 接口中的方法,是一个固定定法
        virtual void BeginContact(b2Contact* contact);
        
    };
    
    
    
    #endif /* defined(___1_cocos2d_x__Box2DScene__) */
    



    //
    //  Box2DScene.cpp
    //  01_cocos2d-x
    //
    //  Created by beyond on 14-10-5.
    //
    //
    
    #include "Box2DScene.h"
    // cocos2d 为宽960 * 高640
    // box2d世界为宽10米 * 6.67米 (由于10米是比較理想的模拟情况)
    // 因此 像素转成米 的比例是 96
    // 假设,要把 像素转成米  仅仅要 像素/RATIO
    // 假设,要把 米转成像素  仅仅要 米*RATIO  (把物理世界中的刚体 在界面上更新坐标时)
    #define RATIO 960.0/10.0f
    
    USING_NS_CC;
    Scene* Box2DScene::createScene()
    {
        // 'scene' 自己主动释放
        // 创建一个scene
        auto scene = Scene::create();
        // 'layer' 自己主动释放
        auto layer = Box2DScene::create();
        // 将图层 加入到场景中
        scene->addChild(layer);
        // 返回 填充好图层的 场景
        return scene;
    }
    
    // 在 "init" 方法中,实例化自己要用的精灵对象
    bool Box2DScene::init()
    {
        // 1. 调用父类的init , cpp 没有super,直接写父类名
        if ( !Layer::init() ) return false;
        // 屏幕尺寸
        winSize = Director::getInstance()->getVisibleSize();
        
        // 2、创建一个物理世界,參数 是x y 方向的重力加速度,负数表示 重力向下
        world = new b2World(b2Vec2(0,-9.8));
        // 设置碰撞检測 的侦听者 为当前Layer
        world->SetContactListener(this);
    
        // 3、开启时钟方法,在时钟方法中,让世界 向前执行
        scheduleUpdate();
        
        // 4、创建并加入一个执行的物体 RectBody
        // 參数 x 5  y 3,x和y是世界坐标中的位置,类型是 b2_dynamicBody
        addRectBody(5,3,b2_dynamicBody);
        
        // 5、加入一个地板
        addGroundBody();
        
        // 6、创建一个漂浮的物体
        addRectBody(1,5,b2_kinematicBody);
        return true;
    }
    #pragma mark - 加入一个刚体
    // 加入一个精巧的或运动的Rect刚体,通过參数type指定,x和y是世界坐标中的位置
    void Box2DScene::addRectBody(float x, float y, b2BodyType body_type)
    {
        // 1.1 结构体b2BodyDef
        // 每一个刚体都有自身的 固有的 必须的 b2BodyDef属性
        b2BodyDef def;
        // 在世界坐标中 的位置:第x米,第y米处
        def.position = b2Vec2(x, y);
        // 设置【b2BodyDef】的 类型 (运动的或精巧的或漂浮的)
        def.type = body_type;
        
        // 设置【b2BodyDef】的 线速度 y = 10 ,表示物体向上飞
        if(body_type == b2_dynamicBody){
            // 动态物体  自由落体
            def.linearVelocity = b2Vec2(0, 9.8);
        }else{
            // 漂浮物体  向右飘动
            def.linearVelocity = b2Vec2(1, 0);
        }
        // 设置【b2BodyDef】的 子弹效应 (防止碰撞检測时 由于速度 太快,而失效;如本应反弹,结果陷入地板内)
        // def.bullet = true;
        
        // 1.2 通过调用world的方法,创建一个Body物体
        // 參数 是一个 b2BodyDef,它是构造一个刚体必须的、固有的东东
        // 由于,每一个刚体都有自身的 b2BodyDef属性
        b2Body* body = world->CreateBody(&def);
        // *************************************************
        // 2.1 形状分为 圆和多边形
        b2PolygonShape shape;
        shape.SetAsBox(0.5, 0.5);
        // 2.2 一个刚体 有多个 b2FixtureDef
        // 一个 b2FixtureDef 是依附在刚体 身上的物理物质的属性
        // 每一个 b2FixtureDef 又有形状shape、密度、摩擦系数等成员属性
        b2FixtureDef fixtureDef;
        // 每一个 b2FixtureDef都有一个成员shape
        fixtureDef.shape = &shape;
        // 密度
        fixtureDef.density = 1;
        // 摩擦系数
        fixtureDef.friction = 0.3;
        // 为刚体 加入一个 b2FixtureDef
        body->CreateFixture(&fixtureDef);
        // *************************************************
        // 3、创建并加入一个 cocos2d 的精灵
        auto s = Sprite::create();
        // 0.5是物理世界中的精灵大小 单位是 米
        // 即在物理世界中,精灵 是一个1米 * 1米的方块
        s->setTextureRect(Rect(0, 0, 0.5*2*RATIO, 0.5*2*RATIO));
        // 加入到图层Layer
        addChild(s);
        // *************************************************
        // 4、绑定 cocos2d界面上的精灵
        body->SetUserData(s);
        
    }
    #pragma mark - 加入一个地板
    void Box2DScene::addGroundBody()
    {
        // 1.1 结构体b2BodyDef
        // 每一个刚体都有自身的 固有的 必须的 b2BodyDef属性
        b2BodyDef def;
        // 在世界坐标中 的位置:第x米,第y米处  这个是在
        log("宽:%f",winSize.width);
        // 位置
        def.position = b2Vec2(480/RATIO,0);
        // 设置【b2BodyDef】的 类型 (运动的或精巧的或漂浮的)
        def.type = b2_staticBody;
        // 1.2 通过调用world的方法,创建一个Body物体
        // 參数 是一个 b2BodyDef,它是构造一个刚体必须的、固有的东东
        // 由于,每一个刚体都有自身的 b2BodyDef属性
        groundBody = world->CreateBody(&def);
        // *************************************************
        // 2.1 形状分为 圆和多边
        b2PolygonShape groundShape;
        // 尺寸: 在物理世界中的 半长和 半宽 多少米
        groundShape.SetAsBox(480/RATIO, 0.5);
        // 2.2 一个刚体 有多个 b2FixtureDef
        // 一个 b2FixtureDef 是依附在刚体 身上的物理物质的属性
        // 每一个 b2FixtureDef 又有形状shape、密度、摩擦系数等成员属性
        b2FixtureDef fixureDef;
        // 形状
        fixureDef.shape = &groundShape;
        // 密度
        fixureDef.density = 1;
        // 摩擦系数
        fixureDef.friction = 0.3;
        groundBody->CreateFixture(&fixureDef);
    }
    
    #pragma mark - 时钟方法
    void Box2DScene::update(float dt)
    {
        // 1、让物理世界 的时间和位置向前迭代
        // 參数:时间差,速度迭代,位置迭代;官方推荐 8和3
        world->Step(dt,8,3);
        
        // 2、取出世界中的全部刚体,改变其位置
        Sprite *s;
        // 链表
        for (b2Body *b = world->GetBodyList(); b; b=b->GetNext()) {
            
            // log("y:%f米",b->GetPosition().y);
            if (b->GetUserData()) {
                // 刚体绑定的 精灵
                s = (Sprite*)b->GetUserData();
                // 更新精灵 在cocos2d中的位置  ; 单位要从米转成像素  仅仅需  米*RATIO 就可以
                s->setPosition(b->GetPosition().x*RATIO, b->GetPosition().y*RATIO);
            }
        }
        
        
    }
    #pragma mark - 碰撞检測
    // 接口中的方法,是一个固定定法
    void Box2DScene::BeginContact(b2Contact *contact){
        // 碰撞有一方 是地板,则说明 检測到了碰撞
        b2Fixture *A = contact->GetFixtureA();
        b2Body *aBody = A->GetBody();
        b2Fixture *B = contact->GetFixtureB();
        b2Body *bBody = B->GetBody();
        if (aBody == groundBody||bBody == groundBody) {
            log("有物体落在了地板上");
        }
    }
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    









  • 相关阅读:
    ODOO开发-Pycharm开启debug模式
    pycharm开启debug模式报错汇总
    星辉Odoo模型开发教程4-常用字段属性
    星辉Odoo模型开发教程3-创建字段
    Business Object 开发
    Ubuntu安装masscan的两种方式
    HFish 蜜罐搭建测试
    【转】如何超过大多数人
    【译】13款入侵检测系统介绍
    【译】修复Ubuntu软件安装的锁文件问题
  • 原文地址:https://www.cnblogs.com/zfyouxi/p/4255167.html
Copyright © 2011-2022 走看看