基于cocos2d-x简易泡泡龙游戏

欢迎转载http://blog.csdn.net/demon_wu/article/details/9919115

最近公司的项目一直没有开工,所以自己给自己点事情做,写了一个简易的泡泡龙游戏。实习三个月接触cocos2d-x,实习完后换了家公司,一个月都还没有开工,实在是无奈呀。

想必很多人都玩过泡泡龙游戏了,本人用了一个下午做基本的界面实现,然后用一个上午开始处理逻辑,也就是泡泡射出过后的相关操作,准备按照这个节奏写,分为两章,开发平台是xcode,先上一个最后结果图。

图中可以看到有掉落的泡泡和正在消失的泡泡以及基础的界面,对于整体我采取的是用了一个负责泡泡的类和一个负责界面的类。泡泡我们需要考虑好它需要额外添加哪些属性,我继承了CCSprite然后添加了私有成员变量:_type、isSame、_isPass和_flag,_type表示的是该泡泡是什么类型的,用于显示泡泡的颜色以及做判断;_isSame是在后面运算的时候需要用来判断是否是与目标是相同颜色,如果是的话做标记,方便我们做判断,_isPass表示是否是有连接的,当没有连接的时候将会是被掉落的情况,_flag是表示当前是否是最靠左,在图中我们可以看到第一行中第一个是最靠左,但是第二行第一个不是最靠左,代码如下。

#ifndef __paopaolong__PaoPao__
#define __paopaolong__PaoPao__

#include "cocos2d.h"
#include "GameEnum.h"
USING_NS_CC;
//泡泡类,包含类型和自己所在的一行是否是左缺的状态
class PaoPao : public CCSprite
{
public:
    PaoPao();
    ~PaoPao();
    static PaoPao *initWithType(PAOPAO_TYPE type);
    CREATE_FUNC(PaoPao);
    CC_SYNTHESIZE(PAOPAO_TYPE, _type, Type);//泡泡的类型
    CC_SYNTHESIZE(bool, _isSame,IsSame); //判断是否是统一类型的
    CC_SYNTHESIZE(bool, _isPass, IsPass); //判断是否路过
    CC_SYNTHESIZE(bool, _flag, Flag);//是否是左缺的状态
private:
    static CCString * getStringByType(PAOPAO_TYPE type);
};

#endif /* defined(__paopaolong__PaoPao__) */

其中用到了自定义的枚举类型PAOPAO_TYPE在GameEnum.h里面,GameEnum.h里面代码如下:

#ifndef paopaolong_GameEnum_h
#define paopaolong_GameEnum_h

enum PAOPAO_TYPE{
    PAOPAO_TYPE_UNKNOW,
    PAOPAO_TYPE1,
    PAOPAO_TYPE2,
    PAOPAO_TYPE3,
    PAOPAO_TYPE4,
    PAOPAO_TYPE5,
    PAOPAO_TYPE6,
    PAOPAO_TYPE7,
    PAOPAO_TYPE8,
};

#endif

PaoPao类的实现代码如下。

#include "PaoPao.h"


PaoPao::PaoPao()//构造函数初始化
{
    _flag = false;
    _type = PAOPAO_TYPE_UNKNOW;
    _isSame = false;
    _isPass = false;
}

PaoPao::~PaoPao()
{
    
}

PaoPao * PaoPao::initWithType(PAOPAO_TYPE type) //根据传过来的类型来生成泡泡
{
    PaoPao *pRet = PaoPao::create();
    if (pRet && pRet->initWithFile(getStringByType(type)->getCString())) //初始化判断
    {
        pRet->setType(type); //初始化成功后,将_type修改成当前的type
    }
    else
    {
        CC_SAFE_RELEASE(pRet);
        pRet = NULL;
    }
    return pRet;
}

CCString * PaoPao::getStringByType(PAOPAO_TYPE type) //不同类型获取不同的图片资源
{
    CCString *pRet = NULL;
    switch (type) {
        case PAOPAO_TYPE1:
        case PAOPAO_TYPE2:
        case PAOPAO_TYPE3:
        case PAOPAO_TYPE4:
        case PAOPAO_TYPE5:
        case PAOPAO_TYPE6:
        case PAOPAO_TYPE7:
        {
            pRet = CCString::createWithFormat("%d.png", static_cast<int>(type));
        }
            break;
            
        default:
            break;
    }
    return pRet;
}

现在这些只是实现了泡泡的基础,我们可以通过调用initWithType静态函数来得到想要的泡泡,接下来将会写主要的scene了,我的逻辑判断最后也是在scene里面写的,还没有很好的学会用MVC框架,所以代码质量不是很好,见谅下。

对于泡泡龙游戏来说主要的就是上面显示的泡泡,并且要错开的放置就会用到PaoPao类里面的_flag,在下面就是需要显示即将被使用到的泡泡和一个正在等待发射的泡泡,我采用了一个二维数组存放上面的泡泡,一个数组存放即将被使用的泡泡和一个变量存放等待发射的泡泡。对于在上方的泡泡来说我们需要知道他们每个泡泡的位置,也就是说我们可以通过行列和_flag来计算出它现在的position,MainLayer.h的代码如下。

#ifndef __paopaolong__MainLayer__
#define __paopaolong__MainLayer__

#include "cocos2d.h"
#include "PaoPao.h"
#include "GameConst.h"
USING_NS_CC;

class MainLayer : public CCLayer
{
public:
    // Method 'init' in cocos2d-x returns bool, instead of 'id' in cocos2d-iphone (an object pointer)
    virtual bool init();
    
    // there's no 'id' in cpp, so we recommend to return the class instance pointer
    static cocos2d::CCScene* scene();
    
    bool ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent);
    void ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent);
    
    // preprocessor macro for "static create()" constructor ( node() deprecated )
    CREATE_FUNC(MainLayer);
    virtual void update(float fDelta);
private:
    
    PaoPao *board[MAX_ROWS][MAX_COLS]; //棋盘
    PaoPao *wait[MAX_WAIT_PAOPAO]; //三个泡泡给用户看
    PaoPao *ready; //准备好一个泡泡准备发射
    CCPoint real; //泡泡移动的比例
    //初始化状态
    bool initTheBoard();
    //随机产生一个泡泡
    PaoPao *randomPaoPao();
    //通过行列获取位置
    CCPoint getPointByRowAndCol(int row, int col, bool flag);
    //初始化等待的泡泡
    void initWaitPaoPao();
    //初始化准备发射的泡泡
    void initReadyPaoPao();
    //触屏启动
    void setEnable();
    //触屏失效
    void setDisable();
    //检验发射泡泡是否碰撞到边界
    bool isCollideBorder();
};

#endif /* defined(__paopaolong__MainLayer__) */

其中有很多使用到了宏定义,宏定义是为了方便修改,因为很多数据重复使用,为了修改统一所以使用宏定义较好,宏定义是在GameConst.h里面的,GameConst.h里面代码如下:
#ifndef paopaolong_GameConst_h
#define paopaolong_GameConst_h

#define MAX_COLS 10
#define MAX_ROWS 20

#define MAX_WAIT_PAOPAO 4

#define READY_PAOPAO_POS ccp(320, 75)

#define PAOPAO_SPEED 30.0


#endif
现在就是MainLayer.cpp了,现在只是为了:一、初始化出所有的数据;二、能够通过点击发射出去泡泡;三、泡泡发射的同时能通过墙壁反射。先上代码:

#include "MainLayer.h"
CCScene* MainLayer::scene()
{
    // 'scene' is an autorelease object
    CCScene *scene = CCScene::create();
    
    // 'layer' is an autorelease object
    MainLayer *layer = MainLayer::create();
    
    // add layer as a child to scene
    scene->addChild(layer);
    
    // return the scene
    return scene;
}

// on "init" you need to initialize your instance
bool MainLayer::init()
{
    //
    // 1. super init first
    if ( !CCLayer::init() )
    {
        return false;
    }
    srand(time(NULL));
    // 设置背景
    CCSprite *background = CCSprite::create("back.png");
    background->setAnchorPoint(CCPointZero);
    background->setPosition(CCPointZero);
    this->addChild(background);
    
    initTheBoard();
    
    //创建两组泡泡,一组为给用户看的,一个是准备发射的
    initWaitPaoPao();
    initReadyPaoPao();
    
    this->setEnable();

    return true;
}

//初始化上方的泡泡数组
bool MainLayer::initTheBoard()
{
    bool bRet = false;
    //初始化为空
    for (int i = 0; i < MAX_ROWS; ++ i)
    {
        for (int j = 0; j < MAX_COLS; ++ j)
        {
            board[i][j] = NULL;
        }
    }
    
    //假定初始化三行
    for (int i = 0; i < 3; ++ i)
    {
        for (int j = 0; j < MAX_COLS; ++ j)
        {
            PaoPao * obj = randomPaoPao();
            obj->setFlag(i % 2 == 0);
            obj->setPosition(getPointByRowAndCol(i, j, obj->getFlag()));
            this->addChild(obj);
            board[i][j] = obj;
        }
    }
    return bRet;
}

//随机产生一个泡泡
PaoPao * MainLayer::randomPaoPao()
{
    PaoPao *pRet = NULL;
    PAOPAO_TYPE type = static_cast<PAOPAO_TYPE>(rand() % 7 + 1);
    pRet = PaoPao::initWithType(type);
    return pRet;
}

//通过行列获取位置
CCPoint MainLayer::getPointByRowAndCol(int row, int col, bool flag)
{
    CCSize winSize = CCDirector::sharedDirector()->getWinSize();
    CCPoint pos = ccp(col * 60 + 30 + (flag ? 0 : 30), winSize.height - row * 60 - 30);
    return pos;
}
//初始化等待被使用的泡泡
void MainLayer::initWaitPaoPao()
{
    for(int i = 0; i < MAX_WAIT_PAOPAO; ++ i)
    {
        PaoPao *obj = randomPaoPao();
        obj->setPosition(ccp(400 + i * 60, 30));
        wait[i] = obj;
        this->addChild(obj);
    }
}
//初始化正在被使用的泡泡
void MainLayer::initReadyPaoPao()
{
    ready = randomPaoPao();
    ready->setPosition(READY_PAOPAO_POS);
    this->addChild(ready);
}

bool MainLayer::ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent)
{
    return true;
}
void MainLayer::ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent)
{
    CCPoint pos = pTouch->getLocation(); //获取当前点击的位置
    this->real = ccpNormalize(ccpSub(pos, ready->getPosition())); //将发射的距离进行换算,为了方便每次update的移动
    setDisable(); //设置触屏失效
    this->scheduleUpdate();//启动update定时任务
}

void MainLayer::setEnable()//设置触屏可以使用
{
    CCDirector::sharedDirector()->getTouchDispatcher()->addTargetedDelegate(this,0,true);
}

void MainLayer::setDisable()//设置触屏失效
{
    CCDirector::sharedDirector()->getTouchDispatcher()->removeDelegate(this);
}

void MainLayer::update(float fDelta) //update函数
{
    if (isCollideBorder()) //先判断是否碰撞
    {
        real.x = -real.x; //如果碰撞就需要反方向移动
    }
    CCPoint pos = ready->getPosition(); //获取当前发射的泡泡的位置
    ready->setPosition(ccp(pos.x + real.x * PAOPAO_SPEED, pos.y + real.y * PAOPAO_SPEED)); //设置泡泡的位置
}

//判断是否碰撞到墙壁了
bool MainLayer::isCollideBorder()
{
    bool bRet = false;
    CCSize size = CCDirector::sharedDirector()->getWinSize();
    CCPoint pos = ready->getPosition();
    CCSize content = ready->getContentSize();
    if(pos.x + content.width / 2 > size.width || pos.x - content.width / 2 < 0)
    {
        bRet = true;
    }
    return bRet;
}

我先假设初始化三个行,其中泡泡都是通过randomPaoPao函数,发射之前是响应触屏的,在发射完后就是每次update里面移动位置,当发现碰撞后就直接反方向运动,其中用到了ccpNormalize,这是直接把两个坐标点的位置经过换算成一个直角三角形的直角两条边那种。

其中x * x + y * y = 1。

源码地址VS版源码源码是完整的。

欢迎大家光临,再过段时间去写第二章,也是重点的泡泡的位置如何停,以及判断哪些泡泡是需要消除的,哪些泡泡是需要掉落的。


  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
### 回答1: cocos2d-x是一款流行的开源游戏引擎,它可以用作开发本地移动游戏和桌面游戏。利用cocos2d-x游戏源码,开发人员可以快速构建流畅、高效、具有吸引力的游戏。该引擎使用C ++语言和脚本语言Lua来实现游戏开发,用户可以根据自己的需要进行选择。 cocos2d-x游戏源码包含许多强大的功能和工具,例如精灵、动画、场景管理、碰撞检测和音频控制等。通过这些功能,开发人员可以方便地创建各种类型的游戏,例如动作游戏、射击游戏、冒险游戏和益智游戏等。 此外,cocos2d-x游戏源码还具有高度定制化的特性,允许开发人员根据他们的需求自定义游戏元素。这种定制化可以通过改进游戏画面,添加新的模式和关卡,甚至整个新的游戏玩法来完成。 总之,cocos2d-x游戏源码是一款功能强大、易于使用和高度定制的游戏引擎,它可以帮助开发人员快速开发各种类型的游戏。无论你是专业开发人员还是无经验的游戏制作者,cocos2d-x都是一个极好的选择。 ### 回答2: Cocos2d-x游戏源码是使用Cocos2d-x引擎进行开发的游戏程序代码。Cocos2d-x引擎是一个开源的跨平台游戏引擎,可以支持iOS、Android、Windows Phone、Windows、MacOS和Linux等多个平台,并且提供了丰富的游戏开发API和工具集。Cocos2d-x游戏源码包含了游戏的核心逻辑、UI设计、动画效果、音频效果等各方面的代码,可以作为开发者学习和借鉴的重要资料。 由于Cocos2d-x引擎支持多种编程语言(如C++、Lua等),因此Cocos2d-x游戏源码也会有对应的编程语言版本。开发者可以通过阅读Cocos2d-x游戏源码,了解游戏开发过程中的技术细节,学习如何使用Cocos2d-x引擎进行游戏开发。同时,开发者也可以通过对Cocos2d-x游戏源码进行修改和优化,来满足游戏的特定需求,提升游戏的性能和用户体验。 总之,Cocos2d-x游戏源码是游戏开发者必备的重要资源,可以帮助开发者更好地了解游戏开发技术,提升游戏开发水平。 ### 回答3: cocos2d-x是一款优秀的游戏开发引擎,其源码包含了许多功能强大的游戏开发工具和API。使用cocos2d-x可以帮助开发者更快速更高效地开发出优秀的游戏作品。 cocos2d-x游戏源码非常丰富,其包含了许多不同类型的游戏示例和模板,如平面射击、塔防、解谜等,这些示例可以帮助开发者更好地了解cocos2d-x的使用方法和原理。 cocos2d-x的源码还包含了许多强大的API和工具,例如场景管理、动画控制、音频引擎等,这些工具和API能够帮助开发者更好地完成游戏的开发和调试。 此外,cocos2d-x的源码还提供了完整的游戏开发框架,包括资源管理、内存管理、事件机制等,这些框架可以帮助开发者更好地组织代码和提高代码的可维护性。 总的来说,cocos2d-x游戏源码提供了丰富的工具和API,可以帮助开发者更高效地进行游戏开发,大大降低了开发难度和成本,是一款非常适合游戏开发者使用的引擎。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值