先将常用的函数与头文件,宏定义等写到一个公共类中
#ifndef __Common_H__#define __Common_H__#include "cocos2d.h"#include "SimpleAudioEngine.h"#include "cocos-ext.h"USING_NS_CC;USING_NS_CC_EXT;#define winSize CCDirector::sharedDirector()->getWinSize()#define TANK_SPEED 2#define BULLET_SPEED 4#define TANK_CREATE_INTERVAL 3#define TANK_SHOOT_INTERVAL 1#define TIME_OVER 300#define TANK_BOMB "TANK_BOMB"class Common{public:enum DIRECTION{UP,RIGHT,DOWN,LEFT,INVALID_DIR};enum TileType{NONE,BLOCK,STEEL,HOME};enum {ZO_LAYER_0=100,ZO_BULLET,ZO_TANK,ZO_LAYER_1,ZO_ITEM,ZO_LAYER_SETUP};static TileType getTileType(int gid){if (gid==5||gid==6||gid==11||gid==12){return STEEL;}if (gid==13||gid==14||gid==19||gid==20){return BLOCK;}if (gid==17||gid==18||gid==23||gid==24){return HOME;}return NONE;}static CCScene* scene(CCLayer *layer){CCScene *s=CCScene::create();s->addChild(layer);return s;}static const char* format(int v,const char *prefix="",const char *suffix=""){static char buf[1024];sprintf(buf,"%s%d%s",prefix,v,suffix);return buf;}static void moveNodeX(CCNode *n,int dx){n->setPositionX(n->getPositionX()+dx);}static void moveNodeY(CCNode *n,int dy){n->setPositionY(n->getPositionY()+dy);}static void moveNode(CCNode*n,CCPoint pt){moveNodeX(n,pt.x);moveNodeY(n,pt.y);}static const CCPoint Map2PointLB(CCTMXTiledMap *_map,CCPoint ptTile){ptTile.y=_map->getMapSize().height-1-ptTile.y;return ccp(ptTile.x*_map->getTileSize().width,ptTile.y*_map->getTileSize().height);}static CCPoint Point2Tile(CCTMXTiledMap *_map,CCPoint ptMap){int dx=_map->getTileSize().width;int dy=_map->getTileSize().height;//CCPoint ptMap=_map->convertToNodeSpace(ptGL);int x=ptMap.x/dx;int y=ptMap.y/dy;y=_map->getMapSize().height-1-y;return ccp(x,y);}};#endif
开始界面与选择界面非常简单,可以略过,游戏主界面包含的方法如下
#ifndef __LayerGame_H__#define __LayerGame_H__#include "Common.h"#include "TankFriend.h"#include "MenuCtrl.h"#include "AI.h"#include "LayerSetup.h"class Item;class LayerGame:public CCLayer{public://CREATE_FUNC(LayerGame);void onExit();static LayerGame*create(unsigned int index){LayerGame *pRt=new LayerGame();if (pRt&&pRt->init(index)){pRt->autorelease();return pRt;}else{delete pRt;pRt=NULL;return pRt;}}bool init(unsigned int index);void update(float);CCTMXTiledMap *_map;TankFriend *_tankFriend;void DirCtrlPress(CCObject*);void Shoot(CCObject*);void Setup(CCObject*);void TimeOut(float);void setGodMode(int interval){_godMode=true;CCDelayTime*delay=CCDelayTime::create(interval);CCCallFunc *callFunc=CCCallFunc::create(this,callfunc_selector(LayerGame::unSetGodMode));this->runAction(CCSequence::createWithTwoActions(delay,callFunc));}void unSetGodMode(){_godMode=false;}void addItem();void eatItem(Item*);void eatItemBomb();void eatItemSteel();void setPause(){CCDirector::sharedDirector()->pause();}enum FAILURE_REASON{TIME_OUT,HOME_DESTORY,TANK_DIE};static void gameOver(FAILURE_REASON reason);CCArray *_bullets;CCArray *_items;AI *_ai;int _victoryCount;int _curCount;int _index;int _life;bool _godMode;};#endif
添加友军坦克
class TankFriend:public CCSprite{public:CREATE_FUNC(TankFriend);bool init();CCTMXTiledMap *getMap();void setTileSize(int tileSize);int _tileSize;void Move(Common::DIRECTION dir);void doMove();void Turn(Common::DIRECTION dir);bool canMove(Common::DIRECTION dir);Bullet *Shoot();Common::DIRECTION _dir;int _damage;};
添加控制按钮,控制坦克的前进,后退与发射
其中前进,后退是按着一直走,发射子弹是按一下,发射一下
bool MenuCtrl::init(){CCMenu::init();schedule(schedule_selector(MenuCtrl::CheckActive));return true;}void MenuCtrl::CheckActive(float){if (this->m_pSelectedItem&&m_eState==kCCMenuStateTrackingTouch){m_pSelectedItem->activate();}}
以上重写了menu方法,使得可以按着按钮一直运动
添加子弹层
class Bullet:public CCSprite{public:CREATE_FUNC(Bullet);bool init();void setPicture(const char *filename);static void CheckBullets(CCTMXTiledMap *_map,CCArray *_bullets);int _damage;};
敌军坦克由电脑随机生成
敌军坦克类继承友军坦克
bool TankEnemy::init()
{CCSprite::initWithFile("tank/armor/armor2U.png");_tileSize=0;_dir=Common::UP;this->setZOrder(Common::ZO_TANK);Turn(Common::DOWN);return true;
}
随机产生敌军坦克方法
#ifndef __AI_H__#define __AI_H__#include "Common.h"class AI:public CCNode{public:CREATE_FUNC(AI);bool init();void onExit();CCTMXTiledMap *getMap(){return (CCTMXTiledMap*)getParent();}//generate enemy tankvoid createTank(float);bool _createFlag;CCArray *_tanks;CCArray *_bullets;//move enemy tankvoid moveTank(float);//make enemy tank shoot bulletvoid Shoot(float);//collision detectionvoid update(float);bool _pause;void pause();void resume();};#endif
添加 多种道具,当打死一坦克时就会有一定概率产生一个道具
class Item:public CCSprite{public:enum ItemType{IT_ACTIVE, IT_BOMB, IT_MINTANK, IT_STAR, IT_STEEL, IT_TIMER, IT_COUNT};CREATE_FUNC(Item);bool init();void setPosition();ItemType _type;};
添加控制按钮,产生模态对话框,控制音量与音效
#ifndef __LayerSetup_H__#define __LayerSetup_H__#include "Common.h"
class MyCCControlSlider : public CCControlSlider{public:static MyCCControlSlider* create(const char* bgFile, const char* progressFile, const char* thumbFile){// Prepare background for sliderCCSprite *backgroundSprite = CCSprite::create(bgFile);// Prepare progress for sliderCCSprite *progressSprite = CCSprite::create(progressFile);// Prepare thumb (menuItem) for sliderCCSprite *thumbSprite = CCSprite::create(thumbFile);MyCCControlSlider *pRet = new MyCCControlSlider();pRet->initWithSprites(backgroundSprite, progressSprite, thumbSprite);pRet->autorelease();return pRet;}bool ccTouchBegan(CCTouch*t, CCEvent*e){return CCControlSlider::ccTouchBegan(t, e);}void ccTouchEnded(CCTouch*t, CCEvent*e){CCControlSlider::ccTouchEnded(t, e);}void ccTouchMoved(CCTouch*t, CCEvent*e){CCControlSlider::ccTouchMoved(t, e);}void ccTouchCancelled(CCTouch*t, CCEvent*e){CCControlSlider::ccTouchCancelled(t, e);}};class LayerSetup:public CCLayer{public:CREATE_FUNC(LayerSetup);bool init();void ChangeBGVolume(CCObject*, CCControlEvent);void ChangeEffectVolume(CCObject*, CCControlEvent);void Close(CCObject*);bool ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent);void ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent);void ccTouchMoved(CCTouch *pTouch, CCEvent *pEvent);void ccTouchCancelled(CCTouch *pTouch, CCEvent *pEvent);CCMenu *_menu;bool _bMenuItemClicked;MyCCControlSlider* _volumeBG;bool _bVolumeBGClicked;MyCCControlSlider* _volumeEffect;bool _bVolumeEffectClicked;};#endif // !--
由于CCControlSlider中有些成员变量是保护的,需要将CCControlSlider重写,才可以进行。
注意:当在实现暂停道具的时候,由于要暂停与重启,重启时报错
Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call. This is usually a result of calling a function declared with one calling convention with a function pointer declared with a different calling convention
原先用//scheduleOnce(schedule_selector(AI::resume), 1);来调用resume函数,老是报错,帧循环发生错误,后来改成
CCDelayTime* delay=CCDelayTime::create(5.0f);
CCCallFunc* callFunc = CCCallFunc::create(this, callfunc_selector(AI::resume));
this->runAction(CCSequence::create(delay,callFunc,NULL));
就成功了,原因暂且不明。