Из этого туториала вы узнаете, как использовать среду Sprite Kit для создания игры с фактами на основе вопросов. Он предназначен как для начинающих, так и для опытных пользователей. По пути вы будете применять ядро Sprite Kit. Серия Facts Game состоит из трех учебных пособий, чтобы полностью охватить каждую тему.
Вступление
Эта серия разделена на три руководства: настройка проекта, создание интерфейса и логика игры. Каждая часть даст практический результат, а сумма всех частей — финальную игру. После серии из трех статей читатели смогут создать простую игру-ответ на вопрос и ответ, включающую звуки, анимацию, меню, правила, таймеры и взаимодействие с UIKit. Несмотря на то, что каждая часть может быть прочитана независимо, для лучшего понимания мы рекомендуем вам следовать учебным пособиям по порядку. Мы также включили исходный код для каждой части в отдельности, тем самым предоставив способ начать учебник в любом разделе.
В конце этого урока результат будет выглядеть так:
1. Начальная настройка
Запустите новый проект SpriteKit
Xcode и назовите его Facts . Информация о развертывании, используемая в трех частях:
- Цель развертывания: 7
- Устройства: iPad
- Ориентация устройства: портрет
- Скрыть стиль строки состояния
Обратите внимание, что следующие четыре фреймворка автоматически включаются в проект: CoreGraphics
, UIKit
, SpriteKit
и Foundation
. Вы увидите три класса, изображение ( Spaceship.png
) и файл Main.storyboard
. Вы можете удалить изображение, так как вы не будете его использовать.
Теперь откройте Myscene.m
и закомментируйте все -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
метода -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
. Вам не нужно создавать жест касания в этой сцене, потому что вы будете использовать несколько UIKit UIButtons
для взаимодействия с пользователем.
2. Фон, метки и кнопки
Начните с изменения цвета фона SKScene, изменив свойства self.backgroundColor
. Обратите внимание, что он использует объект SKColor
с тремя свойствами для красного, синего и зеленого компонентов. Теперь измените текст myLabel
на «Факты !!» или к любому другому названию вашего интереса.
Следующим шагом является добавление необходимых ресурсов в ваш проект; найдите их в папке «Ресурсы». Несмотря на то, что вы не будете сейчас использовать все ресурсы, вам следует добавить их все. Поскольку вы будете использовать инфраструктуру UIKit, добавьте специальный метод -(void) didMoveToView:(SKView *)view
которое определяет, произошел ли переход сцены без проблем. Если проблем не возникает, приложение загружает ресурсы на экран. Добавьте этот метод в свой код. Внутри вы объявите три кнопки: одну для запуска игры, одну для опций и последнюю для выхода из приложения.
Добавьте три UIButtons
на свой MyScene.m
. Это будет выглядеть так:
1
2
3
4
5
|
@implementation MyScene {
UIButton *startButton;
UIButton *optionsButton;
UIButton *exitButton;
}
|
Каждая кнопка имеет определенные конфигурации, касающиеся расположения и размера рамки, цвета фона и фонового изображения. Вы должны попытаться создать UIButton
и добавить его в вид сцены. Кнопки должны выглядеть следующим образом:
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
|
-(void) didMoveToView:(SKView *)view{
startButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
startButton.frame = CGRectMake(CGRectGetMidX(self.frame)-100, CGRectGetMidY(self.frame), 200, 70.0);
startButton.backgroundColor = [UIColor clearColor];
[startButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal ];
UIImage *buttonImageNormal = [UIImage imageNamed:@»StartBtn.png»];
UIImage *strechableButtonImageNormal = [buttonImageNormal stretchableImageWithLeftCapWidth:12 topCapHeight:0];
[startButton setBackgroundImage:strechableButtonImageNormal forState:UIControlStateNormal];
[self.view addSubview:startButton];
optionsButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
optionsButton.frame = CGRectMake(CGRectGetMidX(self.frame)-100, CGRectGetMidY(self.frame)+90, 200, 70.0);
optionsButton.backgroundColor = [UIColor clearColor];
[optionsButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal ];
UIImage *buttonOptionsImageNormal = [UIImage imageNamed:@»OptionsBtn.png»];
UIImage *strechableButtonOptionsImageNormal = [buttonOptionsImageNormal stretchableImageWithLeftCapWidth:12 topCapHeight:0];
[optionsButton setBackgroundImage:strechableButtonOptionsImageNormal forState:UIControlStateNormal];
[self.view addSubview:optionsButton];
exitButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
exitButton.frame = CGRectMake(CGRectGetMidX(self.frame)-100, CGRectGetMidY(self.frame)+180, 200, 70.0);
exitButton.backgroundColor = [UIColor clearColor];
[exitButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal ];
UIImage *buttonExitImageNormal = [UIImage imageNamed:@»ExitBtn.png»];
UIImage *strechableButtonExitImageNormal = [buttonExitImageNormal stretchableImageWithLeftCapWidth:12 topCapHeight:0];
[exitButton setBackgroundImage:strechableButtonExitImageNormal forState:UIControlStateNormal];
[self.view addSubview:exitButton];
}
|
Run
проект и увидите новый корневой интерфейс. Если вы хотите, вы можете настроить местоположение, размер и положение объектов интерфейса. Если вы хотите узнать больше о SKLabelNode
или UIButton
, я советую вам поиграть с этими классами немного больше. Интерфейс должен выглядеть примерно так:
Настало время добавить больше классов в ваш проект.
3. Новая игра и опции SKScenes
Шаг 1
Поскольку вы добавили несколько кнопок, теперь пришло время использовать их для перенаправления пользователя на другой интерфейс. Добавьте два новых класса. Выберите « Файл»> «Создать»> «Файл» и класс Objective-C . Назовите классы FactsScene
и OptionsScene
. Обратите внимание, что оба будут суперклассом SKScene
.
В вашем проекте доступны четыре новых файла: FactsScene.h
, FactsScene.m
, OptionsScene.h
и OptionsScene.m
. Обратите внимание, что файлы реализации обоих классов практически пусты. Следовательно, вы должны добавить инициализаторы класса. Для обоих классов используйте -initWithSize:
метод. Попробуйте и добавьте это самостоятельно. Если у вас возникли проблемы, вам поможет следующий фрагмент кода:
1
2
3
4
5
6
|
-(id)initWithSize:(CGSize)size{
if (self = [super initWithSize:size]) {
NSLog(@»Opstions Scene»);
}
return self;
}
|
Еще раз вы должны применить его для обоих классов. Теперь, когда у вас есть инициализаторы классов, пришло время изменить код UIButton
с последнего шага для переключения между классами. Вернитесь на MyScene.m
и импортируйте оба класса в разделе импорта:
1
2
|
#import «OptionsScene.h»
#import «FactsScene.h»
|
Теперь в startButton
, optionsButton
и exitButton
вам нужно добавить пользовательское действие. На каждую кнопку добавьте соответствующую строку кода.
1
2
3
|
[startButton addTarget:self action:@selector(moveToGame) forControlEvents:UIControlEventTouchUpInside];
[optionsButton addTarget:self action:@selector(moveToOptions) forControlEvents:UIControlEventTouchUpInside];
[exitButton addTarget:self action:@selector(endApplication) forControlEvents:UIControlEventTouchUpInside];
|
Вы должны увидеть три предупреждения («необъявленный селектор»). Не волнуйся! Настало время добавить эти методы в ваш класс.
1
2
3
|
-(void) moveToGame {}
-(void) moveToOptions {}
-(void) endApplication {}
|
Каждый отвечает за определенное действие, а название каждого метода говорит само за себя. -(void) moveToGame
и -(void) moveToOptions
похожи, поскольку оба используются для создания перехода из этого SKScene
в другой. В каждом методе вы должны создать целевой объект SKScene
и объект перехода и представить новую сцену. Обратите внимание, что, поскольку вы используете объекты UIKit, вам также необходимо удалить их со сцены при переходах SKScene
. Если у вас возникли проблемы с этими шагами, вам помогут следующие фрагменты:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
|
-(void) moveToGame{
NSLog(@»moveToGame»);
FactsScene* factsScene = [[FactsScene alloc] initWithSize:CGSizeMake(CGRectGetMaxX(self.frame), CGRectGetMaxY(self.frame))];
SKTransition* transition = [SKTransition revealWithDirection:SKTransitionDirectionUp duration:1];
[startButton removeFromSuperview];
[optionsButton removeFromSuperview];
[exitButton removeFromSuperview];
[self.scene.view presentScene:factsScene transition:transition];
}
-(void) moveToOptions{
NSLog(@»moveToOptions»);
OptionsScene* optionsScene = [[OptionsScene alloc] initWithSize:CGSizeMake(CGRectGetMaxX(self.frame), CGRectGetMaxY(self.frame))];
SKTransition* transition = [SKTransition revealWithDirection:SKTransitionDirectionLeft duration:1];
[startButton removeFromSuperview];
[optionsButton removeFromSuperview];
[exitButton removeFromSuperview];
[self.scene.view presentScene:optionsScene transition:transition];
}
|
Последний метод -(void) endApplication
— проще, поскольку он используется только для завершения приложения.
1
2
3
4
5
6
|
-(void) endApplication{
[startButton removeFromSuperview];
[optionsButton removeFromSuperview];
[exitButton removeFromSuperview];
exit(0);
}
|
Шаг 2
Настало время Run
код и протестировать новые функции. Если все в порядке, вы сможете изменить вид по умолчанию на представление « New Game
и « Options
. Однако вы не можете вернуться в главное меню. Давайте изменим это прямо сейчас.
Следующие шаги — добавить кнопку UIB в сцену Options
, запрограммировать ее для перехода обратно в главное меню и выбрать создание эффекта перехода (или нет). Для этого необходимо выполнить несколько шагов:
- Добавьте
-(void) didMoveToView:(SKView *)view
метод представления - Добавить объект UIButton
- Настройте UIButton
- Добавьте метод
@selector
- Импортируйте
MyScene.h
Сначала перейдите в OptionsScene.h
и добавьте:
1
|
@property (nonatomic, retain) UIButton* backButton;
|
Теперь переключите ваше внимание на OptionsScene.m
. didMoveToView
псевдокода должны добавить метод didMoveToView, UIButton и конфигурацию кнопки.
01
02
03
04
05
06
07
08
09
10
11
|
-(void) didMoveToView:(SKView *)view{
_backButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
_backButton.frame = CGRectMake(CGRectGetMidX(self.frame)-100, CGRectGetMidY(self.frame)+180, 200, 70.0);
_backButton.backgroundColor = [UIColor clearColor];
[_backButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal ];
UIImage *buttonExitImageNormal = [UIImage imageNamed:@»ExitBtn.png»];
UIImage *strechableButtonExitImageNormal = [buttonExitImageNormal stretchableImageWithLeftCapWidth:12 topCapHeight:0];
[_backButton setBackgroundImage:strechableButtonExitImageNormal forState:UIControlStateNormal];
[_backButton addTarget:self action:@selector(moveToHome) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:_backButton];
}
|
Затем добавьте метод @selector
.
1
2
3
4
5
|
-(void) moveToHome{
MyScene* myScene = [[MyScene alloc] initWithSize:CGSizeMake(CGRectGetMaxX(self.frame), CGRectGetMaxY(self.frame))];
[_backButton removeFromSuperview];
[self.scene.view presentScene:myScene];
}
|
Run
свой код, чтобы проверить, все ли работает. Теперь вы можете перейти от корневого интерфейса к OptionsScene
и обратно. Теперь мы можем заполнить сцену параметров.
4. Варианты SKScene
Шаг 1
Опции игры — это то, где пользователь может изменить настройки игры. На данный момент вы сосредоточитесь только на двух вариантах: музыка и звук. Вам нужно добавить SKLabelNode
, UISwitch
и объект OptionsScene.h
в OptionsScene.h
:
1
2
3
4
|
@property (nonatomic, retain) IBOutlet UISwitch *musicSwitch;
@property (nonatomic, retain) IBOutlet UISwitch *soundSwitch;
@property (nonatomic, retain) SKLabelNode* soundTitle;
@property (nonatomic, retain) SKLabelNode* musicTitle;
|
Затем на OptionsScene.m
внутри метода didMoveToView
выделите объекты как:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
|
_soundSwitch = [[UISwitch alloc] initWithFrame:CGRectMake(CGRectGetMidX(self.frame)+50, CGRectGetMidY(self.frame)-26, 100, 100)];[_soundSwitch addTarget: self action: @selector(flipMusicAndSound:) forControlEvents:UIControlEventValueChanged];
[self.view addSubview: _soundSwitch];
_musicSwitch = [[UISwitch alloc] initWithFrame:CGRectMake(CGRectGetMidX(self.frame)+50, CGRectGetMidY(self.frame)+50, 100, 100)];
[_musicSwitch addTarget: self action: @selector(flipMusicAndSound:) forControlEvents:UIControlEventValueChanged];
[self.view addSubview: _musicSwitch];
_soundTitle = [SKLabelNode labelNodeWithFontNamed:@»Chalkduster»];
[_soundTitle setText:@»Sound»];
[_soundTitle setFontSize:40];
[_soundTitle setPosition:CGPointMake(CGRectGetMidX(self.frame)-80, CGRectGetMidY(self.frame))];
[self addChild:_soundTitle];
_musicTitle = [SKLabelNode labelNodeWithFontNamed:@»Chalkduster»];
[_musicTitle setText:@»Music»];
[_musicTitle setFontSize:40];
[_musicTitle setPosition:CGPointMake(CGRectGetMidX(self.frame)-80, CGRectGetMidY(self.frame)-80)];
[self addChild:_musicTitle];
|
Вы получите предупреждение. Чтобы исправить это, добавьте метод flipMusicAndSound
. Этот метод проверяет состояние _soundSwitch
и _musicSwitch
UISwitches и устанавливает ключ по умолчанию для каждого свойства, используя NSUserDefaults
. Прежде чем завершить метод, вы должны добавить объект NSUserDefaults
в класс.
1
2
3
|
@implementation OptionsScene{
NSUserDefaults* defaults;
}
|
Затем вы должны выделить его в методе initWithSize
следующим образом:
1
|
defaults = [NSUserDefaults standardUserDefaults];
|
Шаг 2
Теперь вы готовы использовать преимущества NSUserDefaults
. Вы будете использовать его для хранения состояния звука и музыкальных свойств во всем приложении. Вы можете написать и заполнить метод flipMusicAndSound
. Вы будете использовать integer
значение 1, чтобы включить звук и музыку, и 0 в противном случае. flipMusicAndSound
находится ниже.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
|
— (IBAction)flipMusicAndSound:(id)sender {
if (_musicSwitch.on) {
[defaults setInteger:1 forKey:@»music»];
}
else {
[defaults setInteger:0 forKey:@»music»];
}
if (_soundSwitch.on) {
[defaults setInteger:1 forKey:@»sound»];
}
else {
[defaults setInteger:0 forKey:@»sound»];
}
}
|
Если вы Run
проект и OptionsScene
с обоими переключателями, вы увидите, что каждый раз, когда вы переходите к OptionsScene
оба переключателя имеют состояние по умолчанию, а не последнее определенное состояние. Чтобы изменить это, мы должны прочитать объект didMoveToView
методе didMoveToView
.
Вы будете определять две переменные для звука и музыки и проверять каждый свойственный ключ свойства. Это очень простой и логичный тест решения. Если вы не знаете, как это сделать, вам поможет следующий фрагмент кода:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
|
long soundDefaults = [defaults integerForKey:@»sound»];
long musicDefaults = [defaults integerForKey:@»music»];
if (soundDefaults == 1) {
[_soundSwitch setOn:YES animated:YES];
}
else {
[_soundSwitch setOn:FALSE animated:YES];
}
if (musicDefaults == 1) {
[_musicSwitch setOn:YES animated:YES];
} else{
[_musicSwitch setOn:FALSE animated:YES];
}
|
Последний шаг в файле OptionsScene.m
— удаление элементов UISwitch из суперпредставления каждый раз, когда пользователь нажимает кнопку «Назад»:
1
2
|
[_soundSwitch removeFromSuperview];
[_musicSwitch removeFromSuperview];
|
Вот иллюстрация интерфейса параметров:
Шаг 3
Перейти на FactsScene.m
. Теперь мы можем добавить элементы звука и музыки. Как и в случае с OptionsScene
, нам нужно использовать NSUserDefaults
чтобы получить значение для музыки и звука. Нам также понадобится объект для хранения музыкального пути, а другой — для музыкального проигрывателя iOS. Таким образом, мы объявим их как:
1
2
3
4
|
@implementation FactsScene{
NSUserDefaults* defaults;
NSString* musicPath;
}
|
Также в FactsScene.h
:
1
|
@property (nonatomic, strong) AVAudioPlayer* musicPlayer;
|
Вы должны объявить (как вы сделали с последним классом) метод -(void) didMoveToView:(SKView *)view
. Внутри вы должны проверить, включены ли музыкальные и звуковые настройки, и выделить музыкальные предпочтения. Оба могут быть достигнуты через:
01
02
03
04
05
06
07
08
09
10
11
|
musicPath = [[NSBundle mainBundle] pathForResource:@»music» ofType:@»mp3″];
_musicPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:musicPath] error:NULL];
_musicPlayer.numberOfLoops = -1;
_musicPlayer.volume = 0.7;
long musicFlag = [defaults integerForKey:@»music»];
if (musicFlag == 1){
[_musicPlayer play];
} else {
[_musicPlayer stop];
}
|
Вышеупомянутый код запускает или останавливает музыку, только если ее свойство включено. Мы также хотим создавать звуки, когда происходит касание. Итак, нам нужно ловить сенсорные взаимодействия и реагировать соответственно.
Вы помните — -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
из MyScene.m
реализации MyScene.m
? Вы определите это и будете использовать его здесь.
1
2
3
4
5
|
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
for (UITouch *touch in touches) {
[self touchWillProduceASound:@»False»];
}
}
|
Обратите внимание, что -(void) touchWillProduceASound:(NSString*)answer
еще не объявлен. Объявите это. Он используется для проверки того, является ли данное касание «правильным» или «неправильным» (об этом будет больше в следующем уроке). Он анализирует (NSString*)answer
и издает звук в соответствии с содержимым этой NSString.
Звук создается с SKAction
объекта SKAction
. Создает звуковой объект и воспроизводит определенный звук. Еще раз, это происходит, только если свойство звука (заданное NSUserDefaults
) NSUserDefaults
.
01
02
03
04
05
06
07
08
09
10
11
12
|
-(void) touchWillProduceASound:(NSString*)answer{
long soundFlag = [defaults integerForKey:@»sound»];
if (soundFlag == 1){
SKAction* sound;
if ([answer isEqualToString:@»False»]) {
sound = [SKAction playSoundFileNamed:@»beep.mp3″ waitForCompletion:YES];
NSLog(@»inside»);
}
[self runAction:sound];
}
}
|
Запустите проект и протестируйте новые музыкальные и звуковые взаимодействия. Активируйте и деактивируйте звуковые и музыкальные переключатели UIS и перейдите на новую игровую сцену, чтобы проверить их правильность.
Вывод
Это конец первого урока! На этом этапе вы можете инициировать и настраивать проект SpriteKit, добавлять и инициализировать объекты SKScene
, перемещаться между объектами SKScene
, взаимодействовать между средами SpriteKit и UIKit, а также добавлять и удалять звуки и музыку. В следующих уроках вы будете иметь дело с созданием интерфейса и игровой логикой.