cocos2dx视频教程进阶篇--第2天--打砖块游戏-box2d物理引擎

感谢大家的鼓励和支持,今天我们学习一下box2d物理引擎.

不了解cocos2dx基本概念的朋友,请移步 

http://blog.csdn.net/s_xing/article/details/18557631。

转载请注明出处http://blog.csdn.net/s_xing/article/details/20165097


感觉直接看代码太枯燥的,请关注视频讲解

更新:高清avi视频和源代码已经提供下载:

百度网盘:http://pan.baidu.com/s/1ELk78 里面的进阶篇。



今天一共讲了五堂课,学习的是老外的一个游戏。原文地址:http://www.raywenderlich.com/28602/intro-to-box2d-with-cocos2d-2-x-tutorial-bouncing-balls。源代码如下

1. 主场景

#include "HelloWorldScene.h"
#include "Box2dUtils.h"
#include "MyContactListener.h"
#include "GameOverScense.h"
#include "SimpleAudioEngine.h"

USING_NS_CC;

#define PTM_RATIO 32.0f

CCScene* HelloWorld::scene()
{
    // 'scene' is an autorelease object
    CCScene *scene = CCScene::create();
    
    // 'layer' is an autorelease object
    HelloWorld *layer = HelloWorld::create();

    // add layer as a child to scene
    scene->addChild(layer);

    // return the scene
    return scene;
}

// on "init" you need to initialize your instance
bool HelloWorld::init()
{
    //////////////////////////////
    // 1. super init first
    if ( !CCLayer::init() )
    {
        return false;
    }
    
    CCSize screenSize = CCDirector::sharedDirector()->getVisibleSize();
    CCPoint origin = CCDirector::sharedDirector()->getVisibleOrigin();

	// 创建球的cocos2d图形
	_ballSprite  = CCSprite::create("ball.png");
	_ballSprite->setPosition(ccp(39, 300));
	this->addChild(_ballSprite);

	_paddleSprite = CCSprite::create("paddle.png");
	_paddleSprite->setPosition(ccp(120, 50));
	this->addChild(_paddleSprite);

	// 创建box2d世界
	_world = new b2World(b2Vec2(0, 0));

	// 创建球
	_ball = Box2dUtils::createDynamicBody(_ballSprite->getPositionX() / PTM_RATIO,
		_ballSprite->getPositionY() / PTM_RATIO,
		_ballSprite,
		_world);

	b2CircleShape circle;
	circle.m_radius = _ballSprite->getContentSize().width / 2 / PTM_RATIO;
	Box2dUtils::createFixture(&circle,
		10, 0, 1.0, _ball);

	_ball->ApplyLinearImpulse(_ball->GetMass() * b2Vec2(11, 22), 
		_ball->GetWorldCenter());

	// 添加底座
	_paddle = Box2dUtils::createDynamicBody(_paddleSprite->getPositionX() / PTM_RATIO,
		_paddleSprite->getPositionY() / PTM_RATIO,
		_paddleSprite,
		_world);

	b2PolygonShape boxShape;
	boxShape.SetAsBox(_paddleSprite->getContentSize().width / 2.0f / PTM_RATIO,
		_paddleSprite->getContentSize().height / 2.0f / PTM_RATIO);
	Box2dUtils::createFixture(&boxShape,
		8, 0, 0.5, _paddle);

	// 添加目标   被打击的砖块
	const int padding  = 10; 
	float offsetX = 150.0f;
	for (int i = 0; i < 4; i ++){
		CCSprite* block = CCSprite::create("block.png");
		block->setPosition(ccp(offsetX, 400.0));
		block->setTag(3);
		this->addChild(block);

		//物理 实体
		b2Body* blockBody = Box2dUtils::createDynamicBody(offsetX/ PTM_RATIO, 
			400 / PTM_RATIO,
			block,
			_world);

		b2PolygonShape blockBox;
		blockBox.SetAsBox(block->getContentSize().width / 2.0f / PTM_RATIO,
			block->getContentSize().height / 2.0f / PTM_RATIO);
		Box2dUtils::createFixture(&blockBox,
			10.0f, 0.0f, 0.2f, blockBody);

		offsetX += (padding + block->getContentSize().width);

	}


	// 创建4面墙
	// b2BodyDef -->b2Body

	b2BodyDef groundBodyDef;
	groundBodyDef.type = b2_staticBody;
	groundBodyDef.position.Set(0, 0); // 相当于cocos2d 中的锚点
	_groundBody = _world->CreateBody(&groundBodyDef);

	// b2FixtureDef -->b2Fixture
	b2EdgeShape groundShape;
	groundShape.Set(b2Vec2(0, 0), b2Vec2(screenSize.width / PTM_RATIO, 0));
	b2FixtureDef groundFixDef;
	groundFixDef.shape = &groundShape;
	groundFixDef.friction = 0.9f;
	_bottom = _groundBody->CreateFixture(&groundFixDef);

	// 创建左面 墙
	b2EdgeShape leftWall;
	leftWall.Set(b2Vec2(0, 0), b2Vec2(0, screenSize.height / PTM_RATIO));
	groundFixDef.shape = &leftWall;
	_groundBody->CreateFixture(&groundFixDef);

	// 创建右面的墙
	b2EdgeShape rightWall;
	rightWall.Set(b2Vec2(screenSize.width / PTM_RATIO, 0), 
		b2Vec2(screenSize.width / PTM_RATIO, screenSize.height / PTM_RATIO));

	groundFixDef.shape = &rightWall;
	_groundBody->CreateFixture(&groundFixDef);

	// 创建 顶部
	b2EdgeShape top;
	top.Set(b2Vec2(0, screenSize.height / PTM_RATIO), 
		b2Vec2(screenSize.width / PTM_RATIO, screenSize.height / PTM_RATIO));
	groundFixDef.shape = ⊤
	_groundBody->CreateFixture(&groundFixDef);


	this->scheduleUpdate();

	// 实现  指哪打哪  鼠标拖动到哪里 指定的物体移动到哪里
	// box2d joint 关节  
	this->setTouchEnabled(true);
	CCDirector::sharedDirector()->getTouchDispatcher()->addTargetedDelegate(this, 0, true);


	_mouseJoint = NULL;

	// 平移关节 限制底座 只能水平方向移动
	b2PrismaticJointDef primaticJointDef;
	primaticJointDef.Initialize(_world->CreateBody(new b2BodyDef),
		_paddle,
		_paddle->GetWorldCenter(),
		b2Vec2(3.0, 0));
	_world->CreateJoint(&primaticJointDef);

	listener = new MyContactListener;
	_world->SetContactListener(listener);

	_score = 0;

	CocosDenshion::SimpleAudioEngine::sharedEngine()->playBackgroundMusic("background-music-aac.WAV", true);

    return true;
}


bool HelloWorld::ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent){
	CCPoint touchPos = pTouch->getLocation();
	b2Vec2  touchPhysicsPos(touchPos.x / PTM_RATIO,touchPos.y / PTM_RATIO);

	b2Fixture* paddleFix = _paddle->GetFixtureList(); //得到底座的 fixture ---包含了形状信息


	/*CCRect paddleRect;   // 在cocos2d 世界中判断
	paddleRect.containsPoint(touchPos);*/
	if (paddleFix->TestPoint(touchPhysicsPos)){ //触摸点在paddle的范围内  在物理世界中判断
		// 鼠标关节  鼠标控制我们的底座    applyLinearImpulse
		b2MouseJointDef mouseJointDef;
		mouseJointDef.bodyA = _world->CreateBody(new b2BodyDef);
		mouseJointDef.bodyB = _paddle;
		mouseJointDef.maxForce = 1000.0 * _paddle->GetMass();
		mouseJointDef.target = touchPhysicsPos; //设置物体的目标位置
		_mouseJoint = (b2MouseJoint*)_world->CreateJoint(&mouseJointDef);

		
		//CCLog("touch began true.\n");
		return true;// 该 touch 代理上的ccTouchMoved  ccTouchEnded 会得到执行
	}

	CCLog("touch began false.\n");

	return false; // 该 touch 代理上的ccTouchMoved  ccTouchEnded 不会得到执行
}

void HelloWorld::ccTouchMoved(CCTouch *pTouch, CCEvent *pEvent){
	if (_mouseJoint)
	{
		CCPoint touchPos = pTouch->getLocation();
		b2Vec2  touchPhysicsPos(touchPos.x / PTM_RATIO,touchPos.y / PTM_RATIO);
		_mouseJoint->SetTarget(touchPhysicsPos);//设置物体的目标位置
	}

	//CCLog("touch ccTouchMoved func.\n");
}

void HelloWorld::ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent){
	if (_mouseJoint){
		_world->DestroyJoint(_mouseJoint);
		_mouseJoint = NULL;
	}

	//CCLog("touch ccTouchEnded func.\n");
}

int _getTagForBody(b2Body* body){
	if (body->GetUserData()){
		CCSprite* sp = (CCSprite*) body->GetUserData();
		return sp->getTag();
	}
	return -1;
}


void HelloWorld::update(float delta){
	_world->Step(delta, 6, 6);

	for(b2Body* body = _world->GetBodyList(); body != NULL; body = body->GetNext()){
		if (body->GetUserData()){
			CCSprite* sp = (CCSprite*)body->GetUserData();

			if (sp == _ballSprite){ // 限制球速
				b2Vec2 spped = body->GetLinearVelocity();
				if (spped.LengthSquared() > 200){
					body->SetLinearDamping(0.9); //设置 减震之后 持续生效
				}
				else if (spped.LengthSquared() <200){
					body->SetLinearDamping(0.0); //设置 减震之后 持续生效

					if  (spped.LengthSquared() < 60){
						body->ApplyLinearImpulse(body->GetMass() * 5.0 * spped,
							body->GetWorldCenter());

					}
				
				}

				
			}

			sp->setPosition(ccp(body->GetPosition().x * PTM_RATIO,
				body->GetPosition().y *PTM_RATIO));
		}
	}


	b2Body* bodyToDestroy = NULL;
	vector<MyContactPeer>::iterator it;
	for (it = listener->_contacts.begin();
		it != listener->_contacts.end();
		it ++){
			MyContactPeer curContact = *it;

			b2Body*	bodyA = curContact.fixA->GetBody();
			b2Body*	bodyB = curContact.fixB->GetBody();

			int tagA, tagB;

			tagA = _getTagForBody(bodyA);
			tagB = _getTagForBody(bodyB);


			// 小球和地面碰撞 失败
			if (bodyA == _ball && curContact.fixB == _bottom){
				//CCLog("fail");
				CCDirector::sharedDirector()->replaceScene(GameOverScene::scenseWithWin(false));
			}
			else if (bodyB == _ball && curContact.fixA == _bottom){
				//CCLog("fail");
				CCDirector::sharedDirector()->replaceScene(GameOverScene::scenseWithWin(false));
			}
			else if (bodyA == _ball && 3 == tagB){
				//CCLog("kill block");
				bodyToDestroy = bodyB;
			}
			else if (bodyB == _ball && 3 == tagA){
				//CCLog("kill block");
				//CCLog("kill block");
				bodyToDestroy = bodyA;
				
			}
	}

	if (bodyToDestroy){
		((CCSprite*)bodyToDestroy->GetUserData())->removeFromParentAndCleanup(true);
		_world->DestroyBody(bodyToDestroy);				
		_score ++;

		CocosDenshion::SimpleAudioEngine::sharedEngine()->playEffect("blip.WAV");

		CCLog("_score is %d", _score);

		if (_score >= 4){
			CCDirector::sharedDirector()->replaceScene(GameOverScene::scenseWithWin(true));
		}
	
	}


}


void HelloWorld::menuCloseCallback(CCObject* pSender)
{
#if (CC_TARGET_PLATFORM == CC_PLATFORM_WINRT) || (CC_TARGET_PLATFORM == CC_PLATFORM_WP8)
	CCMessageBox("You pressed the close button. Windows Store Apps do not implement a close button.","Alert");
#else
    CCDirector::sharedDirector()->end();
#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
    exit(0);
#endif
#endif
}

转载注明出处:http://blog.csdn.net/s_xing/article/details/20836727

csdn不给力,文章长度限制,所以请大家跳到续篇--  http://blog.csdn.net/s_xing/article/details/20836693

你可能感兴趣的:(cocos2dx视频教程进阶篇--第2天--打砖块游戏-box2d物理引擎)