zoukankan      html  css  js  c++  java
  • cocos2d-x for android:SimpleGame分析

    cocos2d-x for android:SimpleGame分析

    作为cocos2d-x的标配DEMO,SimpleGame可算是给入门学cocos2d-x的俺们这些新手门学习的对象了,那么来分析分析,把几个关键的代码记录下来。

    设置游戏读取资源的目录

    CCFileUtils::sharedFileUtils()->setResourceDirectory("sd");

    默认路径是Resource目录

    设置游戏的分辨率大小

    CCEGLView::sharedOpenGLView()->setDesignResolutionSize(480, 320, kResolutionNoBorder);

    也可以不设置,自动去获取

    创建精灵

    复制代码
    CCSprite *player=CCSprite::create("Player.png",CCRectMake(0,0,27,40));
    player->setPosition(ccp(
    origin.x+player->getContentSize().width/2, //X轴为:0+游戏角色的宽度/2
    winVisibleSize.height/2 + player->getContentSize().height/2) //y轴为:指定的屏幕分辨率/2+游戏角色的高/2
    );
    this->addChild(player);
    复制代码

    如果你希望精灵在图层初始化的时候就产生,那么精灵的创建最好把它放在于图层(CCLayer)的init函数中。

    创建精灵时,需要为精灵指定位置(position),可接收的参数是CCPoint类型,CCPoint 是一个存放x、y轴数据的对象

    使用时间选择器刷新游戏

    this->schedule(schedule_selector(HelloWorld::gameLogic),1.0);

    调用CCNodes的schedule(SEL_SCHEDULE selector, float interval)方法,这是一个自定义的时间选择器,以秒为单位。这里以秒为单位,每秒产生一个怪物

    设置可接受触摸(Touch)事件

    在场景初始化时,设置可接受触摸

    this->setTouchEnabled(true);

    然后,注册一个触摸事件的分发函数

    void HelloWorld::registerWithTouchDispatcher(){
    CCDirector::sharedDirector()->getTouchDispatcher()->addStandardDelegate(this,0);
    }

    通过以上的做法,游戏即可在ccTouchesEnded回调函数里面得到触摸反馈。

    移动精灵

    上面每一秒钟刷新游戏,产生一个游戏怪物,方法位于HelloWold::addTarget,移动精灵的代码是

    复制代码
    CCFiniteTimeAction* actionMove = CCMoveTo::create( (float)actualDuration,
    ccp(0 - target->getContentSize().width/2, actualY) );
    CCFiniteTimeAction* actionMoveDone = CCCallFuncN::create( this,
    callfuncN_selector(HelloWorld::spriteMoveFinished));
    target->runAction( CCSequence::create(actionMove, actionMoveDone, NULL) );
    复制代码

    actionMove:设置精灵移动方向和移动速度

    actionMoveDone:精灵移动完成后执行可执行的回调函数为 spriteMoveFinished,当游戏移动到屏幕边界外,即回收该对象

    然后通过精灵的runAction设置,精灵移动

    上面代码,怪物的产生位置定在x的最右边,move方向从右到左到消息,需要设置x轴的最小值并且完全可以将怪物移动出屏幕即可,故x轴这里设置移动代码: (0 - target->getContentSize().width/2 ),y轴不变,随机从出来那一刻起一直不变做横向移动。

    控制游戏角色发射飞镖

    上面有提到设置图层可授受触摸 ,接下来我们要通过触摸让游戏主角发射飞镖消灭不断产生的怪物。代码见下方

    得到触摸点坐标

    CCTouch* touch = (CCTouch*)( touches->anyObject() );
    CCPoint location = touch->getLocation();

    每接受触摸一次产生一个飞镖

    复制代码

    CCSize winSize = CCDirector::sharedDirector()->getVisibleSize();

    CCSprite *projectile = CCSprite::create("Projectile.png", CCRectMake(0, 0, 20, 20));
    projectile->setPosition( ccp(20, winSize.height/2+projectile->getContentSize().height/2) );//角色x轴为0+角色的宽度,故飞镖的x轴应和角色有交接,使用户看起来飞镖是从角色身上发出来的
    复制代码

    飞镖移动方向

    复制代码
    float offX=location.x - projectile->getPosition().x;
    float offY=location.y - projectile->getPosition().y;

    if(offX <=0)return;

    this->addChild(projectile);

    float realX=winSize.width+(projectile->getContentSize().width/2);//飞镖的横向方向跟游戏怪物一样,也是要移动出游戏界面并回收的(如果碰到怪物也要回收)
    float ratio = offY/offX;//偏移量
    float realY=(realX*ratio)+projectile->getPosition().y;//飞镖的竖向方向应是飞镖的横向方向*触摸点的偏移量每帧偏移的数值+当前飞镖所在位置的y轴
    CCPoint realDest =ccp(realX,realY);
    复制代码

    控制飞镖移动

    projectile->runAction(CCSequence::create(
    CCMoveTo::create(1.0,realDest),//参数1.移动速度。参数2.移动的x、y轴
    CCCallFuncN::create(this,callfuncN_selector(HelloWorld::spriteMoveFinished)),//设置回调函数
    NULL
    ));

    飞镖与怪物的碰撞检测

    这里需要在图层初始化的时候设置一个时间选择器,监听每帧的游戏变化

    this->schedule(schedule_selector(HelloWorld::updateGame));

    这时委托函数updateGame就启到每帧监听的作用了,代码如下

    复制代码
    void HelloWorld::updateGame(float dt){
    CCArray *projectileToDelete =new CCArray;
    CCObject* it=NULL;
    CCObject* jt = NULL;
    CCARRAY_FOREACH(_projectiles,it){ //循环每一个飞镖
    CCSprite *projectile=dynamic_cast<CCSprite*>(it);
    CCRect projectileRect =CCRectMake(
    projectile->getPosition().x - (projectile->getContentSize().width/2),
    projectile->getPosition().y-(projectile->getContentSize().height/2),
    projectile->getContentSize().width,
    projectile->getContentSize().height);

    CCArray* targetsToDelete=new CCArray;

    CCARRAY_FOREACH(_targets, jt)//循环每一个敌人
    {
    CCSprite *target = dynamic_cast<CCSprite*>(jt);

    CCRect targetRect = CCRectMake(
    target->getPosition().x - (target->getContentSize().width/2),
    target->getPosition().y - (target->getContentSize().height/2),
    target->getContentSize().width,
    target->getContentSize().height);
    if (projectileRect.intersectsRect(targetRect)) //这里做矩形交集检测,如果两者有产生交集则将需要删除的敌人存放于数组里面
    {
    targetsToDelete->addObject(target);
    }
    }

    CCARRAY_FOREACH(targetsToDelete, jt)//循环需要删除的敌人
    {
    CCSprite *target = dynamic_cast<CCSprite*>(jt);
    _targets->removeObject(target); //将敌人从产生的敌人数组里面删除
    this->removeChild(target, true);//从图层删除

    _projectilesDestroyed++; //累积
    if (_projectilesDestroyed >= 10) //当满足消灭一定数量的敌人时,则执行游戏场景切换或者什么的blablabla
    {
    ///
    }
    }
    if(targetsToDelete->count() > 0){ //如果有存在需要删除的敌人,则同时将与敌人交集的飞镖存入需要删除的飞镖数组
    projectileToDelete->addObject(projectile);
    }
    targetsToDelete->release();
    }

    //remove projectile
    CCARRAY_FOREACH(projectileToDelete,it){ //最后循环飞镖将飞镖删除掉
    CCSprite *projectile =dynamic_cast<CCSprite*>(it);
    _projectiles->removeObject(projectile);
    this->removeChild(projectile,true);
    }
    projectileToDelete->release();
    //end
    }
    复制代码

    根据上面,逻辑并不复杂,注意一下当前飞镖与敌人数组之间的关系即可。

    播放游戏音效

    无论是游戏背景音效也好,忍者发射飞镖那一刹那时的声音也好,好的游戏都要加上特殊的音效效果才能使游戏更加引人入胜。 cocos2d-x游戏引擎当然也有相关的音乐播放接口。从网上找到的一段话:

    cocos2d-iphone里包含cocosDenshion库,里面从底到高提供三层接口:CDSoundEngine->CDAudioManager->SimpleAudioEngine,但整个库完全依赖于OpenAL来实现。关于OpenAL,它不是Khronos Group的标准,而是Creative公司的一个开源库,可以软实现或硬件实现。目前硬件实现了OpenAL的好像就只有苹果的产品,因此在其他平台上,我们无法提供cocosDenshion底层的支持,但我们是支持顶层的,它是开发者最常用到的一层。

    那么如何添加音效呢?

    添加背景音

    CocosDenshion::SimpleAudioEngine::sharedEngine()->playBackgroundMusic("background-music-aac.wav",true);//设置背景音循环

    添加发射飞镖音效

    CocosDenshion::SimpleAudioEngine::sharedEngine()->playEffect("pew-pew-lei.wav",false);

    这里发射飞镖音效需要注意一个问题就是,如果这样写在Touch里面,第一次让音效播放是无效的,原因是播放音效需要预加载,不然第一次点击是不会出声音的,之后才会。不知道这是引擎硬性要求的么?解决办法是在图层初始化的时候让音效预加载一次

    CocosDenshion::SimpleAudioEngine::sharedEngine()->preloadEffect("pew-pew-lei.wav");

    关于场景切换

    觉得这方面没什么要说的,该说的网上都有,尤其是nowpaper 这篇文章 ,讲得很形象,可以去看看。

    SimpleGame里面的场景切换类,对应是GameOverScene.cpp,该文件是判断游戏结束时,切换到该界面提示用户失败或者成功。这里有一点需要特点注意的是

    GameOverScene *gameOverScene=GameOverScene::create();

    gameOverScene->getLayer()->getLabel()->setString("you win!!!");
    CCDirector::sharedDirector()->replaceScene(gameOverScene);

    上面红色代码这块,比较难懂,这句话可以这么理解:通过GameOverScene头文件中的CC_SYNTHESIZE_READONLY宏定义生成getLayer方法,该方法返回GameOverLayer类型,然后再通过CC_SYNTHESIZE_READONLY 宏定义生成getLabel方法,返回cocos2d::CCLabelTTF类型,最后调用CCLabelTTF成员里面的setString ,该_label在初始化GameOverLayer的时候就己经this->addChild(_label) ,会不会这样就相当于传参数到另一个CCScene呢?呵呵!

    宏定义代码如下:

    #define CC_SYNTHESIZE_READONLY(varType, varName, funName)
    protected: varType varName;

    public: virtual varType get##funName(void) const { return varName; } //这里组合得到方法名和返回类型
    来源:http://www.cnblogs.com/TerryBlog/archive/2012/10/30/2746150.html

  • 相关阅读:
    JAVA基础——编程练习(二)
    JAVA基础——面向对象三大特性:封装、继承、多态
    JVM内存
    50. Pow(x, n) (JAVA)
    47. Permutations II (JAVA)
    46. Permutations (JAVA)
    45. Jump Game II (JAVA)
    43. Multiply Strings (JAVA)
    42. Trapping Rain Water (JAVA)
    41. First Missing Positive (JAVA)
  • 原文地址:https://www.cnblogs.com/zhusd/p/3165114.html
Copyright © 2011-2022 走看看