程序员必知:如何用cocos2d

简介: 程序员必知:如何用cocos2d

三、添加一个精灵

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

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

现在我们在HelloWorldScene.cpp里面,找到bool //代码效果参考:http://www.zidongmutanji.com/bxxx/394526.html

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</span>/2, winSize.Height</span>/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</span>/2,

winSize.Height</span>/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</span>/2,

winSize.Height</span>/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</span>/2;

int maxY = winSize.height - target->getContentSize().Height</span>/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</span>/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</span>/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</span>/2;

int maxY = winSize.height - target.contentSize.Height</span>/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</span>/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</span>/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

</

相关文章
|
存储 JSON 监控
grafana/promtail 作用
Grafana/ Promtail 是一个日志的收集、存储和可视化工具。它主要用于监控和分析分布式系统的日志数据。Grafana是一个开源的数据可视化工具,而Promtail是Grafana的一个组件,用于收集和发送日志数据。Grafana/ Promtail具有以下作用: 1. 日志收集:Promtail可以从不同的源收集日志数据,如系统日志、应用日志等,并将其发送到中央存储库,如Elasticsearch、Loki等。 2. 自动发现和标记:Promtail可以自动发现并标记正在运行的容器和主机,以便在收集日志时进行标识和过滤。 3. 丰富的日志格式支持:Promtail支持多种常见
582 0
|
消息中间件 存储 网络协议
ZMQ/ZeroMQ简介
ZMQ/ZeroMQ简介
|
12月前
|
算法 Java Linux
java制作海报二:java使用Graphics2D 在图片上合成另一个照片,并将照片切割成头像,头像切割成圆形方法详解
这篇文章介绍了如何使用Java的Graphics2D类在图片上合成另一个照片,并将照片切割成圆形头像的方法。
202 1
java制作海报二:java使用Graphics2D 在图片上合成另一个照片,并将照片切割成头像,头像切割成圆形方法详解
|
12月前
|
缓存 JavaScript Java
vue2知识点:组件的props属性、非props属性、props属性校验
vue2知识点:组件的props属性、非props属性、props属性校验
294 4
|
12月前
|
人工智能 弹性计算 自然语言处理
触手可及,函数计算玩转 AI 大模型
在AI技术迅速发展的背景下,大模型正推动各行业的智能化转型。企业为抓住机遇,纷纷部署AI大模型。阿里云函数计算凭借按量付费、高弹性和快速交付的特点,成为企业部署AI大模型的理想选择。本文介绍阿里云函数计算的技术解决方案,分析其优势,并通过具体应用场景评测其在AI大模型部署中的表现。
|
12月前
|
Java 编译器 Spring
Spring AOP 和 AspectJ 的区别
Spring AOP和AspectJ AOP都是面向切面编程(AOP)的实现,但它们在实现方式、灵活性、依赖性、性能和使用场景等方面存在显著区别。‌
377 2
|
12月前
|
移动开发 小程序 数据可视化
一招学会DIY官网可视化设计支持导出微擎、UNIAPP、H5、微信小程序源码
一招学会DIY官网可视化设计支持导出微擎、UNIAPP、H5、微信小程序源码
228 2
|
机器学习/深度学习 人工智能 监控
人工智能 - 目标检测算法详解及实战
目标检测需识别目标类别与位置,核心挑战为复杂背景下的多目标精准快速检测。算法分两步:目标提取(滑动窗口或区域提议)和分类(常用CNN)。IoU衡量预测与真实框重叠度,越接近1,检测越准。主流算法包括R-CNN系列(R-CNN, Fast R-CNN, Faster R-CNN),YOLO系列,SSD,各具特色,如Faster R-CNN高效候选区生成与检测,YOLO适用于实时应用。应用场景丰富,如自动驾驶行人车辆检测,安防监控,智能零售商品识别等。实现涉及数据准备、模型训练(示例YOLOv3)、评估(Precision, Recall, mAP)及测试。
601 5
|
PHP
CTFSHOW 每周大挑战 RCE极限挑战
CTFSHOW 每周大挑战 RCE极限挑战
171 0
|
移动开发 运维 前端开发
【深入浅出全栈开发】全栈是什么?- 课前必读 #154
【深入浅出全栈开发】全栈是什么?- 课前必读 #154
961 0