三、添加一个精灵

我们先用个简单的方式,把player, projectile, target三个PNG文件拷贝到 D:\Work7\NEWPLUS\TDA_DATA\UserData 目录下,这使其可以在模拟器上直接通过文件路径访问到。Uphone有其资源打包的方式,图片和音乐都可以打包到动态库文件内,这个另外会有教程描述,我们这里先让事情简单化。

                 

关于cocos2d坐标系统的规则,简而言之就是左下角为原点,向上向右按像素递增,这在Wenderlich的原文中有详细描述,我们这里就不再赘述了。直接切入代码

现在我们在HelloWorldScene.cpp里面,找到bool HelloWorld::init()函数,把它替换成下面代码

bool HelloWorld::init()
{
  //
  // 1. super init first
  if ( !CCLayer::init() )
  {
    return false;
  }

/////
  // 2. add a menu item with "X" image, which is clicked to quit the program
  //    you may modify it.

// add a "close" icon to exit the progress. it's an autorelease object
  CCMenuItemImage *pCloseItem = CCMenuItemImage::itemFromNormalImage( "CloseNormal.png", 
                                                                      "CloseSelected.png", 
                                                                      this,
                                                                      menu_selector(HelloWorld::menuCloseCallback) );
  pCloseItem->setPosition( ccp(CCDirector::getSharedDirector()->getWinSize().width - 20, 20) );

// create menu, it's an autorelease object
  CCMenu* pMenu = CCMenu::menuWithItems(pCloseItem, NULL);
  pMenu->setPosition( CGPointZero );
  this->addChild(pMenu);

/////
  // 3. add your codes below...

CGSize winSize = CCDirector::getSharedDirector()->getWinSize();
  CCSprite *player = CCSprite::spriteWithFile("Player.png", 
                                              CGRectMake(0, 0, 27, 40) );
  player->setPosition( ccp(player->getContentSize().width/2, winSize.height/2) );
  this->addChild(player);

return true;
}

其实我们只修改了 // 3. add your codes below 这段。

cocos2d-x和cocos2d-iphone的接口有细微的差别,不过你一旦习惯了这个差别,写起代码来就会很顺手。

我们抛开添加"X"退出按钮的一段,单纯地看一下这两段init函数的差异.

// cpp with cocos2d-x
bool HelloWorld::init()
{
  if ( CCLayer::init() )
  {
    CGSize winSize = CCDirector::getSharedDirector()->getWinSize();
    CCSprite *player = CCSprite::spriteWithFile("Player.png", 
                                    CGRectMake(0, 0, 27, 40) );
    player->setPosition( ccp(player->getContentSize().width/2, 
                              winSize.height/2) );
   this->addChild(player);
  }
  return true;
}

// objc with cocos2d-iphone
-(id) init
{
  if( (self=[super init] )) 
  {
    CGSize winSize = [[CCDirector sharedDirector] winSize];
    CCSprite *player = [CCSprite spriteWithFile:@"Player.png"
                                  rect:CGRectMake(0, 0, 27, 40) ];
    player.position = ccp(player.contentSize.width/2, 
                          winSize.height/2);
    [self addChild:player];
  }
  return self;

转换要点

1. 虽然VC++中有super关键字,但linux下用gcc编译时可不认。所以C++中不能用super::init(),而必须老老实实地指定是执行父类CCLayer::init()方法

2. 由于cpp里没有property的概念,所以在objc里涉及property的地方,我们都用了get/set函数代替。于是,访问CCDirector.SharedDirector属性的代码,就变成了CCDirector::getSharedDirector()函数调用,shared开头小写的s,也变成了大写的S。同样规则,取得winSize属性的地方,则变成了getWinSize()函数调用。这段代码中还有player->getContentSize()也受此影响。但访问结构体中的变量,如winSize中的width和height则不需用getter封装。

3. 设置类的属性,如player.position = ,也改用setter实现,变成player->setPosition(...)

4. C++函数调用不需像OBJC那样在每个参数前面说明这参数是干什么用的,比如rect:CGRectMake(...),只需直接输入参数即可。另一方面, cocos2d-x仿照iOS实现了CGGeometry的一些函数,你可以在cocos2dx\include\CGGeometry.h里看到它们。除了CGRectMake,还有CGPointMake, CGSizeMake, CGPointZero, CGSizeZero, CGRectZero.

5. cocos2d-x所有的游戏元素, sprite,layer,scene,label,action等,都是new在heap上,并且用指针传递的,因此调用其成员函数一定是用->号,而不像objc里的点号

6. cpp里用this替代了objc的self关键字

7. cocos2d-x里的init函数改成返回bool类型了。由于cpp里没有objc的"id"关键字,所以cocos2d-iphone里返回id的地方,都改成返回明确的类指针,或者bool型变量

好了,我们编译运行一下,可以看到带头大哥一袭黑衣,很猥琐地躲在黑色背景上,只露出一双杀红了的眼睛。为了游戏性,我们需要把背景颜色改成白的。只要简单地修改,使HelloWorld不是继承CCLayer,而是继承CCColorLayer就行了。

在HelloWorldScene.h中,修改HelloWorld类声明如下。

(左边为cpp代码,也就是读者现在应该使用的,右边为Cocos2dSimpleGame原来使用cocos2d-iphone的objc代码,用以对比参考。本系列后面的行文也都如此)

// cpp with cocos2d-x
class HelloWorld : public cocos2d::CCColorLayer
// objc with cocos2d-iphone
@interface HelloWorld : CCColorLayer

然后在HelloWorld::init()函数实现中,修改刚开始的

if ( !CCLayer::init() )
{
    return false;
}

变成

if ( !CCColorLayer::initWithColor( ccc4(255,255,255,255) ) )
{
    return false;
}

这里小改了一下逻辑,原版objc里是如果super init成功,就BALA-BALA做后面的工作;我喜欢防御性编程,如果失败则先做出错处理、跳出,然后才继续写正确流程。这么做有两个好处,一是不会写到后面漏掉了错误处理,二是不用做太多层的if嵌套。这个是题外话了。抛开if的逻辑,我们来对比一下这句super init在cpp和objc的区别

// cpp with cocos2d-x
if ( CCColorLayer::initWithColor( ccc4(255,255,255,255) )
// objc with cocos2d-iphone
if ( self = [super initWithColor:ccc4(255,255,255,255)] )

转换要点

1. 首先,cpp的继承默认为private继承,所以类声明的继承处public关键字不可少

2. cocos2d-iphone的作者Ricardo Quesada建议我们采用C++的命名空间把cocos2d整个库包起来。而我们在这里既不想直接到头文件里using namespace cocos2d;感染了所有包含这个头文件的CPP文件,也不想把class HelloWorld归到cocos2d命名空间内,所以HelloWorldScene.h头文件里只好在每个cocos2d类前面加上命名空间cocos2d::

编译后运行,你就可以看到带头大哥孤独地站在白色背景上了,寂寞得泪流满面

四、移动目标

有了带头大哥后,我们就需要添加一些虾兵蟹将让大哥砍。英雄人物一般不喜欢砍木桩,所以我们就用void addTarget()方法在屏幕右边创建一些跑龙套的小兵,让他们以随机速度向左移动。

先到HelloWorldScene.h里添加函数声明 void addTarget(); 然后回到HelloWorldScene.cpp里实现函数

// cpp with cocos2d-x
void HelloWorld::addTarget()
{
  CCSprite *target = CCSprite::spriteWithFile("Target.png", 
                                        CGRectMake(0,0,27,40) );

// Determine where to spawn the target along the Y axis
  CGSize winSize = CCDirector::getSharedDirector()->getWinSize();
  int minY = target->getContentSize().height/2;
  int maxY = winSize.height -  target->getContentSize().height/2;
  int rangeY = maxY - minY;
  srand( TimGetTicks() );
  int actualY = ( rand() % rangeY ) + minY;

// Create the target slightly off-screen along the right edge,
  // and along a random position along the Y axis as calculated
  target->setPosition( 
    ccp(winSize.width + (target->getContentSize().width/2), 
    actualY) );
  this->addChild(target);

// Determine speed of the target
  int minDuration = (int)2.0;
  int maxDuration = (int)4.0;
  int rangeDuration = maxDuration - minDuration;
  srand( TimGetTicks() );
  int actualDuration = ( rand() % rangeDuration ) + minDuration;

// Create the actions
  CCFiniteTimeAction* actionMove = 
    CCMoveTo::actionWithDuration( (ccTime)actualDuration, 
        ccp(0 - target->getContentSize().width/2, actualY) );
  CCFiniteTimeAction* actionMoveDone = 
    CCCallFuncN::actionWithTarget( this, 
                callfuncN_selector(HelloWorld::spriteMoveFinished));
  target->runAction( CCSequence::actions(actionMove, 
                     actionMoveDone, NULL) );
}

// objc with cocos2d-iphone
-(void)addTarget 
{
  CCSprite *target = [CCSprite spriteWithFile:@"Target.png"
                                rect:CGRectMake(0, 0, 27, 40)];

// Determine where to spawn the target along the Y axis
  CGSize winSize = [[CCDirector sharedDirector] winSize];
  int minY = target.contentSize.height/2;
  int maxY = winSize.height - target.contentSize.height/2;
  int rangeY = maxY - minY;

int actualY = (arc4random() % rangeY) + minY;

// Create the target slightly off-screen along the right edge,
  // and along a random position along the Y axis as calculated
  target.position = 
    ccp(winSize.width + (target.contentSize.width/2), 
    actualY);
  [self addChild:target];

// Determine speed of the target
  int minDuration = 2.0;
  int maxDuration = 4.0;
  int rangeDuration = maxDuration - minDuration;

int actualDuration = (arc4random() % rangeDuration) + minDuration;

// Create the actions
  id actionMove = 
    [CCMoveTo actionWithDuration:actualDuration
          position:ccp(-target.contentSize.width/2, actualY)];
  id actionMoveDone = 
    [CCCallFuncN actionWithTarget:self
                selector:@selector(spriteMoveFinished:)];
  [target runAction:[CCSequence actions:actionMove, 
                    actionMoveDone, nil]]; 
}

这里用callfuncN_selector(HelloWorld::spriteMoveFinished)回调了spriteMoveFinished方法,我们需要实现之。同样别忘记在头文件里加入声明, 然后实现之

// cpp with cocos2d-x
void HelloWorld::spriteMoveFinished(CCNode* sender)
{
  CCSprite *sprite = (CCSprite *)sender;
  this->removeChild(sprite, true);
}
// objc with cocos2d-iphone
-(void)spriteMoveFinished:(id)sender 
{
  CCSprite *sprite = (CCSprite *)sender;
  [self removeChild:sprite cleanup:YES]; 

转换要点

1. 随机函数。在iphone上可以用arc4random()直接生成随机函数,而uphone上还是用传统的方法,先获取毫秒级时间(这个函数在uphone上是TimGetTickes()),用srand(int)塞进去作为random seed,然后再调用rand()生成随机数。其中srand和rand是C标准库函数

2. objc中的YES和NO,在cpp中变成true和false,这个容易理解

3. 回调函数.在objc中用 selector:@selector(spriteMoveFinished),在cpp中实现就比较复杂了,具体可以看cocos2dx\include\selector_protocol.h里面的声明。总之每种可能出现selector的地方,都有唯一的函数指针类型与之匹配。一共有5种回调函数类型

  • schedule_selector
  • callfunc_selector
  • callfuncN_selector
  • callfuncND_selector
  • menu_selector

具体使用时,可以看所用函数的变量类型定义来决定。比如使用CCTimer::initWithTarget方法,第二个参数是SEL_SCHEDULE类型,到selector_protocol.h里查一下,可以看到对应是schedule_selector(_SELECTOR)宏,所以调用时就需要在类里头实现一个void MyClass::MyCallbackFuncName(ccTime)函数,然后把schedule_selector(MyClass::MyCallbackFuncName)作为CCTimer::initWithTarget的第二个参数传入。

有了addTarget后,我们需要定时地调用它。所以在init函数返回前增加这个函数调用

// cpp with cocos2d-x
// Call game logic about every second
this->schedule( schedule_selector(HelloWorld::gameLogic), 1.0 );
// objc with cocos2d-iphone
// Call game logic about every second
[self schedule:@selector(gameLogic:) interval:1.0];

然后实现gameLogic这个回调函数

// cpp with cocos2d-x
void HelloWorld::gameLogic(ccTime dt)
{
    this->addTarget();
}
// objc with cocos2d-iphone
-(void)gameLogic:(ccTime)dt
{
    [self addTarget];
}

不要忘记在头文件里增加函数声明,并且应为public函数,否则回调是调用不到的。

编译运行,现在你应该看到小喽啰们张牙舞爪地向大哥扑过来。于是拯救世界、维护人类和平的重任就交给大哥了。

本文转自Walzer博客园博客,原文链接:http://www.cnblogs.com/walzer/archive/2010/10/10/1847100.html,如需转载请自行联系原作者

如何用cocos2d-x来开发简单的Uphone游戏:(二) 移动的精灵相关推荐

  1. [20110209]Cocos2dSimpleGame入门系列《如何用cocos2d-x来开发简单的Uphone游戏》学习小记

    原文: http://www.cnblogs.com/walzer/archive/2010/10/10/1847089.html 拜读王哲王总的cocos2d-x入门教程,将学习过程中对C++或co ...

  2. 翻译:如何用Cocos2d来开发简单的IPhone游戏教程

    这一周接触到Cocos2D开发,在它的官网上看到Ray Wenderlic写的关于cocos2d开发的文章,感觉写的挺好,翻译了一下.  原文链接地址大家可以在上面看到作者的更多内容 初次翻译文章,望 ...

  3. Cocos2D教程:使用SpriteBuilder和Cocos2D 3.x开发横版动作游戏——Part 2

    本文是"使用Cocos2D 3.x开发横版动作游戏"系列教程的第二篇,同时也是最后一篇.是对How To Make A Side-Scrolling Beat Em Up Game ...

  4. 开发Windows贪吃蛇游戏——(二)代码实现

    目录 前言 窗体部分 Frame部分 声明全局变量 Panel的初始化 startGame方法 paintComponent方法 drawGame方法 newSnake方法 newFood方法 mov ...

  5. Cocos2D教程:使用SpriteBuilder和Cocos2D 3.x开发横版动作游戏——Part 1

    本文是对教程How To Make A Side-Scrolling Beat Em Up Game Like Scott Pilgrim with Cocos2D – Part 1的部分翻译,加上个 ...

  6. 如何使用cocos2d-x 3.0来做一个简单的iphone游戏教程(第一部分)

    游戏截图: cocos2d-x 是一个支持多平台的开源框架,用于构建游戏.应用程序和其他图形界面交互应用.Cocos2d-x项目可以很容易地建立和运行在iOS,Android的三星Bada,黑莓Bla ...

  7. HiLink LiteOS IoT芯片 让IoT开发简单高效

    HiLink & LiteOS & IoT芯片 让IoT开发简单高效 华为HiLink & LiteOS & IoT芯片使能三件套,让IoT开发更简单高效.下一代智能手 ...

  8. Unity 2D游戏开发快速入门第1章创建一个简单的2D游戏

    Unity 2D游戏开发快速入门第1章创建一个简单的2D游戏 即使是现在,很多初学游戏开发的同学,在谈到Unity的时候,依然会认为Unity只能用于制作3D游戏的.实际上,Unity在2013年发布 ...

  9. 记事本写python怎么运行-Python开发简单记事本

    摘要: 本文是使用Python,结合Tkinter开发简单记事本. 本文的操作环境:ubuntu,Python2.7,采用的是Pycharm进行代码编辑,个人很喜欢它的代码自动补齐功能. 最近很想对p ...

最新文章

  1. 2012.5.2 学习记录:RadGrid单元格操作
  2. 九度 1376 最近零子序列
  3. Spring依赖注入技术的发展
  4. 【dubbo】http.conn.HttpHostConnectException.host: 'org.apache.http.HttpHost' could not be instantiated
  5. C语言1094题目,P1094 (C语言代码)
  6. HDU 1133 Buy the Ticket
  7. 【每日算法Day 84】面试必考题:Trie(字典树/前缀树)的实现
  8. linux ubuntu 安装 matlab 2010 及破解 详细图解
  9. c语言指向读取的字节数的指针,c - C语言中指针的大小 - SO中文参考 - www.soinside.com...
  10. WordPress插件/WP资源下载管理插件 1.3.4
  11. java解析json list
  12. Falsy Bouncer(算法)
  13. Python语法练习
  14. 图片轮播——Swiper实例
  15. 【QNX Hypervisor 2.2 用户手册】4 构建QNX Hypervisor系统
  16. poi怎么设置某个单元格为下拉框_java excel 多选下拉列表设置
  17. 将ceph与calamari相连(connect ceph servers to calamari)
  18. 当新三板公司踏入币圈 |链捕手
  19. Origin 不连续数据点做出连续曲线
  20. Cmd命令行实验4-ARP

热门文章

  1. latex 数学公式_数学公式、方程式 OCR 识别编辑 LaTeX 公式软件神器—极度公式
  2. Mac OS上用item2连接CentOS7
  3. ov5640帧率配置_赛博朋克2077 优化设置大全!帧数50暴涨100
  4. python------面向对象介绍
  5. vue 限制输入字符长度
  6. 关于今天写Flex视频循环播放所出现的sdk问题
  7. linux笔记2.20
  8. opera9.6 的一个顽固的bug
  9. C# new和override的区别和用途
  10. qt: 获取sql数据表的所有的字段;