cocos2d-x学习札记(17)-简单游戏实例1-双枪手

cocos2d-x学习笔记(17)--简单游戏实例1--双枪手

cocos2d-x学习笔记(17)--简单游戏实例--双枪手

从最初的学习笔记到现在,一直在讲的都是一些基础操作,没有实际去做出一个游戏,有些人可能会疑问之前学得实不实用。为了更好地运用和巩固前面的知识,现在开始,我开始开发一个很简单的游戏--双枪手,是游戏总得有个名字的吧,可能起得不怎么样,大家见谅见谅!

这次游戏我会用到cocos2d-x下面一些知识(前面都学过的):

(1)地图

(2)粒子系统

(3)场景的切换

(4)精灵

(5)按钮

(6)回调函数

(7)动作

(8)精灵表单

step1:创建cocos2d-win32工程,并命名为myGame01;(以后还会陆续写一些游戏cocos2d-x学习札记(17)-简单游戏实例1-双枪手

step2:这个游戏主要分成两大部分,第一部分是游戏的菜单部分,第二部分是游戏运行场景部分。我就先说第二部分吧!因为第一部分菜单按钮中的“开始按钮”会调用第二部分场景,所以从第二部分开始讲起,就不会牵涉到第一部分的代码;两者分开来写,思路会更清晰些,也方便日后代码的修改。

示意图:

cocos2d-x学习札记(17)-简单游戏实例1-双枪手

由于About Game跳转到的场景比较简单这里不算进第二部分场景,可以直接忽略;

在HelloWorldScene.h中添加场景2的类:

class GameLayer:public CCLayerColor
{
protected:
	CCMutableArray<CCSprite*>* m_targets;//用于记录移动的靶子
	CCMutableArray<CCSprite*>* m_fires;//用于记录发射的子弹
	CCTMXTiledMap* m_map;//tmx地图
	CCSprite *m_player;//发射炮弹的主角
	
public:
	GameLayer();
	~GameLayer();

	void addTarget();//添加移动的靶子
	void spriteMoveFinished(CCNode* pSender);//处理那些移动到屏幕之外的靶子
	void gameLogic(ccTime dt);

	void ccTouchesEnded(CCSet *pTouches, CCEvent *pEvent);//响应用户在屏幕上的点击事件

	void update(ccTime dt);//处理每一帧画面中的对象
	void moveMap(ccTime dt);//移动地图 

	void menuCloseCallback(CCObject* pSender);//退出游戏
};


在HelloWorldScene.cpp中添加响应成员函数:

/************************************************************************/
/* GameLayer                                                                     */
/************************************************************************/
GameLayer::GameLayer()
{
	setIsTouchEnabled(true);
	increaseX = 0;//初始化

	m_targets = new CCMutableArray<CCSprite*>(NULL);
	m_fires = new CCMutableArray<CCSprite*>(NULL);

	CCSize size = CCDirector::sharedDirector()->getWinSize();


	//添加关闭按钮
	CCMenuItemImage *pCloseItem = CCMenuItemImage::itemFromNormalImage(
		"CloseNormal.png",
		"CloseSelected.png",
		this,
		menu_selector(GameLayer::menuCloseCallback));
	pCloseItem->setPosition(ccp(CCDirector::sharedDirector()->getWinSize().width - 20, 20));
	CCMenu* pMenu = CCMenu::menuWithItems(pCloseItem, NULL);
	pMenu->setPosition(CCPointZero);
	addChild(pMenu, 10);

	//添加player精灵
	m_player = CCSprite::spriteWithFile("player.png", CCRectMake(0, 0, 40, 40));
	m_player->retain();
	//addChild(m_player, 1);
	//m_player->setPosition(ccp(player->getContentSize().width / 2, size.height / 2));

	//添加地图
	m_map = CCTMXTiledMap::tiledMapWithTMXFile("map.tmx");
	m_map->retain();
	m_map->setPosition(CCPointZero);
	addChild(m_map, 3);
	CCTMXObjectGroup* objGroup = m_map->objectGroupNamed("object");
	CCStringToStringDictionary* startPoint = objGroup->objectNamed("player");
	float posX = startPoint->objectForKey("x")->toFloat(); 
	float posY = startPoint->objectForKey("y")->toFloat(); 

	CCTexture2D* playerTexture = CCTextureCache::sharedTextureCache()->addImage("Player.png");
	m_player->setPosition(ccp(posX, posY));
	m_map->addChild(m_player);


		this->schedule(schedule_selector(GameLayer::gameLogic), 1.0);
		this->schedule(schedule_selector(GameLayer::update));
		this->schedule(schedule_selector(GameLayer::moveMap), 1.0);

}

GameLayer::~GameLayer()
{
	if(m_targets)
	{
		m_targets->release();
		m_targets = NULL;

	}

	if(m_fires)
	{
		m_fires->release();
		m_fires = NULL;
	}
}

void GameLayer::menuCloseCallback(CCObject* pSender)
{
	//跳转到游戏开始处
	CCScene* scene = new CCScene();
	CCLayer* layer = new GameMenuLayer();
	scene->addChild(layer);
	CCDirector::sharedDirector()->replaceScene(scene);
	scene->release();
	layer->release();
}


void GameLayer::moveMap(ccTime dt)
{


	if(increaseX >= 2700)//地图移动到尽头,不能再移动
		return;
	increaseX += 50;
	CCActionInterval* move = CCMoveBy::actionWithDuration(1, ccp(-50,0));
	m_map->runAction(move);
	m_player->runAction(move->reverse());
}

void GameLayer::addTarget()
{

	CCSize size = CCDirector::sharedDirector()->getWinSize();

	//添加Target精灵
	CCSprite* target = CCSprite::spriteWithFile("Target.png", CCRectMake(0, 0, 27, 40));
	addChild(target, 10);
	target->setPosition(ccp(27, 40));

	//target的位置
	float minY = target->getContentSize().height/2;
	float maxY = size.height - target->getContentSize().height/2;
	float rangeY = maxY - minY;
	float actualY = (rand() % int(rangeY)) + minY;
	
	target->setPosition(ccp( size.width + (target->getContentSize().width / 2), actualY ));

	//target的移动速度
	int minDuration = 2;
	int maxDuration = 4;
	int rangeDuration = maxDuration - minDuration;
	int actualDuration = (rand() % rangeDuration) + minDuration;

	//target的动作
	CCFiniteTimeAction* actionMove = CCMoveTo::actionWithDuration((float)actualDuration, ccp(0 - target->getContentSize().width / 2, actualY));
	CCFiniteTimeAction* actionMoveDone = CCCallFuncN::actionWithTarget(this, callfuncN_selector(GameLayer::spriteMoveFinished));

	target->runAction(CCSequence::actions
		(actionMove, actionMoveDone, NULL));

	target->setTag(1);
	m_targets->addObject(target);

}



void GameLayer::spriteMoveFinished(CCNode* pSender)
{
	CCSize size = CCDirector::sharedDirector()->getWinSize();
	CCSprite* sprite = (CCSprite* )pSender;
	this->removeChild(sprite, true);

	if (sprite->getTag() == 1)
	{
		m_targets->removeObject(sprite);
		
	}
	else if (sprite->getTag() == 2)
	{
		m_fires->removeObject(sprite);
	}
}

void GameLayer::gameLogic(ccTime dt)
{
	this->addTarget();
}



void GameLayer::ccTouchesEnded(CCSet *pTouches, CCEvent *pEvent)
{
	CCTouch* touch = (CCTouch*)(pTouches->anyObject());
	CCPoint location = touch->locationInView(touch->view());
	location = CCDirector::sharedDirector()->convertToGL(location);

	CCSize size = CCDirector::sharedDirector()->getWinSize();
	
	//注意:由于游戏中使用两发子弹,所有要添加两个精灵
	CCSprite* fire = CCSprite::spriteWithFile("fire.png", CCRectMake(0,0,10,10));
	fire->setPosition(ccp(10, size.height / 2));
	CCSprite* fire2 = CCSprite::spriteWithFile("fire.png", CCRectMake(0,0,10,10));
	fire2->setPosition(ccp(10, size.height / 2));

	float offX = location.x - fire->getPosition().x;
	float offY = location.y - fire->getPosition().y;

	if(offX <= 0)return ;

	//粒子效果
	CCParticleSystem* particle = CCParticleSun::node();
	fire->addChild(particle);
	particle->setStartSize(5);
	particle->setTexture(CCTextureCache::sharedTextureCache()->addImage("pow.png"));
	particle->setPosition(ccp(5, 5));
	/*
	注意:此处(5, 5)是particle想对于fire精灵的位置,即particle在fire中的坐标位置,由于fire图标大小事10x10,
	          那么particle在屏幕中的位置就是和fire重合,而不是在靠近(0, 0)的位置
	*/

	//粒子效果2
	CCParticleSystem* particle2 = CCParticleSun::node();
	fire2->addChild(particle2);
	particle2->setStartSize(5);
	particle2->setTexture(CCTextureCache::sharedTextureCache()->addImage("pow.png"));
	particle2->setPosition(ccp(5, 5));
	/*
	注意:此处(5, 5)是particle想对于fire精灵的位置,即particle在fire中的坐标位置,由于fire图标大小事10x10,
	那么particle在屏幕中的位置就是和fire重合,而不是在靠近(0, 0)的位置
	*/

	addChild(fire, 10);
	addChild(fire2, 10);

	float realX = size.width + (fire->getContentSize().width / 2);
	float ratio = (float)offY / (float)offX;
	float realY = (realX* ratio) + fire->getPosition().y;
	CCPoint realDest = ccp(realX, realY);

	float offRealX = realX - fire->getPosition().x;
	float offRealY = realY - fire->getPosition().y;
	float length = sqrtf((offRealX * offRealX) 
		+ (offRealY*offRealY));
	float velocity = 480/1; // 480pixels/1sec
    float realMoveDuration = length/velocity;

	

	fire->runAction( CCSequence::actions(
		CCMoveTo::actionWithDuration(realMoveDuration, ccp(realDest.x, realDest.y - 30)),
		CCCallFuncN::actionWithTarget(this, 
		callfuncN_selector(GameLayer::spriteMoveFinished)), 
		NULL) );

	fire2->runAction( CCSequence::actions(
		CCMoveTo::actionWithDuration(realMoveDuration, ccp(realDest.x , realDest.y + 30)),
		CCCallFuncN::actionWithTarget(this, 
		callfuncN_selector(GameLayer::spriteMoveFinished)), 
		NULL) );

	fire->setTag(2);
	m_fires->addObject(fire);

	fire2->setTag(2);
	m_fires->addObject(fire2);

	CocosDenshion::SimpleAudioEngine::sharedEngine()->playEffect("gun.wav");
}



void GameLayer::update(ccTime dt)
{
	CCMutableArray<CCSprite*>*projectilesToDelete = 
		new CCMutableArray<CCSprite*>;

	CCMutableArray<CCSprite*>::CCMutableArrayIterator it, jt ;

	

	for(it = m_fires->begin(); it != m_fires->end(); it++)
	{
		CCSprite* fire = *it;
		CCRect fireRect = CCRectMake(
			fire->getPosition().x - 
			(fire->getContentSize().width / 2),
			fire->getPosition().y - 
			(fire->getContentSize().height / 2),
			fire->getContentSize().width,
			fire->getContentSize().height);

		CCMutableArray<CCSprite*>* targetsToDelete = 
			new CCMutableArray<CCSprite*>;

		for(jt = m_targets->begin(); jt != m_targets->end(); jt++)
		{
			CCSprite* target = *jt;
			CCRect targetRect = CCRectMake(
				target->getPosition().x - (target->getContentSize().width / 2),
				target->getPosition().y - (target->getContentSize().height / 2),
				target->getContentSize().width,
				target->getContentSize().height);

			if(CCRect::CCRectIntersectsRect(fireRect, targetRect))
			{
				targetsToDelete->addObject(target);
				CocosDenshion::SimpleAudioEngine::sharedEngine()->playEffect("bomb.wav");
				CCSprite* pow = CCSprite::spriteWithFile("pow.png");
				CCParticleSystem* particle = CCParticleSmoke::node();
				pow->addChild(particle, 2);
				particle->setTexture(CCTextureCache::sharedTextureCache()->addImage("rain.png"));
				particle->setPosition(ccp(20, 20));
				particle->setDuration(1);
				particle->setStartSize(1);
				particle->setEndSize(1);
				pow->setTag(3);
				addChild(pow, 10);
				
				pow->setPosition(ccp(target->getPosition().x, target->getPosition().y));
				CCAction* action = CCFadeOut::actionWithDuration(1);
				pow->runAction(action);
			}
		}

		for(jt = targetsToDelete->begin(); 
			jt != targetsToDelete->end(); jt++)
		{
			CCSprite* target = *jt;
			m_targets->removeObject(target);
			removeChild(target, true);
		}

		if(targetsToDelete->count() > 0)
		{
			projectilesToDelete->addObject(fire);
		}
		targetsToDelete->release();
	}

	for(it = projectilesToDelete->begin();
		it != projectilesToDelete->end(); it++)
	{
		CCSprite* fire = * it;
		m_fires->removeObject(fire);
		removeChild(fire, true);
	}



	projectilesToDelete->release();
}


step3:然后就是场景1中的类:

class GameMenuLayer:public CCLayerColor
{
public:
	GameMenuLayer();
	~GameMenuLayer();

	void onEnter();

	void startGameCallback(CCObject* pSender);
	void aboutGameCallback(CCObject* pSender);
	void exitGameCallback(CCObject* pSender);
	void backGameCallback(CCObject* pSender);
};


在HelloWorldScene.cpp中添加成员函数:

/************************************************************************/
/* GameMenuLayer                                                                     */
/************************************************************************/
GameMenuLayer::GameMenuLayer()
{
	CCSize size = CCDirector::sharedDirector()->getWinSize();

	//添加三个按钮
	CCLabelTTF* pStartLabel = CCLabelTTF::labelWithString("Start Game", "Arial", 30);
	CCLabelTTF* pExitLabel = CCLabelTTF::labelWithString("Exit Game", "Arial", 30);
	CCLabelTTF* pAboutLabel = CCLabelTTF::labelWithString("About Game", "Arial", 30);

	CCMenuItemLabel* pStartItem = CCMenuItemLabel::itemWithLabel(pStartLabel, this, menu_selector(GameMenuLayer::startGameCallback));
	CCMenuItemLabel* pExitItem = CCMenuItemLabel::itemWithLabel(pExitLabel, this, menu_selector(GameMenuLayer::exitGameCallback));
	CCMenuItemLabel* pAboutItem = CCMenuItemLabel::itemWithLabel(pAboutLabel, this, menu_selector(GameMenuLayer::aboutGameCallback));

	CCMenu* pStartMenu = CCMenu::menuWithItems(pStartItem, NULL);
	CCMenu* pExitMenu = CCMenu::menuWithItems(pExitItem, NULL);
	CCMenu* pAboutMenu = CCMenu::menuWithItems(pAboutItem, NULL);

	pStartItem->setPosition(ccp(size.width / 2, size.height / 2 + 50));
	pExitItem->setPosition(ccp(size.width / 2, size.height / 2  - 50 ));
	pAboutItem->setPosition(ccp(size.width / 2, size.height / 2 ));

	pStartMenu->setPosition(CCPointZero);
	pExitMenu->setPosition(CCPointZero);
	pAboutMenu->setPosition(CCPointZero);

	addChild(pStartMenu, 2);
	addChild(pExitMenu, 2);
	addChild(pAboutMenu, 2);

	//添加背景
	CCSprite* bk = CCSprite::spriteWithFile("background.png");
	addChild(bk, 0);
	bk->setPosition(ccp(size.width / 2, size.height / 2));

	//添加动画
	CCSpriteFrameCache::sharedSpriteFrameCache()->addSpriteFramesWithFile("sunshine.plist");
	CCSpriteBatchNode* spritesheet = CCSpriteBatchNode::batchNodeWithFile("sunshine.png");

	addChild(spritesheet, 1);

	CCMutableArray<CCSpriteFrame*>* animFrames = new CCMutableArray<CCSpriteFrame*>;
	char str[20];
	for (int i=1; i<=6; i++)
	{
		sprintf(str, "sun%d.png", i);
		animFrames->addObject(CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName(str));
	}

	CCAnimation* animation = CCAnimation::animationWithFrames(animFrames, 0.1f);

	CCSprite* sun = CCSprite::spriteWithSpriteFrameName("sun1.png");
	sun->setPosition(ccp(0, 0));
	CCActionInterval* action = CCRepeatForever::actionWithAction(CCAnimate::actionWithAnimation(animation, false));
	sun->runAction(action);
	spritesheet->addChild(sun);

	//太阳运动轨迹
	CCActionInterval* move1 = CCMoveBy::actionWithDuration(3,ccp(size.width / 4, size.height / 4));
	CCActionInterval* move1_back = move1->reverse();
	CCActionInterval* move2 = CCMoveBy::actionWithDuration(3,ccp(size.width / 4, -size.height / 4));
	CCActionInterval* move2_back = move2->reverse();
	spritesheet->runAction(CCRepeatForever::actionWithAction((CCActionInterval*)(CCSequence::actions(move1, move1,move2,move2, move2_back,move2_back,move1_back,move1_back, NULL))));

}

void GameMenuLayer::aboutGameCallback(CCObject* pSender)
{
	CCSize size = CCDirector::sharedDirector()->getWinSize();

	//显示关于的内容
	CCLabelTTF* label = CCLabelTTF::labelWithString("Made by wenbanana \n Email:294299195@qq.com", "Arial", 30);
	label->setPosition(ccp(size.width / 2, size.height / 2));
	CCScene* s = CCScene::node();
	CCLayer* layer = CCLayer::node();
	layer->addChild(label, 1);

	//返回按钮
	CCLabelTTF* pBackLabel = CCLabelTTF::labelWithString("Back", "Arial", 30);
	CCMenuItemLabel* pBackItem = CCMenuItemLabel::itemWithLabel(pBackLabel, this, menu_selector(GameMenuLayer::backGameCallback));
	CCMenu* pBackMenu = CCMenu::menuWithItems(pBackItem, NULL);
	pBackItem->setPosition(ccp(size.width  - 50, 50));
	pBackMenu->setPosition(CCPointZero);
	layer->addChild(pBackMenu, 1);

	s->addChild(layer);

	CCDirector::sharedDirector()->replaceScene(s);
	//s->release();
	//layer->release();

}

void GameMenuLayer::startGameCallback(CCObject* pSender)
{
	//跳转到游戏中
	CCScene* scene = new CCScene();
	CCLayer* layer = new GameLayer();
	scene->addChild(layer);
	CCDirector::sharedDirector()->replaceScene(scene);
	scene->release();
	layer->release();
}


void GameMenuLayer::exitGameCallback(CCObject* pSender)
{
	CCDirector::sharedDirector()->end();
}

void GameMenuLayer::backGameCallback(CCObject* pSender)
{
	CCSize size= CCDirector::sharedDirector()->getWinSize();
	//跳转到游戏中
	CCScene* scene = new CCScene();
	CCLayer* layer = new GameMenuLayer();
	scene->addChild(layer);
	CCDirector::sharedDirector()->replaceScene(scene);
	scene->release();
	layer->release();


}

GameMenuLayer::~GameMenuLayer()
{

}

void GameMenuLayer::onEnter()
{
	CCLayer::onEnter();
}


step4:最后运行程序,效果如下:

开始界面

cocos2d-x学习札记(17)-简单游戏实例1-双枪手

游戏运行界面

cocos2d-x学习札记(17)-简单游戏实例1-双枪手