先将常用的函数与头文件,宏定义等写到一个公共类中
#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 tank
void createTank(float);
bool _createFlag;
CCArray *_tanks;
CCArray *_bullets;
//move enemy tank
void moveTank(float);
//make enemy tank shoot bullet
void Shoot(float);
//collision detection
void update(float);
bool _pause;
void pause();
void resume();
};
#endif
添加 多种道具,当打死一坦克时就会有一定概率产生一个道具@H_218_502@
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 slider CCSprite *backgroundSprite = CCSprite::create(bgFile); // Prepare progress for slider CCSprite *progressSprite = CCSprite::create(progressFile); // Prepare thumb (menuItem) for slider CCSprite *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));
就成功了,原因暂且不明。