您的位置:首页 > 移动开发 > Cocos引擎

cocos2d-x学习之box2d物理引擎打砖块

2015-08-04 21:35 337 查看


cocos2d-x引擎版本是2.2.0

这篇博客其实不是给给人看的,只是给我自己看的,以便自己熟悉里面的代码

总共6个文件:

#ifndef __HELLOWORLD_SCENE_H__
#define __HELLOWORLD_SCENE_H__

#include "cocos2d.h"
#include "../../../../external/Box2D/Box2D.h"
#include "MyContactListener.h"

USING_NS_CC;

class HelloWorld : public cocos2d::CCLayer
{
public:
	~ HelloWorld();

    // Here's a difference. Method 'init' in cocos2d-x returns bool, instead of returning 'id' in cocos2d-iphone
    virtual bool init();  

    // there's no 'id' in cpp, so we recommend returning the class instance pointer
    static cocos2d::CCScene* scene();

    // a selector callback
    void menuCloseCallback(CCObject* pSender);
    
    // implement the "static node()" method manually
    CREATE_FUNC(HelloWorld);

	//每一帧的回调(象征时间的推移)
	void update(float delta);

	//触摸响应
	bool ccTouchBegan(cocos2d::CCTouch* pTouch, cocos2d::CCEvent*pEvent);

	//触摸中
	void ccTouchMoved(CCTouch *pTouch, CCEvent *pEvent);

	//触摸结束
	void ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent);

	//获取标签
	int GetTagForBody(b2Body *body);

	//主要描述重力加速度的信息
	b2World* _world;		

	//物体球
	b2Body * _ball;
	b2Body * _paddle;

	//精灵
	CCSprite *_ballSprite;
	CCSprite *_paddleSprite;

	//鼠标关节
	b2MouseJoint *_mouseJoint;

	//碰撞监听器
	MyContactListener *_contackListener;

	//地面
	b2Body *_groudBody;

	//得分
	int _score;

};

#endif // __HELLOWORLD_SCENE_H__


#include "HelloWorldScene.h"
#include "GameOverScene.h"

USING_NS_CC;

#define PTM_RAITO 26.0f  //屏幕上的26个像素代表物理世界的1米

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;
}

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
}

// on "init" you need to initialize your instance
bool HelloWorld::init()
{
    //////////////////////////////
    // 1. super init first
    if ( !CCLayer::init() )
    {
        return false;
    }

	//获得屏幕大小
	CCSize screenSize = CCDirector::sharedDirector()->getWinSize();
	CCPoint origin = CCDirector::sharedDirector()->getVisibleOrigin();

	//创建小球精灵
	_ballSprite = CCSprite::create("ball.png");
	_ballSprite->setPosition(ccp(320,200));
	this->addChild(_ballSprite);

	//创建托盘精灵
	_paddleSprite = CCSprite::create("button2.PNG");
	_paddleSprite->setPosition(ccp(200,50));
	this->addChild(_paddleSprite);

	//创建一个重力加速度是0的世界
	_world = new b2World(b2Vec2(0, 0));

	//定义一个物体
	b2BodyDef ballBodyDef;
	ballBodyDef.type = b2_dynamicBody;		//是会运动的
	ballBodyDef.position.Set(_ballSprite->getPositionX()/PTM_RAITO, _ballSprite->getPositionY()/PTM_RAITO); //设置位置
	ballBodyDef.userData = _ballSprite;     //和cocos2d中的精灵进行关联
	_ball = _world->CreateBody(&ballBodyDef);  //创建它
	
	//设置物理属性
	b2CircleShape circle;
	circle.m_radius = (_ballSprite->getContentSize().width/2)/PTM_RAITO;
	b2FixtureDef ballFixDef;
	ballFixDef.shape = &circle;//形状
	ballFixDef.density = 10;//密度
	ballFixDef.friction = 0;//摩察系数
	ballFixDef.restitution = 1;//反弹系数
	_ball->CreateFixture(&ballFixDef);

	//创建地面
	b2BodyDef groudBodyDef;
	groudBodyDef.type = b2_staticBody;
	groudBodyDef.position.Set(0, 0);
	_groudBody = _world->CreateBody(&groudBodyDef);

	b2EdgeShape groudShape;
	groudShape.Set(b2Vec2(0, 0), b2Vec2(screenSize.width/PTM_RAITO,0));
	b2FixtureDef groudFixDef;
	groudFixDef.shape = &groudShape;
	_groudBody->CreateFixture(&groudFixDef);

	//建立左边墙壁
	b2BodyDef leftgroudBodyDef;
	leftgroudBodyDef.type = b2_staticBody;
	leftgroudBodyDef.position.Set(0, 0);
	b2Body *leftgroudBody = _world->CreateBody(&leftgroudBodyDef);

	b2EdgeShape leftgroudShape;
	leftgroudShape.Set(b2Vec2(0, 0), b2Vec2(0,screenSize.height/PTM_RAITO));
	b2FixtureDef leftgroudFixDef;
	leftgroudFixDef.shape = &leftgroudShape;
	leftgroudBody->CreateFixture(&leftgroudFixDef);

	//建立右边墙壁
	b2BodyDef rightgroudBodyDef;
	rightgroudBodyDef.type = b2_staticBody;
	rightgroudBodyDef.position.Set(0, 0);
	b2Body *rightgroudBody = _world->CreateBody(&rightgroudBodyDef);

	b2EdgeShape rightgroudShape;
	rightgroudShape.Set(b2Vec2(screenSize.width/PTM_RAITO, 0), b2Vec2(screenSize.width/PTM_RAITO,screenSize.height/PTM_RAITO));
	b2FixtureDef rightgroudFixDef;
	rightgroudFixDef.shape = &rightgroudShape;
	rightgroudBody->CreateFixture(&rightgroudFixDef);

	//建立上边墙壁
	b2BodyDef topgroudBodyDef;
	topgroudBodyDef.type = b2_staticBody;
	topgroudBodyDef.position.Set(0, 0);
	b2Body *topgroudBody = _world->CreateBody(&topgroudBodyDef);

	b2EdgeShape topgroudShape;
	topgroudShape.Set(b2Vec2(0, screenSize.height/PTM_RAITO), b2Vec2(screenSize.width/PTM_RAITO,screenSize.height/PTM_RAITO));
	b2FixtureDef topgroudFixDef;
	topgroudFixDef.shape = &topgroudShape;
	topgroudBody->CreateFixture(&topgroudFixDef);

	//定义一托盘个物体
	b2BodyDef paddleBodyDef;
	paddleBodyDef.type = b2_dynamicBody;		//是会运动的
	paddleBodyDef.position.Set(_paddleSprite->getPositionX()/PTM_RAITO, _paddleSprite->getPositionY()/PTM_RAITO); //设置位置
	paddleBodyDef.userData = _paddleSprite;     //和cocos2d中的精灵进行关联
	_paddle = _world->CreateBody(&paddleBodyDef);  //创建它

	//设置物理属性
	b2PolygonShape boxShape;
	boxShape.SetAsBox(_paddleSprite->getContentSize().width/2/PTM_RAITO,_paddleSprite->getContentSize().height/2/PTM_RAITO);
	b2FixtureDef paddleFixDef;
	paddleFixDef.shape = &boxShape;//形状
	paddleFixDef.density = 20;//密度
	paddleFixDef.friction = 0;//摩察系数
	paddleFixDef.restitution = 0;//反弹系数
	_paddle->CreateFixture(&paddleFixDef);

	//开启贞回调动画
	this->scheduleUpdate();

	//开启触屏
	this->setTouchEnabled(true);
	CCDirector::sharedDirector()->getTouchDispatcher()->addTargetedDelegate(this, 0, true);

	//小球初始冲量
	_ball->ApplyLinearImpulse(_ball->GetMass() * b2Vec2(-15,-5), _ball->GetWorldCenter());

	//初始化鼠标关节
	_mouseJoint = NULL;

	//创建水平移动关节
	b2PrismaticJointDef primaticJointDef;
	primaticJointDef.Initialize(_world->CreateBody(new b2BodyDef),
		_paddle,
		_paddle->GetWorldCenter(),
		b2Vec2(3.0,0));
	_world->CreateJoint(&primaticJointDef);

	//添加目标
	const int padding = 30;
	int offsetX = 150;
	for (int i=0; i<4; i++)
	{
		//添加经精灵
		CCSprite* blockSprite = CCSprite::create("meta_tiles.png");
		blockSprite->setPosition(ccp(offsetX, 400));
		blockSprite->setTag(3);
		this->addChild(blockSprite);

		//创建对应的砖块物理实体
		b2BodyDef blockBodyDef;
		blockBodyDef.type = b2_dynamicBody;		//是会运动的
		blockBodyDef.position.Set(blockSprite->getPositionX()/PTM_RAITO, blockSprite->getPositionY()/PTM_RAITO); //设置位置
		blockBodyDef.userData = blockSprite;     //和cocos2d中的精灵进行关联
		b2Body* block = _world->CreateBody(&blockBodyDef);  //创建它

		//设置物理属性
		b2PolygonShape blockShape;
		blockShape.SetAsBox(blockSprite->getContentSize().width/2/PTM_RAITO,blockSprite->getContentSize().height/2/PTM_RAITO);
		b2FixtureDef blockFixDef;
		blockFixDef.shape = &blockShape;//形状
		blockFixDef.density = 20;//密度
		blockFixDef.friction = 0;//摩察系数
		blockFixDef.restitution = 0;//反弹系数
		block->CreateFixture(&blockFixDef);

		//左右间隔
		offsetX += (padding + blockSprite->getContentSize().width);
	}

	//添加碰撞监听器
	_contackListener = new MyContactListener;
	_world->SetContactListener(_contackListener);

	//得分清零
	_score = 0;

    return true;
}

//每一帧的回调(象征时间的推移)
void HelloWorld::update(float delta)
{
	//物理世界时间推移
	_world->Step(delta, 6, 6);

	//物理世界的移动反映到cocos2d界面上
	//遍历物理世界的物体
	for (b2Body *b = _world->GetBodyList(); b; b= b->GetNext())
	{
		if (b->GetUserData())
		{
			//获取该精灵
			CCSprite *sp = (CCSprite *)b->GetUserData();

			//给小球限速
			if (sp == _ballSprite)
			{
				b2Vec2 speed = b->GetLinearVelocity();
				if (speed.LengthSquared() > 200)
				{
					b->SetLinearDamping(1-200/speed.LengthSquared());
				}

			}
			//先得到物理世界的位置
			b2Vec2 physicPos = b->GetPosition();

			//设置位置
			sp->setPosition(ccp(physicPos.x*PTM_RAITO, physicPos.y*PTM_RAITO));
		}
	}

	//处理碰撞事件
	b2Body *bodyNeedDestroy = NULL;
	for (vector<contactPeerFix>::iterator it=_contackListener->_contacts.begin(); it!=_contackListener->_contacts.end(); it++)
	{
		contactPeerFix curContact = *it;

		//获取两个碰撞的物体
		b2Body* bodyA = curContact.fixA->GetBody();
		b2Body* bodyB = curContact.fixB->GetBody();

		//获取标签
		int tagA = GetTagForBody(bodyA);
		int tagB = GetTagForBody(bodyB);

		//小球和地面碰撞
		if (bodyA==_ball&&bodyB==_groudBody
			||bodyB==_ball&&bodyA==_groudBody)
		{
			//游戏失败
			CCLog("fail");
			CCDirector::sharedDirector()->replaceScene(GameOverScene::sceneWithWin(false));
		}
		else if (bodyA==_ball&&3==tagB
			||bodyB==_ball&&3==tagA)//小球碰撞砖块
		{
			CCLog("pengzhuandaozhuankuai");

			//需要删除的砖块
			bodyNeedDestroy = (bodyA==_ball ? bodyB : bodyA);

			_score ++;
			if (_score==4)
			{
				CCDirector::sharedDirector()->replaceScene(GameOverScene::sceneWithWin(true));
			}
		}
	}
	
	//需要删除的砖块
	if (bodyNeedDestroy != NULL)
	{
		//消除对应的方砖精灵
		((CCSprite*)bodyNeedDestroy->GetUserData())->removeFromParentAndCleanup(true);

		//从物理世界消除方砖
		_world->DestroyBody(bodyNeedDestroy);
	}
}

//析构函数
HelloWorld::~HelloWorld()
{
}

//触摸响应
bool HelloWorld::ccTouchBegan(CCTouch* pTouch, CCEvent*pEvent)
{
	//触摸从而加速小球
// 	CCPoint touchPos = pTouch->getLocation();
// 	b2Vec2 touchPhysicsPos(touchPos.x/PTM_RAITO, touchPos.y/PTM_RAITO);
// 	b2Vec2 ballPhysics = _ball->GetPosition();
// 	b2Vec2 impulse = touchPhysicsPos - ballPhysics;
// 
// 	//冲量等于 = 质量 * 矢量
// 	impulse *= _ball->GetMass();
// 	//第二个参数表示作用在质心上
// 	_ball->ApplyLinearImpulse(impulse, _ball->GetWorldCenter());

	//CCLog("ccTouchBegan");

	//获取触摸点
	CCPoint touchPos = pTouch->getLocation();
	b2Vec2 touchPhysicsPos(touchPos.x/PTM_RAITO,touchPos.y/PTM_RAITO);

	//得到底座的形状信息
	b2Fixture* paddleFix = _paddle->GetFixtureList();
	if (paddleFix->TestPoint(touchPhysicsPos))
	{
		//创建鼠标关节,引领托盘移动
		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);

		return true;
	}

	return false;
}

//触摸中
void HelloWorld::ccTouchMoved(CCTouch *pTouch, CCEvent *pEvent)
{
	//CCLog("ccTouchMoved");

	if (_mouseJoint)
	{
		//获取触摸点
		CCPoint touchPos = pTouch->getLocation();
		b2Vec2 touchPhysicsPos(touchPos.x/PTM_RAITO,touchPos.y/PTM_RAITO);

		//设置目标位置
		_mouseJoint->SetTarget(touchPhysicsPos);
	}
}

//触摸结束
void HelloWorld::ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent)
{
	//CCLog("ccTouchEnded");

	if (_mouseJoint)
	{
		//销毁关节
		_world->DestroyJoint(_mouseJoint);
		_mouseJoint = NULL;
	}
}

//获取标签
int HelloWorld::GetTagForBody(b2Body *body)
{
	if (body->GetUserData())
	{
		CCSprite *sp = (CCSprite *)body->GetUserData();
		return sp->getTag();
	}
	return -1;
}
#pragma once
#include "../../../../external/Box2D/Box2D.h"
#include <vector>

using namespace std;

struct contactPeerFix 
{
	b2Fixture *fixA;
	b2Fixture *fixB;
};

class MyContactListener : public b2ContactListener
{
public:
	MyContactListener(void);
	~MyContactListener(void);

	//储存所有碰撞
	vector<contactPeerFix> _contacts;

	void BeginContact(b2Contact* contact);
	void EndContact(b2Contact* contact);
	//void PreSolve(b2Contact* contact, const b2Manifold* oldManifold);
	//void PostSolve(b2Contact* contact, const b2ContactImpulse* impulse);
};


#include "MyContactListener.h"

MyContactListener::MyContactListener(void) : _contacts()
{
}
MyContactListener::~MyContactListener(void)
{
}

//开始撞击
void MyContactListener::BeginContact( b2Contact* contact )
{
	contactPeerFix contactFix = {contact->GetFixtureA(), contact->GetFixtureB()};
	_contacts.push_back(contactFix);
}

//结束撞击
void MyContactListener::EndContact( b2Contact* contact )
{
	contactPeerFix peer = {contact->GetFixtureA(), contact->GetFixtureB()};
	vector<contactPeerFix>::iterator pos,posFound;
	for (pos=_contacts.begin(); pos!=_contacts.end(); pos++)
	{
		contactPeerFix onePeer = *pos;
		if (onePeer.fixA==peer.fixA && onePeer.fixB==peer.fixB)
		{
			posFound = pos;
			_contacts.erase(posFound);
			return ;
		}
	}
}


#pragma  once

#include "cocos2d.h"

USING_NS_CC;

class GameOverScene : public CCLayer
{
public:

	//初始化
	bool initWithWin(bool isWin);

	//创建场景
	static CCScene* sceneWithWin(bool isWin);
};


#include "GameOverScene.h"

//初始化
bool GameOverScene::initWithWin( bool isWin )
{
	//父类初始化
	if (!CCLayer::init())
	{
		return false;
	}
	
	//显示字符串
	char words[64];
	if (!isWin)
	{
		sprintf(words,"you xi shi bai!");
	}
	else
	{
		sprintf(words,"you xi cheng gong!");
	}
	CCLabelTTF *lable = CCLabelTTF::create(words,"Arial",30);
	lable->setPosition(ccp(320,300));
	this->addChild(lable);

	return false;
}

//创建场景
CCScene* GameOverScene::sceneWithWin( bool isWin )
{
	CCScene* sc = CCScene::create();
	GameOverScene *layer = new GameOverScene;
	layer->initWithWin(isWin);
	sc->addChild(layer);

	return sc;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: