转自:http://www.cocoachina.com/bbs/read.php?tid=15554
这一周接触到Cocos2D开发,在它的官网上看到Ray Wenderlic写的关于cocos2d开发的文章,感觉写的挺好,翻译了一下。
原文链接地址大家可以在上面看到作者的更多内容
初次翻译文章,望各位关照,想说的话在作者的文章里边也有表述,就直接开始吧
游戏截图
例子下载: Cocos2DSimpleGame.zip (776 K) 下载次数:4730
Cocos2D是iPhone开发中一个非常有用的库,它可以让你在创建自己的iPhone游戏时节省很多的时间。它具有很多的功能,比如sprite(精灵)扶持,非常酷的图形效果,动画效果,物理库,音频引擎等等。
我是一个Cocos2D开发的新手,尽管有很多有用的教程来介绍如何开始利用Cocos2D开发,但我不能找到一个教程是我期待的那样,它可以创建一个简单但功能丰富的游戏,这个游戏具有动画,碰撞还有音频,不需要其它更多的高级功能。我最终自己完成了一个简单的例子,并且在我自己的经验下写了这篇教程以便于它对于其它的新手会有用。
这篇教程将带你从头到尾的来了解用Cocos2D来创建一个简单的iPhone游戏的过程。你可以一步步的按教程来,也可能跳过直接从文章的最后来下载例子工程。当然,里边会有ninjas(忍者)
。
下载与安装Cocos2D
你可以从 the Cocos2D Google Code page 下载Cocos2D,现在的最新版本是0.99.0-final(这也是这篇教程使用的)。
在你下载完代码后,你应该安装有用的工程模板。打开Terminal window(终端窗口),找到下载的Cocos2D所在的目录,输入下面的命令:./install_template.sh。
如果你的XCode不是安装在默认的目录下面(比如说你的机器上面可能安装了多个版本的SDK),你可以在安装脚本里边手工的添加一个参数。(译者注,我没试过,试过的大大可以给指明一下,17楼写明了, 谢谢17楼的提示)
Hello, Cocos2D
让我们开始来用刚刚安装的Cocos2D工程模板来建立并运行一个简单的Hello World 工程。启动XCode ,选中 cocos2d-0.99.0 Applicati*****模板创建一个新的Cocos2D工程,给工程命名为“Cocos2DSimpleGame”.
继续编译并运行该工程。如果一切正常,你将看到下图:
Cocos2D被组织到”scenes”(场景)的概念中,有点类似于游戏中的”levels”(等级)或是”screens”(屏幕).比如你需要有一个场景来为游戏初始化菜单,一个场景为游戏的主要动作,一个场景为游戏结束。在场景里边,你要有许多的图层(就像Photoshop里边的一样),图层可能包含多个(nodes)结点,比如sprites(精灵),labels(标签),menus(菜单)及其它。当然结点也包含其它的结点(比如,一个精灵可以有一个子精灵)。
在这个例子工程中,你可以看到有一个场景-HelloWorldScene,我们也将在它里边开始实现我们的游戏。继续打开源文件,你会看到在init这个方法中,它加入了一个label来在场景中显示”Hello World”。我们将要放入一个精灵来代替它。
添加一个精灵
在添加精灵之前,我们需要即将用到的图片。你可以自己创建,或者是用Ray Wenderlich妻子为这个工程专门绘制的图片:
a player Image
a Projectile Image
a Target Image
当你得到这些图片后,把它们直接拖到XCode里边的resources文件夹里边去,一定要选中"Copy items into destination group’s folder (if needed)”。
既然我们已经有了自己的图片,我们就要找出应该在哪来放置玩家。请注意,在Cocos2D里边屏幕的左下角是坐标原点(0,0),x和y值向右上角递增。因为工程是在横向模式,这意味着右上角的坐标值是(480, 320)。
还需要注意的是在默认状态下当我们为一个物体设置position属性时,position属性是和我们添加的精灵的中心点关联起来的。因此如果我们想把玩家精灵放置在屏幕水平方向的左边,垂直方向的中间:
position的X坐标,要设置成[player sprite's width]/2.
Position的Y坐标,要设置成[window height]/2
下面这张图可以帮助我们更好的理解
让我们试一下吧!打开Classes文件夹选中HelloWorldScene.m,用下面的代码来代替init方法:
-(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;
}
你现在可以编译并运行这个工程,你的精灵应该会正确显示,但背景默认是黑色的。对这个作品来说,白色背景会更好。在Cocos2D中,把一个图层的的背景颜色更改成为一个算定义颜色的简单方法是利用CCColoredLayer这个类。来尝试一下吧。选中HelloWorldScene.h并且改变HelloWorld接口省明像下面的那样:
@interface HelloWorld : CCColorLayer
然后选中HelloWorldScene.m并对init方法进行一个细微的修改来把背景色改为白色。
if( (self=[super initWithColor:ccc4(255,255,255,255)] )) {
继续编译并运行工程,你会看到你的玩家精灵在白色的背景上。噢,我们的忍者已经准备表演了。
移动目标
下面我们需要在场景中添加一些目标让忍者去打击。为了让事情变的更有趣一些,我们要让这些目标移动起来-要不然没什么挑战性。我们在稍稍偏屏幕右边的地方创建一些目标,并为它们建立动作来让它们向左移动。
在init方法之前添加下面的方法:
-(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 above
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 acti*****
id actionMove = [CCMoveTo actionWithDuration:actualDuration
position:ccp(-target.contentSize.width/2, actualY)];
id actionMoveDone = [CCCallFuncN actionWithTarget:self
selector:@selector(spriteMoveFinished:)];
[target runAction:[CCSequence acti*****:actionMove, actionMoveDone, nil]];
CCSprite *sprite = (CCSprite *)sender;
[self removeChild:sprite cleanup:YES];
// Choose one of the touches to work with
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInView:[touch view]];
location = [[CCDirector sharedDirector] convertToGL:location];
// Set up initial location of projectile
CGSize winSize = [[CCDirector sharedDirector] winSize];
CCSprite *projectile = [CCSprite spriteWithFile:@"Projectile.png"
rect:CGRectMake(0, 0, 20, 20)];
projectile.position = ccp(20, winSize.height/2);
// Determine offset of location to projectile
int offX = location.x - projectile.position.x;
int offY = location.y - projectile.position.y;
// Bail out if we are shooting down or backwards
if (offX <= 0) return;
// Ok to add now - we've double checked position
[self addChild:projectile];
// Determine where we wish to shoot the projectile to
int realX = winSize.width + (projectile.contentSize.width/2);
float ratio = (float) offY / (float) offX;
int realY = (realX * ratio) + projectile.position.y;
CGPoint realDest = ccp(realX, realY);
// Determine the length of how far we're shooting
int offRealX = realX - projectile.position.x;
int offRealY = realY - projectile.position.y;
float length = sqrtf((offRealX*offRealX)+(offRealY*offRealY));
float velocity = 480/1; // 480pixels/1sec
float realMoveDuration = length/velocity;
// Move projectile to actual endpoint
[projectile runAction:[CCSequence acti*****:
[CCMoveTo actionWithDuration:realMoveDuration position:realDest],
[CCCallFuncN actionWithTarget:self selector:@selector(spriteMoveFinished:)], nil]];
[_targets removeObject:sprite];}
} else if (sprite.tag == 2) { // projectile
[_projectiles removeObject:sprite];
NSMutableArray *projectilesToDelete = [[NSMutableArray alloc] init];
for (CCSprite *projectile in _projectiles) {
CGRect projectileRect = CGRectMake(
projectile.position.x - (projectile.contentSize.width/2),
projectile.position.y - (projectile.contentSize.height/2),
projectile.contentSize.width,
projectile.contentSize.height);
NSMutableArray *targetsToDelete = [[NSMutableArray alloc] init];
for (CCSprite *target in _targets) {
CGRect targetRect = CGRectMake(}
target.position.x - (target.contentSize.width/2),
target.position.y - (target.contentSize.height/2),
target.contentSize.width,
target.contentSize.height);
if (CGRectIntersectsRect(projectileRect, targetRect)) {
[targetsToDelete addObject:target];
}
for (CCSprite *target in targetsToDelete) {
[_targets removeObject:target];}
[self removeChild:target cleanup:YES];
if (targetsToDelete.count > 0) {
[projectilesToDelete addObject:projectile];}
[targetsToDelete release];
}
for (CCSprite *projectile in projectilesToDelete) {
[_projectiles removeObject:projectile];}
[self removeChild:projectile cleanup:YES];
[projectilesToDelete release];
|
if ((self = [super init])) {
self.layer = [GameOverLayer node];
[self addChild:_layer];
}
return self;
[_layer release];
_layer = nil;
[super dealloc];
if( (self=[super initWithColor:ccc4(255,255,255,255)] )) {
CGSize winSize = [[CCDirector sharedDirector] winSize];
self.label = [CCLabel labelWithString:@"" fontName:@"Arial" fontSize:32];
_label.color = ccc3(0,0,0);
_label.position = ccp(winSize.width/2, winSize.height/2);
[self addChild:_label];
[self runAction:[CCSequence acti*****:
[CCDelayTime actionWithDuration:3],
[CCCallFunc actionWithTarget:self selector:@selector(gameOverDone)],
nil]];
}
return self;
[[CCDirector sharedDirector] replaceScene:[HelloWorld scene]];
[_label release];
_label = nil;
[super dealloc];
GameOverScene *gameOverScene = [GameOverScene node];
[gameOverScene.layer.label setString:@"You Win!"];
[[CCDirector sharedDirector] replaceScene:gameOverScene];