cocs2d-x 学习例子 box2d 实现类似愤怒的小鸟的简单参考例子

首先贴出最初的出处:http://www.raywenderlich.com/4756/how-to-make-a-catapult-shooting-game-with-cocos2d-and-box2d-part-1

再贴出我主要参考的贴:http://mssyy2010.blog.51cto.com/4595971/847000

然后是我稍加调整后可以在cocos2d-2.14编译运行的代码(整个vs project包括resources):https://github.com/serika00/android/tree/master/cocos2d-x/CatapultShootingGame


再顺手把代码贴上,原来两个出处解释得都比较清楚了,不多加解释。


HelloWorld.h

#ifndef __HELLOWORLD_SCENE_H__
#define __HELLOWORLD_SCENE_H__

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

USING_NS_CC;

class HelloWorld : public cocos2d::CCLayer
{
public:
    // 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);

	HelloWorld() {};
	~HelloWorld();
	void tick(float dt);
	void ccTouchesBegan(CCSet* pTouches, CCEvent* pEvent);
	void ccTouchesMoved(CCSet* pTouches, CCEvent* pEvent);
	void ccTouchesEnded(CCSet* pTouches, CCEvent* pEvent);
	void createBullets(int count);
	bool attachBullet();
	void resetGame();
	void createTarget(char   *imageName,
					  CCPoint position,
					  float   rotation,
					  bool	  isCircle,
					  bool    isStatic,
					  bool    isEnemy);
	void createTargets();
	void resetBullet();
private:
	b2World* m_world;
	b2Body* m_groundBody;
	b2RevoluteJoint *m_armJoint;
	b2MouseJoint *m_mouseJoint;
	b2Fixture* m_armFixture;
	b2Body* m_armBody;
	std::vector<b2Body*> m_bullets;
	int m_currentBullet;
	b2Body* m_bulletBody;
	b2WeldJoint* m_bulletJoint;
	bool m_releasingArm;
	vector<b2Body*> *targets;
	vector<b2Body*> *enemies;
	MyContactListener* contactListener;
};

#endif // __HELLOWORLD_SCENE_H__


HelloWorld.cpp

#include "HelloWorldScene.h"
#define PTM_RATIO 32
#define FLOOR_HEIGHT 62.0f

USING_NS_CC;

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
	targets = new vector<b2Body*>;
	enemies = new vector<b2Body*>;
    CCSprite* sprite1 = CCSprite::create("bg.png");
	sprite1->setAnchorPoint(CCPointZero);
	addChild(sprite1, -1);

	CCSprite* sprite2 = CCSprite::create("catapult_base_2.png");
	sprite2->setAnchorPoint(CCPointZero);
	sprite2->setPosition(CCPointMake(181.0, FLOOR_HEIGHT));
	addChild(sprite2, 0);

	CCSprite* sprite3 = CCSprite::create("squirrel_1.png");
	sprite3->setAnchorPoint(CCPointZero);
	sprite3->setPosition(CCPointMake(11.0, FLOOR_HEIGHT));
	addChild(sprite3, 0);

	CCSprite* sprite4 = CCSprite::create("catapult_base_1.png");
	sprite4->setAnchorPoint(CCPointZero);
	sprite4->setPosition(CCPointMake(181.0, FLOOR_HEIGHT));
	addChild(sprite4, 9);

	CCSprite* sprite5 = CCSprite::create("squirrel_2.png");
	sprite5->setAnchorPoint(CCPointZero);
	sprite5->setPosition(CCPointMake(240.0, FLOOR_HEIGHT));
	addChild(sprite5, 9);

	CCSprite* sprite6 = CCSprite::create("fg.png");
	sprite6->setAnchorPoint(CCPointZero);
	addChild(sprite6, 10);

	b2Vec2 gravity;
	gravity.Set(0.0f, -10.0f);
	m_world = new b2World(gravity);
	m_world->SetAllowSleeping(true);
	m_world->SetContinuousPhysics(true);

	b2BodyDef groundBodyDef;
	groundBodyDef.position.Set(0, 0);
	m_groundBody = m_world->CreateBody(&groundBodyDef);

	b2EdgeShape groundBox;
	CCSize screenSize = CCDirector::sharedDirector()->getWinSize();

	 groundBox.Set(b2Vec2(0,FLOOR_HEIGHT/PTM_RATIO), b2Vec2(screenSize.width*2.0f/PTM_RATIO,FLOOR_HEIGHT/PTM_RATIO)); 
    m_groundBody->CreateFixture(&groundBox, 0); 
     
    // top 
    groundBox.Set(b2Vec2(0,screenSize.height/PTM_RATIO), b2Vec2(screenSize.width*2.0f/PTM_RATIO,screenSize.height/PTM_RATIO)); 
    m_groundBody->CreateFixture(&groundBox, 0); 
     
    // left 
    groundBox.Set(b2Vec2(0,screenSize.height/PTM_RATIO), b2Vec2(0,0)); 
    m_groundBody->CreateFixture(&groundBox, 0); 
     
    // right 
//    groundBox.Set(b2Vec2(screenSize.width*1.5f/PTM_RATIO,screenSize.height/PTM_RATIO), b2Vec2(screenSize.width*1.5f/PTM_RATIO,0)); 
//    m_groundBody->CreateFixture(&groundBox, 0); 

    
	CCSprite *arm = CCSprite::create("catapult_arm.png");
	addChild(arm, 1);
	b2BodyDef armBodyDef;
	armBodyDef.type = b2_dynamicBody;
	armBodyDef.linearDamping = 1;
	armBodyDef.angularDamping = 1;
	armBodyDef.position.Set(230.0f/PTM_RATIO, (FLOOR_HEIGHT+91.0f)/PTM_RATIO);
	armBodyDef.userData = arm;
	m_armBody = m_world->CreateBody(&armBodyDef);

	b2PolygonShape armBox;
	b2FixtureDef armBoxDef;
	armBoxDef.shape = &armBox;
	armBoxDef.density = 0.3f;
	armBox.SetAsBox(11.0f/PTM_RATIO, 91.0f/PTM_RATIO);
	m_armFixture = m_armBody->CreateFixture(&armBoxDef);


	b2RevoluteJointDef armJointDef;
	armJointDef.Initialize(m_groundBody, m_armBody,
		b2Vec2(233.0f / PTM_RATIO, 50/PTM_RATIO));
	armJointDef.enableMotor = true;
	armJointDef.enableLimit = true;
	armJointDef.motorSpeed = -10;
	armJointDef.lowerAngle = CC_DEGREES_TO_RADIANS(9);
	armJointDef.upperAngle = CC_DEGREES_TO_RADIANS(75);
	armJointDef.maxMotorTorque = 700;
	m_armJoint = (b2RevoluteJoint*) m_world->CreateJoint(&armJointDef);
	
	m_mouseJoint = NULL;

	resetGame();
	m_releasingArm = false;
	createTargets();

	contactListener = new MyContactListener();
	m_world->SetContactListener(contactListener);

	setTouchEnabled(true);
	schedule(schedule_selector(HelloWorld::tick));
    return true;
}


void HelloWorld::menuCloseCallback(CCObject* pSender)
{
    CCDirector::sharedDirector()->end();

#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
    exit(0);
#endif
}

void HelloWorld::tick(float dt) {
	int velocityIterations = 8;
	int positionIterations = 1;
	
	m_world->Step(dt, velocityIterations, positionIterations);
	for (b2Body* b = m_world->GetBodyList(); b; b = b->GetNext()) {
		if (b->GetUserData() != NULL) {
			CCSprite* sprite = (CCSprite*)(b->GetUserData());
			sprite->setPosition(ccp(b->GetPosition().x * PTM_RATIO, b->GetPosition().y * PTM_RATIO));
			sprite->setRotation( -1 * CC_RADIANS_TO_DEGREES(b->GetAngle()));
			
		}
	}
	if (m_releasingArm && m_bulletJoint != NULL) {
		if (m_armJoint->GetJointAngle() <= CC_DEGREES_TO_RADIANS(10)) {
			m_releasingArm = false;
			m_world->DestroyJoint(m_bulletJoint);
			m_bulletJoint = NULL;

			CCDelayTime* delayAction = CCDelayTime::create(5.0f);
			CCCallFunc* callSelectorAction = CCCallFunc::create(this, callfunc_selector(HelloWorld::resetBullet));
			this->runAction(CCSequence::create(delayAction, callSelectorAction, NULL));
		}
	}
	if (m_bulletBody && m_bulletJoint == NULL) {
		b2Vec2 position = m_bulletBody->GetPosition();
		CCPoint myPosition = this->getPosition();
		CCSize screenSize = CCDirector::sharedDirector()->getWinSize();
		if (position.x > screenSize.width/2.0f/PTM_RATIO) {
			myPosition.x = -MIN(screenSize.width*2.0f - screenSize.width,
				position.x*PTM_RATIO - screenSize.width/2.0f);
			this->setPosition(myPosition);
		}
	}
    std::set<b2Body*>::iterator pos;
	for (pos = contactListener->contacts.begin(); pos != contactListener->contacts.end(); ++pos) {
		b2Body* body = *pos;
		for (vector<b2Body*>::iterator iter = targets->begin(); iter != targets->end(); ++iter) {
			if (body == *iter) {
				iter = targets->erase(iter);
				break;
			}
		}
		for (vector<b2Body*>::iterator iter = enemies->begin(); iter != enemies->end(); ++iter) {
			if (body == *iter) {
				iter = enemies->erase(iter);
				break;
			}
		}
		CCNode* contactNode = (CCNode*)body->GetUserData();
		CCPoint position = contactNode->getPosition();
		removeChild(contactNode, true);
		m_world->DestroyBody(body);

		CCParticleSun *explosion = CCParticleSun::create();
		explosion->retain();
		explosion->setTexture(CCTextureCache::sharedTextureCache()->addImage("fire.png"));
//		explosion->initWithTotalParticles(200);
		explosion->setAutoRemoveOnFinish(true);
		explosion->setStartSizeVar(10.0f);
		explosion->setSpeed(70.0f);
		explosion->setAnchorPoint(ccp(0.5f, 0.5f));
		explosion->setPosition(position);
		explosion->setDuration(1.0f);
		addChild(explosion, 11);
		explosion->release();
	}
	contactListener->contacts.clear();
}

void HelloWorld::ccTouchesBegan(CCSet* pTouches, CCEvent* pEvent) {
	if (m_mouseJoint != NULL) { return; }
	CCTouch* touch = (CCTouch*)pTouches->anyObject();
	CCPoint location = touch->getLocation();
	location = CCDirector::sharedDirector()->convertToGL(location);
	b2Vec2 locationWorld = b2Vec2(location.x/PTM_RATIO, location.y/PTM_RATIO);

	if (locationWorld.x < m_armBody->GetWorldCenter().x + 150.0/PTM_RATIO) {
		b2MouseJointDef md;
		md.bodyA = m_groundBody;
		md.bodyB = m_armBody;
		md.target = locationWorld;
		md.maxForce = 2000;

		m_mouseJoint = (b2MouseJoint*)m_world->CreateJoint(&md);
	}
}

void HelloWorld::ccTouchesMoved(CCSet* pTouches, CCEvent* pEvent) {
	if (m_mouseJoint == NULL) { return; }

	CCTouch* touch = (CCTouch*)pTouches->anyObject();
	CCPoint location = touch->getLocation();
	location = CCDirector::sharedDirector()->convertToGL(location);
	b2Vec2 locationWorld = b2Vec2(location.x/PTM_RATIO, location.y/PTM_RATIO);

	m_mouseJoint->SetTarget(locationWorld);
}

void HelloWorld::ccTouchesEnded(CCSet* pTouches, CCEvent* pEvent) {
	if (m_mouseJoint != NULL) {
		if (m_armJoint->GetJointAngle() >= CC_DEGREES_TO_RADIANS(5)) {
			m_releasingArm = true;
		}
		m_world->DestroyJoint(m_mouseJoint);
		m_mouseJoint = NULL;
		return;
	}
}

void HelloWorld::createBullets(int count) {
	m_currentBullet = 0;
	float pos = 62.0f;

	if (count > 0) {
		float delta = (count > 1) ? ((165.0f - 62.0f - 30.0f) / (count - 1)):0.0f;
		for (int i = 0; i < count; i++, pos += delta) {
			CCSprite* sprite = CCSprite::create("acorn.png");
			addChild(sprite, 1);

			b2BodyDef bulletBodyDef;
			bulletBodyDef.type = b2_dynamicBody;
			bulletBodyDef.bullet = true;
			bulletBodyDef.position.Set(pos/PTM_RATIO, (FLOOR_HEIGHT+15.0f)/PTM_RATIO);
			bulletBodyDef.userData = sprite;
			b2Body* bullet = m_world->CreateBody(&bulletBodyDef);
			bullet->SetActive(false);

			b2CircleShape circle;
			circle.m_radius = 15.0/PTM_RATIO;

			b2FixtureDef ballShapeDef;
			ballShapeDef.shape = &circle;
			ballShapeDef.density = 0.8f;
			ballShapeDef.restitution = 0.2f;
			ballShapeDef.friction = 0.99f;
			bullet->CreateFixture(&ballShapeDef);
			m_bullets.push_back(bullet);
		}
	}
}

bool HelloWorld::attachBullet() {
	if (m_currentBullet < m_bullets.size()) {
		m_bulletBody = (b2Body*)m_bullets.at(m_currentBullet++);
		m_bulletBody->SetTransform(b2Vec2(230.0f/PTM_RATIO, (156.0f+FLOOR_HEIGHT)/PTM_RATIO), 0.0f);
		m_bulletBody->SetActive(true);
		b2WeldJointDef weldJointDef;
		weldJointDef.Initialize(m_bulletBody, m_armBody, b2Vec2(230.0f/PTM_RATIO, (150.0f+FLOOR_HEIGHT)/PTM_RATIO));
		weldJointDef.collideConnected = false;
		m_bulletJoint = (b2WeldJoint*)m_world->CreateJoint(&weldJointDef);
		return true;
	}
	return false;
}

void HelloWorld::resetGame() {
	if (m_bullets.size() != 0) {
		for (vector<b2Body*>::iterator bulletPointer = m_bullets.begin(); bulletPointer != m_bullets.end(); ++bulletPointer) {
			b2Body* bullet = (b2Body*)*bulletPointer;
			CCNode* node = (CCNode*)bullet->GetUserData();
			m_world->DestroyBody(bullet);
		}
		m_bullets.clear();
	}
	if (targets->end() - targets->begin() != 0) {
		for (vector<b2Body*>::iterator targetPointer = (*targets).begin(); targetPointer != (*targets).end(); targetPointer++) {
			b2Body* target = (b2Body*)*targetPointer;
			CCNode* node = (CCNode*)target->GetUserData();
			removeChild(node, true);
			m_world->DestroyBody(target);
		}
		(*targets).clear();
		(*enemies).clear();
	}

	this->createBullets(3);
	this->createTargets();
	this->attachBullet();

	CCFiniteTimeAction *action1 = CCMoveTo::create(1.5f, ccp(-480.0f, 0.0f));
//	CCCallFuncN *action2 = CCCallFuncN::create(this, callfuncN_selector(HelloWorld::attachBullet));
	CCDelayTime *action3 = CCDelayTime::create(1.0f);
	CCFiniteTimeAction* action4 = CCMoveTo::create(1.5f, CCPointZero);
	runAction(CCSequence::create(action1,action3, action4, NULL));

	
}

HelloWorld::~HelloWorld()
{
	delete m_world;
	m_world = NULL;
}

void HelloWorld::resetBullet() {
	if (enemies->size() == 0) {
		CCDelayTime* delayAction = CCDelayTime::create(2.0f);
		CCCallFunc* callSelectorAction = CCCallFunc::create(this, callfunc_selector(HelloWorld::resetGame));
		this->runAction(CCSequence::create(delayAction, callSelectorAction, NULL));
	} else if (attachBullet()) {
		CCAction *action = CCMoveTo::create(0.2f, CCPointZero);
		runAction(action);
	} else {
		CCDelayTime* delayAction = CCDelayTime::create(2.0f);
		CCCallFunc* callSelectorAction = CCCallFunc::create(this, callfunc_selector(HelloWorld::resetGame));
		this->runAction(CCSequence::create(delayAction, callSelectorAction, NULL));
	}
}

void HelloWorld::createTarget(char   *imageName,
					  CCPoint position,
					  float   rotation,
					  bool	  isCircle,
					  bool    isStatic,
					  bool    isEnemy) {

						  CCSprite *sprite = CCSprite::create(imageName); 
    this->addChild(sprite, 1); 
 
    b2BodyDef bodyDef; 
    bodyDef.type = isStatic ? b2_staticBody : b2_dynamicBody; 
    bodyDef.position.Set((position.x+sprite->getContentSize().width/2.0f)/PTM_RATIO, 
                                     (position.y+sprite->getContentSize().height/2.0f)/PTM_RATIO); 
    bodyDef.angle = CC_DEGREES_TO_RADIANS(rotation); 
    bodyDef.userData = sprite; 
 
    b2Body *body = m_world->CreateBody(&bodyDef); 
 
    b2FixtureDef boxDef; 
    b2Fixture *fixtureTemp; 
     
    if (isCircle){ 
        b2CircleShape circle; 
        boxDef.shape = &circle; 
        circle.m_radius = sprite->getContentSize().width/2.0f/PTM_RATIO; 
         
        fixtureTemp = body->CreateFixture(&circle, 0.5f); 
        targets->push_back(body); 
    } 
    else{ 
        b2PolygonShape box; 
        boxDef.shape = &box; 
        box.SetAsBox(sprite->getContentSize().width/2.0f/PTM_RATIO, sprite->getContentSize().height/2.0f/PTM_RATIO); 
        body->CreateFixture(&box, 0.5f); 
        targets->push_back(body); 
    } 
 
    if (isEnemy){ 
        fixtureTemp->SetUserData((void*)1);     //  boxDef.userData = (void*)1; 
        enemies->push_back(body); 
    } 
}

void HelloWorld::createTargets() {
	createTarget("brick_2.png", CCPointMake(675.0, FLOOR_HEIGHT), 0.0f, false, false, false); 
    createTarget("brick_1.png", CCPointMake(741.0, FLOOR_HEIGHT), 0.0f, false, false, false); 
    createTarget("brick_1.png", CCPointMake(741.0, FLOOR_HEIGHT+23.0), 0.0f, false, false, false); 
    createTarget("brick_3.png", CCPointMake(673.0, FLOOR_HEIGHT+46.0), 0.0f, false, false, false); 
    createTarget("brick_1.png", CCPointMake(707.0, FLOOR_HEIGHT+58.0), 0.0f, false, false, false); 
    createTarget("brick_1.png", CCPointMake(707.0, FLOOR_HEIGHT+81.0), 0.0f, false, false, false); 
 
    createTarget("head_dog.png", CCPointMake(702.0, FLOOR_HEIGHT), 0.0f, true, false, true); 
    createTarget("head_cat.png", CCPointMake(680.0, FLOOR_HEIGHT+58.0), 0.0f, true, false, true); 
    createTarget("head_dog.png", CCPointMake(740.0, FLOOR_HEIGHT+58.0), 0.0f, true, false, true); 
 
    // 2 bricks at the right of the first block 
    createTarget("brick_2.png", CCPointMake(770.0, FLOOR_HEIGHT), 0.0f, false, false, false); 
    createTarget("brick_2.png", CCPointMake(770.0, FLOOR_HEIGHT+46.0), 0.0f, false, false, false); 
 
    // The dog between the blocks 
    createTarget("head_dog.png", CCPointMake(830.0, FLOOR_HEIGHT), 0.0f, true, false, true); 
 
    // Second block 
    createTarget("brick_platform.png", CCPointMake(839.0, FLOOR_HEIGHT), 0.0f, false, true, false); 
    createTarget("brick_2.png", CCPointMake(854.0, FLOOR_HEIGHT+28.0), 0.0f, false, false, false); 
    createTarget("brick_2.png", CCPointMake(854.0, FLOOR_HEIGHT+28.0+46.0), 0.0f, false, false, false); 
    createTarget("head_cat.png", CCPointMake(881.0, FLOOR_HEIGHT+28.0), 0.0f, true, false, true); 
    createTarget("brick_2.png", CCPointMake(909.0, FLOOR_HEIGHT+28.0), 0.0f, false, false, false); 
    createTarget("brick_1.png", CCPointMake(909.0, FLOOR_HEIGHT+28.0+46.0), 0.0f, false, false, false); 
    createTarget("brick_1.png", CCPointMake(909.0, FLOOR_HEIGHT+28.0+46.0+23.0), 0.0f, false, false, false); 
    createTarget("brick_2.png", CCPointMake(882.0, FLOOR_HEIGHT+108.0), 90.0f, false, false, false); 
	
}

MyContactListener.h

#ifndef __MYCONTACTLISTENER_H__
#define __MYCONTACTLISTENER_H__

#include "Box2D/Box2D.h"
#include <set>
#include <algorithm>

class MyContactListener: public b2ContactListener {
public:
	std::set<b2Body*> contacts;
	MyContactListener();
	~MyContactListener();

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

};

#endif


MyContactListener.cpp

#include "MyContactListener.h"

MyContactListener::MyContactListener():contacts() {}
MyContactListener::~MyContactListener() {}

void MyContactListener::BeginContact(b2Contact* contact) {}
void MyContactListener::EndContact(b2Contact* contact) {}
void MyContactListener::PreSolve(b2Contact* contact, const b2Manifold* oldManifold) {}
void MyContactListener::PostSolve(b2Contact* contact, const b2ContactImpulse* impulse) {
	bool isAEnemy = (contact->GetFixtureA()->GetUserData() != NULL);
	bool isBEnemy = (contact->GetFixtureB()->GetUserData() != NULL);
	if (isAEnemy || isBEnemy) {
		int32 count = contact->GetManifold()->pointCount;
		float32 maxImpulse = 0.0f;
		for (int32 i = 0; i < count; ++i) {
			maxImpulse = b2Max(maxImpulse, impulse->normalImpulses[i]);
		}
		if (maxImpulse > 1.0f) {
			if (isAEnemy) contacts.insert(contact->GetFixtureA()->GetBody());
			if (isBEnemy) contacts.insert(contact->GetFixtureB()->GetBody());
		}
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值