//
// 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;
}
cocos2d-x中box2d的关节
最新推荐文章于 2024-05-20 09:31:57 发布