cocos2dx读书笔记(Box2D 物理引擎)

转载:http://blog.csdn.net/u012945598/article/details/17787243

Box2dHandler.h

#include "cocos2d.h"
#include "Box2D.h"
#include "GLES-Render.h"
USING_NS_CC;
#define PTM_RATIO 32

class B2Sprite :public CCSprite
{
public:
 //   static B2Sprite *spriteWithSpriteFrameName(const char*file);
 //   bool initWithSpriteFrameName(const char *pszSpriteFrameName);
//    物理世界的“物体”
    CC_SYNTHESIZE(b2Body*, m_b2Body, B2Body);
//    是否死去
//    IsDead为true,表示彻底从屏幕上消失
    CC_SYNTHESIZE(bool, m_isDead, IsDead);
//    是否存活
//    IsAlive为true,则物体存活,代表仍然存在碰撞体积,需要考虑碰撞
    CC_SYNTHESIZE(bool, m_isAlive, IsAlive);
};

class Box2dHandler:public CCNode,public b2ContactListener
{
    public:
//    用于调试绘图
    GLESDebugDraw *m_debugDraw;
//    物理世界
    b2World *m_world;
//    用于保存死亡对象对容器
//    typedef pair<b2Fixture *, b2Fixture *> MyContact;
//    set<MyContact> m_contacts;
//    初始化物理世界
    bool initBox2D();
//    设置物体    密度为10
    void addBodyForSprite(B2Sprite *sprite,double density=10.0);
//    设置夹具   密度为10
    void addFixtureForSprite(B2Sprite *sprite,double density=10.0);
//此方法用于销毁死亡对象,因为物体不可以则碰撞检测方法中直接销毁,可以中updata函数最后执行
    void dealCollisions();

//    碰撞检测方法 开始重叠
    virtual void BeginContact(b2Contact *contact);
//    结束重叠
    virtual void EndContact(b2Contact *contact);
//    对应碰撞处理对前后时间点
//    virtual void ProSolve(b2Contact *contact,const b2Manifold *oldManifold);
//    virtual void PostSolve(b2Contact *contact,const b2ContactImpulse *impulse);
    
    static Box2dHandler* handler();
    bool init();
    void draw();
    void update(float dt);
//    void removeSprite(B2Sprite *node);
//    CC_SYNTHESIZE(Box2dHandlerDe, , )
};

Box2dHandler.cpp

#include "Box2dHandler.h"
//把Box2dHandler设置成单例
Box2dHandler* Box2dHandler::handler()
{
    static Box2dHandler *handler=NULL;
    if(handler==NULL)
    {
        handler=new Box2dHandler();
        handler->init();
        return handler;
    }
    else
        return handler;
}

//Box2dHandler初始化
bool Box2dHandler::init()
{
    this->initBox2D();
    this->scheduleUpdate();
    
 //    GLESDebugDraw m_debugDraw(PTM_RATIO);
//    调试绘图
    m_debugDraw=new GLESDebugDraw(PTM_RATIO);
    
    uint32 flags=0;
    flags+=b2Draw::e_shapeBit;
    m_debugDraw->SetFlags(flags);
    m_world->SetDebugDraw(m_debugDraw);
    return true;
}
//初始化物理引擎
bool Box2dHandler::initBox2D()
{
    CCSize s=CCDirector::sharedDirector()->getWinSize();
//    设置物理世界中的重力xy。
    b2Vec2 gravity;
    gravity.Set(0.0f, -1.0f);
    m_world=new b2World(gravity);
//    允许睡眠,可以提高物体的处理效率,只有中受到物理效果影响时才会唤醒对象
    m_world->SetAllowSleeping(true);
//    开启连续物理测试
//    连续物理测试会使物理模拟时间间隔缩短,提高模拟精度,避免速度较快的两个物体直接穿透
//    但该方法同样会降低引擎但运行性能
    m_world->SetContinuousPhysics(true);
//    设置碰撞事件的监听器
    m_world->SetContactListener(this);
//    定义一个边界范围,存在碰撞效果
    b2BodyDef groundBodyDef;
    groundBodyDef.position.Set(0, 0);
    
    b2Body *groundBody=m_world->CreateBody(&groundBodyDef);
//    定义边缘形状
    b2EdgeShape groundBox;
//    底部
    groundBox.Set(b2Vec2(0,0), b2Vec2(s.width/PTM_RATIO,0));
    groundBody->CreateFixture(&groundBox,0);
//    顶部
    groundBox.Set(b2Vec2(0,s.height/PTM_RATIO), b2Vec2(s.width/PTM_RATIO,s.height/PTM_RATIO));
    groundBody->CreateFixture(&groundBox,0);
//    左侧
    groundBox.Set(b2Vec2(0,s.height/PTM_RATIO), b2Vec2(0,0));
    groundBody->CreateFixture(&groundBox,0);
//    右侧
    groundBox.Set(b2Vec2(s.width/PTM_RATIO,s.height/PTM_RATIO), b2Vec2(s.width/PTM_RATIO,0));
    groundBody->CreateFixture(&groundBox,0);
    
    
    return true;
}
//为物理世界但精灵添加夹具
 void Box2dHandler::addFixtureForSprite(B2Sprite *sprite,double density)
{
//    定义形状,多边形
    b2PolygonShape spriteShape;
//    得到精灵的大小
    CCSize size =sprite->getContentSize();
    spriteShape.SetAsBox(size.width/PTM_RATIO/2, size.height/PTM_RATIO/2);
//    创建一个夹具的对象
    b2FixtureDef spriteShapeDef;
//    设置夹具的形状
    spriteShapeDef.shape=&spriteShape;
//    设置夹具的密度
    spriteShapeDef.density=density;
//  设置精灵物理世界的“物体”的夹具
    b2Body *spriteBody=sprite->getB2Body();
    spriteBody->CreateFixture(&spriteShapeDef);
}
//为物理世界的精灵创建Box2D物体
void Box2dHandler::addBodyForSprite(B2Sprite *sprite,double density)
{
//  创建一个物体对象
    b2BodyDef spriteBodyDef;
//    物体对象--b2Body
//    静态物体(b2_staticBody)。质量为 0,不可以移动,通常模拟我们游戏的物理边
//    界:大地、墙壁等。
//    平台物体(b2_kinematicBody)。按照固定路线运动的物体,比如说电梯,运动的
//    滚梯,运行的火车等等。
//    动态物体(b2_dynamicBody)。我们最常见的精灵对象对应的物体。
//    物体类型为动态物体
    spriteBodyDef.type=b2_dynamicBody;
    
    spriteBodyDef.position.Set((sprite->getPosition().x)/PTM_RATIO, (sprite->getPosition().y)/PTM_RATIO);
//    设置用户数据,允许存放一个任意类型的指针向我们自定义的数据
//    用于将物体与游戏程序关联起来,所有物体的用完数据应指向相同的数据类型
    spriteBodyDef.userData=sprite;
//    在物理世界中创建物体
    b2Body *spriteBody=m_world->CreateBody(&spriteBodyDef);
//    为精灵添加物体
    sprite->setB2Body(spriteBody);
//    为精灵添加夹具
    this->addFixtureForSprite(sprite,density);
}
//   更新状态
 void Box2dHandler::update(float dt)
{
//    遍历物理世界中的物体
    for(b2Body *b=m_world->GetBodyList();b;b=b->GetNext())
    {
//        是否没有精灵数据
        if(b->GetUserData()!=NULL)
        {
            
            B2Sprite *sprite =static_cast<B2Sprite*>(b->GetUserData());
//            b2Vec2 pos=b->GetPosition();
//            b2Vec2 bPosition=b2Vec2(pos.x+sprite->getPosition().x/PTM_RATIO,pos.y+sprite->getPosition().y/PTM_RATIO);
//            sprite->setPosition(ccp(pos.x*PTM_RATIO+sprite->getPosition().x,pos.y*PTM_RATIO+sprite->getPosition().y));
//            float32 bAngle=-CC_DEGREES_TO_RADIANS(sprite->getRotation());
//            b->SetTransform(bPosition, bAngle);
//       //     sprite->setRotation(-b->GetAngle()/0.01745329252f);
            sprite->setPosition(ccp(b->GetPosition().x*PTM_RATIO,b->GetPosition().y*PTM_RATIO));
            sprite->setRotation(-CC_RADIANS_TO_DEGREES(b->GetAngle()));
        }
    }
//    Box世界的刷新接口,第一个参数为更新引擎的间隔时间,第二个参数为计算速度,第三个参数为位置时迭代的次数
    m_world->Step(dt, 8, 8);
    //this->dealCollisions();
}
//使调试绘图显示到屏幕上
void Box2dHandler::draw()
{
    CCNode::draw();
//    保存opengl绘图状态
    ccGLEnableVertexAttribs(kCCVertexAttribFlag_Position);
//    用kmGLPushMatrix函数来保存状态
    kmGLPushMatrix();
//    绘制调试图案
    m_world->DrawDebugData();
//    用kmGLPopMatrix函数来恢复状态
    kmGLPopMatrix();
    
}
void Box2dHandler::BeginContact(b2Contact *contact)
{
    printf("开始碰撞");
}
void Box2dHandler::EndContact(b2Contact *contact)
{
    printf("结束碰撞");
}
测试代码:

//    获取可视区域大小
    CCSize visibleSize = CCDirector::sharedDirector()->getVisibleSize();
//    获取可视区域左下角坐标
    CCPoint origin = CCDirector::sharedDirector()->getVisibleOrigin();
//    创建物理世界
    Box2dHandler *handler =Box2dHandler::handler();
    this->addChild(handler);

    B2Sprite* pSprite =new B2Sprite();
    pSprite->initWithFile("CloseNormal.png");
    pSprite->setPosition(ccp(visibleSize.width/2 + origin.x, visibleSize.height/1.1 + origin.y));
    handler->addBodyForSprite(pSprite);
    
    B2Sprite* pSprite2 =new B2Sprite();
    pSprite2->initWithFile("CloseNormal.png");
    pSprite2->setPosition(ccp(visibleSize.width/2 + origin.x, visibleSize.height/6 + origin.y));
    handler->addBodyForSprite(pSprite2);
    
    this->addChild(pSprite);
    this->addChild(pSprite2);




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值