设为首页 收藏本站
查看: 741|回复: 0

[经验分享] 在Mac OS 下学习 COCOS2D-X

[复制链接]

尚未签到

发表于 2015-12-30 14:12:39 | 显示全部楼层 |阅读模式
  学习的第一个例程来自下面连接
  http://blog.csdn.net/akof1314/article/details/8268882
  
  系统版本: Mac OS MotainLion 10.8.2+XCode 4.6 4H127+ cocos2d-x 2.04版
  
  
  1.打开XCODE
  新建一个COCOS2D-X工程,如图所示.与在WIN下不同的是 这里没有 Box2D选项
  2.编译运行,如图所示:
  
  3.下载游戏所需要的资源,链接如下:
  链接来源:
  http://www.raywenderlich.com/25736/how-to-make-a-simple-iphone-game-with-cocos2d-2-x-tutorial
  资源链接:
  http://cdn3.raywenderlich.com/downloads/Cocos2DSimpleGameResourcePack.zip
  资源文件有两个文件夹,Art  和 Sounds,将资源拖入工程的 Resources 中
  4.现在需要的文件已经准备就绪,开始这个简单的游戏.
  
  首先,游戏需要一个白色背景,使用 CCLayerColor 来实现,将HelloWorldScene.h文件"HelloWorld"类改为如下:



class HelloWorld : public cocos2d::CCLayerColor
  
  并且需要在 HelloWorldScene.cpp 文件的init函数中设置背景色(红色语句):
  在变更类为CCLayerColor之后,如果不设置背景,似乎并不能执行下去.
  之前在Visual Studio 2010+ cocos2d-x下也生成过这个HELLOWORD程序,在XCODE下重温的时候,在这里发现了不同.
  VS中init的代码是包含在 do{} while(0) 这段语句中,但是在XCODE中并没有这部分.按下不表,以后再了解.
  



bool HelloWorld::init()
{
//////////////////////////////
    // 1. super init first
if ( !CCLayer::init() )
{
return false;
}
CCLayerColor::initWithColor(ccc4(255,255,255,255));
return true;
}
  
  
  
继续修改init代码,首先添加玩家:完成后的init 代码如下:



    //////////////////////////////
    // 1. super init first
if ( !CCLayer::init() )
{
return false;
}
CCLayerColor::initWithColor(ccc4(255,255,255,255));
//获取屏幕size
CCSize size = CCDirector::sharedDirector()->getWinSize();
//创建一个精灵,加载忍着的图片
CCSprite *player = CCSprite::create("player.png",CCRectMake(0, 0, 27, 70));
//设定精灵的位置为 左边正中间
player->setPosition(ccp(player->getContentSize().width / 2, size.height / 2));
//将精灵加入场景
this->addChild(player);
return true;
  编译运行,可以看到忍者已经显示在白色背景下.
  
  接下来继续添加怪物,并且让怪物可以移动.
  我们在HelloWorld这个类中添加一个方法addMonster,顺便添加一个spriteMoveFinished方法,待会要用到.



  void  spriteMoveFinished(CCNode* pSender);
void addMonster();
  spriteMoveFinished 方法很简单,就是从场景中删除精灵对象.



void  HelloWorld::spriteMoveFinished(CCNode* pSender)
{
CCSprite *sprite = (CCSprite*)pSender;
this->removeChild(sprite, true);
}
  现在继续写addMonster方法代码,完整的代码如下:



void  HelloWorld::addMonster()
{
CCSprite *monster = CCSprite::create("monster.png");
CCSize size = CCDirector::sharedDirector()->getWinSize();
//计算可以显示在屏幕上最上方和最下方的位置
int minY = monster->getContentSize().height / 2;
int maxY = size.height - monster->getContentSize().height / 2;
int rangeY = maxY - minY;
//随机一个出现的位置
int actualY = (rand() % rangeY) + minY;
//设置精灵的位置
monster->setPosition(ccp(size.width + monster->getContentSize().width / 2, actualY));
//将精灵加入场景
this->addChild(monster);
//设定怪物移动速度的最小最大数值,并且在其中取值
int minDuration = 2;
int maxDuration = 4;
int rangeDuration = maxDuration - minDuration;
int actualDuration = (rand() % rangeDuration) + minDuration;
//精灵的移动方式,从右到左移动.
CCMoveTo *actionMove = CCMoveTo::create(actualDuration, ccp(-monster->getContentSize().width / 2, actualY));
//精灵移动完成之后的回调函数,用 CCCallFuncN 定义, 这里是调用之前写的类方法 spriteMoveFinished 删除精灵
CCCallFuncN *actionMoveDone = CCCallFuncN::create(this, callfuncN_selector(HelloWorld::spriteMoveFinished));
//精灵应用动作
monster->runAction(CCSequence::create(actionMove, actionMoveDone, NULL));
}
  CCSequence相当于一个队列,它会按顺序执行里面的所有action,最后一个加NULL。表示到这里就没有了。
  接下来就是定时创建怪物,并且每秒都执行一次,即增加一个怪物.
  首先还是先增加一个 gameLogic 方法



void  HelloWorld::gameLogic(float dt)
{
this->addMonster();
}
  然后在 init 函数返回之前,安装定时器,



this->schedule(schedule_selector(HelloWorld::gameLogic), 1.0);
  
  保存修改,现在运行试试,可以看到怪物在增加,并且以不同的速度从右到左移动.
  
  接着,让忍着可以发射飞镖,当用户在屏幕点击时,让玩家往点击的方向发射飞镖.
  首先,要让层支持触摸,得在 init 中添加如下代码



this->setTouchEnabled(true);
  然后重载 ccTouchesEnabled 方法



virtual void ccTouchesEnded(cocos2d::CCSet* pTouches, cocos2d::CCEvent * pEvent);
  方法实现代码:



void HelloWorld::ccTouchesEnded(cocos2d::CCSet* pTouches, cocos2d::CCEvent * pEvent)
{
//得到触摸点
CCTouch *touch = (CCTouch*)pTouches->anyObject();
CCPoint location = this->convertTouchToNodeSpace(touch);
CCSize size = CCDirector::sharedDirector()->getWinSize();
//创建一个飞镖精灵
CCSprite *projectile = CCSprite::create("projectile.png");
projectile->setPosition(ccp(20, size.height / 2));
CCPoint offset = ccpSub(location, projectile->getPosition());
if (offset.x <= 0) {
return;
}
this->addChild(projectile);
//各种计算
int realX = size.width + projectile->getContentSize().width / 2;
float ratio = (float)offset.y / (float)offset.x;
int realY = realX * ratio + projectile->getPosition().y;
CCPoint realDest = ccp(realX, realY);
int offRealX = realX - projectile->getPosition().x;
int offRealY = realY - projectile->getPosition().y;
//用三角攻击算出飞镖的移动距离
float length = sqrtf(offRealX * offRealX + offRealY * offRealY);
float velocity = 480 / 1;
float realMoveDuration = length / velocity;
//指定飞镖的移动轨迹,为忍着和触摸点之前的一条线,移动距离
//原参考博客的代码合并到一起有点长,我这里分开了.
CCMoveTo *actionMove = CCMoveTo::create(realMoveDuration, realDest);
CCCallFuncN *actionMoveDone = CCCallFuncN::create(this, callfuncN_selector(HelloWorld::spriteMoveFinished));
projectile->runAction(CCSequence::create(actionMove, actionMoveDone, NULL));
}
  完成这些之后,可以稍事休息,运行程序试试.
  在屏幕上点击,可以看到飞镖向点击的位置飞出去了.
  现在飞镖在飞,怪物也在跑,但是还缺少最重要的功能,就是消灭怪物.
  回到XCODE里来.
  在HelloWorldScene.h添加如下声明,用于记录怪物和飞镖



  cocos2d::CCArray *_monsters;
cocos2d::CCArray *_projectiles;
  并且添加构造函数和析构函数,添加如下:



  HelloWorld();
~HelloWorld();
  函数代码如下,分别用户在初始化类和销毁类时初始化数组和释放数组:



HelloWorld::HelloWorld()
{
_monsters = NULL;
_projectiles = NULL;
}
HelloWorld::~HelloWorld()
{
if (_monsters) {
_monsters->release();
_monsters = NULL;
}
if (_projectiles)
{
_projectiles->release();
_projectiles = NULL;
}
}
  
  接下来,在 init 函数中初始化 数组  
  在这里我煩了个错误,红字部分,本来应该是 _projectiles 的,然而我录入的时候没录入正确,以至于在后面的调试不能继续.
  回过头来查找好久终于找到问题所在



  this->_monsters = CCArray::create();
this->_monsters->retain();
this->_projectiles= CCArray::create();
this->_monsters->retain();
  修改 addMonster 函数,为怪物精灵添加标签,并且加入数组,



  monster->setTag(1);
_monsters->addObject(monster);
  同样修改 ccTouchesEnded 函数,为子弹精灵添加标签,并且计入数组.



  projectile->setTag(2);
_projectiles->addObject(projectile);
  修改 spriteMoveFinished 函数,用于移除一个计数



  if (sprite->getTag() == 1) {
_monsters->removeObject(sprite);
}
else if (sprite->getTag() == 2) {
_projectiles->removeObject(sprite);
}
  添加一个update(float dt)方法,用于消除飞镖和怪物



1 void HelloWorld::update(float dt)
2 {
3   CCArray *projectilesToDelete = CCArray::create();
4   CCObject *pObject = NULL;
5   CCObject *pObject2 = NULL;
6   //遍历飞镖精灵
7   CCARRAY_FOREACH(_projectiles, pObject)
8   {
9     CCSprite *projectile = (CCSprite*)pObject;
10     CCArray *monstersToDelete = CCArray::create();
11     //和每一个怪物精灵的边框交叉检测
12     CCARRAY_FOREACH(_monsters, pObject2)
13     {
14       CCSprite *monster = (CCSprite*)pObject2;
15       //如果有重合,代表击中目标,将怪物精灵加入待删除列表
16       //从这里的代码上来看,如果一个飞镖和两个怪物有所碰撞,两只怪物应该是都被消灭
17       if (CCRect::CCRectIntersectsRect(projectile->boundingBox(), monster->boundingBox())) {
18         monstersToDelete->addObject(monster);
19       }
20     }
21     //删除在待删除怪物数组中的怪物
22     CCARRAY_FOREACH(monstersToDelete, pObject2)
23     {
24       CCSprite *monster = (CCSprite*)pObject2;
25       _monsters->removeObject(monster);
26       this->removeChild(monster, true);
27     }
28     //如果
29     if (monstersToDelete->count() > 0) {
30       projectilesToDelete->addObject(projectile);
31     }
32     monstersToDelete->release();
33     
34   }
35   
36   CCARRAY_FOREACH(projectilesToDelete, pObject)
37   {
38     CCSprite *projectile =(CCSprite*)pObject;
39     _projectiles->removeObject(projectile);
40     this->removeChild(projectile, true);
41   }
42   projectilesToDelete->release();
43   
44 }
  根据原微博的评论,修改了Update函数的以下语句,如果使用原语句会提示:'CCRectIntersectsRect' is deprecated



1       if (CCRect::CCRectIntersectsRect(projectile->boundingBox(), monster->boundingBox())) {
2        monstersToDelete->addObject(monster);
3       }
  替换为



      if (projectile->boundingBox().intersectsRect(monster->boundingBox())) {
monstersToDelete->addObject(monster);
}
  
  然后在init函数中安装定时器



1 this->schedule(schedule_selector(HelloWorld::update));
  在ccTouchesEnded函数,添加子弹音效,代码如下:



1 CocosDenshion::SimpleAudioEngine::sharedEngine()->playEffect("pew-pew-lei.caf");
  添加音效,在init函数添加背景音乐,代码如下:



1 CocosDenshion::SimpleAudioEngine::sharedEngine()->playBackgroundMusic("background-music-aac.caf");
  现在运行游戏,已经可以,点击模拟器屏幕,已经可以发射飞镖和消灭怪物.
  并且还有动感的音乐.
  再坚持一下,还有最后一步了,加入一个新的场景,用于显示游戏失败.
  添加新的C++ Class 文件,输入文件名GameOverLayer确定.
  就新增了GameOverLayer.cpp 和 GameOverLayer.h文件
  修改 GameOverLayer.h 如下:
  



#ifndef __simpleGame__GameOverLayer__
#define __simpleGame__GameOverLayer__
#include "cocos2d.h"
class GameOverLayer : public cocos2d::CCLayerColor
{
public:
GameOverLayer(void);
~GameOverLayer(void);
bool initWithWon(bool won);
static cocos2d::CCScene* seneWithWon(bool won);
static GameOverLayer* createWithWon(bool won);
void gameoverDone();
}

#endif /* defined(__simpleGame__GameOverLayer__) */
  修改.cpp文件如下



1 #include "GameOverLayer.h"
2 #include "HelloWorldScene.h"
3 using namespace cocos2d;
4
5 GameOverLayer::GameOverLayer(void)
6 {
7 }
8
9 GameOverLayer::~GameOverLayer(void)
10 {
11 }
12
13 GameOverLayer* GameOverLayer::createWithWon(bool won)
14 {
15   GameOverLayer *pRet = new GameOverLayer();
16   if (pRet && pRet->initWithWon(won))
17   {
18     pRet->autorelease();
19     return pRet;
20   }
21   else
22   {
23     CC_SAFE_DELETE(pRet);
24     return NULL;
25   }
26 }
27
28 bool GameOverLayer::initWithWon(bool won)
29 {
30   bool bRet = false;
31   do
32   {
33     CC_BREAK_IF(! CCLayerColor::initWithColor(ccc4(255, 255, 255, 255)));
34     
35     char *message;
36     if (won)
37     {
38       message = "You Won!";
39     }
40     else
41     {
42       message = "You Lose :[";
43     }
44     
45     CCSize winSize = CCDirector::sharedDirector()->getWinSize();
46     CCLabelTTF *label = CCLabelTTF::create(message, "Arial", 32);
47     label->setColor(ccc3(0, 0, 0));
48     label->setPosition(ccp(winSize.width / 2, winSize.height / 2));
49     this->addChild(label);
50     
51     this->runAction(CCSequence::create(CCDelayTime::create(3),
52                                        CCCallFunc::create(this, callfunc_selector(GameOverLayer::gameOverDone)),
53                                        NULL));
54     
55     bRet = true;
56   } while (0);
57   
58   return bRet;
59 }
60
61 cocos2d::CCScene* GameOverLayer::sceneWithWon(bool won)
62 {
63   CCScene * scene = NULL;
64   do
65   {
66     scene = CCScene::create();
67     CC_BREAK_IF(! scene);
68     
69     GameOverLayer *layer = GameOverLayer::createWithWon(won);
70     CC_BREAK_IF(! layer);
71     
72     scene->addChild(layer);
73   } while (0);
74   
75   return scene;
76 }
77
78 void GameOverLayer::gameOverDone()
79 {
80   CCDirector::sharedDirector()->replaceScene(HelloWorld::scene());
81 }
  
  这里我暂时先直接拷贝贴过来.
  14.最后,为游戏添加一些游戏逻辑。记录玩家消灭怪物的数量,进而决定该玩家输赢。在HelloWorldScene.h文件中,添加如下:





1


int _monstersDestroyed;
  在HelloWorldScene.cpp文件,HelloWorld()构造函数,添加如下代码:





1


_monstersDestroyed = 0;
  添加头文件引用:





1


#include "GameOverLayer.h"
  在update定时函数中,monstersToDelete循环removeChild(monster, true)的后面添加被消灭怪物的计数,并判断胜利条件,代码如下:





1
2
3
4
5
6


_monstersDestroyed++;
if (_monstersDestroyed > 30)
{
    CCScene *gameOverScene = GameOverLayer::sceneWithWon(true);
    CCDirector::sharedDirector()->replaceScene(gameOverScene);
}
  
最后为玩家添加失败条件,规定只要有一只怪物跑到左边屏幕里,则玩家失败,在spriteMoveFinished函数里,sprite->getTag() == 1条件的后面,添加如下:





1
2


CCScene *gameOverScene = GameOverLayer::sceneWithWon(false);
CCDirector::sharedDirector()->replaceScene(gameOverScene);
  
14.编译并运行,到此已完成了一个简单的游戏,包含音效,并带有胜利和失败的结束。游戏效果如下:
  
  最后这段完了之后,由于本人C++新手,所以阅读了一下代码,来记录一下流程:
  首先是两个静态函数
  static cocos2d::CCScene* sceneWithWon(bool won);
  static GameOverLayer* createWithWon(bool won);
  第一个函数,作为类的入口
  cocos2d::CCScene* GameOverLayer::sceneWithWon(bool won)
  {
  CCScene* scene = NULL;
  do {
      //创建一个场景
  scene = CCScene::create();
  CC_BREAK_IF(!scene);
      //如果成功,则调用第二个静态函数来创建layer
      GameOverLayer* layer = GameOverLayer::createWithWon(won);
  CC_BREAK_IF(!layer);
  
  scene->addChild(layer);
  } while (0);
  return scene;
  }
  
  创建layer
  经过进一步的阅读代码,发现这个函数感觉上可以用宏CREATE_FUNC(GameOverLayer)来代替,来看看这个宏的原型,
  在对比了blog中后来添加的类和原来的helloworld之后,可以发现参照官方的示例是不错的.
  CREATE_FUNC实际上就是create函数.当然这里是传递参数的需要来写函数



1 #define CREATE_FUNC(__TYPE__) \
2 static __TYPE__* create() \
3 { \
4     __TYPE__ *pRet = new __TYPE__(); \
5     if (pRet && pRet->init()) \
6     { \
7         pRet->autorelease(); \
8         return pRet; \
9     } \
10     else \
11     { \
12         delete pRet; \
13         pRet = NULL; \
14         return NULL; \
15     } \
16 }
  
  
  GameOverLayer* GameOverLayer::createWithWon(bool won)
  {
   //创建一个新的layer对象
  GameOverLayer* pRet = newGameOverLayer();
  //如果创建对象不为空,则返回这个对象  
  if (pRet && pRet->initWithWon(won)) {
  pRet->autorelease();
  return pRet;
  }
    else
  {
      CC_SAFE_DELETE(pRet);
      returnNULL;
  }
  }
  
  bool GameOverLayer::initWithWon(bool won)
  {
  bool bRet = false;
  do
  {
  CC_BREAK_IF(!CCLayerColor::initWithColor(ccc4(255,255,255,255)));
  char* message;
  if (won) {
  message = "you won";
  }
  else
  {
  message = "you lose";
  }
      CCSize size = CCDirector::sharedDirector()->getWinSize();
  CCLabelTTF* label = CCLabelTTF::create(message, "Arial", 32);
  label->setColor(ccc3(0, 0, 0));
  label->setPosition(ccp(size.width / 2, size.height / 2));
  this->addChild(label);
  
      this->runAction(CCSequence::create(CCDelayTime::create(3),
  CCCallFuncN::create(this, callfuncN_selector(GameOverLayer::gameOverDone)), NULL));
  bRet = true;
  
  } while (0);
  return bRet;
  }
  参考资料
  http://blog.sina.com.cn/s/blog_9c3d739101017d2n.html

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-158474-1-1.html 上篇帖子: 在windows、linux、mac OS x 上安装与卸载netbeans java集成包的方法与最低硬件要求 下篇帖子: Mac OS X Support Essentials v10.5 (Leopard 101)
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表