若是你看过第一部分介绍,你应该大致知道一个横版游戏该怎么样去作,须要什么东西了....本部分介绍一些细节设计...字体
第一个:单例对象咱们应该怎么设计才比较方便用呢?里面须要放置哪些对象的引用和指针呢?动画
在一个战斗场景里,就当前这个游戏来讲,GameLayer(游戏层),OptionLayer(操做层) 是他最基础的构成部分,天然在每一个层中的child你都是能够访问的,对于英雄和NPC也是同样,若是将这些对象的引用当成一个全局的指针放置在一个单例对象里,那在接下来的开发访问中将会有很大的便利,由于这些对象基本上是不可缺的....ui
这里我先介绍一个很好用的单例模版类,全部你须要建立的单例类只要继承它就能够了,很是方便lua
#ifndef _SINGLETON_H #define _SINGLETON_H using namespace std; template <class T> class Singleton { public: //获取类的惟一实例 static inline T* instance(); //释放类的惟一实例 void release(); protected: Singleton(void){} ~Singleton(void){} static T* _instance; }; template <class T> inline T* Singleton<T>::instance() { if(NULL == _instance){ _instance = new T; } return _instance; } template <class T> void Singleton<T>::release() { if (!_instance) return; delete _instance; _instance = 0; } //cpp文件中须要先声明静态变量 #define DECLARE_SINGLETON_MEMBER(_Ty) \ template <> _Ty* Singleton<_Ty>::_instance = NULL; #endif//_SINGLETON_H
那么单例中你能够引用这如下对象,方便访问,可是要注意cpp文件中须要声明静态变量,能够经过模板中的宏 DECLARE_SINGLETON_MEMBER(XXX);spa
//需引入如下类,不然在这些类中访问单例对象会报错 class GameDisplayLayer; class OptionLayer; class Hero; class Role; USING_NS_CC; //全局单例 class Global:public Singleton<Global> { public: Global(void); ~Global(void); //GameScene *gameScene; GameDisplayLayer *gameLayer; //游戏层 OptionLayer *optionLayer; //操做层 Hero *hero; //英雄 CCArray *npcs; //怪物 CCTMXTiledMap *tmxTileMap; //地图
//还有其余一些对象的引用和公共方法也能够放这里......本身定义
}
第二,咱们得介绍一下人物和地图的移动的细节问题,好比:地图通常状况下是比当前屏幕大的,横版游戏人物在各个方向移动时,必须考虑何时该由地图自己移动位置,而不是英雄移动,不过这个问题应该是比较好获得答案的,只要人物移动的下一帧地址快要超出屏幕中间,咱们就让地图超反方向移动相等距离,这样能够形成英雄向前移动的效果,可是若是地图最边缘方向快要移动完毕时,为了保证不把黑色的越界区域显示出来,你还得在每次移动前判断是否地图边缘位置快要超过屏幕了,这时候,就算任务下一帧到达屏幕中间部分,你也得让英雄移动;除此以外,若让地图移动,那么你也必须遍历Npc,道具什么的,让他们跟着地图一块儿移动....如下贴出部分代码。设计
if (heroCtrl->getAllowMove()&&(Direction.x != 0||Direction.y != 0)) { CCSize size=CCDirector::sharedDirector()->getWinSize(); //制造一个矩形框,人物只会在当前框里活动,经过地图移动来形成更大面积的活动范围 CCRect rect=CCRectMake(heroCtrl->getContentSize().width/2,heroCtrl->getContentSize().height/2,size.width-(heroCtrl->getContentSize().width/2),size.height-(heroCtrl->getContentSize().height/2)); if(rect.containsPoint(position)){ float mapMaxX = 0; //计算是不是人移动仍是地图移动,注意:地图在初始化时锚点已设为cpp(0,0) if(heroCtrl->getPosition().x <= SCREEN.width/2 && Direction.x>0 && position.x > SCREEN.width/2){ //地图须要左移动,position表示人物下一帧的位置 //计算地图最右端x轴下一次位置 mapMaxX = tmxTileMap->getPositionX()+tmxTileMap->getContentSize().width-Direction.x; //保证地图不会把越界部分移出来 if(mapMaxX > SCREEN.width){ global->tmxTileMap->setPositionX(global->tmxTileMap->getPositionX()-Direction.x); OptionLayer::npcMoveByMap(ccp(-Direction.x,0)); if(Direction.y != 0){ heroCtrl->setPositionY(heroCtrl->getPositionY() + Direction.y);//防止地图移动时,人物Y轴不能移动 } }else{ heroCtrl->setPosition(position); //地图快要越界,人物移动便可 } }else if(heroCtrl->getPosition().x >= SCREEN.width/2 && Direction.x<0 && position.x < SCREEN.width/2){//地图须要像右移动 //计算地图最左端x轴下一次位置 mapMaxX = tmxTileMap->getPositionX()+Direction.x; //保证地图不会把越界部分移出来 if(mapMaxX < 0){ global->tmxTileMap->setPositionX(global->tmxTileMap->getPositionX()-Direction.x); OptionLayer::npcMoveByMap(ccp(-Direction.x,0)); if(Direction.y != 0){ heroCtrl->setPositionY(heroCtrl->getPositionY() + Direction.y);//防止地图移动时,人物Y轴不能移动 } }else{ heroCtrl->setPosition(position); //地图快要越界,人物移动 } }else{ heroCtrl->setPosition(position); //人物移动便可 } } }
第三,英雄跟怪物的相互遮挡问题,一个比较偷懒但颇有效的解决办法是,根据Y轴的位置来设置当前对象的zOrder值......指针
第四,AI 自动追杀英雄的问题,方法有不少种,其中之一的方法,能够参考摇杆控制的办法来一步步靠近英雄......(这个功能点能够花点心思考虑考虑,AI智能....提及来很广了)code
第五,英雄跟怪物之间释放攻击技能的碰撞问题,这个貌似比较简单,可是有一点须要注意的是,png图片的大小每每要比精灵实际的大小要大,若是计算有效的攻击范围,可被攻击的范围等到 rect = CCRectMake(originX,originY,width,height);这个须要根据实际状况来定,经过attackReck.intersectsRect(hurtReck)方法判断碰撞是否有效对象
代码里以前写的地方有错,CCRect理解出错,应该是左下角原点+宽和高(汗.....)blog
//计算有效攻击区域 CCRect PublicFun::getAttackRect(Role* role){ CCRect rect ; float originX = 0; float originY = 0; float width = 0; float height = 0; //计算正前方攻击区域 if(role->getRoleDirection() == RolelTurnRight){//朝右 originX = role->getPositionX(); originY = role->getPositionY() - role->getContentSize().height/2; width = role->getContentSize().width/2; height = role->getContentSize().height/2; rect = CCRectMake(originX,originY,width,height); }else{ originX = role->getPositionX() -role->getContentSize().width/2; originY = role->getPositionY() - role->getContentSize().height/2; width = role->getContentSize().width/2; height = role->getContentSize().height/2; rect = CCRectMake(originX,originY,width,height); } return rect; } //计算可被攻击有效区域(当前精灵大小) CCRect PublicFun::getHurtRect(Role* role){ CCRect rect ; float originX = 0; float originY = 0; float width = 0; float height = 0; //受攻击范围 originX = role->getPositionX() - role->getContentSize().width/2; originY = role->getPositionY() - role->getContentSize().height/2; width = role->getContentSize().width; height = role->getContentSize().height; rect = CCRectMake(originX,originY,width,height); return rect; }
以后计算是否被攻击
CCRect hurtReck = PublicFun::getHurtRect(npc);//怪物受伤区域 if(attackReck.intersectsRect(hurtReck)){ npc->setAllowMove(false); //此处可处理怪物被攻击后的后续 Hero::damageDisplay("-999", npc); npc->RunHurtAction(); }
第六,技能伤害数字渐隐效果,这个问题也比较好解决,只要在当前角色头顶上方生成CCLabelBMFont 或者其余字体都行,经过CCFadeOut产生渐隐效果,以后移除掉该字体便可
void Hero::damageDisplay(const char* str,NPC* npc){//产生数字动画 CCFadeOut *labelFadeOut = CCFadeOut::create(1.5f); CCLabelBMFont* atLabel = CCLabelBMFont::create(str, "fonts/helvetica-32.fnt"); atLabel->setColor(ccRED); atLabel->setPosition(ccp(npc->getPositionX()-5,npc->getPositionY()+npc->getContentSize().height/2+5)); global->gameLayer->addChild(atLabel, 1); CCFiniteTimeAction * callFuncN = CCCallFuncN::create(atLabel, callfuncN_selector(Hero::FontsCallBackAction)); CCFiniteTimeAction *sequence = CCSequence::create(labelFadeOut, callFuncN,NULL); atLabel->runAction(sequence); }
说到这里,貌似整个游戏的介绍都算比较彻底了,麻雀虽小,涵盖的东西细节上仍是有很多须要处理的,后续考虑用quick-cocos2dx用全lua实现移植它
代码和资源附件后续会上传上来....
http://pan.baidu.com/s/1ntFQwrB 这是源代码,在vs2012 cocos2dx 2.2.2上运行,3.0如下~2.0版本的应该是均可以运行的