Это седьмая и последняя часть нашей серии руководств по Cocos2D по клонированию Сороконожка для iOS. Убедитесь, что вы завершили предыдущие части, прежде чем начать.
Последний раз…
В последнем уроке мы обсуждали, как сделать простое обнаружение столкновений между всеми объектами в нашей игре.
В сегодняшнем уроке мы подведем итоги, обсудив выигрыш, условия победы, игровой звук и игру поверх экрана.
Шаг 1: продвижение игры
На данный момент, когда вы уничтожаете гусеницу, ничего не происходит. Способ продвинуться вперед состоит в том, чтобы повысить уровень и перезапустить с новыми побегами и новой гусеницей. Это легко сделать, поскольку мы строили игру, чтобы поддерживать это с самого начала. Откройте GameLayer.m и добавьте следующий метод:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
|
— (void)checkNextLevel {
if([self.caterpillars count] == 0) { //1
self.level++;
// 3
CGPoint startingPosition = ccp(kGameAreaStartX, kGameAreaHeight + kGameAreaStartY — kGridCellSize / 2);
Caterpillar *caterpillar = [[[Caterpillar alloc] initWithGameLayer:self level:self.level position:startingPosition] autorelease];
[self.caterpillars addObject:caterpillar];
// 4
int minSproutCount = kStartingSproutsCount + self.level * 2;
if([self.sprouts count] < minSproutCount) {
int numberOfSproutsToPlace = minSproutCount — [self.sprouts count];
for(int x = 0; x < numberOfSproutsToPlace; x++) {
[self placeRandomSprout];
}
}
}
}
|
- Проверьте, не осталось ли гусениц
- Увеличить уровень
- Создайте новую гусеницу и добавьте ее в игру (на основе нового уровня)
- Добавьте ростки в соответствии с minSproutCount
Теперь, когда у нас реализован метод, мы должны вызывать его каждый раз, когда гусеница попадает в цель. Внутри splitCaterpillar:atSegment:
метод добавьте следующую строку перед оператором return внутри первого оператора if:
1
2
3
4
5
6
|
if([caterpillar.segments count] == 1) {
// …
// Add this line
[self checkNextLevel];
return;
}
|
Это состояние, когда гусеница представляет собой всего один сегмент. В дополнение к добавлению здесь, добавьте его в самый конец этого метода. Это должно охватывать все случаи.
Если вы запустите игру на этом этапе, вы сможете играть бесконечно, скорость гусеницы увеличивается на каждом уровне.
Шаг 2: Оценка
В игре есть несколько мест, где игрок может увеличить свой счет. Они есть:
- Бить росток
- Удар гусеницы
- Переход на следующий уровень
Мы собираемся немного попрыгать, чтобы добавить подсчет очков к каждому из этих действий, так что оставайтесь со мной.
Прежде чем мы начнем обновлять счет, нам нужно определить еще три константы, которые будут базовыми для оценки. Откройте GameConfig.h и добавьте следующие 3 строки:
1
2
3
|
#define kSproutHitPoints 25
#define kCaterpillarHitPoints 200
#define kNextLevelPoints 1000
|
Вы увидите, как они используются, когда мы немного углубимся в это руководство.
Давайте начнем с добавления к счету игроков, когда они попали в росток в игре. Откройте Missile.m, импортируйте Player.h и добавьте следующий код в цикл, который проверяет столкновение с ростком:
1
2
3
4
|
self.gameLayer.player.score += kSproutHitPoints +
(arc4random() % self.gameLayer.level) *
(arc4random() % self.gameLayer.level);
[[NSNotificationCenter defaultCenter] postNotificationName:kNotificationPlayerScore object:nil];
|
Это увеличивает счет игрока на основе базовых очков и некоторой степени случайности на основе текущего уровня. Таким образом, когда игрок поднимается по уровню, он получает больше очков за уничтожение побегов.
Как и при настройке начального счета, нам нужно опубликовать уведомление, которое обновит метку счета игрока. Это делается при каждом обновлении счета. Если вы запустите игру в этот момент, вы должны видеть, что метка счета игрока обновляется каждый раз, когда вы попадаете в росток.
Следующее место, которое мы собираемся добавить, — это когда гусеница поражена. В самом низу метода update:
в Missile.m добавьте следующий код перед разбиением гусеницы:
01
02
03
04
05
06
07
08
09
10
|
if(hitCaterpillar && hitSegment) {
// Add these lines
self.gameLayer.player.score += kCaterpillarHitPoints +
(arc4random() % self.gameLayer.level) *
(arc4random() % self.gameLayer.level);
[[NSNotificationCenter defaultCenter] postNotificationName:kNotificationPlayerScore object:nil];
// … code to split the caterpillar …
}
|
Этот код не сильно отличается от того, что вы видели выше. Последнее место для добавления очков — это когда игрок поднимается по уровню. Этот код будет размещен внутри метода checkNextLevel
который вы написали выше. Откройте GameLayer.m, перейдите к методу checkNextLevel
и добавьте следующий код сразу после оператора if:
1
2
|
self.player.score += kNextLevelPoints * self.level;
[[NSNotificationCenter defaultCenter] postNotificationName:kNotificationPlayerScore object:nil];
|
Здесь нет сюрпризов. Если вы хотите добавить некоторые вариации к оценке в вашей собственной игре, не стесняйтесь изменять значения счета.
Шаг 3: Игра окончена
На данный момент ваш игрок имеет Game Genie и имеет бесконечные жизни. Нам нужно это изменить. Сначала создайте новый файл с именем GameOverLayer.m, который расширяет CCLayer.
Добавьте следующий код в GameOverLayer.h:
1
2
3
4
5
6
7
8
9
|
#import «cocos2d.h»
#import «GameConfig.h»
@interface GameOverLayer : CCLayer
@property (nonatomic, assign) NSInteger score;
@property(nonatomic, retain) CCLabelTTF *scoreLabel;
@property(nonatomic, retain) CCLabelTTF *highScoreLabel;
+(CCScene *) sceneWithScore:(NSInteger) score;
@end
|
Я объясню, что каждое из этих свойств и методов делает во время реализации. Теперь добавьте следующий код в GameOverLayer.m
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
|
#import «GameOverLayer.h»
#import «GameLayer.h»
#import «SimpleAudioEngine.h»
@implementation GameOverLayer
@synthesize score = _score;
@synthesize scoreLabel = _scoreLabel;
@synthesize highScoreLabel = _highScoreLabel;
// 1
+(CCScene *) sceneWithScore:(NSInteger) score
{
// ‘scene’ is an autorelease object.
CCScene *scene = [CCScene node];
// ‘layer’ is an autorelease object.
GameOverLayer *layer = [GameOverLayer node];
layer.score = score;
// add layer as a child to scene
[scene addChild: layer];
// return the scene
return scene;
}
// 2
— (void)dealloc {
[_scoreLabel release];
[_highScoreLabel release];
[super dealloc];
}
-(id) init
{
if( (self=[super init])) {
// 3
[CCTexture2D setDefaultAlphaPixelFormat:kCCTexture2DPixelFormat_RGB565];
CCSprite * background = [CCSprite spriteWithFile:@»game-over.png»];
background.anchorPoint = ccp(0,0);
[self addChild:background];
// 4
_scoreLabel = [[CCLabelTTF labelWithString:@»0″
dimensions:CGSizeMake(320, 30)
alignment:UITextAlignmentCenter
fontName:@»Helvetica»
fontSize:30] retain];
_scoreLabel.anchorPoint = ccp(0,0);
_scoreLabel.position = ccp(0,155);
[self addChild:_scoreLabel];
_highScoreLabel = [[CCLabelTTF labelWithString:[NSString stringWithFormat:@»High: %d»,0]
dimensions:CGSizeMake(320, 35)
alignment:UITextAlignmentCenter
fontName:@»Helvetica»
fontSize:30] retain];
_highScoreLabel.anchorPoint = ccp(0,0);
_highScoreLabel.color = (ccColor3B){255,0,0};
_highScoreLabel.position = ccp(0,195);
[self addChild:_highScoreLabel];
// 5
[[CCTouchDispatcher sharedDispatcher] addTargetedDelegate:self priority:0 swallowsTouches:YES];
[[SimpleAudioEngine sharedEngine] playEffect:@»game-over.caf»];
}
return self;
}
— (void)setScore:(NSInteger)score {
_score = score;
self.scoreLabel.string = [NSString stringWithFormat:@»Score: %d»,_score];
// 6
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSInteger highScore = [defaults integerForKey:@»CentipedeHighScore»];
// 7
if(score > highScore) {
highScore = score;
[defaults setInteger:score forKey:@»CentipedeHighScore»];
[defaults synchronize];
}
self.highScoreLabel.string = [NSString stringWithFormat:@»High: %d»,highScore];
}
// 8
— (BOOL)ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event {
[[CCDirector sharedDirector] replaceScene:[CCTransitionFade transitionWithDuration:.5 scene:[GameLayer scene] withColor:ccWHITE]];
return YES;
}
@end
|
- Это наш стандартный метод для создания новой сцены. Единственная разница в том, что он берет NSInteger и устанавливает его в текущий счет.
- Убирать
- Визуализировать фон
- Установите метки для отображения счета и рекорда
- Включить касания
- Посмотрите на высокий балл
- Сравните новый счет с самым высоким, сохраните новый, если он выше.
- Начните новую игру, если игрок касается экрана
Вот скриншот того, как должен выглядеть этот экран:
Последний шаг — открыть GameLayer.m и добавить следующие строки в конец метода updateLives
:
1
2
3
|
if (lifeCount == 0) {
[[CCDirector sharedDirector] replaceScene:[CCTransitionFade transitionWithDuration:.5 scene:[GameOverLayer sceneWithScore:self.player.score] withColor:ccWHITE]];
}
|
Это проверяет, установлены ли жизни на 0. Если это так, мы заменяем текущую сцену сценой Game Over.
Шаг 4: Аудио игры
Последний шаг в нашей игре — добавить звук. Сначала загрузите звуки ниже и добавьте их в свой проект:
Традиционно обработка звука была довольно болезненной в игре OpenGL. Вы должны будете использовать что-то вроде OpenAL или другую сложную библиотеку C ++. Cocos2D значительно упростил работу с библиотекой SimpleAudioEngine
. Это дает вам возможность легко воспроизводить фоновую музыку, а также быстрые звуки.
Опять же, мы будем прыгать совсем немного. Так что, если размещение какого-либо кода неясно для вас, пожалуйста, спросите меня в комментариях или обратитесь к исходному коду этого руководства.
Откройте AppDelegate.m и импортируйте SimpleAudioEngine.h и добавьте следующую строку в конец метода applicationDidFinishLaunching
.
1
|
[[SimpleAudioEngine sharedEngine] playBackgroundMusic:@»background.caf»];i
|
Это оно! Для воспроизведения фоновой музыки на протяжении всего времени воспроизведения необходима только одна строка. Теперь нам просто нужно воспроизводить звуковые эффекты в ответ на различные действия.
В Caterpillar.m, когда Caterpillar сталкивается с игроком (ближе к концу update:
метод):
1
|
[[SimpleAudioEngine sharedEngine] playEffect:@»player-hit.caf»];
|
В Missile.m, когда Ракета попадает в Росток:
1
|
[[SimpleAudioEngine sharedEngine] playEffect:@»sprout-hit.caf»];
|
Также в Missile.m, когда Ракета попадает в Гусеницу:
1
|
[[SimpleAudioEngine sharedEngine] playEffect:@»caterpillar-hit.caf»];
|
В методе init в GameOverLayer.m:
1
|
[[SimpleAudioEngine sharedEngine] playEffect:@»game-over.caf»];
|
Это должно охватывать все звуки, которые я использовал в игре. Кроме того, обязательно импортируйте SimpleAudioEngine.h в каждый из перечисленных выше классов.
Вывод
На этом мы завершаем серию из 7 частей по созданию игры Caterpillar с использованием Cocos2D для iPhone. К настоящему времени у вас должно быть четкое понимание того, как проектировать и создавать простую игру, используя игровой движок Cocos2D. Если у вас есть какие-либо вопросы или комментарии, пожалуйста, оставляйте их в разделе комментариев здесь или пишите мне в Twitter .
Удачного кодирования!