В этом уроке я покажу вам, как создать простую многопользовательскую игру, используя платформу Multipeer Connectivity, которая была представлена в iOS 7. В первой части этой серии мы заложили основу игры. В этой статье мы реализуем игровую логику.
1. Реализация игровой логики
На этом этапе приложение может обнаружить других соседних игроков, установить соединение и отобразить подключенные узлы в текстовом представлении контроллера представления параметров. Однако реализация класса OptionsViewController
еще не закончена.
Шаг 1
Контроллер представления параметров содержит текстовое поле в верхней части его представления. Мы будем использовать это текстовое поле, чтобы позволить пользователю изменить отображаемое имя устройства. На данный момент имя устройства используется в качестве отображаемого имени партнера. Давайте рассмотрим, как мы можем настроить это отображаемое имя.
Давайте начнем с принятия протокола OptionsViewController
классе OptionsViewController
. Откройте OptionsViewController.h и измените интерфейс класса, как показано ниже.
1
|
@interface OptionsViewController : UIViewController <MCBrowserViewControllerDelegate, UITextFieldDelegate>
|
В файле реализации класса установите контроллер представления в качестве делегата текстового поля в методе viewDidLoad
.
1
2
3
4
|
— (void)viewDidLoad {
// … //
[self.txtPlayerName setDelegate:self];
}
|
Нам нужно реализовать только один метод протокола textFieldShouldReturn:
, textFieldShouldReturn:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
|
— (BOOL)textFieldShouldReturn:(UITextField *)textField {
[self.txtPlayerName resignFirstResponder];
if (self.appDelegate.mpcHandler.peerID != nil) {
[self.appDelegate.mpcHandler.session disconnect];
self.appDelegate.mpcHandler.peerID = nil;
self.appDelegate.mpcHandler.session = nil;
}
[self.appDelegate.mpcHandler setupPeerWithDisplayName:self.txtPlayerName.text];
[self.appDelegate.mpcHandler setupSession];
[self.appDelegate.mpcHandler advertiseSelf:self.swVisible.isOn];
return YES;
}
|
Сначала мы вызываем resignFirstResponder
в текстовом поле, чтобы закрыть клавиатуру. Далее, если объекты peerID
и session
не равны nil
, мы сбрасываем оба значения, устанавливая их peerID
nil
. Мы также вызываем disconnect
connect для объекта session
чтобы отключить устройство от любых одноранговых узлов, к которым оно может подключаться. Затем мы инициализируем объект peerID
используя имя, введенное пользователем в текстовое поле, и настраиваем объект session
. Попробуйте это, запустив приложение и изменив отображаемое имя. Если все идет хорошо, вместо имени устройства будет использоваться пользовательское имя.
Есть одно предупреждение: при использовании настраиваемого отображаемого имени устройство отключается от любого активного сеанса, частью которого он является в настоящее время. Это также означает, что любая игра, которая находится в процессе, заканчивается. Несмотря на то, что мы не добавили никаких мер для предотвращения этого, убедитесь, что вы не разрешаете пользователям изменять отображаемое имя, когда устройство является частью активного сеанса.
Шаг 2
Следующим шагом является реализация действия toggleVisibility:
мы объявили ранее. Его реализация не может быть проще. Всякий раз, когда переключатель переключается, мы вызываем advertiseSelf:
метод объекта mpcHandler
и передаем ему состояние переключателя. Запустите приложение, чтобы попробовать.
1
2
3
|
— (IBAction)toggleVisibility:(id)sender {
[self.appDelegate.mpcHandler advertiseSelf:self.swVisible.isOn];
}
|
Шаг 3
Нам также необходимо реализовать действие disconnect:
action. Отключить устройство от сеанса так же просто. Посмотрите на реализацию disconnect:
ниже.
1
2
3
|
— (IBAction)disconnect:(id)sender {
[self.appDelegate.mpcHandler.session disconnect];
}
|
Это завершает его для класса OptionsViewController
. Приложение в его текущем состоянии может установить соединение, обновить отображаемое имя устройства и отключиться от активного сеанса. Пришло время сосредоточиться на самой игре, исследуя, как мы можем обмениваться данными между сверстниками.
2. Создание новой игры
Шаг 1
Теперь давайте сосредоточимся на реализации класса ViewController
. Начните с объявления свойства делегата приложения и установки его в методе viewDidLoad
контроллера представления. Это включает в себя три шага.
- Откройте ViewController.m и добавьте оператор импорта для класса
AppDelegate
.1#import «AppDelegate.h» -
AppDelegate
свойство для объектаAppDelegate
.12345@interface ViewController ()@property (nonatomic, strong) AppDelegate *appDelegate;@end - В
viewDidLoad
сохраните ссылку на делегат приложения в свойствеappDelegate
.12345— (void)viewDidLoad {[super viewDidLoad];self.appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;}
Шаг 2
На следующем шаге мы объявим три свойства, которые будем использовать для отслеживания состояния игры.
1
2
3
4
5
6
7
8
9
|
@interface ViewController ()
@property (nonatomic, strong) AppDelegate *appDelegate;
@property (nonatomic) int secretNumber;
@property (nonatomic) BOOL hasCreatedGame;
@property (nonatomic) BOOL isGameRunning;
@end
|
- Свойство
secretNumber
будет хранить секретный номер, выбранный игроком, принимающим игру. - Флаг
hasCreatedGame
указывает, является ли текущий игрок тем, кто начал текущую игру. - Флаг
isGameRunning
указывает, идет ли игра в данный момент.
Шаг 3
Чтобы начать новую игру, игрок, который начинает игру, должен установить секретный номер. Основное внимание в этом руководстве уделяется инфраструктуре Multipeer Connectivity, поэтому мы не будем беспокоиться о сложном механизме установки секретного номера. А что проще, чем просмотр предупреждений, запрашивающий у игрока секретный номер?
Новая игра начинается, когда игрок нажимает кнопку « Пуск» на панели навигации, а это значит, что нам нужно реализовать действие startGame:
. Как вы можете видеть в его реализации ниже, мы сначала проверяем, идет ли уже игра, перед тем, как представить представление предупреждений. Мы не хотим начинать новую игру, пока идет другая.
01
02
03
04
05
06
07
08
09
10
11
12
13
|
— (IBAction)startGame:(id)sender {
if (!self.isGameRunning) {
UIAlertView *newGameAlert = [[UIAlertView alloc] initWithTitle:@»MPCDemo»
message:@»Please enter a number between 1 and 100:»
delegate:self
cancelButtonTitle:@»Cancel»
otherButtonTitles:@»Start Game», nil];
newGameAlert.alertViewStyle = UIAlertViewStylePlainTextInput;
[[newGameAlert textFieldAtIndex:0] setKeyboardType:UIKeyboardTypeNumberPad];
[newGameAlert show];
}
}
|
Если для параметра alertViewStyle
значение UIAlertViewStylePlainTextInput
, в представление предупреждений добавляется текстовое поле.
Шаг 4
Как только игрок введет секретный номер, нам нужно позаботиться о трех вещах.
- Нам нужно обработать нажатие игроком кнопки « Начать игру» .
- Нам также необходимо проверить, находится ли выбранное число между
1
и100
. - Другие игроки в игре должны быть уведомлены о том, что игра началась и был установлен секретный номер.
Давайте начнем с первой задачи с реализации alertView:clickedButtonAtIndex:
метод делегата протокола UIAlertViewDelegate
. Откройте файл заголовка контроллера представления и UIAlertViewDelegate
протокол UIAlertViewDelegate
, как показано ниже.
1
|
@interface ViewController : UIViewController <UIAlertViewDelegate>
|
Затем реализуйте alertView:clickedButtonAtIndex:
метод протокола UIAlertViewDelegate
. Чтобы убедиться, что представление предупреждений содержит текстовое поле, мы сначала проверяем его свойство alertViewStyle
чтобы увидеть, равно ли оно UIAlertViewStylePlainTextInput
. Мы также удостоверимся, что кнопка « Начать игру» была нажата, проверив, что свойство buttonIndex
нажатой кнопки равно 1
.
1
2
3
4
5
|
— (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
if (alertView.alertViewStyle == UIAlertViewStylePlainTextInput && buttonIndex == 1) {
}
}
|
Затем мы извлекаем ввод текстового поля и преобразуем его в целое число, которое сохраняем в свойстве secretNumber
контроллера представления.
1
2
3
4
5
6
7
|
— (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
if (alertView.alertViewStyle == UIAlertViewStylePlainTextInput && buttonIndex == 1) {
UITextField *textField = [alertView textFieldAtIndex:0];
self.secretNumber = [textField.text intValue];
}
}
|
Следующим шагом является проверка, является ли выбранное число от 1
до 100
, что очень легко сделать. Если число не попадает в требуемый диапазон, мы выводим на экран предупреждение для игрока. Однако, если секретный номер пройдет наш тест, мы создадим сообщение для других игроков и отправим его подключенным партнерам, используя инфраструктуру Multipeer Connectivity. Как это работает?
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
|
— (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
if (alertView.alertViewStyle == UIAlertViewStylePlainTextInput && buttonIndex == 1) {
UITextField *textField = [alertView textFieldAtIndex:0];
self.secretNumber = [textField.text intValue];
// Make sure that the given number is between 1 and 100.
if (self.secretNumber >= 1 && self.secretNumber <= 100) {
// Create a message to tell other players that a new game has been created,
// convert it to a NSData object and send it.
NSString *messageToSend = @»New Game»;
NSData *messageAsData = [messageToSend dataUsingEncoding:NSUTF8StringEncoding];
NSError *error;
[self.appDelegate.mpcHandler.session sendData:messageAsData
toPeers:self.appDelegate.mpcHandler.session.connectedPeers
withMode:MCSessionSendDataReliable
error:&error];
// If any error occurs, just log it.
// Otherwise set the following couple of flags to YES, indicating that the current player is the creator
// of the game and a game is in progress.
if (error != nil) {
NSLog(@»%@», [error localizedDescription]);
} else{
self.hasCreatedGame = YES;
self.isGameRunning = YES;
[self.tvHistory setText:@»»];
}
} else{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@»MPCDemo»
message:@»Please enter a valid number.»
delegate:nil
cancelButtonTitle:nil
otherButtonTitles:@»Okay», nil];
[alert show];
}
}
}
|
Мы создаем экземпляр NSString
, устанавливаем его значение в New Game
и кодируем строку в объект NSData
. Помните, что экземпляр NSString
не может быть отправлен с использованием инфраструктуры Multipeer Connectivity. Сначала он должен быть преобразован в объект NSData
.
Самая интересная строка кода показана ниже. В этой единственной строке мы отправляем объект NSData
всем подключенным узлам. Мы передаем адрес указателя NSError
чтобы перехватить любые ошибки, которые могут возникнуть в процессе.
1
2
3
4
|
[self.appDelegate.mpcHandler.session sendData:messageAsData
toPeers:self.appDelegate.mpcHandler.session.connectedPeers
withMode:MCSessionSendDataReliable
error:&error];
|
Как вы уже могли догадаться, sendData:toPeers:withMode:error:
метод объявлен в платформе многопользовательского подключения. Поскольку мы хотим, чтобы каждый self.appDelegate.mpcHandler.session.connectedPeers
получил сообщение, мы передаем self.appDelegate.mpcHandler.session.connectedPeers
в качестве второго аргумента. Третий аргумент метода, MCSessionSendDataReliable
, указывает режим передачи. Если вы помните из введения , структура Multipeer Connectivity может отправлять данные одним из двух способов, надежным или ненадежным. В этом примере это ключ к надежной отправке данных, чтобы каждый игрок получал сообщение без икоты.
Если не было hasCreatedGame
никакой ошибки, мы устанавливаем hasCreatedGame
и isGameRunning
в YES
. Мы также очищаем текстовое представление, чтобы подготовить пользовательский интерфейс для новой игры.
3. Обновление пользовательского интерфейса
Если бы вы тестировали приложение в его текущем состоянии, вы бы заметили, что ничего не изменилось с точки зрения игрока. Другие игроки не уведомляются о начале новой игры. Нам все еще нужно позаботиться о нескольких вещах для достижения этой цели.
Однако сначала нам нужно обновить пользовательский интерфейс приложения, чтобы отразить состояние текущей игры. В настоящее время кнопки и текстовые поля включены даже при запуске новой игры. Например, когда один игрок начинает новую игру, игрок, который присоединился к игре, не должен иметь возможность начать новую игру. Мы будем реализовывать простой вспомогательный метод для решения этой проблемы.
1
2
3
4
5
|
— (void)toggleSubviewsState:(BOOL)shouldEnable {
self.btnCancel.enabled = shouldEnable;
self.txtGuess.enabled = shouldEnable;
self.btnSend.enabled = shouldEnable;
}
|
В toggleSubviewsState:
мы toggleSubviewsState:
или отключаем кнопки и текстовое поле в зависимости от состояния игры. Давайте toggleSubviewsState:
в методе viewDidLoad
контроллера представления.
1
2
3
4
|
— (void)viewDidLoad {
// … //
[self toggleSubviewsState:NO];
}
|
4. Обработка сообщений
Каждый раз, когда одноранговый узел получает объект NSData
, session:didReceiveData:fromPeer:
метод session:didReceiveData:fromPeer:
делегат платформы Multipeer Connectivity. Это также приводит к публикации уведомления, как вы, возможно, помните из ранее в этом руководстве. Чтобы получать и обрабатывать эти уведомления, нам нужно добавить контроллер представления в качестве наблюдателя, как показано ниже. Всякий раз, когда публикуется уведомление с именем MPCDemo_DidReceiveDataNotification
, handleReceivedDataWithNotification:
метод.
1
2
3
4
5
6
7
|
— (void)viewDidLoad {
// … //
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(handleReceivedDataWithNotification:)
name:@»MPCDemo_DidReceiveDataNotification»
object:nil];
}
|
Реализация handleReceivedDataWithNotification:
может показаться сложной, поэтому давайте handleReceivedDataWithNotification:
на handleReceivedDataWithNotification:
куски.
01
02
03
04
05
06
07
08
09
10
11
12
|
— (void)handleReceivedDataWithNotification:(NSNotification *)notification {
// Get the user info dictionary that was received along with the notification.
NSDictionary *userInfoDict = [notification userInfo];
// Convert the received data into a NSString object.
NSData *receivedData = [userInfoDict objectForKey:@»data»];
NSString *message = [[NSString alloc] initWithData:receivedData encoding:NSUTF8StringEncoding];
// Keep the sender’s peerID and get its display name.
MCPeerID *senderPeerID = [userInfoDict objectForKey:@»peerID»];
NSString *senderDisplayName = senderPeerID.displayName;
}
|
Мы получаем словарь userInfo
уведомления, извлекаем объект NSData
, воссоздаем объект NSString
и сохраняем его в переменной с именем message
. Следующее действие зависит от значения объекта message
. Мы также извлекаем имя партнера, который отправил сообщение, чтобы мы могли использовать его для обновления пользовательского интерфейса игры.
Если значение message
равно New Game
, новая игра была запущена. Затем мы уведомляем пользователя об этом событии, обновляем значение isGameRunning
и обновляем интерфейс пользователя, чтобы игрок мог делать предположения. Взгляните на обновленную реализацию handleReceivedDataWithNotification:
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
|
— (void)handleReceivedDataWithNotification:(NSNotification *)notification {
// Get the user info dictionary that was received along with the notification.
NSDictionary *userInfoDict = [notification userInfo];
// Convert the received data into a NSString object.
NSData *receivedData = [userInfoDict objectForKey:@»data»];
NSString *message = [[NSString alloc] initWithData:receivedData encoding:NSUTF8StringEncoding];
// Keep the sender’s peerID and get its display name.
MCPeerID *senderPeerID = [userInfoDict objectForKey:@»peerID»];
NSString *senderDisplayName = senderPeerID.displayName;
if ([message isEqualToString:@»New Game»]) {
// In case the message is about a new game, then show an alert view telling that the sender of the message
// has just started a new game.
NSString *alertMessage = [NSString stringWithFormat:@»%@ has started a new game.», senderDisplayName];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@»MPCDemo»
message:alertMessage
delegate:nil
cancelButtonTitle:nil
otherButtonTitles:@»Done», nil];
[alert show];
// Also, indicate that a game is in progress.
self.isGameRunning = YES;
// Enable all subviews.
[self toggleSubviewsState:YES];
// Clear all previous history from the text view.
[self.tvHistory setText:@»»];
}
}
|
Интересно отметить две детали. Во-первых, имя игрока, запустившего игру, упоминается в сообщении с предупреждением, чтобы убедиться, что другие игроки знают, кто является хозяином игры. Во-вторых, мы вызываем toggleSubviewsState:
для обновления пользовательского интерфейса. Если вы еще раз протестируете приложение, вы заметите, что при запуске новой игры каждому подключенному игроку показывается предупреждение.
5. Играть
Шаг 1
Следующий шаг — добавить возможность другим игрокам угадать секретный номер, выбранный хозяином игры. Поток, который мы используем для уведомления подключенных пиров, очень похож на то, что мы видели до сих пор. Давайте начнем с реализации действия sendGuess:
.
Перед тем, как отправлять предположение другим игрокам в игре, мы проверяем, является ли предположение игрока действительным числом и находится ли оно в требуемом диапазоне. Если это так, мы преобразуем содержимое текстового поля txtGuess
в объект NSData
и отправляем его подключенным узлам. На устройстве игрока, который сделал предположение, мы добавляем предположение к содержимому текстового представления.
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
|
— (IBAction)sendGuess:(id)sender {
// Check if a number has been entered or not, and if it’s valid.
if (self.txtGuess.text.length == 0 || [self.txtGuess.text intValue] < 1 || [self.txtGuess.text intValue] > 100) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@»MPCDemo»
message:@»Please enter a valid number.»
delegate:nil
cancelButtonTitle:nil
otherButtonTitles:@»Okay», nil];
[alert show];
} else{
// Convert the guess string to a NSData object and send it to all peers (players).
NSData *guessAsData = [self.txtGuess.text dataUsingEncoding:NSUTF8StringEncoding];
NSError *error;
[self.appDelegate.mpcHandler.session sendData:guessAsData
toPeers:self.appDelegate.mpcHandler.session.connectedPeers
withMode:MCSessionSendDataReliable
error:&error];
// If any error occurs just log its description.
if (error != nil) {
NSLog(@»%@», [error localizedDescription]);
}
// Add to the history text view the number value given by the current player.
NSString *history = [NSString stringWithFormat:@»I guessed the number: %@\n\n», self.txtGuess.text];
[self.tvHistory setText:[history stringByAppendingString:self.tvHistory.text]];
}
self.txtGuess.text = @»»;
[self.txtGuess resignFirstResponder];
}
|
Шаг 2
Когда действительные предположения отправляются другим игрокам в игре, handleReceivedDataWithNotification:
Ранее мы уже частично реализовали этот метод в этом руководстве, чтобы уведомлять других игроков о начале новой игры. Текущая реализация включает в себя только один условный оператор для проверки новой игры.
1
2
3
4
5
6
7
8
9
|
— (void)handleReceivedDataWithNotification:(NSNotification *)notification {
// … //
if ([message isEqualToString:@»New Game»]) {
// … //
}
// … //
}
|
Пришло время добавить предложение else
для обработки других входящих сообщений. На данный момент мы хотим обработать только предположение, сделанное другим игроком, что означает, что нам нужно проверить, содержит ли сообщение верный номер. Следующий фрагмент кода определяет, содержит ли объект NSString
число.
1
2
3
4
5
6
|
NSCharacterSet *numbersSet = [NSCharacterSet decimalDigitCharacterSet];
NSCharacterSet *messageSet = [NSCharacterSet characterSetWithCharactersInString:message];
if ([numbersSet isSupersetOfSet:messageSet]) {
}
|
Если сообщение действительно содержит правильное предположение, мы отображаем его в текстовом представлении. Кроме того, мы проверяем, является ли игрок хозяином игры, и, если она есть, мы отображаем окно предупреждения с тремя возможными действиями, чтобы приложение могло отправлять отзывы другим игрокам. Взгляните на обновленную реализацию handleReceivedDataWithNotification:
для пояснения.
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
|
— (void)handleReceivedDataWithNotification:(NSNotification *)notification {
// … //
if ([message isEqualToString:@»New Game»]) {
// … //
} else {
// Check if the message contains only digits.
// that means that it contains a guess from the player who sent it.
NSCharacterSet *numbersSet = [NSCharacterSet decimalDigitCharacterSet];
NSCharacterSet *messageSet = [NSCharacterSet characterSetWithCharactersInString:message];
if ([numbersSet isSupersetOfSet:messageSet]) {
// The message contains the guess from another player.
// Convert it to a number.
int guess = [message intValue];
// Add this guess to the history text view.
NSString *history = [NSString stringWithFormat:@»Player %@ guessed the number: %d\n\n», senderDisplayName, guess];
[self.tvHistory setText:[history stringByAppendingString:self.tvHistory.text]];
// If self is the game creator, then show all available options regarding this guess.
if (self.hasCreatedGame) {
NSString *optionsMessage = [NSString stringWithFormat:@»%@\n\nThe secret number is %d.\n\nWhat’s your answer?», history, self.secretNumber];
UIAlertView *optionsAlert = [[UIAlertView alloc] initWithTitle:@»MPCDemo»
message:optionsMessage
delegate:self
cancelButtonTitle:nil
otherButtonTitles:@»Correct Guess!», @»Give a greater number», @»Give a lower number», nil];
[optionsAlert show];
}
}
}
}
|
На следующем снимке экрана показано представление предупреждений, которое хост увидит, когда игрок сделает правильное предположение.
Шаг 3
Чтобы обработать ответ хоста, нам нужно обновить alertView:clickedButtonAtIndex:
метод протокола UIAlertViewDelegate
, как показано ниже. Все, что мы делаем, это отправляем заголовок кнопки в виде сообщения другим игрокам в игре.
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
|
— (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
if (alertView.alertViewStyle == UIAlertViewStylePlainTextInput && buttonIndex == 1) {
// … //
} else {
// Get the tapped button’s title as the answer, convert it to a NSData object and send it to other players.
NSString *selectedAnswer = [alertView buttonTitleAtIndex:buttonIndex];
NSData *answerAsData = [selectedAnswer dataUsingEncoding:NSUTF8StringEncoding];
NSError *error;
[self.appDelegate.mpcHandler.session sendData:answerAsData
toPeers:self.appDelegate.mpcHandler.session.connectedPeers
withMode:MCSessionSendDataReliable
error:&error];
if (error != nil) {
NSLog(@»%@», [error localizedDescription]);
}
// In case of correct guess then turn the flags to off.
if (buttonIndex == 0) {
self.hasCreatedGame = NO;
self.isGameRunning = NO;
}
}
}
|
Когда противник делает правильное предположение, мы заканчиваем игру, устанавливая hasCreatedGame
и isGameRunning
в NO
. На следующем этапе мы обработаем сообщение, отправленное другим игрокам в игре.
Шаг 4
Я уверен, что вы начинаете понимать, как разные части игры сочетаются друг с другом. Это немного похоже на игру в теннис, в которой игроки бьют друг друга по мячу, пока один не уронит мяч. Чтобы завершить игру, нам нужно вернуться к handleReceivedDataWithNotification:
еще раз, чтобы обработать ответ, отправленный хостом игры после того, как игрок сделал правильное предположение.
Мы начнем с добавления предложения else
ко второму оператору if
как показано ниже. Все, что мы делаем, это добавляем сообщение, заголовок кнопки, которую нажал хост, к содержимому текстового представления. Если сообщение равно Correct Guess , мы заканчиваем игру и отключаем управление игрой, вызывая toggleSubviewsState:
и передавая NO
.
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
|
— (void)handleReceivedDataWithNotification:(NSNotification *)notification {
// … //
} else {
// Check if the message contains only digits.
// that means that it contains a guess from the player who sent it.
NSCharacterSet *numbersSet = [NSCharacterSet decimalDigitCharacterSet];
NSCharacterSet *messageSet = [NSCharacterSet characterSetWithCharactersInString:message];
if ([numbersSet isSupersetOfSet:messageSet]) {
// … //
} else {
// If the message doesn’t contain digits, then it contains the answer from the player who started the game.
// For starters, just show answer to the history text view.
NSString *history = [NSString stringWithFormat:@»%@ says:\n%@\n\n», senderDisplayName, message];
[self.tvHistory setText:[history stringByAppendingString:self.tvHistory.text]];
// Check if the game creator answered that the last guess was the correct one.
// should stop.
if ([message isEqualToString:@»Correct Guess!»]) {
self.isGameRunning = NO;
[self toggleSubviewsState:NO];
}
}
}
}
|
Шаг 5
Приложение почти закончено. Нам осталось только реализовать действие cancelGuessing:
. В этом методе мы скрываем клавиатуру, вызывая resignFirstResponder
в текстовом поле txtGuess
.
1
2
3
|
— (IBAction)cancelGuessing:(id)sender {
[self.txtGuess resignFirstResponder];
}
|
6. Построить и запустить
Наша простая игра готова к игре. Имейте в виду, что реализация игры проста, так как основное внимание в этом уроке было уделено изучению платформы Multipeer Connectivity, которая была представлена в iOS 7. На следующем снимке экрана должно быть дано представление о различных состояниях, в которых может находиться игра.
Вывод
Надеюсь, я убедил вас, что платформа Multipeer Connectivity является отличным новым дополнением к iOS SDK. Из этого туториала вы узнали, что отправка данных от однорангового узла очень проста с платформой Multipeer Connectivity. Фреймворк может предложить гораздо больше, поэтому я советую вам изучить документацию Apple для более глубокого понимания ее возможностей.