Соответствия в реальном времени
В соответствии в реальном времени плееры подключаются к Центру Гэйма (и таким образом друг другу) одновременно. Эта форма соответствия подходит для реализации любого типа игры, требующей живого участия. Главное преимущество соответствий в реальном времени - то, что Гэйм Кит и Гэйм Сентер предоставляют обширную поддержку для соответствий в реальном времени, упрощающую код, который необходимо записать. В частности это решает много проблем нахождения, что проигрыватели присоединяются в соответствие, это обеспечивает высокоуровневый сетевой интерфейс, позволяющий Вам проигнорировать многие проблемы базового сетевого уровня, и это предоставляет обширную встроенную поддержку для голосового чата. Гэйм Кит позволяет Вам фокусироваться на реализации Вашей игры, не волнуясь о точной механике того, как поставлены игра и речевая информация.
Однако даже при том, что Гэйм Кит решает многие из этих проблем, Ваш игровой дизайн все еще должен быть подготовлен иметь дело со сложными вопросами, являющимися результатом сетей в реальном времени, включая:
Потребность в многократных экземплярах Вашей игры (работающий на различных устройствах) для выполнения задачи одновременно или рядом одновременно, при синхронизации состояний между устройствами
Надежность сети
Сетевая задержка
Реализация соответствия в реальном времени требует обширной разработки работы, реализации и тестирования Вашей игры.
Контрольный список для добавления Matchmaking в реальном времени к Вашей игре
Контрольный список для создания игры, поддерживающей соответствия в реальном времени, более обширен, чем это для других Игровых технологий Центра и включает три основных области: matchmaking, обмен данными и голосовой чат. Как часть этого процесса, у Вас также есть много проектных решений сделать о том, как матчи сыграны в Вашей игре, включая:
Сколько проигрывателей может играть сразу
То, что делает сетевую версию Вашей игры, похоже
Какие данные должны быть совместно использованы для создания проекта
Эти и другие вопросы влияют на проект Вашего геймплея и объединяющий код в сеть.
Начало работы
Следующие задачи должны быть выполнены прежде, чем запустить Вашу matchmaking реализацию:
Если Ваше приложение является приложением OS X, необходимо добавить следующие права или все сбои функциональности в реальном времени:
com.apple.security.network.client
com.apple.security.network.server
Добавьте код к своей игре для аутентификации местного игрока. Посмотрите Работу с Проигрывателями в Игровом Центре.
Ознакомьте себя с matchmaking понятиями, описанными в Обзоре Matchmaking, а также содержании этой главы.
Нахождение проигрывателей для соответствия
Определите, будет ли Ваша игра использовать стандарт matchmaking интерфейс, выведите на экран пользовательский интерфейс matchmaking или используйте комбинацию обоих. Независимо от которой реализации Вы выбираете, необходимо поддерживать выбранное поведение реализации в игре, а также добавить поддержку обработки приглашений, полученных из за пределами игры.
При реализации стандартного пользовательского интерфейса посмотрите Используя Стандартный Пользовательский интерфейс Matchmaking.
При реализации настроенного пользовательского интерфейса посмотрите Реализацию Пользовательского Пользовательского интерфейса Соответствия.
Обмен данными между участниками соответствия
Это - самый сложный шаг процесса, поскольку это требует, чтобы Вы выполнили обширную дизайнерскую работу и для игровой механики для соответствия в реальном времени и для низкоуровневых подробных данных синхронизирующейся коммуникации между участниками соответствия.
Разработайте сетевые сообщения Ваше игровое использование для передачи с другими участниками соответствия. Большинство игр обменивается информацией в начале соответствия, чтобы предоставить каждому участнику то же начальное игровое состояние, и затем отправить обновления, как события имеют место в игре. Посмотрите Разработку Вашей Сетевой Игры.
Запишите код для использования объекта соответствия отправить данные другим участникам соответствия. Ваша игра кодирует игровое состояние в двоичных данных и использует объект соответствия передать его к другим проигрывателям. Посмотрите Передающие Данные к Другим Проигрывателям.
Реализуйте делегата соответствия для обработки событий, которые могут произойти во время соответствия:
Когда другие плееры подключаются в начале игры, делегат уведомляется. Ваш делегат обычно ожидает, пока все не соединяются прежде, чем запустить игру. Посмотрите Начинание Матча.
Делегат получает данные, которые отправляют другие проигрыватели. Ваш делегат инвертирует процедуру, используемую для отправки данных путем декодирования и действия на данные от других проигрывателей. Посмотрите Данные Получения от Других Проигрывателей.
Если проигрыватели разъединяются, в то время как Ваша игра работает, делегат получает уведомление и должен решить, прекратить ли соответствие или реконфигурировать Вашу игру для обработки сокращенного числа игроков. Посмотрите Разъединение от Соответствия.
Добавление голосового чата к соответствию
Поддержка голосового чата является дополнительной, но может взять хорошую игру и превратить ее в большую игру. Это позволяет проигрывателям более близкий и более естественный уровень взаимодействия. Вот шаги для реализации голосового чата в Вашей игре:
Решите, в каком количестве речевых каналов Ваша игра нужна. Например, общедоступное соответствие может использовать единственный канал для всех участников, в то время как соответствие с многократными командами могло бы использовать отдельный канал для каждой команды и дополнительного канала, включающего все проигрыватели в игру.
Если Ваша игра работает в iOS, сконфигурируйте аудио сеанс для включения микрофона. Все игры, записывающие или играющие аудио, должны иметь аудио сеанс. Посмотрите Создание Аудио Сеанса (только iOS).
Создайте речевой канал путем вызова объекта соответствия
voiceChatWithName:
метод. Соответствие возвращает aGKVoiceChat
объект. Посмотрите Речевые каналы Создания.Вызовите объект голосового чата
start
метод для активации канала. Посмотрите Запуск и Остановку Голосового чата.Включите микрофон для канала чата, когда проигрыватель должен будет говорить в него. Каждый участник может говорить только в один канал за один раз. Посмотрите Включение и Отключение Микрофона.
Обеспечьте средства управления в своей игре, позволяющие пользователю включать и отключать голосовой чат, устанавливать уровни громкости или отключать звук проигрывателей в канале. Посмотрите Управление Объемом Голосового чата.
Решите, должна ли Ваша игра поддерживать модель услуги «Нажми и говори» или должна ли она постоянно выбирать микрофон. В игре услуги «Нажми и говори» обеспечьте управление, которое проигрыватель нажимает для передачи речевой информации к другим проигрывателям. В игре, постоянно выбирающей микрофон, обеспечьте управление для отключения звука микрофона.
Реализуйте обработчик обновления, который вызывают, когда проигрыватель соединяется или разъединяется, или когда проигрыватель запускает или прекращает говорить. Когда проигрыватель говорит, Как правило, Вы используете этот обработчик для обновления пользовательского интерфейса игры для отображения актуальной информации для каждого проигрывателя в голосовом чате — например, выделяя элемент интерфейса пользователя. Посмотрите Наблюдение Когда Изменения состояния Проигрывателя.
Обзор соответствий в реальном времени в игровом центре
Таблица 8-1 перечисляет классы, которые Вы используете при разработке игры, использующей соответствия в реальном времени в Игровом Центре.
Класс | Описание |
---|---|
Объект запроса соответствия указывает свойства соответствия, которое будет создаваться. Посмотрите, что Создание Любого Вида Соответствия Запускается с Запроса Соответствия. | |
Этот одиночный элемент используется всеми играми, поддерживающими matchmaking в реальном времени. Игра должна обеспечить обработчик приглашения для объекта антрепренера так, чтобы уведомления нажатия, запускающие игру, были обработаны быстро. Дополнительно, игра, хотящая создать пользовательский matchmaking пользовательский интерфейс, использует антрепренера, чтобы программно искать соответствия. | |
Поставленный, когда проигрыватель принимает приглашение играть в соответствии. | |
Класс контроллера представления, выводящий на экран стандарт matchmaking пользовательский интерфейс. Пользовательский интерфейс по умолчанию позволяет проигрывателям добавлять друзей для соответствия, искать другие плееры, подключенные к Игровому Центру, или даже находить проигрыватели, которые находятся физически в непосредственной близости друг от друга, даже если у них в настоящее время нет соединения с Игровым Центром. | |
Этот объект, возвращающийся к Вашей игре, содержит информацию о проигрывателях в соответствии. Каждый экземпляр Вашей игры использует свое собственное | |
Возвращенный соответствием возражают, и представляет определенный речевой канал, который проигрыватели могут передать. |
Нахождение проигрывателей для соответствия
Когда проигрыватель хочет создать соответствие, Ваша игра должна вывести на экран пользовательский интерфейс, чтобы позволить проигрывателю видеть и конфигурировать состояние соответствия. Самый простой способ реализовать это состоит в том, чтобы использовать стандартный пользовательский интерфейс, предоставленный GKMatchmakerViewController
класс. Это реализует много общих matchmaking сценариев с маленькими инвестициями в код. Однако, если Вы хотите реализовать свое собственное поведение, можно разработать собственный пользовательский интерфейс и затем вызвать GKMatchmaker
класс для выполнения этой задачи программно. Класс антрепренера возвращает данные Вашей игре так, чтобы это могло обновить свой собственный пользовательский интерфейс.
Используя стандартный пользовательский интерфейс Matchmaking
Стандарт matchmaking пользовательский интерфейс часто выводится на экран в ответ на пользователя, касающегося кнопки на экране заголовка Вашей игры. Это может сразу появиться после того, как кнопка касается или после нескольких временных экранов между экраном заголовка и экраном matchmaking. Например, если Ваш запрос соответствия включает группы проигрывателя или атрибуты проигрывателя, у Вас обычно есть свой собственный экран интерфейса пользователя для конфигурирования запроса соответствия прежде, чем вывести на экран значение по умолчанию matchmaking пользовательский интерфейс.
Представление пользовательского интерфейса Matchmaking
Перечисление 8-1 показывает, как контроллер представления представляет matchmaking пользовательский интерфейс проигрывателю. Это создает и конфигурирует запрос соответствия и затем инициализирует новый объект контроллера представления антрепренера использование запроса соответствия. Контроллер представления представления делает себя, matchmaking просматривают делегата контроллера, и затем представляет интерфейс matchmaking по себе. Проигрыватель взаимодействует с экраном matchmaking, пока матч не готов начаться, или ошибка происходит.
Перечисление 8-1 , Показывающее стандарт matchmaking интерфейс
- (IBAction)hostMatch: (id) sender |
{ |
GKMatchRequest *request = [[GKMatchRequest alloc] init]; |
request.minPlayers = 2; |
request.maxPlayers = 2; |
GKMatchmakerViewController *mmvc = [[GKMatchmakerViewController alloc] initWithMatchRequest:request]; |
mmvc.matchmakerDelegate = self; |
[self presentViewController:mmvc animated:YES completion:nil]; |
} |
Как делегат, Ваш контроллер представления (или некоторый другой класс) должен реализовать несколько методов для ответа на события. Каждый из этих методов отклоняет контроллер представления, и затем выполняет любые определенные действия, требуемые для Вашей игры.
matchmakerViewControllerWasCancelled:
метод делегата вызывают, когда проигрыватель отменяет процесс matchmaking, прежде чем было создано соответствие. Как правило, Ваша игра отклоняет контроллер представления и затем отступает на экран заголовка (или некоторый другой разумный экран интерфейса пользователя).
Перечисление 8-2 Реализовывая метод отмены
- (void)matchmakerViewControllerWasCancelled:(GKMatchmakerViewController *)viewController |
{ |
[self dismissViewControllerAnimated:YES completion:nil]; |
// Implement any specific code in your game here. |
} |
matchmakerViewController:didFailWithError:
метод делегата вызывают, когда matchmaking встречается с ошибкой при попытке установить соответствие — например, когда устройство теряет свое сетевое соединение. Подобный тому, когда проигрыватель отменяет процесс matchmaking, Ваша игра отклоняет контроллер представления и перемещается в предыдущий экран.
Перечисление 8-3 Реализовывая метод обработки ошибок
- (void)matchmakerViewController:(GKMatchmakerViewController *)viewController didFailWithError:(NSError *)error |
{ |
[self dismissViewControllerAnimated:YES completion:nil]; |
// Implement any specific code in your game here. |
} |
Наконец, если соответствие было создано, и все готовы запуститься, Ваш делегат matchmakerViewController:didFindMatch:
метод вызывают. Этот метод возвращает a GKMatch
возразите против своей игры. Как правило, когда матч начинается, соответствие возвращается всем участникам, таким образом, этот метод делегата вызывают на многократных устройствах одновременно.
Перечисление 8-4 показывает возможную реализацию метода делегата. Этот метод присваивает объект соответствия свойству на объекте и затем добавляет объект как делегата объекта соответствия. На этом этапе процесса были найдены все проигрыватели, но для объекта соответствия возможно быть возвращенным, прежде чем будут успешно подключены все плееры. Если все плееры уже подключаются к соответствию, игра распознает это и сразу начинает матч. Иначе, это ничего не делает; когда последний проигрыватель соединяется, делегат соответствия начинает матч. Посмотрите “Starting a match”
для роли делегата соответствия в этом коде запуска.
Перечисление 8-4 Реализовывая соответствие нашло метод
- (void)matchmakerViewController:(GKMatchmakerViewController *)viewController didFindMatch:(GKMatch *)match |
{ |
[self dismissViewControllerAnimated:YES completion:nil]; |
self.myMatch = match; // Use a retaining property to retain the match. |
match.delegate = self; |
if (!self.matchStarted && match.expectedPlayerCount == 0) |
{ |
self.matchStarted = YES; |
// Insert game-specific code to start the match. |
} |
} |
Обработка приглашений от других проигрывателей
Когда проигрыватель принимает приглашение от другого проигрывателя, Ваша игра запускается (если необходимый), и приглашение поставлено Вашей игре. Ваша игра получает это приглашение путем реализации обработчика приглашения. При использовании стандартного пользовательского интерфейса обработчик приглашения создает контроллер представления соответствия и инициализирует его с данными, предоставленными обработчику приглашения. Обработчик приглашения тогда представляет контроллер представления соответствия, подобный тому, когда проигрыватель хотел создать новое соответствие непосредственно; в большинстве случаев Вы используете тот же код делегата.
Перечисление 8-5 показывает код, который Вы используете для установки нового обработчика приглашения. Обработчик приглашения является блоком, таким образом, реализация предоставлена встроенная. Когда обработчик работает, проигрыватель уже принял приглашение, таким образом, обработчик останавливает любой геймплей, уже происходящий, инстанцирует нового контроллера представления и представляет его проигрывателю.
Обработчик приглашения берет два различных параметра; на любом вызове к Вашему приглашению hander, только один из этих параметров содержит не -nil
значение:
acceptedInvite
параметр не -nil
когда Ваша игра получает приглашение непосредственно от другого проигрывателя. В этой ситуации экземпляр другого проигрывателя Вашей игры уже создал запрос соответствия, таким образом, этот экземпляр не должен создавать запрос соответствия.playersToInvite
параметр не -nil
когда Ваша игра запускается непосредственно из Игрового приложения Центра для хостинга соответствия. Этот параметр содержит массив идентификаторов проигрывателя, перечисляющих проигрыватели для приглашения в соответствие. Ваша игра должна создать новый запрос соответствия, присвоить его параметры, как она обычно была бы, и затем установила запрос соответствияplayersToInvite
свойство к значению передало вplayersToInvite
параметр. Когда экран matchmaking выведен на экран, он предварительно заполняется со списком проигрывателей, уже включенных в соответствие.
Перечисление 8-5 , Устанавливающее обработчик приглашения
[GKMatchmaker sharedMatchmaker].inviteHandler = ^(GKInvite *acceptedInvite, NSArray *playersToInvite) { |
// Insert game-specific code here to clean up any game in progress. |
if (acceptedInvite) |
{ |
GKMatchmakerViewController *mmvc = [[GKMatchmakerViewController alloc] initWithInvite:acceptedInvite]; |
mmvc.matchmakerDelegate = self; |
[self presentViewController:mmvc animated:YES completion:nil]; |
} |
else if (playersToInvite) |
{ |
GKMatchRequest *request = [[GKMatchRequest alloc] init]; |
request.minPlayers = 2; |
request.maxPlayers = 2; |
request.playersToInvite = playersToInvite; |
GKMatchmakerViewController *mmvc = [[GKMatchmakerViewController alloc] initWithMatchRequest:request]; |
mmvc.matchmakerDelegate = self; |
[self presentViewController:mmvc animated:YES completion:nil]; |
} |
}; |
Добавление проигрывателей к существующему соответствию
Иногда, соответствие может опуститься ниже числа игроков, которого требует Ваша игра. Например, если проигрыватель теряет их сетевое соединение, эта ситуация может произойти. В этом случае, вместо того, чтобы расформировать соответствие полностью, Вы могли бы хотеть добавить дополнительные проигрыватели.
Для реализации этого в игре создайте и представьте контроллер представления антрепренера, как Вы сделали в случае по умолчанию. Вы только делаете это от одного устройства, уже участвующего в соответствии. После представления контроллера представления вызовите контроллер представления addPlayersToMatch:
метод, передающий в соответствии для добавления проигрыватели к. Интерфейс соответствия использует информацию в запросе соответствия, чтобы добавить проигрыватели к существующему соответствию, вместо того, чтобы создать новое соответствие. Объект соответствия все еще возвращается Вашему делегату matchmakerViewController:didFindMatch:
метод.
В то время как экран matchmaking выведен на экран, соответствие все еще активно; устройства в соответствии могут все еще обмениваться данными друг с другом. Однако Вы, возможно, должны были бы приостановить фактический геймплей, пока не найден новый проигрыватель. Поскольку соответствие активно каналы голосового чата продолжают работать.
Реализация пользовательского пользовательского интерфейса соответствия
Реализация полного пользовательского интерфейса соответствия может быть столь же простой как отображение сетевого индикатора хода выполнения, пока автосоответствие не завершается, или столь же сложный как реализация полного пользовательского контроллера представления, тиражирующего стандартное поведение. Последний является потенциально значительными инвестициями в программирование времени, поскольку это должно включать поддержку всего следующего:
Приглашение определенных проигрывателей в соответствие
Прислушивание к ответам от приглашенных проигрывателей
Поиск соседних проигрывателей (доступный через Wi-Fi или Bluetooth)
Этот раздел запускается с самого простого сценария — нахождения соответствия без реализации пользовательского интерфейса — и затем создает к более подробным понятиям, должен был создать Ваш собственный пользовательский интерфейс.
Автосоответствие для заполнения соответствия
Самый простой интерфейс, который может обеспечить Ваша игра, является “мгновенным соответствием” кнопка. Когда эта кнопка нажимается, проигрыватель добавляется к соответствию, не будучи должен ввести любую дополнительную информацию.
Перечисление 8-6 показывает, как программно запросить соответствие. Код создает запрос соответствия, получает одноэлементный объект антрепренера и просит, чтобы он счел достойным проигрывателя. Обработчик завершения соответствия вызывают, когда соответствие найдено или если происходит ошибка. Если соответствие возвращается к обработчику завершения, соответствие присваивается свойству. Как прежде, Ваша игра выполняет код, чтобы определить, готов ли матч начаться.
Перечисление 8-6 , Программно находящее соответствие
- (IBAction)findProgrammaticMatch: (id) sender |
{ |
GKMatchRequest *request = [[GKMatchRequest alloc] init]; |
request.minPlayers = 2; |
request.maxPlayers = 4; |
[[GKMatchmaker sharedMatchmaker] findMatchForRequest:request withCompletionHandler:^(GKMatch *match, NSError *error) { |
if (error) |
{ |
// Process the error. |
} |
else if (match != nil) |
{ |
self.myMatch = match; // Use a retaining property to retain the match. |
match.delegate = self; |
if (!self.matchStarted && match.expectedPlayerCount == 0) |
{ |
self.matchStarted = YES; |
// Insert game-specific code to begin the match. |
} |
} |
}]; |
} |
Как в примере со стандартом matchmaking интерфейс, можно также добавить проигрыватели к существующему соответствию. Вместо того, чтобы вызвать findMatchForRequest:withCompletionHandler:
метод, Ваша игра вызывает addPlayersToMatch:matchRequest:completionHandler:
метод, передающий в соответствии для добавления проигрыватели к.
Отмена поиска
Процесс matchmaking занимает время и может не завершиться достаточно быстро для некоторых проигрывателей. Если Ваша игра включает поддержку программируемого соответствия, это должно обеспечить пользовательский интерфейс, позволяющий проигрывателю отменять активный поиск. Перечисление 8-7 показывает, как Ваша игра может завершить незаконченный поиск.
Перечисление 8-7 , Отменяющее поиск соответствия
[[GKMatchmaker sharedMatchmaker] cancel]; |
Приглашение определенных проигрывателей к соответствию
При реализации полного настроенного пользовательского интерфейса необходимо позволить проигрывателям приглашать своих друзей для соответствия. Как правило, это означает, что Ваша игра представляет интерфейс, в настоящее время показывающий все проигрыватели в соответствии с пустыми слотами для позиций, чтобы быть заполненным. Проигрыватель может тогда выбрать один или больше тех пустых слотов и выпустить приглашение на определенный проигрыватель. Когда приглашения обрабатываются, для выполнения этого игра должна быть в состоянии отправить приглашения и получить уведомления.
Вы решаете обе из этих проблем путем присвоения большей информации запросу соответствия. Необходимо присвоить список проигрывателей для приглашения и обработчик приглашенного. Поскольку каждое приглашение обрабатывается, Ваш обработчик вызывают. Перечисление 8-8 показывает, что типичная реализация соответствия запрашивает обработать это. В этом примере создается запрос соответствия, и список идентификаторов проигрывателя присваивается запросу. Кроме того, этот код обеспечивает пользовательское сообщение приглашения; в Вашей игре необходимо позволить проигрывателю настраивать это сообщение.
Если ответ равен, когда получен ответ GKInviteeResponseAccepted
, проигрыватель добавляется к соответствию. В этом случае код пользовательского интерфейса (не показанный здесь) обновляется, чтобы показать, что этот проигрыватель является теперь частью соответствия. Если какой-либо другой ответ получен, проигрыватель удален из пользовательского интерфейса так, чтобы слот казался пустым снова. Дополнительно, более сложный пример мог бы вывести на экран определенное сообщение об ошибке к детализации проигрывателя, почему не было принято приглашение; посмотрите Ссылку класса GKMatchRequest для подробных данных.
Перечисление 8-8 , Программно добавляющее друзей для соответствия
- (void)inviteFriends: (NSArray*) friends |
{ |
GKMatchRequest *request = [[GKMatchRequest alloc] init]; |
request.minPlayers = 2; |
request.maxPlayers = 4; |
request.playersToInvite = friends; |
request.inviteMessage = @"Your Custom Invitation Message Here"; |
request.inviteeResponseHandler = ^(NSString *playerID, GKInviteeResponse response) |
{ |
[self updateUIForPlayer: playerID accepted: (response == GKInviteeResponseAccepted)]; |
}; |
... |
} |
Когда запрос соответствия включает список идентификаторов проигрывателя, тогда matchmaking изменения поведения (независимо от того, создаете ли Вы новое соответствие или добавляете проигрыватели к определенному соответствию). Нормальный процесс нахождения проигрывателей для соответствия приостановлен. Вместо этого единственная вещь, которую делает код matchmaking, расширяются, приглашения на проигрыватели в соответствии запрашивают и ожидают ответов. Принятие Вашей игры не отменяет процесс matchmaking, это завершает и возвращает соответствие Вашей игре, когда обрабатываются все приглашения.
Поскольку некоторые приглашения не могут быть приняты, возможно, что можно получить соответствие, которому все еще нужно больше проигрывателей. С этим в памяти, Ваш настроенный пользовательский интерфейс должен реализовать следующее поведение:
В первый раз проигрыватель приглашает проигрыватели присоединяться к соответствию, создавать запрос соответствия с теми проигрывателями и вызывать
findMatchForRequest:withCompletionHandler:
метод. Ожидайте соответствия, которое будет возвращено (или отмените запрос, если проигрыватель отменяет приглашения).Если проигрыватель хочет добавить больше проигрывателей к соответствию после того, как приглашения будут обработаны, выполнят ту же процедуру снова, но вызовут
addPlayersToMatch:matchRequest:completionHandler:
метод вместо этого.Если проигрыватель хочет автосоответствовать остающиеся слоты, создать запрос соответствия, но не включает список проигрывателей для приглашения. Вызовите
addPlayersToMatch:matchRequest:completionHandler:
метод для заполнения остающихся слотов. Необходимо ожидать, пока все приглашенные проигрыватели не соединились, поскольку все незаконченные запросы соответствия отменяются при автосоответствии остающихся слотов проигрывателя.Если проигрыватель хочет начать матч с проигрывателями уже в соответствии, вызовите
finishMatchmakingForMatch:
метод для окончания matchmaking полностью.
Если Вы хотите создать соответствие, содержащее и приглашенные проигрыватели и автосоответствующие проигрыватели, необходимо сначала создать соответствие с приглашенными проигрывателями. После того, как все приглашенные проигрыватели соединились, можно тогда добавить проигрыватели посредством автосоответствия.
Поиск соседних проигрывателей
Стандартный пользовательский интерфейс позволяет проигрывателям обнаруживать другие соседние проигрыватели, даже когда никакой плеер в настоящее время не подключается к Игровому Центру непосредственно. Открытие использует локальный Wi-Fi или Bluetooth для нахождения других проигрывателей. Когда проигрыватели вдали от своей нормальной сети, но все еще хотят играть против друг друга, эта возможность очень полезна. Можно реализовать подобное поведение в настроенном пользовательском интерфейсе.
Вот то, как Вы обычно реализуете это поведение:
Обеспечьте кнопку в своем пользовательском интерфейсе, чтобы позволить проигрывателю искать соседние проигрыватели. Когда нажато, эта кнопка представляет новый экран интерфейса пользователя, выводящий на экран любые соседние проигрыватели, которые она находит. Также Ваш пользовательский интерфейс может просто вывести на экран соседние проигрыватели автоматически. При выборе этого подхода он обычно целесообразен сохранять этот список проигрывателя разделенным от остальной части пользовательского интерфейса.
Вызовите совместно используемого антрепренера
startBrowsingForNearbyPlayersWithReachableHandler:
метод, передающий в блоке для получения уведомления о проигрывателях, как они вводят и оставляют область. Когда проигрыватель будет найден, добавьте проигрыватель к своему видимому списку проигрывателей. Когда проигрыватель исчезнет, удалите проигрыватель.Если проигрыватель выбирает один или несколько проигрывателей, чтобы отправить приглашение на, создать запрос соответствия и добавить идентификаторы проигрывателя для тех проигрывателей к запросу соответствия. Затем следуйте за поведением, описанным в Приглашении Определенных Проигрывателей к Соответствию.
Когда Ваш экран просмотра удален из экрана (или потому что проигрыватель отменил просмотр или потому что он или она уже пригласил проигрыватели), вызывают
stopBrowsingForNearbyPlayers
метод.
Обработка приглашений от других проигрывателей
Процедура для получения приглашений от других проигрывателей почти идентична процедуре, которую Вы выполнили бы при использовании стандартного пользовательского интерфейса. Вы устанавливаете обработчик приглашения, но вместо того, чтобы показать стандартный пользовательский интерфейс, Вы показываете свой собственный интерфейс. Ваш код использует acceptedInvite
и playersToInvite
параметры для определения, какое приглашение было получено. Посмотрите Приглашения Обработки от Других Проигрывателей.
Нахождение действия проигрывателя в игре
Проигрыватели, кто ищет многопользовательское соответствие часто, хотят быть соответствующими сразу, или по крайней мере знать, когда matchmaking может занять больше времени. Например, если проигрыватель является онлайновым в течение промежутка времени, когда проигрыватели не являются регулярно онлайновыми, число игроков, кто интересуется присоединением к соответствию, может быть существенно меньшим, чем в прайм-тайм. Определение того, сколько проигрывателей является онлайновым, упоминается как действие проигрывателя. GKMatchmaker
класс обеспечивает пару методов, которые можно использовать для тестирования на действие на Игровом Центре, связанном с игрой.
Перечисление 8-9 , Ищущее все действие для Вашей игры на Игровом Центре
- (void)findAllActivity |
{ |
[[GKMatchmaker sharedMatchmaker] queryActivityWithCompletionHandler:^(NSInteger activity, NSError *error) { |
if (error) |
{ |
// Process the error. |
} |
else |
{ |
// Use the activity value to display activity to the player. |
} |
}]; |
} |
Если Ваша игра использует группы проигрывателя, можно использовать queryPlayerGroupActivity:withCompletionHandler:
метод для получения действия для определенной группы проигрывателя.
Значение, возвращенное любым методом, является числом игроков, кто недавно запросил соответствие.
Обмен данными между участниками соответствия
После создания соответствия участники соответствия должны обмениваться данными для синхронизации состояния соответствия друг между другом. В этом разделе описывается реализовать и разработать эту часть Вашего кода matchmaking.
Разработка сетевой игры
Каждый участник соответствия полагается на a GKMatch
объект обмениваться данными с другими участниками соединился с соответствием. GKMatch
класс не определяет формат или содержание Ваших сетевых сообщений. Вместо этого это просто рассматривает Ваши сообщения как байты для передачи. Это дает Вам большую гибкость в разработке Вашей сетевой игры. Остальная часть этого раздела описывает ключевые понятия, которые необходимо понять прежде, чем реализовать сетевую игру.
Каждый раз, когда Вы отправляете данные другим участникам, Вы решаете, сколько усилия соответствие должно приложить для отправки данных. Соответствия могут отправить Ваши данные надежно, что означает, что соответствие ретранслирует данные, пока это не получено к установленному сроку (s), или ненадежно, что означает, что это отправляет данные только один раз.
Надежная передача более проста, но потенциально медленнее; медленная или подверженная ошибкам сеть может потребовать, чтобы устройство отправило сообщение многократно, прежде чем это будет успешно поставлено его предполагаемым получателям. Соответствие также гарантирует, что многократные надежные сообщения, отправленные от одного устройства до того же получателя, передаются в порядке, который они были отправлены.
Сообщения, переданные ненадежно, никогда могут не достигать своего места назначения или могут быть переданы не в порядке. Ненадежные передачи являются самыми полезными для транзакций в реальном времени, где любая задержка передачи, вызванной при помощи надежного обмена сообщениями, лишает законной силы содержание сообщения. Например, если Ваша игра передает позицию и информацию о скорости для алгоритма точного расчета траектории, надежные сообщения могли бы предоставить данные расположения, плохо устаревшие к тому времени, когда это поставлено получателю. При помощи ненадежных сообщений сообщения передаются быстрее. Ваша игра берет на себя ответственность за сетевые ошибки путем отправки новых сообщений с обновленной позицией и счета информации.
Размер Ваших сообщений также играет важную роль в том, как быстро данные могут быть поставлены его целям. Большие сообщения должны быть разделены на пакеты меньшего размера (такое разделение вызывают фрагментацией), и повторно собрался каждой целью. Каждый из этих пакетов меньшего размера мог бы быть потерян во время передачи или поставлен не в порядке. Большие сообщения должны быть отправлены надежно, так, чтобы Гэйм Кит мог обработать фрагментацию и блок. Однако процесс повторной отправки и блока занимает время. Вы не должны использовать надежные передачи для отправки больших сумм данных реального времени.
Будьте внимательны, что Ваши сетевые данные передаются через серверы и маршрутизаторы, находящиеся вне Вашего контроля. Ваши сообщения подлежат проверке и модификация другими устройствами в сети. Когда Ваша игра на одном устройстве получает сетевые данные от участников на других устройствах, это должно обработать то сообщение как недоверяемые данные и проверить его содержание перед использованием его. Посмотрите Безопасное Руководство по Кодированию для получения информации о том, как избежать уязвимостей системы обеспечения безопасности.
Вот некоторые общие руководящие принципы для следования при разработке сетевой игры:
Ваш формат сообщения должен включать способ дифференцироваться между типами сообщений.
GKMatch
класс ничего не знает о содержании Ваших сообщений, таким образом, необходимо реализовать ту функциональность в игре. Например, Вы могли бы создать перечислимый тип, идентифицирующий различные виды сообщений, и запустите каждое сообщение с того перечислимого типа.Отправьте сообщения в самой низкой частоте, позволяющей Вашей игре функционировать хорошо. Графический механизм Вашей игры может достигать 30 - 60 кадров в секунду, но Ваш сетевой код может отправлять обновления намного менее часто.
Используйте самый маленький формат сообщения, сделавший задание. Сообщения, часто отправляющиеся или сообщения, которые должны быть получены быстро другими участниками, должны тщательно тщательно исследоваться, чтобы гарантировать, что не отправляются никакие ненужные данные.
Упакуйте свои данные в наименьшее представление, Вы можете, не теряя ценную информацию. Например, целое число в Вашей программе может использовать 32 или 64 бита, чтобы хранить ее данные. Если значение, сохраненное в целом числе, всегда находится в диапазоне
1
через10
, можно сохранить его в сетевом сообщении только в 4 битах.Ограничьте размер ненадежных сообщений к 1 000 байтов или меньший.
Ограничьте размер надежных сообщений к 87 килобайтам или меньший.
Отправьте сообщения только участникам, которым нужна информация, содержавшаяся в сообщении. Например, если Ваша игра имеет две различных команды, связанные с командой сообщения должны быть отправлены только элементам той же команды. Отправка данных всем участникам соответствия израсходовала сетевую пропускную способность для небольшого усиления.
Несмотря на то, что
GKMatch
объект создает полное одноранговое соединение между всеми участниками, можно сократить сетевой трафик путем разделения на уровни кольцевой или архитектуры сетевых соединений клиент-сервер поверх него. Рисунок 8-1 показывает три возможных топологии сети для игры с четырьмя проигрывателями. Слева, одноранговая игра имеет 12 соединений между различными устройствами. Однако Вы могли разделить клиент-серверную архитектуру на уровни поверх этого путем выдвижения одного из устройств для действия как узел. Если Ваша игра передает к или от узла только, можно разделить на два число соединений. Архитектура кольцевой сети позволяет устройствам передавать сетевые пакеты к следующему устройству только, но далее сокращает количество соединений. Каждая топология обеспечивает различные показатели производительности, таким образом, Вы захотите протестировать различные модели для нахождения той, обеспечивающей производительность, которой требует игра.Укажите, как обработать сбои сети. Сети являются по сути ненадежным носителем коммуникации. В то время как соответствие происходит, участник может быть разъединен в любое время. Ваша игра должна обработать сообщения разъединения. Например, при реализации игры для использования топологии клиент-сервер, тогда когда разъединения сервера от соответствия, игра могла бы хотеть назначить новое устройство для становления новым сервером.
Начинание матча
Когда Гэйм Кит поставляет a GKMatch
возразите против своей игры, соединения с другими участниками соответствия еще не могут быть установлены. playerIDs
массив на устройстве того пользователя может быть пустым, если никакие другие плееры не подключаются, или это могло бы содержать подмножество уже подключенных плееров. Ваша игра должна ожидать, пока все плееры не подключаются прежде, чем начать матч. Для определения, сколько проигрывателей ожидает для присоединения к соответствию игра читает соответствие expectedPlayerCount
свойство. Когда достигает значение этого свойства 0
, все плееры подключаются, и матч готов начаться.
Надлежащее место для выполнения этой проверки находится в делегате соответствия match:player:didChangeState:
метод. Этот метод вызывают каждый раз, когда элемент подключений соответствия или разъединений. Перечисление 8-10 является примером реализации Вашего match:player:didChangeState:
метод. В этом примере делегат соответствия определяет его собственное matchStarted
свойство, чтобы записать, происходит ли соответствие уже. Если матч не начался, и количество ожидаемых проигрывателей достигает нуля, метод начинает матч. В Вашей игре это - то, куда любое начальное состояние соответствия было бы передано к другим проигрывателям или где дополнительные согласования между различными участниками имеют место.
Даже, прежде чем матч начинается, все плееры, уже подключенные к соответствию, могут уже обмениваться данными друг с другом. Это позволяет Вашей игре создавать речевые каналы (или Ваш собственный пользовательский интерфейс), который уже позволяет проигрывателям там связываться друг с другом.
Перечисление 8-10 , Начинающее матч
- (void)match:(GKMatch *)match player:(NSString *)playerID didChangeState:(GKPlayerConnectionState)state |
{ |
switch (state) |
{ |
case GKPlayerStateConnected: |
// Handle a new player connection. |
break; |
case GKPlayerStateDisconnected: |
// A player just disconnected. |
break; |
} |
if (!self.matchStarted && match.expectedPlayerCount == 0) |
{ |
self.matchStarted = YES; |
// Handle initial match negotiation. |
} |
} |
Определение лучшего сервера
При реализации клиент-серверной архитектуры поверх одноранговой модели, предоставленной объектом соответствия выбирание правильного сервера критически важно по отношению к достижению хорошей производительности сети и задержки в получающемся соответствии. Поэтому Гэйм Кит предоставляет встроенную поддержку, позволяющую всем коллегам в игре тестировать друг друга для определения лучшего сервера. Вы реализуете это путем вызова chooseBestHostPlayerWithCompletionHandler:
метод. Когда работа завершается, возвращающийся идентификатор проигрывателя является лицом, устройство которого сделало бы лучший сервер для Вашей игры.
Если Вы намереваетесь искать лучший сервер с помощью этого метода, все устройства в соответствии должны работать на версиях Гэйма Кита, поддерживающих этот метод, и каждое устройство в соответствии должно вызвать этот метод одновременно. Это позволяет всем устройствам тестировать и связываться друг с другом одновременно. Как правило, Вы находите лучший сервер после того, как все соединяются, и геймплей готов запуститься.
Отправка данных к другим проигрывателям
Для отправки данных с одного устройства на другие устройства, подключенные к соответствию, игра создает сообщение и инкапсулирует его в NSData
объект. Вы отправляете это сообщение во все подключенные плееры с помощью sendDataToAllPlayers:withDataMode:error:
метод, или к подмножеству проигрывателей с помощью sendData:toPlayers:withDataMode:error:
метод.
Перечисление 8-11 показывает, как игра могла бы отправить обновление позиции другим участникам. Метод заполняет структуру данными позиции, обертывает их в NSData
объект, и затем вызывает соответствие sendDataToAllPlayers:withDataMode:error:
метод.
Перечисление 8-11 , Отправляющее позицию во все проигрыватели
- (void) sendPosition |
{ |
NSError *error; |
PositionPacket msg; |
msg.messageKind = PositionMessage; |
msg.x = currentPosition.x; |
msg.y = currentPosition.y; |
NSData *packet = [NSData dataWithBytes:&msg length:sizeof(PositionPacket)]; |
[match sendDataToAllPlayers: packet withDataMode: GKMatchSendDataUnreliable error:&error]; |
if (error != nil) |
{ |
// Handle the error. |
} |
} |
Когда сеть доступна, когда возвраты метода, не сообщая об ошибке, сообщение было поставлено в очередь и будет отправлено.
Получение данных от других проигрывателей
Когда соответствие получает данные, отправленные другим участником, сообщение передается путем вызова делегата соответствия match:didReceiveData:fromPlayer:
метод. Ваша реализация этого метода должна декодировать сообщение и действовать на его содержание.
- (void)match:(GKMatch *)match didReceiveData:(NSData *)data fromPlayer:(NSString *)playerID |
{ |
Packet *p = (Packet*)[data bytes]; |
if (p.messageKind == PositionMessage) |
// Handle a position message. |
} |
Разъединение от соответствия
Когда проигрыватель готов оставить соответствие, Ваша игра вызывает объект соответствия disconnect
метод. Если их устройство не отвечает на определенный период времени, проигрыватель может также быть автоматически разъединен. Когда проигрыватель разъединяется от соответствия, другие участники соответствия уведомляются путем вызова делегата соответствия match:player:didChangeState:
метод.
Добавление голосового чата к соответствию
Игровой Набор обеспечивает все низкоуровневое речевое кодирование и передачу так, чтобы Вы не обрабатывали это сами. Однако любая игра, поддерживающая голосовой чат, должна обеспечить свой собственный пользовательский интерфейс, позволяющий проигрывателям конфигурировать голосовой чат. Это означает, что проигрыватель должен быть в состоянии:
Выберите - в, или из любых опций голосового чата Вы обеспечиваете.
Отключите звук других проигрывателей, а также управляйте полным объемом голосового чата.
Отключите звук микрофона.
Выберите, в какой канал он или она говорит, если Ваша игра поддерживает многократные каналы.
Посмотрите, какой проигрыватель говорит.
Создание Аудио Сеанса (только iOS)
Прежде чем Ваша игра может использовать услуги голосового чата, предоставленные объектом соответствия, необходимо создать аудио сеанс, имеющий возможность и играть и записать звуки. Если Ваша игра обеспечивает другие звуковые эффекты, у Вас, вероятно, уже есть аудио сеанс. Перечисление 8-12 показывает код, необходимый для создания аудио сеанса, позволяющего микрофону использоваться.
Перечисление 8-12 , Создающее аудио сеанс, который может играть и записать
AVAudioSession *audioSession = [AVAudioSession sharedInstance]; |
[audioSession setCategory:AVAudioSessionCategoryPlayAndRecord error:myErr]; |
[audioSession setActive: YES error: myErr]; |
Для получения дополнительной информации при создании и использовании аудио сеансов, см. Аудио Руководство по программированию Сеанса.
Создание речевых каналов
Ваша игра никогда непосредственно создает GKVoiceChat
объекты. Вместо этого объекты голосового чата создаются от Вашего имени GKMatch
объект. Единственное соответствие может создать многократные каналы, и сингл может быть присвоен больше чем одному каналу за один раз. Аудио, полученное на любом из каналов, смешано вместе и выведено через динамики.
Для многократных участников на различных устройствах для присоединения к тому же каналу им нужен способ идентифицировать определенный канал. Эта идентификация выполняется через название канала. Название канала является строкой, определенной Вашей игрой, уникально называющей канал. Когда два или больше участника присоединяются к каналу с тем же именем, они автоматически подключены к голосовому чату друг с другом.
Перечисление 8-13 обеспечивает код, создающий два канала. Первый вызов к voiceChatWithName:
создает канал команды, и второе создает глобальный канал. Код сохраняет оба канала.
Перечисление 8-13 , Создающее речевые каналы
GKMatch* match; |
GKVoiceChat *teamChannel = [[match voiceChatWithName:@"redTeam"] retain]; |
GKVoiceChat *allChannel = [[match voiceChatWithName:@"allPlayers"] retain]; |
Запуск и остановка голосового чата
Речевая информация не отправлена или получена через речевой канал, пока не запускается канал. Вы запускаете голосовой чат путем вызова объекта голосового чата start
метод:
[teamChannel start]; |
После start
если следующее является истиной, метод вызывают, объект голосового чата на том устройстве подключения к другим участникам канала:
Устройство находится на сети Wi-Fi.
Существует микрофон, подключенный к устройству.
Если любому из этих условий не удовлетворяют, объект голосового чата ожидает, пока оба не истина прежде, чем соединиться с каналом.
Точно так же, когда проигрыватель готов оставить канал или каждый раз, когда Вы хотите, чтобы канал был временно выключен, Вы останавливаете использование чата:
[teamChannel stop]; |
Преимущество для остановки канала (вместо того, чтобы просто отключить звук других проигрывателей) состоит в том, что другие проигрыватели не требуются, чтобы отправлять данные в проигрыватель, кто оставил канал. Это уменьшение в передаче данных оставляет больше пропускной способности доступным для обмена сообщениями Вашей игры.
Включение и отключение микрофона
Когда Вы хотите, чтобы проигрыватель был в состоянии говорить, Вы включаете микрофон. В зависимости от природы Вашей игры можно хотеть включить микрофон постоянно, в то время как игра работает, или можно хотеть включать микрофонную клавишу в интерфейс.
Канал включает микрофон путем установки объекта голосового чата active
свойство к YES
:
teamChannel.active = YES; |
Только один канал может включить микрофон за один раз. Когда Вы включаете микрофон для одного канала, active
свойство на предыдущем владельце автоматически установлено в NO
.
Управление объемом голосового чата
Ваша игра может управлять объемом голосового чата двумя способами. Во-первых, Ваша игра может установить полный уровень громкости для чата путем изменения объекта голосового чата volume
свойство:
allChannel.volume = 0.5; |
volume
свойство принимает значения между 0.0
и 1.0
, включительно. Значение 0.0
отключает звук всего канала; объем 1.0
выходная речевая информация в полном объеме.
Во-вторых, Ваша игра может выборочно отключить звук проигрывателей в канале. Как правило, если Ваша игра намеревается отключить звук проигрывателей, она должна предложить пользовательский интерфейс, позволяющий проигрывателю выбирать, каких проигрывателей они хотят отключить звук. Для отключения звука проигрывателя Вы вызываете объект голосового чата setMute:forPlayer:
метод:
[teamChannel setMute: YES forPlayer: player]; |
Для неотключения звук проигрывателя Вы выполняете тот же вызов, передавая NO
вместо этого.
[teamChannel setMute: NO forPlayer: player]; |
Наблюдение, когда изменения состояния проигрывателя
Когда игра хочет быть уведомленной об изменениях в состоянии проигрывателя, можно реализовать обработчик обновления. Обработчик является блочным объектом, что вызовы объектов голосового чата, когда проигрыватель соединяется с или разъединяется от канала и когда проигрыватель запускает и прекращает говорить. Например, когда тот проигрыватель говорит, Вы используете обработчик обновления для выделения имени проигрывателя в пользовательском интерфейсе.
Перечисление 8-14 показывает реализацию обработчика обновления для состояния проигрывателя.
Перечисление 8-14 , Получающее обновления о проигрывателе
teamChat.playerStateUpdateHandler = ^(NSString *playerID, GKVoiceChatPlayerState state) { |
switch (state) |
{ |
case GKVoiceChatPlayerSpeaking: |
// Insert code to highlight the player's picture. |
break; |
case GKVoiceChatPlayerSilent: |
// Insert code to dim the player's picture. |
break; |
} |
}; |