`
runfeel
  • 浏览: 902637 次
文章分类
社区版块
存档分类
最新评论

[cocos2dx开发技巧3]工具CocosBuilder的使用--Box2d

 
阅读更多

转发,请保持地址:http://blog.csdn.net/stalendp/article/details/8757660

前面的文章,我介绍了cocosBuilder的简单集成,这篇将介绍怎么使用cocosBuilder开发物理类的游戏。

机器人模型

先介绍结合机器人模型。如下图,机器人有10个图片组合而成,我们先要在cocosBuilder中把各种图片位置摆正确,然后在代码中读取图片之间的位置等信息,创建对应的body,然后用Revolute joint连成一个整体。


在cocosBuilder中创建一个名为robot的ccb,然后组合组成如下的情况:

调整各个模块的anchor(Chest除外),这些anchor点将被程序读取,作为joint点。然后导出ccbi文件。
在xcode中导入robot.ccbi,然后创建一个robot类,继承于CcbBase类(参见上一片文章《[cocos2dx开发技巧2]工具CocosBuilder的使用--集成》);覆盖onAssignCCBMemberVariable方法,如下:
   bool onAssignCCBMemberVariable(cocos2d::CCObject * pTarget, const char * pMemberVariableName, cocos2d::CCNode * pNode) {
        CCB_MEMBERVARIABLEASSIGNER_GLUE(this, "head", CCSprite *, this->head);
        CCB_MEMBERVARIABLEASSIGNER_GLUE(this, "chess", CCSprite *, this->chess);
        CCB_MEMBERVARIABLEASSIGNER_GLUE(this, "leftArm", CCSprite *, this->leftArm);
        CCB_MEMBERVARIABLEASSIGNER_GLUE(this, "leftHand", CCSprite *, this->leftHand);
        CCB_MEMBERVARIABLEASSIGNER_GLUE(this, "leftLeg", CCSprite *, this->leftLeg);
        CCB_MEMBERVARIABLEASSIGNER_GLUE(this, "leftFoot", CCSprite *, this->leftFoot);
        CCB_MEMBERVARIABLEASSIGNER_GLUE(this, "rightArm", CCSprite *, this->rightArm);
        CCB_MEMBERVARIABLEASSIGNER_GLUE(this, "rightHand", CCSprite *, this->rightHand);
        CCB_MEMBERVARIABLEASSIGNER_GLUE(this, "rightLeg", CCSprite *, this->rightLeg);
        CCB_MEMBERVARIABLEASSIGNER_GLUE(this, "rightFoot", CCSprite *, this->rightFoot);
        return NULL;
    }

覆盖onNodeLoaded方法如下:
 void onNodeLoaded(cocos2d::CCNode * pNode, cocos2d::extension::CCNodeLoader * pNodeLoader) {
        
        CCSpriteBatchNode* robot = CCSpriteBatchNode::createWithTexture(head->getTexture());  //这里将使用SpriteBatchNode来提高性能
        addChild(robot);
        
        MyPhysicsSprite::attach(robot, head);
        MyPhysicsSprite::attach(robot, chess);
        MyPhysicsSprite::attach(robot, leftArm);
        MyPhysicsSprite::attach(robot, leftHand);
        MyPhysicsSprite::attach(robot, leftLeg);
        MyPhysicsSprite::attach(robot, leftFoot);
        MyPhysicsSprite::attach(robot, rightArm);
        MyPhysicsSprite::attach(robot, rightHand);
        MyPhysicsSprite::attach(robot, rightLeg);
        MyPhysicsSprite::attach(robot, rightFoot);
        
        createJoin(chess, head, head->getAnchorPoint());
        createJoin(chess, leftArm, leftArm->getAnchorPoint());
        createJoin(leftArm, leftHand, leftHand->getAnchorPoint());
        createJoin(chess, rightArm, rightArm->getAnchorPoint());
        createJoin(chess, leftLeg, leftLeg->getAnchorPoint());
        createJoin(chess, rightLeg, rightLeg->getAnchorPoint());
        
        createJoin(rightArm, rightHand, rightHand->getAnchorPoint());
        createJoin(leftLeg, leftFoot, leftFoot->getAnchorPoint());
        createJoin(rightLeg, rightFoot, rightFoot->getAnchorPoint());
        
        
    }

关于Join的创建,代码如下:
    void createJoin(CCSprite* a, CCSprite* b, CCPoint anchor) {
        b2RevoluteJointDef rjd;
        rjd.maxMotorTorque = 50.0f;
        rjd.enableMotor = false;
        rjd.collideConnected=false;
        rjd.motorSpeed= 20*DEGTORAD;
        rjd.Initialize(((MyPhysicsSprite*)a)->getBody(), ((MyPhysicsSprite*)b)->getBody(), ((MyPhysicsSprite*)b)->getBody()->GetPosition()); 
        MyWorld::getWorld()->CreateJoint(&rjd);
    }

场景的建立

这里将创建一个robot玩耍的场地。新建一个ccb文件,布置场景如下:

导出ccbi,在xcode中导入ccbi,接着创建一个playground类,关联相关属性如下:
 virtual bool onAssignCCBMemberVariable(cocos2d::CCObject * pTarget, const char * pMemberVariableName, cocos2d::CCNode * pNode) {
        CCB_MEMBERVARIABLEASSIGNER_GLUE(this, "apple", CCSprite *, this->apple);
        CCB_MEMBERVARIABLEASSIGNER_GLUE(this, "ground", CCSprite *, this->ground);
        CCB_MEMBERVARIABLEASSIGNER_GLUE(this, "wleft", CCSprite *, this->wleft);
        CCB_MEMBERVARIABLEASSIGNER_GLUE(this, "wright", CCSprite *, this->wright);
        return false;
    }

创建box2d物体:
  virtual void onNodeLoaded(cocos2d::CCNode * pNode, cocos2d::extension::CCNodeLoader * pNodeLoader) {
        GB2ShapeCache::sharedGB2ShapeCache()->addShapesWithFile("apple_pe.plist");

        MyWorld::init();
        MyPhysicsSprite::attach(this, apple, false, "apple");
        MyPhysicsSprite::attach(this, ground, true);
        MyPhysicsSprite::attach(this, wleft, true);
        MyPhysicsSprite::attach(this, wright, true);
        
        scheduleUpdate();
        robot = (Robot*)RobotLoader::loadCcbi();
        addChild(robot);
        CCSize size = CCDirector::sharedDirector()->getVisibleSize();
        robot->setPhysicPos(ccp(size.width/2, size.height/2));
        //robot->setPosition(ccp(size.width/2, size.height/2));
    }
    

对物体施加作用

接着就是实现Play按钮的功能了,在响应Play按钮的点击时,为apple和robot的chess施加一个向上的impluse,使得它们运动起来。
在cocosBuilder中选择Play按钮,在右侧的CCMenuItem中为selector命名为onPlay,并选择target为Document root。具体如下:

在Playground类中,实现如下代码:
    virtual cocos2d::SEL_MenuHandler onResolveCCBCCMenuItemSelector(cocos2d::CCObject * pTarget, const char * pSelectorName) {
            CCB_SELECTORRESOLVER_CCMENUITEM_GLUE(this, "onPlay", Playground::btnPlay);
        return NULL;
    }

实现btnPlay功能:
  void btnPlay(cocos2d::CCObject *pSender) {
        // 对apple施加向上的大小为30的impulse
        b2Body* body = dynamic_cast<MyPhysicsSprite*>(apple)->getBody();
        body->ApplyLinearImpulse(b2Vec2(0, 30), body->GetWorldCenter());
        
        // 对robot的chess施加b2Vec2(10,20)的impulse
        b2Body* bb = ((MyPhysicsSprite*)robot->chess)->getBody();
        bb->ApplyLinearImpulse(b2Vec2(10,20), b2Vec2(bb->GetWorldCenter().x + 0.5, bb->GetWorldCenter().y));
    }

ok,至此box2d就集成完毕了。效果请参考《[cocos2dx开发技巧1]工具CocosBuilder的使用--demo介绍

另外附一些代码:
这个MyPhysicsSprite可以使用CCSpritecsSprite类。
#ifndef ShootTheApple_PhysicsSprite_h
#define ShootTheApple_PhysicsSprite_h

#include "cocos2d.h"
#include "cocos-ext.h"

#include "Box2D.h"
#include "MyWorld.h"
#include "GB2ShapeCache-x.h"

#define PTM_RATIO 32

USING_NS_CC;
USING_NS_CC_EXT;

#define DEGTORAD 0.0174532925199432957f
#define RADTODEG 57.295779513082320876f

class MyPhysicsSprite : public cocos2d::CCSprite
{
private:
    b2Body* m_pBody;    // strong ref
    
public:
    static MyPhysicsSprite* attach(CCNode* parent, CCSprite*& sprite, bool isStatic = false, const char* peName=NULL) {
        
        MyPhysicsSprite *pobSprite = new MyPhysicsSprite(sprite, isStatic, peName);
        CCSpriteFrame *pSpriteFrame = sprite->displayFrame();
        CCPoint anchor = sprite->getAnchorPoint();
        
        if (pSpriteFrame && pobSprite && pobSprite->initWithSpriteFrame(pSpriteFrame))
        {
            pobSprite->autorelease();
            parent->addChild(pobSprite);
            
            
            cocos2d::CCLog(cocos2d::CCString::createWithFormat("anchor<%.2f, %.2f>", anchor.x, anchor.y)->getCString());
            sprite->autorelease(); // no need anymore
            sprite->setVisible(false);
            sprite = pobSprite;
            sprite->setAnchorPoint(anchor);
            
            return pobSprite;
        }
        CC_SAFE_DELETE(pobSprite);
        return NULL;
    }
    
    b2Body* getBody() {
        return m_pBody;
    }
    
    MyPhysicsSprite(CCSprite* sprite, bool isStatic, const char* peName): m_pBody(NULL) {
        init(sprite, isStatic, peName);
    }
    
    virtual void init(CCSprite* sprite, bool isStatic, const char* peName) {
        b2World* world = MyWorld::getWorld();
        b2Body *body = NULL;
        
            CCPoint p = sprite->getPosition();
            CCSize size = sprite->getContentSize();
            CCPoint anchor = sprite->getAnchorPoint();
            float angle = -sprite->getRotation()*DEGTORAD;
            
            b2BodyDef bodyDef;
            bodyDef.type = isStatic ? b2_staticBody : b2_dynamicBody;
            bodyDef.position.Set(p.x/PTM_RATIO, p.y/PTM_RATIO);
            bodyDef.angle = angle;
            
            body = world->CreateBody(&bodyDef);
        
        
//        if(peName!=NULL) {
//            GB2ShapeCache *sc = GB2ShapeCache::sharedGB2ShapeCache();
//            sc->addFixturesToBody(body, peName);
//            setAnchorPoint(sc->anchorPointForShape(peName));
//        } else {
            // Define another box shape for our dynamic body.
            b2PolygonShape dynamicBox;
            b2Vec2 center((0.5-anchor.x)*size.width/PTM_RATIO, (0.5-anchor.y) * size.height/PTM_RATIO);
            dynamicBox.SetAsBox(size.width/PTM_RATIO/2, size.height/PTM_RATIO/2, center, 0);//These are mid points for our 1m box
            
            // Define the dynamic body fixture.
            b2FixtureDef fixtureDef;
            fixtureDef.shape = &dynamicBox;
            fixtureDef.density = 1.0f;
            fixtureDef.friction = 0.1f;
            // fixtureDef.restitution = 0.5f;
            body->CreateFixture(&fixtureDef);
//        }
        this->m_pBody = body;
    }
    
    virtual bool isDirty(void) {
        return m_pBody!=NULL && m_pBody->IsAwake(); // 只有物体在运动中,才需要更新显示
    }
    
    void setPhysicPos(CCPoint pos) {
        m_pBody->SetTransform(b2Vec2(pos.x/PTM_RATIO, pos.y/PTM_RATIO), 0);
    }
    
    void physicsTrans(CCPoint pos) {
        if(m_pBody==NULL)
            return;
        b2Vec2 cur = m_pBody->GetPosition();
        m_pBody->SetTransform(b2Vec2(cur.x + pos.x/PTM_RATIO, cur.y + pos.y/PTM_RATIO), 0);
    }
    
    
    virtual cocos2d::CCAffineTransform 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;
    }
};


#endif

#ifndef ShootTheApple_MyWorld_h
#define ShootTheApple_MyWorld_h

#include "Box2D.h"

#define VELOCITY_ITER 8
#define POSITION_ITER 1

class MyWorld {
private:
    static b2World* world;
public:
    static void init() {
        if (world!=NULL) {
            return;
        }
        b2Vec2 gravity;
        gravity.Set(0.0f, -10.0f);
        world = new b2World(gravity);
        
        // Do we want to let bodies sleep?
        world->SetAllowSleeping(true);
        
        world->SetContinuousPhysics(true);
    }
    
    static b2World* getWorld() {
        if(world==NULL) {
            init();
        }
        return world;
    }
    
    static void update(float dt) {
        getWorld()->Step(dt, VELOCITY_ITER, POSITION_ITER);
    }

};

b2World* MyWorld::world=NULL;

#endif






分享到:
评论

相关推荐

    Cocos2D-X游戏开发技术精解.pdf

    《Cocos2D-X游戏开发技术精解》详细介绍如何使用Cocos2D-X引擎开发自己的移动平台游戏。全书共15章,主要内容包括:Cocos2D-X引擎简介;如何建立跨平台的开发环境;引擎的核心模块——渲染框架;如何实现动态画面和...

    cocos2dx2.1.4解决win32中文乱码编译自vs2012

    下下来后,请在VC++包含目录中链接(F:\cocos2d-x-2.1.4\cocos2dx\platform\win32;F:\cocos2d-x-2.1.4\cocos2dx\platform\third_party\win32\OGLES\GL\;F:\cocos2d-x-2.1.4\cocos2dx\platform\third_party\win32\...

    基于Cocos2dx + box2d 实现的愤怒的小鸟Demo

    压缩文件目录内容: AngryBird source 愤怒的小鸟Demo源代码,基于Cocos2dx C++,box2d技术。 run 可执行程序目录

    教你用Cocos2D-X开发跨平台移动应用

    Cocos2d-x源于Cocos2d,是一款开源游戏引擎项目,是一款基于对原有iOS平台cocos2d重写为C++的开源代码,封装了OpenGL,Box2d,LibCurl,LibPng等开源的跨平台代码。由于基于C++和STL特点使其广泛应用于游戏开发、移动...

    IOS 开发源码:cocos2dx+box2d的库和演示实例

    IOS 开发源码:cocos2dx+box2d的库和演示实例.包含cocos2d-x的库和box2d的库,实现模拟物理碰撞、弹跳的源码

    cocos2dx_box2d实例1

    cocos2dx_box2d实例1:瓦片积木,完成box2d渲染调试的基本框架,并完成TestCpp中的tiles示例

    cocos2d-x box2d入门示例

    一个cocos2d-x使用box2d的简单明了的示例。适合初学者。

    cocos2dx-3.0+Box2D例子

    使用cocos2dx 3.0的版本,没有使用他提供的接口,直接使用的Box2D的API接口 Box2D为2.2.1版本,本身不想要分的,关键不设置资源分审核好慢,所以设置了1分,大家原谅。

    瘸腿蛤蟆笔记39-cocos2d-x-3.2 Box2d物理引擎自由落体代码

    瘸腿蛤蟆笔记39-cocos2d-x-3.2 Box2d物理引擎自由落体代码

    瘸腿蛤蟆笔记38-cocos2d-x-3.2 Box2d物理引擎Ray-cast代码

    瘸腿蛤蟆笔记38-cocos2d-x-3.2 Box2d物理引擎Ray-cast代码

    Cocos2d-x 3.0 开发(九)使用Physicals代替Box2D和chipmunk

    通常这种事情都是交给物理引擎来做 但它们使用的过程中有个令人讨厌的地方 参数太多了 为了初始化一个简单的场景要写很多代码 在cocos2d x 3 0版本中 出现了一个新类族 physicals 它将Box2D或者chipmunk做了一层封装...

    cocos2dx测试debugDraw box2d

    cocos2dx用与物理引擎,之前测试,一直显示不出box2d自带的物理引擎绘制框,终于被我解决了,相信很多人同我有一样的问题

    cocos2dx2.0.4

    GB2ShapeCache-x PhysicsEditor 加快 cocos2dx-Box2D 开发 cocos2d-x 2.0.4

    cocos2d-x_Box2d实例代码

    学习cocos2dx后自己整的物理引擎(box2d)的类似helloworld的示例代码。cocos2d-x_Box2d实例代码,完整可运行的工程例子。对初学cocos2dx的物理引擎开发的同志们非常有用!

    cocos2d实现slider滑块效果

    使用cocos2d和box2d 。开发游戏变的简单多了。这游戏开发了半年多了。直到最近这个游戏停止了,因为资金问题,老大没法在发更多的工资了。哎,真的非常遗憾,我一个人完成游戏的编辑器开发,脚本开发,游戏代码开发...

    cocos2d实现RollNunber(数字滚动效果)

    使用cocos2d和box2d 。开发游戏变的简单多了。这游戏开发了半年多了。直到最近这个游戏停止了,因为资金问题,老大没法在发更多的工资了。哎,真的非常遗憾,我一个人完成游戏的编辑器开发,脚本开发,游戏代码开发...

    Cocos2d-x.by.Example.Beginners.Guide.2nd.Edition.1785288857

    Title: Cocos2d-x by Example: Beginner’s Guide, 2nd Edition Author: Roger Engelbert Length: 250 pages Edition: 1 Language: English Publisher: Packt Publishing Publication Date: 2015-04-30 ISBN-10: ...

Global site tag (gtag.js) - Google Analytics