第二课:
初篇:
第一节课已经教会你如何使用
Cocos2d应用
模板创建一个新的工程。那么首先让我们新建一个
Cocos2d-Application
工程,将它命名为“
Lesson1
”并把它保存到你喜欢的任意地方,然后运行它,确定它是否能够显示你所预期的“
Hello World
”。
在你运行程序时可能会看到一个漂亮的
Cocos2d
启动画面,并且当你按下“
Home
”按键退出
演示程序时,你会看到一个可爱的
Cocos2d icon
图标,它们都源自于你项目资源
(Resources)
文件的“特殊命名图片”。现在让我们在
Resources
文件下找到它们,当你希望替换上你自己的图片时,你可以随时删除它们。另外
Resoures
文件也是你增添放置背景图片和精灵
(
角色移动
)
图片的地方。
(
如果你希望现在替换启动画面和
icon
图标,你只需要找到同样尺寸和格式的图片,并将它们命名成“
Default.png
”和“
Icon.png”
覆盖掉原有的图片即可。
)
下面让我们增添一个额外的图片作为精灵,将图片保存在你的项目
Resources
文件中,并将它重命名为“
seeker.png
”。现在让我们回到
Xcode
,查看你
Xcode
中的
Resources
文件,你会发现你找不到“
seeker.png
”图片的踪影,这是因为
Xcode
不会自动将磁盘中的文件增添到你的项目中去。你需要将图片文件拖拽到
Xcode
的项目
Resources
文件中,这时会弹出一个对话框,里面有一些选项,你可以保持默认并且点击增添按钮。
在这节课中,我们将会使用到两个精灵,但是为了节约时间,就让我们使用项目
Resources
文件中的“
Icon.png
”图片作为我的第二个精灵吧。
创建一个精灵:
现在展开项目中的
Classes
文件。你会看到里面有
4
个文件,它们分别是:
HelloWorldScene.h
,
HelloWorldScene.m
,
Lesson1AppDelegate.h
和
Lesson1AppDelegate.m
文件。这节课我们将会把所有的代码写入
HelloWorldScene.m
文件中,因此请点选打开它。
我们首先需要做的是通过一些方法与精灵交互信息,如果你仅仅希望在一个方法中进行交互,那么一个局部变量就可以做到,但那是一种十分罕见的情况,通常我们需要移动一些精灵来回应触屏事件,或者根据一些逻辑在不同的画面下移动精灵,那么我们就需要在多个方法中与精灵交互。
我们有若干种方法来解决上述问题,大多数演示代码通过为每一个被增添到层
(layer)
中的精灵分派一个数值标签
(tag)
来完成工作
(
具体你可以使用
getChildByTag
方法
)
。这是一种安全的方法,但是可能需要做大量额外的工作,并且当程序在拥有成百上千个精灵的大游戏中运行时可能会出现性能问题。
因此我们将使用简单的方法,它同样是安全的,只要你的程序中没有比一个更多的场景实例同时运行就没有问题。我们可以在程序中简单的声明精灵类型
(CCSprite)
的指针变量。请在“
#import
”代码行下面增添如下两行代码:
CCSprite *seeker1;
CCSprite *cocosGuy;
上面创建的两个用以与精灵对象交互的
CCSprite
指针变量,起初是无法与任何对象交互的,但是下一步我们将会把他们增添到“
init
”方法中。
在程序中找到“
-(id)init
”方法代码。这个方法会在场景初始创建的时候被自动调用。方法中的“
if
”语句和尾部的“
return self
”语句很容易让人感到迷惑,其实你完全可以把它们当作模板文件,将它们放在一边不去理会。所有负责场景切换的代码都包含在这个“
if
”块中。
删除当前“
if
”块中内容,比如那些创建“
Hello World
”标签的语句,我们不再需要它们了。使用如下代码替换它们:
// create and initialize our seeker sprite, and add it to this layer
seeker1 = [CCSprite spriteWithFile: @"seeker.png"];
seeker1.position = ccp( 50, 100 );
[self addChild:seeker1];
// do the same for our cocos2d guy, reusing the app icon as its image
cocosGuy = [CCSprite spriteWithFile: @"Icon.png"];
cocosGuy.position = ccp( 200, 300 );
[self addChild:cocosGuy];
我们需要为每个精灵增添三行代码。第一行代码调用“
spriteWithFlie
”方法是为了创建一个新的
CCSprite
对象,用以将一张图像素材加载到程序中。
下一行代码设置了精灵的中心点在屏幕上的位置,我们使用“
cpp
”宏在
X,Y
坐标轴上创建
2D
坐标点。注意,在
cocos2d
中,
X
坐标轴起始于屏幕左边并向右边逐渐递增,
Y
坐标起始于屏幕低端并向上端逐渐递增。
最后,第三行代码调用了“
addChild
”方法用以将最近创建的精灵显示在层
(layer)
上。
保存并且运行你的代码。运行结果如下:
制作物体移动:
现在你知道了如何让精灵显示在屏幕上,你可能更希望他们能四处移动。有两种基本方法可以让精灵动起来:
1.
使用一个行为
(Action)
方法让精灵在一定时间后自动移动到目标地点。
2.
自己使用一个在游戏运行期间能够被周期性调用的方法移动精灵。
让我们先来看看第二种方法。回到
HelloWorldScene.m
文件的“
init
”方法。其中“
if
”块中包含的代码用以创建你的精灵。我们打算把一段周期回调代码增添到初始化
(init)
方法中,请将如下代码放置在“
if
”块内,紧跟在“
[self addChild:cocosGuy];
”代码行的后面:
// schedule a repeating callback on every frame
[self schedule:@selector(nextFrame:)];
这里的“
schedule
”方法被其自身
self(the HelloWorld CCLayer)
调用
,
并且通过地址传输的方式调用“
nextFrame
”方法作为它的一个参数。不确定“
nextFrame
”方法是否存在?没有关系,我们马上就要创建它。找一处不包含在任何方法中的空行,例如,
init
方法之后,
dealloc
方法之前的空位。插入如下代码:
- (void) nextFrame:(ccTime)dt {
seeker1.position = ccp( seeker1.position.x + 100*dt, seeker1.position.y );
if (seeker1.position.x > 480+32) {
seeker1.position = ccp( -32, seeker1.position.y );
}
}
这段代码会作用于每一个动画画面,
cocos2d
库将会调用你的“
nextFrame
”事件,经过指定的时间直到最后一个画面结束。这样你就有机会得心应手的处理很多事情,比如:四处移动你的精灵,检测碰撞,更新一个物理模型,生成一个敌人,或是在你不需要的时候移除精灵等等。
我们所遇到的情况是需要我们移动“
seeker1
”精灵。移动一个精灵,你只要为“
position
”属性设置一个新的值就可以了。
(
你可能会被误导仅设置
x
坐标或者
y
坐标的值,但那样是无法运行的,你必须设置一个完整的新坐标值。
)
我们通过
100*dt
语句来改变精灵在
x
坐标上的位置,你可以将它理解为:精灵会以每秒钟
100
像素的速度移动。通过设定一个值与
dt
的乘积来确定精灵的移动量是一种很好的方法,因为它可以使运动保持恒速,虽然画面帧数可能会发生一点变化。
接下来,我们来做精灵的边界检查。假设你要在一个屏宽为
480
像素的
iPhone
上设置精灵的边界检查,常规的做法是调用
[[CCDirector sharedDirector] winSize]
方法获得屏幕的实际尺寸,在加上
32
,因为
32
是精灵宽度的一半,当精灵超过
480+32
时,精灵的中心点刚好在屏幕之外。这种情况发生的时候,我们将精灵的
x
坐标设为
-32
,这样就保证了精灵刚好不会超出屏幕的边缘。
响应触摸:
处理事件和安排一个回调有点不同。事件中可能包含有类似于屏幕触摸和加速器的东西。
Cocos2d
中已经为此定义了一些特殊的方法用来处理它们,并且针对触摸事件,有两种不同的处理方法:“标准
(standard)
”和“定向
(targeted)
”。
这节课,我们将会使用定向
(targeted)
方法。我们需要修改几处代码。首先,在“
HelloWorldScene.h
”头文件之后增添:
#import "CCTouchDispatcher.h"
下一步,再次找到“
init
”方法,并且在“
if
”块结束语句之前插入这段定向
(targeted)
触摸事件注册代码:
// register to receive targeted touch events
[[CCTouchDispatcher sharedDispatcher] addTargetedDelegate:self
priority:0
swallowsTouches:YES];
现在找一个空地放置新的方法,或许写在
nextFrame
方法之后是一个不错的注意。因为我们正在使用“定向
(targeted)
”方法处理触摸事件,我们不得不执行一段
ccTouchBegan
方法,这里返回
YES
是为了告诉触摸感受器你即将进行一次屏幕触摸:
- (BOOL)ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event {
return YES;
}
在同一次触摸发生时还会有其他的触摸方法被调用。让我们增添一些通过触摸来使第二个精灵移动的代码:
- (void)ccTouchEnded:(UITouch *)touch withEvent:(UIEvent *)event {
CGPoint location = [touch locationInView: [touch view]];
CGPoint convertedLocation = [[CCDirector sharedDirector] convertToGL:location];
[cocosGuy stopAllActions];
[cocosGuy runAction: [CCMoveTo actionWithDuration:1 position:convertedLocation]];
}
下面让我们来分析一下上述代码的功能:
1.
首先它获取了屏幕触摸的位置。
2.
然后我们通知
CCDirector
去转换
GL
坐标,例如,我们使用相同的坐标系统进行绘制,那么程序将会在人物与场景图之间转换。
3.
下一步我们将会停止精灵早先的动作。
4.
最后我们执行新的动作,将精灵移动到触摸的位置。
我们不需要在
nextFrame
事件中增添任何代码去控制精灵的移动,因为我们正在使用动作替换方法。
运行这个程序,你会发现当你的手指离开屏幕的时候,
cocos2d icon
图标将会移动到指定的位置,并且
seeker
机器人将会穿越屏幕。
实例源代码下载地址: http://down.51cto.com/data/130517