cocos2d-x学习笔记(17)--简单游戏实例1--双枪手
cocos2d-x学习笔记(17)--简单游戏实例--双枪手
从最初的学习笔记到现在,一直在讲的都是一些基础操作,没有实际去做出一个游戏,有些人可能会疑问之前学得实不实用。为了更好地运用和巩固前面的知识,现在开始,我开始开发一个很简单的游戏--双枪手,是游戏总得有个名字的吧,可能起得不怎么样,大家见谅见谅!
这次游戏我会用到cocos2d-x下面一些知识(前面都学过的):
(1)地图
(2)粒子系统
(3)场景的切换
(4)精灵
(5)按钮
(6)回调函数
(7)动作
(8)精灵表单
step1:创建cocos2d-win32工程,并命名为myGame01;(以后还会陆续写一些游戏)
step2:这个游戏主要分成两大部分,第一部分是游戏的菜单部分,第二部分是游戏运行场景部分。我就先说第二部分吧!因为第一部分菜单按钮中的“开始按钮”会调用第二部分场景,所以从第二部分开始讲起,就不会牵涉到第一部分的代码;两者分开来写,思路会更清晰些,也方便日后代码的修改。
示意图:
由于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)的位置*///粒子效果2CCParticleSystem* 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:最后运行程序,效果如下:
开始界面
游戏运行界面