zoukankan      html  css  js  c++  java
  • 基于cocos2dx的横版动作游戏制作(二)

    如果你看过第一部分介绍,你应该大体知道一个横版游戏该怎么样去做,需要什么东西了....本部分介绍一些细节设计...

    第一个:单例对象我们应该怎么设计才比较方便用呢?里面需要放置哪些对象的引用和指针呢?

    在一个战斗场景里,就当前这个游戏来说,GameLayer(游戏层),OptionLayer(操作层) 是他最基础的构成部分,自然在每个层中的child你都是可以访问的,对于英雄和NPC也是一样,如果将这些对象的引用当成一个全局的指针放置在一个单例对象里,那在接下来的开发访问中将会有很大的便利,因为这些对象基本上是不可缺的....

    这里我先介绍一个很好用的单例模版类,所有你需要创建的单例类只要继承它就可以了,非常方便

    #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);

    //需引入以下类,否则在这些类中访问单例对象会报错
    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智能....说起来很广了)

    第五,英雄跟怪物之间释放攻击技能的碰撞问题,这个貌似比较简单,但是有一点需要注意的是,png图片的大小往往要比精灵实际的大小要大,如果计算有效的攻击范围,可被攻击的范围等到 rect = CCRectMake(originX,originY,width,height);这个需要根据实际情况来定,通过attackReck.intersectsRect(hurtReck)方法判断碰撞是否有效

    代码里之前写的地方有错,CCRect理解出错,应该是左下角原点+宽和高(汗.....)

    //计算有效攻击区域
    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版本的应该是都可以运行的

  • 相关阅读:
    C++ #include .h extern 的相关关系及说明
    VC++ list函数详解
    VC++ 限制窗口的大小范围的方法
    VC++ CTreeCtrl 使用NM_CLICK和TVN_SELCHANGED
    Vc++ 控件用法总结之List Control
    VC++ 将IP字符串转为 DWORD值
    C语言提供了几个标准库函数 itoa() atoi()
    C语言 malloc calloc realloc alloc 在分配内存时的 区别
    C语言 malloc、calloc、realloc的区别
    VC++ MFC中如何将应用程序的配置信息保存到注册表中(二)
  • 原文地址:https://www.cnblogs.com/zouly/p/3844531.html
Copyright © 2011-2022 走看看