一、原文出处
http://www.raywenderlich.com/25736/how-to-make-a-simple-iphone-game-with-cocos2d-2-x-tutorial
二、
1.新建一个cocos2d iOS项目工程,名为 Cocos2DSimpleGame
a.运行工程,可以看到 Hello World。
b.Cocos2D主要应用的是场景(scenes)的概念。所谓场景就是游戏里的各个层次或者显示屏幕。例如游戏初始菜单的场景,游戏中的场景,游戏结束的场景。
c.一个场景可以有很多的层(layers)(类似Photoshop里的层),而每个层可以有各种不同的节点,如精灵(sprites),标签(labels),菜单(menus)。一个节点可以包含别的节点,例如一个精灵可以包含子精灵。
d.看下工程里的文件,你会发现有两个层IntroLayer和HelloWorldLayer,各个层都有自己的场景。看下code,director里调用的第一个场景是IntroLayer的场景,在IntroLayer里切换成HelloWorldLayer的场景。
2.增加一个精灵
a.从resources for this tutorial下载资源,将资源文件加到工程,记得勾选 “Copy items into destination group's folder (if needed)”。
b.在Coco2D里,屏幕的左下角是坐标原点。如果手机是横向模式的,对4寸屏来说,右上角坐标就是(568,320)。Retina显示屏,1点=2像素。
c.打开HelloWorldLayer.m,修改init函数,给层添加一个玩家精灵
if((self = [super init])){
CGSize size = [CCDirectorsharedDirector].winSize;
CCSprite *player = [CCSpritespriteWithFile:@"player.png"];
player.position =ccp(player.contentSize.width/2,size.height/2); //ccp是一个宏,会返回一个CGPoint对象
[selfaddChild:player];
}
return self;
d.打开HelloWorldLayer.h,修改接口
@interface HelloWorldLayer: CCLayerColor
修改init函数,将[super init] 改为[super initWithColor:ccc4(255,255,255,255)],把背景色改为白色
ccc4是一个宏,返回一个ccColor4B类型。
a.给HelloWorldLayer增加成员函数addMonster,这个函数负责产生一个从右向左移动的怪物精灵
-(void) addMonster
{
CCSprite * monster = [CCSpritespriteWithFile:@"monster.png"];
CGSize size = [[CCDirectorsharedDirector]winSize];
int minY = monster.contentSize.height/2;
int maxY = size.height - monster.contentSize.height/2;
int rangeY = maxY - minY;
//The arc4random() function returns pseudo-random numbers in the range of 0 to (2**32)-1
int actualY = (arc4random()%rangeY)+minY;
// Create the monster slightly off-screen along the right edge,
// and along a random position along the Y axis as calculated above
monster.position =ccp(size.width + monster.contentSize.width/2, actualY);
[selfaddChild:monster];
//Determine the speed of monster
int minDuration =2;
int maxDuration =4;
int rangeDuration = maxDuration - minDuration;
int actualDuration = (arc4random()%rangeDuration)+ minDuration;
//Create the actions
CCMoveTo * actionMove = [CCMoveToactionWithDuration:actualDurationposition:ccp(-monster.contentSize.width/2,actualY)];
CCCallBlockN *actionMoveDone = [CCCallBlockNactionWithBlock:^(CCNode *node) {
[node removeFromParentAndCleanup:YES];
}];
[monsterrunAction:[CCSequenceactions:actionMove,actionMoveDone,nil]];
}
这个函数用到了Cocos2D提供的3种行为CCMoveTo,CCCallBlockN,CCSequence。
CCMoveTo指定要到达的目标点及所花的时间,这里目标是屏幕左边刚好看不到精灵的位置,时间为2到4秒的随机时间。
CCCallBlockN容许我们指定行为结束后要执行的代码块,这里是当怪物精灵从屏幕左边消失时,把它从层里删除,避免内存泄露。
CCSequence容许我们将各种行为串接在一起,按顺序执行,这里是先执行CCMoveTo,然后执行CCCallBlockN。
b.在HelloWorldLayer的init函数返回前增加
[selfschedule:@selector(gameLogic:)interval:1.0];
gamelogic是个回调函数,每隔1秒会被调用一次。
c.增加gameLogic函数
-(void)gamelogic:(ccTime)dt
{
[selfaddMonster];
}
有许多方法可以完成射击功能,本游戏实现的是当用户点击屏幕时,子弹会从玩家精灵射出到用户点击的方向。
作为入门,我想用行为CCMoveTo来实现它,但这需要简单的数学计算,因为CCMoveTo需要我们提供子弹经过用户点击的位置,离开屏幕的最后一个点的坐标。
a.在init函数里添加代码,使HelloWorldLayer能接受屏幕点击事件
[self setIsTouchEnabled:YES]; 或者 [selfsetTouchEnabled:YES];
b.增加函数,具体算法看原文,不复杂的三角运算
- (void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
// Choose one of the touches to work with
UITouch *touch = [touchesanyObject];
CGPoint location = [selfconvertTouchToNodeSpace:touch];//from view to current layer
// Set up initial location of projectile
CGSize winSize = [[CCDirectorsharedDirector]winSize];
CCSprite *projectile = [CCSpritespriteWithFile:@"projectile.png"];
projectile.position =ccp(20, winSize.height/2);
// Determine offset of location to projectile
CGPoint offset =ccpSub(location, projectile.position);
// Bail out if you are shooting down or backwards
if (offset.x <=0)return;
// Ok to add now - we've double checked position
[selfaddChild:projectile];
int realX = winSize.width + (projectile.contentSize.width/2);
float ratio = (float) offset.y / (float) offset.x;
int realY = (realX * ratio) + projectile.position.y;
CGPoint realDest =ccp(realX, realY);
// Determine the length of how far you'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
[projectilerunAction:
[CCSequence actions:
[CCMoveToactionWithDuration:realMoveDurationposition:realDest],
[CCCallBlockNactionWithBlock:^(CCNode *node) {
[node removeFromParentAndCleanup:YES];
}],
nil]];
}
4.击中检测
有很多种方法可以实现击中检测,例如使用Box2D或者ChipMunk。简单起见,由自己来实现检测函数。
a.打开HelloWorldLayer.h
@interface HelloWorldLayer :CCLayerColor
{
NSMutableArray* _monsters;//怪物数组
NSMutableArray* _projectiles;//子弹数组
}
b.在init函数初始化
_monsters = [[NSMutableArrayalloc]init];
_projectiles = [[NSMutableArrayalloc]init];
c.在dealloc里释放
[_monsters release];
_monsters = nil;
[_projectiles release];
_projectiles =nil;
d.修改addMonster函数,增加
monster.tag =1;//以后会用
[_monstersaddObject:monster];
修改CCCallBlock的回调代码如下
[_monstersaddObject:monster];
CCCallBlockN *actionMoveDone = [CCCallBlockNactionWithBlock:^(CCNode *node) {
[_monstersremoveObject:node];
[node removeFromParentAndCleanup:YES];
}];
e.修改ccTouchesEnded函数,增加projectile.tag = 2;//以后会用
[_projectiles addObject:projectile];
修改CCCallBlock的回调代码如下
[projectile runAction:
[CCSequence actions:
[CCMoveTo actionWithDuration:realMoveDurationposition:realDest],
[CCCallBlockN actionWithBlock:^(CCNode *node) {
[_projectiles removeObject:node];
[node removeFromParentAndCleanup:YES];
}],
nil]];
f.增加新函数,在场景中清除击中的怪物和子弹
- (void)update:(ccTime)dt {
NSMutableArray *projectilesToDelete = [[NSMutableArrayalloc]init];
for (CCSprite *projectilein_projectiles) {
NSMutableArray *monstersToDelete = [[NSMutableArrayalloc]init];
for (CCSprite *monsterin_monsters) {
//判断两个矩形是否相交,相交则表示怪物被击中
if (CGRectIntersectsRect(projectile.boundingBox, monster.boundingBox)) {
[monstersToDelete addObject:monster];
}
}
for (CCSprite *monsterin monstersToDelete) {
[_monsters removeObject:monster];
[self removeChild:monster cleanup:YES];
}
if (monstersToDelete.count >0) {
[projectilesToDelete addObject:projectile];
}
[monstersToDelete release];
}
for (CCSprite *projectilein projectilesToDelete) {
[_projectiles removeObject:projectile];
[self removeChild:projectilecleanup:YES];
}
[projectilesToDelete release];
}
g.在init函数里增加定时刷新任务
[self schedule:@selector(update:)];
5.增加游戏音效和音乐
修改HelloWorldLayer.m
增加 #import "SimpleAudioEngine.h"
在init函数增加背景音乐
[[SimpleAudioEnginesharedEngine]playBackgroundMusic:@"background-music-aac.caf"];
在ccTouchesEnded函数增加子弹音效
[[SimpleAudioEnginesharedEngine]playEffect:@"pew-pew-lei.caf"];
6.增加游戏结束层
a.从CCNode类创建新类GameOverLayer,改其父类为CCLayerColor
b.GameOverLayer.h代码如下
#import <Foundation/Foundation.h>
#import "cocos2d.h"
@interface GameOverLayer :CCLayerColor {
}
+(CCScene*) sceneWithWon:(BOOL)won;
-(id) initWithWon:(BOOL)won;
@end
c.GameOverLayer.m代码如下
#import "GameOverLayer.h"
#import "HelloWorldLayer.h"
@implementation GameOverLayer
+(CCScene *) sceneWithWon:(BOOL)won {
CCScene *scene = [CCScenenode];
GameOverLayer *layer = [[[GameOverLayeralloc]initWithWon:won]autorelease];
[sceneaddChild: layer];
return scene;
}
- (id)initWithWon:(BOOL)won {
if ((self = [superinitWithColor:ccc4(255,255,255,255)])) {
NSString * message;
if (won) {
message =@"You Won!";
}else {
message =@"You Lose :[";
}
CGSize winSize = [[CCDirectorsharedDirector]winSize];
CCLabelTTF * label = [CCLabelTTFlabelWithString:messagefontName:@"Arial"fontSize:32];
label.color =ccc3(0,0,0);
label.position =ccp(winSize.width/2, winSize.height/2);
[selfaddChild:label];
[selfrunAction:
[CCSequenceactions:
[CCDelayTimeactionWithDuration:3],
[CCCallBlockNactionWithBlock:^(CCNode *node) {
[[CCDirectorsharedDirector]replaceScene:[HelloWorldLayerscene]];
}],
nil]];
}
return self;
}
@end
修改update函数,在 [selfremoveChild:monstercleanup:YES];后面添加代码:
_monstersDestroyed++;
if (_monstersDestroyed >30) {
CCScene *gameOverScene = [GameOverLayersceneWithWon:YES];
[[CCDirectorsharedDirector]replaceScene:gameOverScene];
}
d.游戏失败条件
修改addMonster函数,在[noderemoveFromParentAndCleanup:YES];后面添加代码:
CCScene *gameOverScene = [GameOverLayersceneWithWon:NO];
[[CCDirectorsharedDirector]replaceScene:gameOverScene];