[cocos2d-x]box2d的简单应用

box2d创建简单的入门示例:

实现功能:

1.实现刚体的创建

2.能够创建自定义的精灵刚体

3.精灵之间的相互碰撞

工具的使用:

要创建一个 自定义的刚体精灵(不规则形状),就要用到一个工具PhysicalEditor,下载地址:http://yun.baidu.com/share/link?shareid=1782518146&uk=1209145999&third=0
我们将图片添加到工程中,但要确保图片精灵周围是透明的才行,然后选择Exporter->Box2D generic(PLIST),最后直接publish就可以了,然后将plist文件和原图片资源一起导入到工程的Resource下。

操作步骤:

1.导入外部的GLES-Render类

2.主场景类:

class QueryCallback : public b2QueryCallback
{
public:
    b2Vec2 m_point;
    b2Fixture * m_fixture;
    
    QueryCallback(const b2Vec2 & point)
    {
        m_point = point;
        m_fixture = NULL;
    }
    bool ReportFixture(b2Fixture * fixture)
    {
        b2Body * body = fixture->GetBody();
        if (body->GetType() == b2_dynamicBody)
        {
            bool inside = fixture->TestPoint(m_point);
            if(inside)
            {
                m_fixture = fixture;
                return false;
            }
        }
        return true;
    }
    
};

class SecondScene : public CCLayer
{
public:
    ~SecondScene();
    SecondScene();

    static CCScene* scene();
    
    void initPhysics();
    void addNewSpriteAtPosition(CCPoint p);
    
    virtual void draw();
    void update(float dt);
    
    void ccTouchesBegan(CCSet *pTouches, CCEvent *pEvent);
    void ccTouchesMoved(CCSet *pTouches, CCEvent *pEvent);
    void ccTouchesEnded(CCSet* touches, CCEvent* event);
    
    bool MouseDown(const b2Vec2 & p);
    void MouseMove(const b2Vec2 & p);
    void MouseUp();
    
private:
    GLESDebugDraw * m_debugDraw;
    b2World * world;
    CCTexture2D * m_pSpriteTexture;
    b2MouseJoint * m_mouseJoint;  //鼠标关节节点
    b2Body * m_groundBody;
};
#endif /* defined(__box2dDemo__SecondHelloScene__) */


cpp

#include "SecondHelloScene.h"
#include "SimpleAudioEngine.h"
#include "GLES-Render.h"
#include "GB2ShapeCache-x.h"
#include "ContactListener.h" //碰撞检测
using namespace cocos2d;
using namespace CocosDenshion;

#define PTM_RATIO 32

enum {
    kTagParentNode = 1,
};

//PhysicsSprite::PhysicsSprite()
//: m_pBody(NULL)
//{
//    
//}
//
//void PhysicsSprite::setPhysicsBody(b2Body * body)
//{
//    m_pBody = body;
//}
//
//bool PhysicsSprite::isDirty(void)
//{
//    return true;
//}
//
//// returns the transform matrix according the Chipmunk Body values
//CCAffineTransform PhysicsSprite::nodeToParentTransform(void)
//{
//    b2Vec2 pos  = m_pBody->GetPosition();
//    
//    float x = pos.x * PTM_RATIO;
//    float y = pos.y * PTM_RATIO;
//    
//    if ( isIgnoreAnchorPointForPosition() ) {
//        x += m_obAnchorPointInPoints.x;
//        y += m_obAnchorPointInPoints.y;
//    }
//    
//    // Make matrix
//    float radians = m_pBody->GetAngle();
//    float c = cosf(radians);
//    float s = sinf(radians);
//    
//    if( ! m_obAnchorPointInPoints.equals(CCPointZero) ){
//        x += c*-m_obAnchorPointInPoints.x + -s*-m_obAnchorPointInPoints.y;
//        y += s*-m_obAnchorPointInPoints.x + c*-m_obAnchorPointInPoints.y;
//    }
//    
//    // Rot, Translate Matrix
//    m_sTransform = CCAffineTransformMake( c,  s,
//                                         -s,    c,
//                                         x,    y );
//    
//    return m_sTransform;
//}

SecondScene::SecondScene()
{
    setTouchEnabled( true );
    setAccelerometerEnabled( true );
    
    CCSize s = CCDirector::sharedDirector()->getWinSize();
    this->initPhysics();
    
    addNewSpriteAtPosition(ccp(s.width / 2, s.height / 2));
    
//    CCSpriteBatchNode *parent = CCSpriteBatchNode::create("blocks.png", 100);
//    m_pSpriteTexture = parent->getTexture();
//    
//    addChild(parent, 0, kTagParentNode);
//    
//    
//    addNewSpriteAtPosition(ccp(s.width/2, s.height/2));
//    
//    CCLabelTTF *label = CCLabelTTF::create("Tap screen", "Marker Felt", 32);
//    addChild(label, 0);
//    label->setColor(ccc3(0,0,255));
//    label->setPosition(ccp( s.width/2, s.height-50));
    
    scheduleUpdate();
}

SecondScene::~SecondScene()
{
    delete world;
    world = NULL;
    
    //delete m_debugDraw;
}

void SecondScene::initPhysics()
{
    //添加自定义的精灵
    GB2ShapeCache::sharedGB2ShapeCache()->addShapesWithFile("zhizhu.plist");
    
    CCSize s = CCDirector::sharedDirector()->getWinSize();
    
    b2Vec2 gravity;
    gravity.Set(0.0f, -10.0f);
    world = new b2World(gravity);
    
    b2BodyDef bodydef;
    m_groundBody = world->CreateBody(&bodydef);
    
    world->SetAllowSleeping(true);
    
    world->SetContinuousPhysics(false);//隧道效应,穿透,true表示不能穿透
    
    
    //接触监听,碰撞检测
    b2ContactListener *contactListener = new ContactListener();
    world->SetContactListener(contactListener);
    
    //静态刚体
    m_debugDraw = new GLESDebugDraw( PTM_RATIO );
    world->SetDebugDraw(m_debugDraw);
    
    uint32 flags = 0;
    flags += b2Draw::e_shapeBit;
    //        flags += b2Draw::e_jointBit;
    //        flags += b2Draw::e_aabbBit;
    //        flags += b2Draw::e_pairBit;
    //        flags += b2Draw::e_centerOfMassBit;
    m_debugDraw->SetFlags(flags);
    
    
    // Define the ground body.
    b2BodyDef groundBodyDef;
    groundBodyDef.position.Set(5, 1);

    
    b2Body* groundBody = world->CreateBody(&groundBodyDef);
    
    // Define the ground box shape.
    b2EdgeShape groundBox;
    
    // bottom
    
    groundBox.Set(b2Vec2(0,0), b2Vec2(s.width/PTM_RATIO,0));
    groundBody->CreateFixture(&groundBox,0);
    
    // top
    groundBox.Set(b2Vec2(0,s.height/PTM_RATIO), b2Vec2(s.width/PTM_RATIO,s.height/PTM_RATIO));
    groundBody->CreateFixture(&groundBox,0);
    
    // left
    groundBox.Set(b2Vec2(0,s.height/PTM_RATIO), b2Vec2(0,0));
    groundBody->CreateFixture(&groundBox,0);
    
    // right
    groundBox.Set(b2Vec2(s.width/PTM_RATIO,s.height/PTM_RATIO), b2Vec2(s.width/PTM_RATIO,0));
    groundBody->CreateFixture(&groundBox,0);
}

void SecondScene::draw()
{
    CCLayer::draw();
    
    ccGLEnableVertexAttribs( kCCVertexAttribFlag_Position );
    
    kmGLPushMatrix();
    
    world->DrawDebugData();
    
    kmGLPopMatrix();
}

void SecondScene::addNewSpriteAtPosition(CCPoint p)
{
    
    
    string name = "alien";
    CCSprite * sprite = CCSprite::create((name + ".png").c_str());
    sprite->setPosition(p);
    this->addChild(sprite);
    
//    CCSprite * sp = CCSprite::create("Icon.png");
//    sp->setPosition(CCPointMake(100, 100));
//    this->addChild(sp);
    
    b2BodyDef bodyDef;
    bodyDef.type = b2_dynamicBody;
    bodyDef.position.Set(p.x/PTM_RATIO, p.y/PTM_RATIO);
    bodyDef.userData = sprite;
    
    
    b2Body *body = world->CreateBody(&bodyDef);
    
    
    // Define another box shape for our dynamic body.
    //通过vertexHelper工具生成多边形
    b2PolygonShape dynamicBox;
//    b2Vec2 verts[] = {
//        b2Vec2(-12.8f / PTM_RATIO, 50.9f / PTM_RATIO),
//        b2Vec2(-48.8f / PTM_RATIO, 2.3f / PTM_RATIO),
//        b2Vec2(-30.7f / PTM_RATIO, -37.9f / PTM_RATIO),
//        b2Vec2(28.8f / PTM_RATIO, -18.9f / PTM_RATIO),
//        b2Vec2(30.8f / PTM_RATIO, 16.9f / PTM_RATIO),
//        b2Vec2(20.8f / PTM_RATIO, 44.9f / PTM_RATIO)
//    };
//    dynamicBox.Set(verts, 6);
    //dynamicBox.SetAsBox(.5f, .5f);//These are mid points for our 1m box
    
    
//    b2FixtureDef fixtureDef;
//    fixtureDef.shape = &dynamicBox;
//    fixtureDef.density = 1.0f;//密度
//    fixtureDef.friction = 0.3f;//摩擦
//    fixtureDef.restitution = 0.5f;//恢复,也可看成弹性系数
//    
//    
//    body->CreateFixture(&fixtureDef);
    
    GB2ShapeCache * sc = GB2ShapeCache::sharedGB2ShapeCache();
    sc->addFixturesToBody(body, name);
    sprite->setAnchorPoint(sc->anchorPointForShape(name));
}


void SecondScene::update(float dt)
{
    int velocityIterations = 8;
    int positionIterations = 1;

    world->Step(dt, velocityIterations, positionIterations);

    for (b2Body* b = world->GetBodyList(); b; b = b->GetNext())
    {
        if (b->GetUserData() != NULL) {
            //Synchronize the AtlasSprites position and rotation with the corresponding body
            CCSprite* myActor = (CCSprite*)b->GetUserData();
            myActor->setPosition( CCPointMake( b->GetPosition().x * PTM_RATIO, b->GetPosition().y * PTM_RATIO) );
            myActor->setRotation( -1 * CC_RADIANS_TO_DEGREES(b->GetAngle()) );//CC_RADIANS_TO_DEGREES弧度转角度
        }
    }
}

CCScene* SecondScene::scene()
{
    // 'scene' is an autorelease object
    CCScene *scene = CCScene::create();
    
    // add layer as a child to scene
    CCLayer* layer = new SecondScene();
    scene->addChild(layer);
    layer->release();
    
    return scene;
}

void SecondScene::ccTouchesBegan(cocos2d::CCSet *pTouches, cocos2d::CCEvent *pEvent)
{
    CCSetIterator it;
    CCTouch * touch;
    for(it = pTouches->begin(); it != pTouches->end(); it++)
    {
        touch = (CCTouch *)(*it);
        if(!touch)
            break;
        CCPoint location = touch->getLocation();
        
        if(!this->MouseDown(b2Vec2(location.x / PTM_RATIO, location.y / PTM_RATIO)))
        {
            this->addNewSpriteAtPosition(location);
        }
    }
}

void SecondScene::ccTouchesMoved(cocos2d::CCSet *pTouches, cocos2d::CCEvent *pEvent)
{
    CCSetIterator it;
    CCTouch * touch;
    for(it = pTouches->begin(); it != pTouches->end(); it++)
    {
        touch = (CCTouch *)(*it);
        if(!touch)
            break;
        CCPoint location = touch->getLocation();
        
        this->MouseMove(b2Vec2(location.x / PTM_RATIO,location.y / PTM_RATIO));
    }
}

void SecondScene::ccTouchesEnded(CCSet* touches, CCEvent* event)
{
    CCSetIterator it;
    CCTouch* touch;
    
    for( it = touches->begin(); it != touches->end(); it++)
    {
        touch = (CCTouch*)(*it);
    
        if(!touch)
            break;
    
        CCPoint location = touch->getLocationInView();
    
        location = CCDirector::sharedDirector()->convertToGL(location);
    
        addNewSpriteAtPosition( location );
    }
    this->MouseUp();
}

bool SecondScene::MouseDown(const b2Vec2 &p)
{
    if(m_mouseJoint != NULL)
    {
        return false;
    }
    
    b2AABB aabb;
    b2Vec2 d;
    d.Set(0.001f, 0.001f);
    aabb.lowerBound = p - d;
    aabb.upperBound = p + d;
    
    QueryCallback callback(p);
    
    world->QueryAABB(&callback, aabb);
    
    if (callback.m_fixture)
    {
        b2Body * body = callback.m_fixture->GetBody();
        b2MouseJointDef md;
        md.bodyA = m_groundBody;  //m_groundBody需要在上面init方法里定义一下
        md.bodyB = body;
        md.target = p;
        md.maxForce = 1000.0f * body->GetMass();
        m_mouseJoint = (b2MouseJoint *)world->CreateJoint(&md);
        body->SetAwake(true);
        return true;
    }
    
    return true;
}

void SecondScene::MouseMove(const b2Vec2 &p)
{
    if(m_mouseJoint)
    {
        m_mouseJoint->SetTarget(p);
    }
}

void SecondScene::MouseUp()
{
    if(m_mouseJoint)
    {
        world->DestroyJoint(m_mouseJoint);
        m_mouseJoint = NULL;
    }
}


3.碰撞检测类(ContactListener)

#ifndef __box2dDemo__ContactListener__
#define __box2dDemo__ContactListener__

//碰撞检测
#include <iostream>

#include "cocos2d.h"
#include "Box2D.h"

using namespace cocos2d;

class ContactListener : public b2ContactListener
{
    void BeginContact(b2Contact * contact);
    void EndContact(b2Contact *contact);
};

#endif /* defined(__box2dDemo__ContactListener__) */

cpp

#include "ContactListener.h"

void ContactListener::BeginContact(b2Contact *contact)
{
    b2Body *bodyA = contact->GetFixtureA()->GetBody();
    b2Body *bodyB = contact->GetFixtureB()->GetBody();
    CCSprite *spriteA = (CCSprite *)bodyA->GetUserData();
    CCSprite *spriteB = (CCSprite *)bodyB->GetUserData();
    
    if (spriteA != NULL && spriteB != NULL) {
        spriteA->setColor(ccMAGENTA);
        spriteB->setColor(ccMAGENTA);
    }
}

void ContactListener::EndContact(b2Contact *contact)
{
    b2Body *bodyA = contact->GetFixtureA()->GetBody();
    b2Body *bodyB = contact->GetFixtureB()->GetBody();
    CCSprite *spriteA = (CCSprite *)bodyA->GetUserData();
    CCSprite *spriteB = (CCSprite *)bodyB->GetUserData();
    
    if (spriteA != NULL && spriteB != NULL) {
        spriteA->setColor(ccWHITE);
        spriteB->setColor(ccWHITE);
    }
}


运行效果:

[cocos2d-x]box2d的简单应用_第1张图片

[cocos2d-x]box2d的简单应用_第2张图片


cocos2d-x游戏开发QQ交流群:280818155

备注:加入者必须修改:地区-昵称,很少有动态的将定期清理


你可能感兴趣的:([cocos2d-x]box2d的简单应用)