cocos2d-x中box2d的关节

//
//  HelloWorldScene.cpp
//  Box2dDemo
//
//  Created by gaocong on 13-6-24.
//  Copyright __MyCompanyName__ 2013年. All rights reserved.
//
#include "HelloWorldScene.h"
#include "SimpleAudioEngine.h"
#include "GLES-Render.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;
}

// this method will only get called if the sprite is batched.
// return YES if the physics values (angles, position ) changed
// If you return NO, then nodeToParentTransform won't be called.
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_tAnchorPointInPoints.x;
//        y += m_tAnchorPointInPoints.y;
//    }
//
//    // Make matrix
//    float radians = m_pBody->GetAngle();
//    float c = cosf(radians);
//    float s = sinf(radians);
//
//    if( ! CCPoint::CCPointEqualToPoint(m_tAnchorPointInPoints, CCPointZero) ){
//        x += c*-m_tAnchorPointInPoints.x + -s*-m_tAnchorPointInPoints.y;
//        y += s*-m_tAnchorPointInPoints.x + c*-m_tAnchorPointInPoints.y;
//    }
//
//    // Rot, Translate Matrix
//    m_tTransform = CCAffineTransformMake( c,  s,
//        -s,    c,
//        x,    y );
//
//    return m_tTransform;
//}

HelloWorld::HelloWorld()
{
    setTouchEnabled( true );
    setAccelerometerEnabled( true );
    
    CCSize s = CCDirector::sharedDirector()->getWinSize();
    // init physics
    this->initPhysics();
    
    CCSpriteBatchNode *parent = CCSpriteBatchNode::create("blocks.png", 100);
    m_pSpriteTexture = parent->getTexture();
    
    addChild(parent, 0, kTagParentNode);
    
    
    // addDynamicBody(ccp(s.width/2, s.height/2));
//    addDistanceJoint(ccp(s.width/2, s.height/2));
//    addRevoluteJoint(ccp(s.width/2, s.height/2));
//    addPrismaticJoint(ccp(s.width/2, s.height/2));
//    addPulleyJoint(ccp(s.width/2, s.height/2));
    addGearJoint(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();
}

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

void HelloWorld::initPhysics()
{
    
    CCSize s = CCDirector::sharedDirector()->getWinSize();
    
    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);
    
    world->SetContactListener(this);
    
    GLESDebugDraw* 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(0, 0); // bottom-left corner
    
    // Call the body factory which allocates memory for the ground body
    // from a pool and creates the ground box shape (also from a pool).
    // The body is also added to the world.
    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 HelloWorld::draw()
{
    //
    // IMPORTANT:
    // This is only for debug purposes
    // It is recommend to disable it
    //
    CCLayer::draw();
    
    ccGLEnableVertexAttribs( kCCVertexAttribFlag_Position );
    
    kmGLPushMatrix();
    
    world->DrawDebugData();
    
    kmGLPopMatrix();
}


b2Body * HelloWorld::addNewSpriteAtPositionAndType(CCPoint p, b2BodyType type)
{
    
    b2BodyDef bodyDef;
    bodyDef.type = type;
    bodyDef.position.Set(p.x/PTM_RATIO, p.y/PTM_RATIO);
    b2Body *body = world->CreateBody(&bodyDef);
    
    // Define another box shape for our dynamic body.
    b2PolygonShape dynamicBox;
    dynamicBox.SetAsBox(.5f, .5f);//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.3f;
    body->CreateFixture(&fixtureDef);
    
    bodyAddSprite(body);
    return body;
}

//在body上添加精灵
void HelloWorld::bodyAddSprite(b2Body * body)
{
    CCNode* parent = getChildByTag(kTagParentNode);
    
    //We have a 64x64 sprite sheet with 4 different 32x32 images.  The following code is
    //just randomly picking one of the images
    int idx = (CCRANDOM_0_1() > .5 ? 0:1);
    int idy = (CCRANDOM_0_1() > .5 ? 0:1);
    PhysicsSprite *sprite = new PhysicsSprite();
    sprite->initWithTexture(m_pSpriteTexture, CCRectMake(PTM_RATIO * idx,PTM_RATIO * idy,PTM_RATIO,PTM_RATIO));
    sprite->autorelease();
    
    parent->addChild(sprite);
    
    sprite->setPosition( CCPointMake( body->GetPosition().x, body->GetPosition().y) );
    
    sprite->setPhysicsBody(body);
    body->SetUserData(sprite);
}

//距离关节
void HelloWorld::addDistanceJoint(CCPoint p)
{
    b2Body *body = addNewSpriteAtPositionAndType(p, b2_staticBody);
    
    b2Body *body2 = addNewSpriteAtPositionAndType(ccpAdd(p, ccp(PTM_RATIO, PTM_RATIO)), b2_dynamicBody);
    
    b2DistanceJointDef jointDef;
    //方法一
    jointDef.Initialize(body, body2, body->GetWorldCenter(), body2->GetWorldCenter());
    //方法二
//    jointDef.bodyA = body;
//    jointDef.bodyB = body2;
//    jointDef.length = 2;
    world->CreateJoint(&jointDef);
    
}

//旋转关节
void HelloWorld::addRevoluteJoint(CCPoint p)
{
    b2Body *body = addNewSpriteAtPositionAndType(p, b2_staticBody);
    
    b2Body *body2 = addNewSpriteAtPositionAndType(ccpAdd(p, ccp(PTM_RATIO, PTM_RATIO)), b2_dynamicBody);
    
    
    b2RevoluteJointDef jointDef;
    jointDef.Initialize(body, body2,  body2->GetWorldCenter());
    jointDef.lowerAngle = -0.25f * b2_pi; // -45 degrees
    jointDef.upperAngle = 0.5f * b2_pi; // 90 degrees
    jointDef.enableLimit = true;
    jointDef.maxMotorTorque = 10.0f;
    jointDef.motorSpeed = 1.0f;
    jointDef.enableMotor = true;
    world->CreateJoint(&jointDef);
}

//移动关节
void HelloWorld::addPrismaticJoint(CCPoint p)
{
    b2Body *body = addNewSpriteAtPositionAndType(p, b2_staticBody);
    
    b2Body *body2 = addNewSpriteAtPositionAndType(ccpAdd(p, ccp(PTM_RATIO, -PTM_RATIO)), b2_dynamicBody);
    
    
    b2PrismaticJointDef jointDef;
    b2Vec2 worldAxis(1.0f, -1.0f);//可以移动的方向
    jointDef.Initialize(body, body2,  body2->GetWorldCenter(), worldAxis);
    jointDef.lowerTranslation = -2.0f;
    jointDef.upperTranslation = 4.0f;
    jointDef.enableLimit = true;
    jointDef.motorSpeed = 0.0f;
    jointDef.enableMotor = true;
    world->CreateJoint(&jointDef);
}

//滑轮关节
void HelloWorld::addPulleyJoint(CCPoint p)
{
    b2Body *body = addNewSpriteAtPositionAndType(p, b2_dynamicBody);
    
    b2Body *body2 = addNewSpriteAtPositionAndType(ccpAdd(p, ccp(PTM_RATIO, -PTM_RATIO)), b2_dynamicBody);
    
    b2Vec2 anchor1 = body->GetWorldCenter();
    b2Vec2 anchor2 = body2->GetWorldCenter();    
    
    b2Vec2 groundAnchor1(anchor1.x, anchor1.y + 2.0f);//滑轮的位置
    b2Vec2 groundAnchor2(anchor2.x, anchor2.y + 4.0f);
    
    float32 ratio = 0.5f;//比率
    b2PulleyJointDef jointDef;
    
    jointDef.Initialize(body, body2, groundAnchor1, groundAnchor2, anchor1, anchor2, ratio);

    world->CreateJoint(&jointDef);
}

//齿轮关节
void HelloWorld::addGearJoint(CCPoint p)
{
    b2Body *body = addNewSpriteAtPositionAndType(p, b2_dynamicBody);

    b2Body *body2 = addNewSpriteAtPositionAndType(ccpAdd(p, ccp(PTM_RATIO, 0)), b2_dynamicBody);
    
    //通过地面生成一个旋转关节
    b2RevoluteJointDef jd1;
    jd1.bodyA = groundBody;
    jd1.bodyB = body;
    jd1.localAnchorA = groundBody->GetLocalPoint(body->GetPosition());
    jd1.localAnchorB = body->GetLocalPoint(body->GetPosition());
    jd1.referenceAngle = body->GetAngle() - groundBody->GetAngle();
    b2RevoluteJoint* joint1 = (b2RevoluteJoint*)world->CreateJoint(&jd1);
    
    //通过地面生成一个移动关节
    b2PrismaticJointDef jd3;
    jd3.Initialize(groundBody, body2, body2->GetPosition(), b2Vec2(0.0f, 1.0f));
    jd3.lowerTranslation = -5.0f;
    jd3.upperTranslation = 5.0f;
    jd3.enableLimit = true;
    b2PrismaticJoint *joint2 = (b2PrismaticJoint*)world->CreateJoint(&jd3);
    
    //通过旋转关节和移动关节生成一个齿轮关节
    b2GearJointDef jointDef3;
    jointDef3.bodyA = body;
    jointDef3.bodyB = body2;
    jointDef3.joint1 = joint1;
    jointDef3.joint2 = joint2;
    jointDef3.ratio = 4.0f;//比率
    world->CreateJoint(&jointDef3);    
}




void HelloWorld::BeginContact(b2Contact* contact)
{
    CCSprite * sp1 = (CCSprite *)contact->GetFixtureA()->GetBody()->GetUserData();
    CCSprite * sp2 = (CCSprite *)contact->GetFixtureB()->GetBody()->GetUserData();
    if (sp1 != NULL && sp2 != NULL) {
        sp1->setColor(ccRED);
        sp2->setColor(ccRED);
    }
}

void HelloWorld::update(float dt)
{
    //It is recommended that a fixed time step is used with Box2D for stability
    //of the simulation, however, we are using a variable time step here.
    //You need to make an informed choice, the following URL is useful
    //http://gafferongames.com/game-physics/fix-your-timestep/
    
    int velocityIterations = 8;
    int positionIterations = 1;
    
    // Instruct the world to perform a single step of simulation. It is
    // generally best to keep the time step and iterations fixed.
    world->Step(dt, velocityIterations, positionIterations);
    
    //Iterate over the bodies in the physics world
    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()) );
        }
    }
}

//鼠标关节
void HelloWorld::ccTouchesBegan(CCSet *pTouches, CCEvent *pEvent)
{
    CCTouch * touch = (CCTouch*)pTouches->anyObject();
    //判断鼠标是否点在了刚体上。
    CCPoint mousePt = touch->getLocation();
    b2Body *pBody = world->GetBodyList();//获得所有刚体
    for(; pBody != NULL; pBody = pBody->GetNext())
    {
        b2Fixture *pFixture = pBody->GetFixtureList();//获的每个刚体的所有Fixture,因为类似于ground就有好几个Fixture
        for(;pFixture != NULL;pFixture = pFixture->GetNext())
        {
            b2Vec2 mouseVec;
            mouseVec.Set(mousePt.x/PTM_RATIO, mousePt.y/PTM_RATIO);
            if(pFixture->TestPoint(mouseVec))//判断鼠标点是否在这个刚体上
            {
                //创建鼠标关节.
                b2MouseJointDef md;
                md.bodyA=groundBody;//一般为世界边界
                md.bodyB=pBody;//需要拖动的物体
                md.target=mouseVec;//指定拖动的坐标
                md.collideConnected=true; //是否进行碰撞检测
                md.maxForce=1000.0f*pBody->GetMass(); //给一个拖动的力
                mouseJoint=(b2MouseJoint*)world->CreateJoint(&md);//创建
                pBody->SetAwake(true);//将刚体唤醒,原来可能睡眠了,会少一帧
                return ;
            }  
        }  
    }
}
void HelloWorld::ccTouchesMoved(CCSet *pTouches, CCEvent *pEvent)
{
    if(mouseJoint == NULL )
        return;
    
    CCTouch * touch = (CCTouch*)pTouches->anyObject();
    b2Vec2 vecMouse;
    vecMouse.Set((touch->getLocation().x)/PTM_RATIO, (touch->getLocation().y)/PTM_RATIO);
    //控制鼠标关节,改变关节位置.
    mouseJoint->SetTarget(vecMouse);
}


void HelloWorld::ccTouchesEnded(CCSet* touches, CCEvent* event)
{
    //销毁关节.
    if(mouseJoint != NULL)
    {
        world->DestroyJoint(mouseJoint);
        mouseJoint = NULL;
    }
    
    //    //Add a new body/atlas sprite at the touched location
    //    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);
    //
    //        addNewSpriteAtPositionAndType( location, b2_dynamicBody );
    //    }
}




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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值