Cocos2dx入门小游戏---Runner教程

来源:互联网 发布:淘宝破损补寄怎么设置 编辑:程序博客网 时间:2024/06/11 08:40

本人初学cocos2dx,网上找了个例子,写一遍,自己领悟一翻,现在把自己的理解配上注释,

一步步深入理解这个小程序,希望可以帮助初始入门的朋友们。

首先建立一个Entity实体类,以便怪物类和玩家类可以继承:#include "cocos2d.h"/** * @brief 精灵实体类 * * 绑定精灵、获取精灵 */class Entity : public cocos2d::CCNode {public:    /** @{     * @name 构造函数、析构函数、     */        /// 构造函数    Entity();        /// 析构函数    virtual ~Entity();        /** @}     */        /** @{     * @name getter、setter方法     */        /**     * @brief 获取精灵     */    cocos2d::CCSprite *getSprite();        /**     * @brief 绑定精灵     */    void setSprite(cocos2d::CCSprite *pSprite);        /** @}     */    private:    cocos2d::CCSprite *m_pSprite; ///< 精灵对象};


#include "Entity.h"USING_NS_CC;Entity::Entity() : CCNode(), m_pSprite(NULL) {    return;}Entity::~Entity() {    // 使用自带的宏,方便安全    CC_SAFE_RELEASE_NULL(m_pSprite);    return;}CCSprite *Entity::getSprite() {    return m_pSprite;}void Entity::setSprite(cocos2d::CCSprite *pSprite) {    this->m_pSprite = pSprite;    CC_SAFE_RETAIN(this->m_pSprite); // 防止被释放        this->addChild(m_pSprite);    return;}


接下来,先创建一个有特效效果的文本显示类:

/** * @brief 文字飘动特效效果类 */class FlowTextLabel : public cocos2d::CCNode {public:    /**      * 构造函数      */    FlowTextLabel();        /**     * 析构函数     */    virtual ~FlowTextLabel();        /**     * 初始化函数     */    virtual bool init();        /**     * 创建FlowTextLabel对象,自动释放对象     */    CREATE_FUNC(FlowTextLabel);        /**     * @brief 显示文本     * @param pText 文本     * @param pos 显示的位置     */    void showText(const char *pText, cocos2d::CCPoint pos);        /**     * @brief 隐藏文本     */    void hideText();    private:    cocos2d::CCLabelTTF *m_pText; ///< 文本文字};

#include "FlowTextLabel.h"USING_NS_CC;FlowTextLabel::FlowTextLabel() : m_pText(NULL) {    CCNode::CCNode();    return;}FlowTextLabel::~FlowTextLabel() {    CC_SAFE_RELEASE_NULL(m_pText);    CCNode::~CCNode();    return;}bool FlowTextLabel::init() {    bool bRet = false;    do {        CC_BREAK_IF(!CCNode::init());                m_pText = CCLabelTTF::create("", "Arial", 30);        CC_BREAK_IF(!m_pText);                m_pText->setColor(ccc3(255, 0, 0));        m_pText->setVisible(false);        this->addChild(m_pText);                bRet = true;    } while (0);        return bRet;}void FlowTextLabel::showText(const char *pText, CCPoint pos) {    m_pText->setString(pText);    m_pText->setPosition(pos);    m_pText->setVisible(true);    m_pText->setAnchorPoint(ccp(1, 0));        // 先放大后缩小效果    CCScaleTo *pScaleLarge = CCScaleTo::create(0.3f, 2.5f, 2.5f);    CCScaleTo *pScaleSmall = CCScaleTo::create(0.4f, 0.5f, 0.5f);    // 动作回调    CCCallFunc *pCallFunc = CCCallFunc::create(this, callfunc_selector(FlowTextLabel::hideText));    CCActionInterval *pActions = CCSequence::create(pScaleLarge, pScaleSmall, pCallFunc, NULL);    this->runAction(pActions);    return;}void FlowTextLabel::hideText() {    m_pText->setVisible(false);    // 从父节点移除,并移除节点的动作和回调函数    m_pText->removeFromParentAndCleanup(true);    return;}


接下来,创建一个继承于Entity的类,也就是玩家类:

#include "cocos2d.h"#include "Entity.h"/** * @brief 玩家类 * 玩家动作:跳、受到攻击攻击伤害、吃掉金币 */class Player : public Entity {public:    ///    /// 构造函数、析构函数、初始化函数、创建玩家函数    Player();    virtual ~Player();    virtual bool init();    CREATE_FUNC(Player);    /**     * @brief 玩家跳起     */    void jumpBegin();        /**     * @brief 玩家跳完毕     */    void jumpEnd();        /**     * @brief 玩家与怪物碰撞(玩家受到攻击伤害)     */    void hit();        /**     * @brief 获取得到的金币     */    int getMoney();        /**     * @brief 获取碰撞范围     */    cocos2d::CCRect getBoundingBox();        /**     * @brief 恢复数据到原始状态     */    void resetDataToNormal();        /**     * @brief 动作结束     */    void actionEnd();    private:    bool m_bIsJumping; ///< 玩家是否正处于跳起状态    int m_nMoney;      ///< 玩家获取的金币};

#include "Player.h"#include "FlowTextLabel.h"#include "SimpleAudioEngine.h"USING_NS_CC;using namespace CocosDenshion;Player::Player() : Entity(), m_bIsJumping(false), m_nMoney(0) {    return;}Player::~Player() {    return;}bool Player::init() {    return true;}void Player::jumpBegin() {    // 如果没有玩家或者如果玩家还在跳跃中,则不重复跳跃    if (!getSprite() || m_bIsJumping) {        return;    }        m_bIsJumping = true;        // 创建动作    // 1.秒内跳起200高度,只跳一次    CCJumpBy *pJumpBy = CCJumpBy::create(1.0f, ccp(50, 0), 200, 1);    // 这种也算是一种动作吧    CCCallFunc *pCallFunc = CCCallFunc::create(this, callfunc_selector(Player::jumpEnd));    // 瞬时动作    CCActionInterval *pJumpActions = CCSequence::create(pJumpBy, pCallFunc, NULL);    this->runAction(pJumpActions);    return;}void Player::jumpEnd() {    m_bIsJumping = false;    return;}void Player::hit() {    do {        CC_BREAK_IF(!getSprite());                // 获取金币特效提示        FlowTextLabel *pFlowLabel = FlowTextLabel::create();        CC_BREAK_IF(!pFlowLabel);        this->addChild(pFlowLabel);        pFlowLabel->showText("+15", getSprite()->getPosition());                m_nMoney += 15;                // 创建4种动作对象        // 0.1秒内,x轴方向向左移动20,y方向不变        CCMoveBy *pBackMoveBy = CCMoveBy::create(0.1, ccp(-20, 0));        // 0.1秒内,x轴方向右向移动20,y方向不变        CCMoveBy *pForwardMoveBy = CCMoveBy::create(0.1, ccp(20, 0));        // 0.1秒内,x方向逆时间旋转5度,y方向顺时间旋转0度        CCRotateBy *pBackRotateBy = CCRotateBy::create(0.1, -5.0, 0);        // 0.1秒内,x方向顺时针旋转5度,y方向不变        CCRotateBy *pForwardRotateBy = CCRotateBy::create(0.1, 5.0, 0);                // 创建并行动作        // 过程为:玩家0.1秒内先后退内20宽度,并0.1秒内逆时针旋转5度        //        再0.1秒内向前移动20宽度,并0.1秒内顺时针旋转5度,回复到原来的状态        CCSpawn *pBackActions = CCSpawn::create(pBackMoveBy, pBackRotateBy, NULL);        CCSpawn *pForwardActions = CCSpawn::create(pForwardMoveBy, pForwardRotateBy, NULL);                // 动作执行完毕时的回调        CCCallFunc *pCallFunc = CCCallFunc::create(this, callfunc_selector(Player::actionEnd));        CCActionInterval *pActions = CCSequence::create(pBackActions,                                                        pForwardActions,                                                        pCallFunc,                                                        NULL);        this->runAction(pActions);                SimpleAudioEngine::sharedEngine()->playEffect("hitEffect.wav");    } while (0);    return;}void Player::resetDataToNormal() {    m_bIsJumping = false;        this->setPosition(ccp(200, 500 / 4));    this->setScale(1.0f);    this->setRotation(0);    return;}int Player::getMoney() {    return m_nMoney;}CCRect Player::getBoundingBox() {    CCRect rect = CCRectZero;    do {        CC_BREAK_IF(!getSprite());                // 获取玩家可视范围大小,用于检测玩家的碰撞范围        CCSize spriteSize = getSprite()->getContentSize();        // 获取玩家的中心位置        CCPoint entityPos = this->getPosition();                // 获取玩家左下角x坐标        float leftBottomX = entityPos.x - spriteSize.width / 2;        // 获取玩家左下角y坐标        float leftBottomY = entityPos.y - spriteSize.height / 2;        rect = CCRectMake(leftBottomX, leftBottomY, spriteSize.width, spriteSize.height);            } while (0);    return rect;}void Player::actionEnd() {    this->setScale(1.0f);    this->setRotation(0);    return;}

接下来,创建怪物类:

#include "cocos2d.h"#include "Entity.h"#include "Player.h"/** * @brief 怪物类(也就是金币类),继承于实体类 */class Monster : public Entity {public:    /// 构造函数    Monster();    /// 析构函数    virtual ~Monster();    /// 初始化函数    virtual bool init();    /// 创建怪物对象,自动释放    CREATE_FUNC(Monster);        /**     * @brief 显示怪物(金币)     */    void show();    /**     * @brief 隐藏怪物(金币)     */    void hide();    /**     * @brief 重置怪物数据(金币)     */    void reset();        /**     * @brief 怪物是否活着(金币)     */    bool isAlive();    /**     * @brief 怪物是否与指定玩家对象相碰撞(金币)     * @param pPlayer 玩家对象     */    bool isCollideWithPlayer(Player *pPlayer);    private:    bool m_bIsAlive; ///< 怪物是否还活着};

#include "Monster.h"USING_NS_CC;Monster::Monster() : Entity(), m_bIsAlive(false) {    return;}Monster::~Monster() {    return;}bool Monster::init() {    bool bRet = false;    do {        //                bRet = true;    } while (0);        return bRet;}void Monster::show() {    if (NULL != getSprite()) {        this->setVisible(true);        // 标记为活动状态        m_bIsAlive = true;    }    return;}void Monster::hide() {    do {        CC_BREAK_IF(!getSprite());                this->setVisible(false);        reset();        m_bIsAlive = false;    } while (0);    return;}void Monster::reset() {    do {        CC_BREAK_IF(!getSprite());                // 范围在800 ~ 2000        this->setPosition(ccp(800 + CCRANDOM_0_1() * 2000, 200 - CCRANDOM_0_1() * 100));    } while (0);    return;}bool Monster::isAlive() {    return m_bIsAlive;}bool Monster::isCollideWithPlayer(Player *pPlayer) {    bool bRet = false;    do {        CC_BREAK_IF(!pPlayer);                // 获取玩家碰撞范围        CCRect rect = pPlayer->getBoundingBox();        // 获取怪物(金币)的中心位置        CCPoint monsterPos = this->getPosition();                bRet = rect.containsPoint(monsterPos);    } while (0);    return bRet;}

创建怪物管理类:

#include "cocos2d.h"#include "Player.h"const int g_nMaxMonsterNumber = 10;class MonsterManager : public cocos2d::CCNode {public:    MonsterManager();    virtual ~MonsterManager();    virtual bool init();    CREATE_FUNC(MonsterManager);        // 更新绘制    void update(float delta);        /**     * @brief 设置玩家     * @param pPlayer 玩家对象指针     */    void setPlayer(Player *pPlayer);    private:    /**     * @brief 创建怪物(金币)     */    void createMonsters();    private:    cocos2d::CCArray *m_pArrMonsters; ///< 怪物对象数组    Player *m_pPlayer;                ///< 玩家对象};

#include "MonsterManager.h"#include "Monster.h"USING_NS_CC;MonsterManager::MonsterManager(): CCNode(),  m_pArrMonsters(NULL),  m_pPlayer(NULL) {    return;}MonsterManager::~MonsterManager() {    CC_SAFE_DELETE_ARRAY(m_pArrMonsters);    CC_SAFE_RELEASE_NULL(m_pPlayer);    return;}bool MonsterManager::init() {    bool bRet = false;    do {        createMonsters();        // 启用update        this->scheduleUpdate();                bRet = true;    } while (0);    return bRet;}void MonsterManager::createMonsters() {    m_pArrMonsters = CCArray::create();    CC_SAFE_RETAIN(m_pArrMonsters); // 防止数组被释放        Monster *pMonster = NULL;    CCSprite *pSprite = NULL;        for (int i = 0; i < g_nMaxMonsterNumber; i++) {        pMonster = Monster::create();        CC_BREAK_IF(!pMonster);                pSprite = CCSprite::create("monster.png");        CC_BREAK_IF(!pSprite);                pMonster->setSprite(pSprite);        pMonster->reset();                this->addChild(pMonster); // 将怪物添加到管理器中        m_pArrMonsters->addObject(pMonster);    }    return;}void MonsterManager::update(float delta) {    CCObject *pObject = NULL;    Monster *pMonster = NULL;        CCARRAY_FOREACH(m_pArrMonsters, pObject) {        pMonster = dynamic_cast<Monster *>(pObject);        // 如果怪物是否处于活动状态        if (pMonster->isAlive()) {            // 左移3个宽度            pMonster->setPositionX(pMonster->getPositionX() - 3);            // 若到达屏幕最左,超出屏幕就隐藏            if (pMonster->getPositionX() < 0) {                pMonster->hide();            } else if (pMonster->isCollideWithPlayer(m_pPlayer)) {                m_pPlayer->hit();                pMonster->hide();            }        } else { // 非活动状态            pMonster->show();        }    }    return;}void MonsterManager::setPlayer(Player *pPlayer) {    this->m_pPlayer = pPlayer;    CC_SAFE_RETAIN(m_pPlayer);    return;}

最后,就是需要创建一个游戏场景:

#include "cocos2d.h"#include "Player.h"#include "cocos-ext.h"USING_NS_CC;using namespace extension;/** * @brief 游戏运行场景 */class GameRunningScene : public CCLayer {public:    GameRunningScene();    virtual ~GameRunningScene();    virtual bool init();    static CCScene *scene();    CREATE_FUNC(GameRunningScene);        virtual void update(float delta);    private:    void initBackground();  ///< 初始化关卡背景    void createJumpButton();///< 创建跳跃按钮    void jumpEvent(CCObject *pSender, CCControlEvent event); // 响应点击事件    void createScoreLabel();///< 分数    void createTimeSlider();///< 创建时间条        CCSprite *m_pBgSprite1;         ///< 背景1    CCSprite *m_pBgSprite2;         ///< 背景2        Player *m_pPlayer;              ///< 玩家    CCLabelTTF *m_pScoreLabel;      ///< 分类标签    CCControlSlider *m_pTimeSlider; ///< 时间条        int m_nScore;       ///< 得分    int m_nCurrentTime; ///< 当前时间};

#include "GameRunningScene.h"#include "MonsterManager.h"#include "SimpleAudioEngine.h"using namespace CocosDenshion;GameRunningScene::GameRunningScene(): m_pBgSprite1(NULL),  m_pBgSprite2(NULL),  m_nCurrentTime(0),  m_pTimeSlider(NULL),  m_pPlayer(NULL),  m_pScoreLabel(NULL),  m_nScore(0) {    CCLayer::CCLayer();        return;}GameRunningScene::~GameRunningScene() {    CC_SAFE_RELEASE_NULL(m_pBgSprite1);    CC_SAFE_RELEASE_NULL(m_pBgSprite2);    CC_SAFE_RELEASE_NULL(m_pPlayer);    CC_SAFE_RELEASE_NULL(m_pScoreLabel);    CC_SAFE_RELEASE_NULL(m_pTimeSlider);        CCLayer::~CCLayer();    return;}CCScene *GameRunningScene::scene() {    CCScene *pScene = NULL;    do {        pScene = CCScene::create();        CC_BREAK_IF(!pScene);                GameRunningScene *pLayer = GameRunningScene::create();        CC_BREAK_IF(!pLayer);                pScene->addChild(pLayer, 1);    } while (0);        return pScene;}bool GameRunningScene::init() {    bool bRet = false;    do {        CCSize visibleSize = CCDirector::sharedDirector()->getVisibleSize();                CCSprite *pSprite = CCSprite::create("sprite.png");        m_pPlayer = Player::create();        CC_BREAK_IF(!m_pPlayer);        m_pPlayer->setSprite(pSprite);        m_pPlayer->setPosition(ccp(200, visibleSize.height / 4));        this->addChild(m_pPlayer, 1);                // 初始化背景图片        initBackground();                // 创建按钮        createJumpButton();                // 设置启用CCNode的update函数,游戏会在每一帧调用update函数        this->scheduleUpdate();                // 怪物管理器        MonsterManager *pMonsterManager = MonsterManager::create();        CC_BREAK_IF(!pMonsterManager);        pMonsterManager->setPlayer(m_pPlayer);        this->addChild(pMonsterManager, 4);                // 创建分数标签        createScoreLabel();                // 创建时间条        createTimeSlider();                SimpleAudioEngine::sharedEngine()->playBackgroundMusic("bgMusic.wav", true);                bRet = true;    } while (0);        return bRet;}void GameRunningScene::initBackground() {    CCSize visibleSize = CCDirector::sharedDirector()->getVisibleSize();        m_pBgSprite1 = CCSprite::create("tollgateBG.jpg");    m_pBgSprite1->setPosition(ccp(visibleSize.width / 2, visibleSize.height / 2));    this->addChild(m_pBgSprite1, 0);        m_pBgSprite2 = CCSprite::create("tollgateBG.jpg");    m_pBgSprite2->setPosition(ccp(visibleSize.width / 2 * 3, visibleSize.height / 2));    m_pBgSprite2->setFlipX(true);    this->addChild(m_pBgSprite2, 0);        return;}void GameRunningScene::update(float delta) {    // 地图大小    CCSize mapSize = m_pBgSprite1->getContentSize();        // 地图1和地图2的X坐标    int posX1 = m_pBgSprite1->getPositionX();    int posX2 = m_pBgSprite2->getPositionX();        int nMapScrollSpeed = 5; // 地图滚动的速度    posX1 -= nMapScrollSpeed;    posX2 -= nMapScrollSpeed;        // 创建无限循环    if (posX1 <= -mapSize.width / 2) {        posX1 = mapSize.width + mapSize.width / 2;        posX2 = mapSize.width / 2;    }        if (posX2 <= -mapSize.width / 2) {        posX1 = mapSize.width / 2;        posX2 = mapSize.width + mapSize.width / 2;    }        m_pBgSprite1->setPositionX(posX1);    m_pBgSprite2->setPositionX(posX2);        // 得分    m_nScore = m_pPlayer->getMoney();    m_pScoreLabel->setString(CCString::createWithFormat("Score: %d", m_nScore)->getCString());    m_pTimeSlider->setValue(--m_nCurrentTime);        return;}void GameRunningScene::createJumpButton() {    CCSize visibleSize = CCDirector::sharedDirector()->getVisibleSize();        do {        // 按钮标题        CCLabelTTF *pJumpLabel = CCLabelTTF::create("Jump", "Arial", 35);        CC_BREAK_IF(!pJumpLabel);                // 按钮状态图片        CCScale9Sprite *pJumpNormalSprite = CCScale9Sprite::create("button.png");        CC_BREAK_IF(!pJumpNormalSprite);                CCScale9Sprite *pJumpLightSprite = CCScale9Sprite::create("buttonHighlighted.png");        CC_BREAK_IF(!pJumpLightSprite);                // 创建按钮        CCControlButton *pJumpButton = CCControlButton::create(pJumpLabel, pJumpNormalSprite);        CC_BREAK_IF(!pJumpButton);                pJumpButton->setPosition(visibleSize.width - 80, 50);        pJumpButton->setBackgroundSpriteForState(pJumpLightSprite, CCControlStateHighlighted);        pJumpButton->addTargetWithActionForControlEvents(this,                                                         cccontrol_selector(GameRunningScene::jumpEvent),                                                         CCControlEventTouchDown);        this->addChild(pJumpButton);    } while (0);        return;}void GameRunningScene::jumpEvent(cocos2d::CCObject *pSender, CCControlEvent event) {    m_pPlayer->jumpBegin();    return;}void GameRunningScene::createScoreLabel() {    m_nScore = m_pPlayer->getMoney();    CCSize visibleSize = CCDirector::sharedDirector()->getVisibleSize();        m_pScoreLabel = CCLabelTTF::create(              CCString::createWithFormat("Score: %d", m_nScore)->getCString(), "Arial", 35);    m_pScoreLabel->setAnchorPoint(ccp(0, 1));    m_pScoreLabel->setPosition(ccp(0, visibleSize.height));        this->addChild(m_pScoreLabel);    return;}void GameRunningScene::createTimeSlider() {    CCSize visibleSize = CCDirector::sharedDirector()->getVisibleSize();    m_nCurrentTime = 10000;    m_pTimeSlider = CCControlSlider::create(CCSprite::create("background.png"),                                            CCSprite::create("progress.png"),                                            CCSprite::create("sliderThumb.png"));    m_pTimeSlider->setPosition(            ccp(m_pTimeSlider->getContentSize().width / 2,            visibleSize.height - m_pTimeSlider->getContentSize().height - m_pScoreLabel->getContentSize().height            ));    m_pTimeSlider->setTouchEnabled(false);    m_pTimeSlider->setMaximumValue(10000);    m_pTimeSlider->setMinimumValue(0);    m_pTimeSlider->setValue(m_nCurrentTime);    this->addChild(m_pTimeSlider, 3);        return;}



0 0
原创粉丝点击