Проблемы

Достижения и списки лидеров оба позволяют проигрывателям измерять свой прогресс, играющий в Вашу игру. Но проигрывателям также свойственно хотеть протестировать их прогресс друг против друга. Больше удовлетворяет бить счет друга, чем просто достигнуть достойного счета. Игровой Центр охватывает эту идею в форме проблем. Проигрыватели на Игровом Центре могут бросить вызов другим Игровым элементам Центра бить заработанные очки или достижения. Проблемы представляют различный стиль многопользовательского опыта, где проигрыватели конкурируют друг против друга косвенно.

Когда проблема выпущена одним проигрывателем другому, уведомление нажатия отправляется в оспариваемый проигрыватель. Оспариваемый проигрыватель может тогда принять или отказаться от проблемы. Если проигрыватель принимает проблему, проблема помещается в список проблем, связанных с тем проигрывателем. Позже, если проигрыватель бьет проблему, Игровой Центр уведомляет и оспариваемый проигрыватель и претендента, что проблема завершена.

Игровой Центр поддерживает два вида проблем:

Если Ваша игра поддерживает достижения или списки лидеров, она автоматически поддерживает проблемы, не требуя никакого дополнительного кода. В этом случае проигрыватели переходят к Игровому приложению Центра для оспаривания их друзьям. Однако можно также настроить игру для прямой поддержки проблем:

Контрольный список для поддержки проблем

Для добавления вызовов игре необходимо взять следующие шаги:

Выпуск вызовов со стороны игры

Вы выпускаете проблему из своей игры с помощью любого a GKScore объект или a GKAchievement объект. Оба класса реализуют issueChallengeToPlayers:message: метод с подобной подписью. Выпуск проблемы не выводит на экран пользовательский интерфейс к проигрывателю, выпуская проблему; это - код, который необходимо реализовать сами. Следующий раздел показывает серию методов, которые можно использовать для выпуска проблемы достижения.

Проект для основанных на счете проблем подобен. Создайте объект счета, представьте счет, затем используйте его для генерации запроса проблемы.

Отображение пользовательского интерфейса проблемы

Перечисление 6-1 начинает процесс проблемы. Когда проигрыватель завершает достижение, этот метод вызывают. Первая вещь, которую делает код, создают новый объект достижения сказать Игровому Центру, что было завершено достижение. Если проигрыватель завершает многократные достижения для проблемы сразу, создайте новый объект для каждого достижения и добавьте достижение к массиву. Обратите внимание на то, что проблема может только быть выполнена на завершенном достижении. Это отключает баннер завершения достижения по умолчанию, потому что это планирует вывести на экран пользовательский экран проблемы вместо этого. Метод сообщает о прогрессе Игровому Центру и затем инициировал переход для отображения пользовательского пользовательского интерфейса проблемы игры.

Перечисление 6-1  , Выводящее на экран пользовательский интерфейс проблемы

- (void) bossMonsterDefeated
{
    GKAchievement *achievement = [[GKAchievement alloc] initWithIdentifier:@"MyGame.bossDefeated"];
    achievement.percentComplete = 100.0;
    achievement.showsCompletionBanner = NO;
 
    [achievement reportAchievements: [NSArray arrayWithObjects:achievement, nil] WithCompletionHandler:NULL];
    [self performSegueWithIdentifier:@"achievementChallenge" sender:achievement];
}

Отображение и отклонение контроллера представления проблемы

Перечисление 6-2 показывает, что выпуск просматривает контроллер prepareForSegue:sender: метод. Когда метод обнаруживает, что это - переход для показа пользовательского интерфейса достижения, он устанавливает контроллер представления выпуска как делегата. Объект достижения также предоставлен для контроллера представления проблемы так, чтобы это могло настроить свой пользовательский интерфейс для соответствия заработанного достижения.

Перечисление 6-2  , Подготавливающее проблему, просматривает контроллер

- (void )prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([segue.identifier isEqualToString:@"achievementChallenge"])
    {
        MyAchievementChallengeViewController* challengeVC = (MyAchievementChallengeViewController*) segue.destinationViewController;
        challengeVC.delegate = self;
        challengeVC.achievement = (GKAchievement*) sender;
    }
}

Перечисление 6-3 показывает реализацию контроллера выпуска метода делегата. Когда пользователь отклоняет контроллер представления проблемы, делегата вызывают. Метод делегата берет параметр, утверждающий, выпустил ли проигрыватель проблему. Если проигрыватель выпустил проблему, то метод получает список проигрывателей и сообщение от контроллера представления проблемы и выпускает проблему. Обратите внимание на то, что этот проект дает контроль над выпуском вызова исходному контроллеру представления. Если для Вашего проекта не нужна эта дополнительная гибкость, Вы могли бы просто выпустить вызов непосредственно со стороны контроллера представления проблемы вместо этого.

Перечисление 6-3  Отклоняя проблему просматривает контроллер

- (void) challengeViewController:(MyAchievementChallengeViewController*)controller wasDismissedWithChallenge:(BOOL)issued
{
    [self dismissViewControllerAnimated:YES completion:NULL];
    if (issued)
    {
        [controller.achievement issueChallengeToPlayers:controller.players message:controller.message];
    }
}

Методы наиболее успешной практики для выпуска проблем

Местный игрок должен всегда управлять, когда и как выпущена проблема. Ваша игра никогда не должна выпускать проблему от имени проигрывателя без проигрывателя, сначала утверждая проблему. При реализации настроенного пользовательского интерфейса для проблем необходимо гарантировать, что проигрыватель имеет опцию не выпустить проблему. Даже когда проигрыватель выпускает проблему, проигрыватель должен управлять, кто получает проблему и какое сообщение выведено на экран к тем проигрывателям.

Идеально, Ваша игра должна обеспечить поведение по умолчанию, соответствующее ожидания проигрывателя. Сообщение по умолчанию и список проигрывателей должны быть разумным выбором, который мог бы сделать проигрыватель. Например, когда проигрыватель хочет выпустить проблему счета, Ваш первый импульс мог бы состоять в том, чтобы включать всех друзей проигрывателя в проблеме. На практике это может не быть лучшим ответом. Некоторые друзья проигрывателя, возможно, уже заработали намного более высокие очки. Вместо этого рассмотрите что-то как алгоритм в Перечислении 6-4. Это ищет список лидеров с помощью фильтра только для друзей. Получающийся список друзей тогда отфильтрован так, чтобы только проигрывателям, кто не заработал как высоко счета, бросили вызов.

Перечисление 6-4  , Получающее список проигрывателей с более низкими очками, чем тот просто, заработано

- (void) challengeLesserMortalsForScore: (int64_t) playerScore inCategory: (NSString*) category
{
    GKLeaderboard *query = [[GKLeaderboard alloc] init];
    query.category = category;
    query.playerScope = GKLeaderboardPlayerScopeFriendsOnly;
    query.range = NSMakeRange(1,100);
    [query loadScoresWithCompletionHandler:^(NSArray *scores, NSError *error) {
        NSPredicate *filter = [NSPredicate predicateWithFormat:@"value < %qi",playerScore];
        NSArray *lesserScores = [scores filteredArrayUsingPredicate:filter];
        [self presentChallengeWithPreselectedScores: lesserScores];
    }];
}

Ваш контроллер представления проблемы может тогда использовать данные счета для заполнения его пользовательского интерфейса. Например, это может использовать идентификаторы проигрывателя, встроенные в счет для загрузки имени и фотографии каждого оспариваемого проигрывателя. Можно выполнить подобную работу для проблем достижения с помощью selectChallengeablePlayerIDs:withCompletionHandler: метод класса. Перечисление 6-5 показывает возможную реализацию этого.

Перечисление 6-5  , Определяющее список проигрывателей, кто может завершить проблему достижения

- (void) challengePlayersToCompleteAchievement: (GKAchievement*) achievement
{
    [achievement selectChallengeablePlayerIDs:[GKLocalPlayer localPlayer].friends withCompletionHandler:^(NSArray *challengeablePlayerIDs, NSError *error) {
        if (challengeablePlayerIDs)
        {
            [self presentChallengeWithPreselectedPlayerIDs: challengeablePlayerIDs];
        }
    }];
}

Получение информации о существующих проблемах

Общий проект для игры, непосредственно поддерживающей проблемы, должен предложить кнопку Challenges на экране заголовка. Когда кнопка касается, Ваша игра представляет список проблем, выпущенных местному игроку. Если проблема тогда выбрана из списка, Ваша игра автоматически переходы к экрану, позволяющему проигрывателю работать для завершения выбранной проблемы.

Проблемы представлены в системе GKChallenge объекты. Можно получить список выдающихся проблем путем вызова loadReceivedChallengesWithCompletionHandler: метод класса. Перечисление 6-6 показывает простую реализацию этого понятия. Этот метод загружает объекты проблемы и когда та задача завершается, проблемы передаются другому методу для заполнения пользовательского интерфейса для представленного содержания.

Перечисление 6-6  , Получающее список проблем

- (void) showChallengesList
{
    [GKChallenge loadReceivedChallengesWithCompletionHandler:^(NSArray *challenges, NSError *error) {
        if (challenges)
            [self presentChallengeList: challenges];
    }];
}

Таблица 6-1 перечисляет наиболее распространенные свойства, используемые для заполнения пользовательского интерфейса.

Таблица 6-1  Общие свойства проблемы

Свойство

Описание

issuingPlayerID

Идентификатор проигрывателя для проигрывателя выпуска.

receivingPlayerID

Идентификатор проигрывателя для проигрывателя, получившего проблему.

issueDate

Дата проблема была выпущена.

completionDate

Дата проблема была завершена.

Каждый тип проблемы определяется отличным подклассом GKChallenge. Таблица 6-2 перечисляет подклассы и как получить остающуюся информацию, должен был вывести на экран вызов проигрывателю.

Табличные 6-2  подклассы проблемы

Подкласс

Описание

GKScoreChallenge

Читайте score свойство для получения объекта счета представление счета раньше генерировало проблему.

GKAchievementChallenge

Читайте achievement свойство для получения объекта достижения представление достижения, завершающего проблему.

Реакция на события проблемы

Ваша игра может непосредственно соединиться с системой уведомления так, чтобы это вызвали непосредственно, когда обновляются проблемы, выпущенные к или местным игроком. Значением по умолчанию Гэйм Кит автоматически выводит на экран баннер, когда состояние проблемы изменяется, но можно также подавить определенные баннеры, если Вы хотите вывести на экран настроенный пользовательский интерфейс вместо этого.

Вы сцепляетесь в систему уведомления проблемы путем установки обработчика событий проблемы, определяющегося GKChallengeEventHandlerDelegate протокол. После того, как местный игрок аутентифицируется на устройстве, Ваше приложение устанавливает обработчик событий проблемы и тогда уведомляется, когда проблемы изменяют состояние. Перечисление 6-7 показывает код для установки нового обработчика событий.

Перечисление 6-7  , Устанавливающее обработчик событий проблемы

- (void) installChallengeHandler
{
    GKChallengeEventHandler *eventHandler = [GKChallengeEventHandler challengeEventHandler];
    eventHandler.delegate = self;
}

Ответ на события проблемы

Игровой Набор выводит на экран баннеры местному игроку при следующих обстоятельствах:

  • Когда местный игрок получает проблему

  • Когда местный игрок завершает проблему

  • Когда удаленный проигрыватель завершает проблему, выпущенную местным игроком

В каждой из этих ситуаций можно настроить поведение с помощью пары методов. Методы для переопределения способов поведения показаны в Таблице 6-3. Первый метод в каждой паре позволяет Вам выбирать, выведен ли баннер на экран вообще. Второй метод в каждой паре позволяет Вам обрабатывать событие самим.

Табличные 6-3  Виды событий проблемы

Событие

Метод для управления представлением баннера

Метод для обработки события

Местный игрок получает проблему

shouldShowBannerForLocallyReceivedChallenge:

localPlayerDidReceiveChallenge:

Местный игрок завершает проблему

shouldShowBannerForLocallyCompletedChallenge:

localPlayerDidCompleteChallenge:

Удаленный проигрыватель завершает проблему

shouldShowBannerForRemotelyCompletedChallenge:

remotePlayerDidCompleteChallenge:

Например, если бы Вы хотели полностью настроить появление, когда местный игрок завершает проблему, то сначала Вы подавили бы баннер от того, чтобы быть выведенным на экран, как показано в Перечислении 6-8:

Перечисление 6-8  , Подавляющее баннер проблемы, когда проигрыватель завершает проблему

- (BOOL)shouldShowBannerForLocallyCompletedChallenge:(GKChallenge *)challenge
{
    return NO;
}

Тогда Вы реализуете a localPlayerDidCompleteChallenge: метод для обработки проблемы. Перечисление 6-9 показывает возможную реализацию этого метода. Во-первых, это загружает данные проигрывателя для проигрывателя, выпуская проблему. В обработчике завершения для этого первого вызова это тогда загружает фотографию того проигрывателя. Наконец, когда фотография загружается, она вызывает свой собственный метод для отображения загруженных данных проблемы.

Перечисление 6-9  , Выводящее на экран настроенный пользовательский интерфейс, когда проигрыватель завершает проблему

- (void)localPlayerDidCompleteChallenge:(GKChallenge *)challenge
{
    NSString *issuerID = challenge.issueingPlayerID;
    [GKPlayer loadPlayersForIdentifiers@[issuerID] withCompletionHandler:^(NSArray *players, NSError *error) {
        GKPlayer *player = [players lastObject];
        // Load the challenging player's photo.
        [player loadPhotoForSize: GKPhotoSizeNormal withCompletionHandler:^(UIImage *photo, NSError *error) {
            [self presentCompletedChallenge: challenge photo: photo name:player.displayName];
        }];
    }];
}

Ответ, когда местный игрок выбирает проблему

Когда проигрыватель получает новую проблему, и баннер появляется, проигрыватель может коснуться баннера проблемы для непосредственной игры проблемы. Точно так же проигрыватель может искать проблему в Игровом приложении Центра и принять решение запустить Вашу игру для игры проблемы. Чтобы быть уведомленными, когда проигрыватель хочет играть проблему, Вы реализуете localPlayerDidSelectChallenge: метод. Если Ваша игра была запущена для обработки проблемы, обработчик localPlayerDidSelectChallenge: метод сразу вызывают после того, как процесс аутентификации завершается.

Вы реализуете localPlayerDidSelectChallenge: метод так же к другим методам обработчиков. Например, Вы могли бы использовать реализацию, подобную этому в Перечислении 6-9, чтобы загрузить информацию о проигрывателе и вывести на экран интерфейс к проигрывателю.