Применение GameplayKit Randomization и State Machine в iOS-проектах
В предыдущей статье было описано, как применять игровой 2D-движок SpriteKit для быстрого создания простых анимаций в iOS. В новой статье я хочу поделиться, как использовать GameplayKit в неигровых приложениях.
GameplayKit — это набор инструментов, который Apple представляет для быстрого конструирования игровых процессов и алгоритмов. Рассмотрим инструменты, которые применимы даже в UIKit/Appkit-проектах.
Randomization
Так называется инструмент, позволяющий применять различные алгоритмы рандома, которые довольно часто приходится использовать в играх. Здесь не будет обсуждаться генерация рандомных чисел для создания секретных ключей шифрования, так как даже в самой документации у Apple указано, что эти сервисы рандомизации не являются криптографически устойчивыми, и для таких целей рекомендуется применять совсем другие инструменты.
Раньше чаще всего многие применяли метод random() или arc4random(), построенный на ARC4-алгоритме и генерирующий числа между 0 и 4294967295. После выхода Swift 4.2 появились новые методы для генерации рандома:
let randomInt = Int.random(in: 0..<10) let randomDouble = Double.random(in: 5.71838...6.15249) let randomBool = Bool.random()
Обычно этих инструментов достаточно, если нам нужно просто сгенерировать случайное число, не задумываясь о последствиях. В таких случаях вы никак не сможете влиять на алгоритм рандомизации, последовательность и частоту выпадения определенных значений. А если попытаться влиять на этот процесс, производя генерацию несколько раз, чтобы получать нужный range значений, и еще это нужно делать на каждый кадр, то производительность работы может сильно пострадать. Такая ситуация обусловлена тем, что в современных играх часто происходит одновременная генерация нескольких случайных чисел за один кадр и, таким образом, чтобы поддерживать 60 кадров в секунду, придется несколько десятков, а иногда и сотен раз в секунду инициализировать генерацию и обработку случайных чисел.
Такой подход имеет и проблемы в создании последовательности одинаковых чисел у двух и более пользователей, особенно если эти люди используют различные платформы, код которых написан на других языках программирования.
Именно для этого и применяется Randomization из GameplayKit, позволяя сделать генерацию более детерминированной.
Random Source
Собственно, весь процесс рандома состоит из объекта-суперкласса GKRandomSource, который является источником рандомных чисел (Random Source), а также наследования от протокола GKRandom.
Сам протокол GKRandom представляет минимальный интерфейс для генерации случайных чисел и состоит всего из 4 методов:
let randomSource = GKRandomSource.sharedRandom() // возвращает случайное значение Int32.min и Int32.max // диапазон чисел от -2 147 483 648 до 2 147 483 647 randomSource.nextInt() // возвращает случайное значение Int между 0 и 9 randomSource.nextInt(upperBound: 10) // возвращает случайное Float значение в диапазоне от 0.0 до 1.0 randomSource.nextUniform() // возвращает случайное Bool randomSource.nextBool()
GameplayKit предлагает один базовый и 3 альтернативных Random Source, которые являются детерминированными и могут быть сериализованы с использованием NSCoding, чтобы, к примеру, была возможность сохранить текущее состояние последовательности.
- GKRandomSource — базовый генератор случайных чисел, от которого наследуются все последующие Random Source классы.
- GKARC4RandomSource — генератор случайных чисел, реализующий уже привычный в iOS алгоритм ARC4 (arc4random). Особенность также состоит в том, что у этого источника есть метод dropValues(_:), который помогает отбросить определенное количество первых последовательностей, чтобы было сложнее предугадать вероятное следующее значение.
let arc4 = GKARC4RandomSource() // Минимальное рекомендуемое количество отбрасываемых значений в последовательности arc4.dropValues(768) // Генерация случайного числа от 0 до 10 arc4.nextInt(upperBound: 11)
- GKLinearCongruentialRandomSource — генератор чисел, реализующий алгоритм линейного конгруэнтного генератора, который быстрее, но менее случайный, чем стандартный ARC4. Основное преимущество его в том, что этот алгоритм есть в стандартных библиотеках некоторых языков программирования. Поэтому иногда его можно применять для создания одинаковой последовательности случайных чисел на разных платформах. К примеру, в Java этот алгоритм используется в java.util.Random. Также его стоит применять в том случае, если вы действительно делаете десятки или сотни генераций в секунду, иначе разница в производительности будет практически незаметна.
let linearCongruential = GKLinearCongruentialRandomSource() // Генерация случайного числа от 0 до 10 linearCongruential.nextInt(upperBound: 11)
- GKMersenneTwisterRandomSource — генератор случайных чисел, реализующий алгоритм вихрь Мерсенна, разработанный японскими учеными, который является более случайным, но и менее производительным, чем ARC4. Реализован в стандартных библиотеках: C++, Python, Ruby, PHP.
let mersenneTwister = GKMersenneTwisterRandomSource() mersenneTwister.nextInt(upperBound: 11)
Очень удобно, что все эти источники имеют одинаковый интерфейс и не нужно каждый раз изучать специфику использования каждого в отдельности.
За счет того, что все эти классы наследуются от GKRandomSource, который является суперклассом для всех представленных алгоритмов, это позволяет создавать сразу все генераторы независимыми друг от друга и в то же время детерминированными. При этом мы можем легко производить репликацию с сохранением последовательности каждого из алгоритмов.
Random Distribution
Еще одним важным преимуществом рандомизации через GameplayKit является возможность формировать Random Source вместе с Random Distribution (методом случайного распределения).
Всего нам представлено 3 класса для Random Distribution:
- GKRandomDistribution — распределение, где равномерная вероятность генерации любого числа в указанном диапазоне приблизительно равнозначна. Таким образом, исключается предвзятость в отношении любого возможного результата. Что приятно, этот класс имеет удобный интерфейс, чтобы сразу инициализировать аналог
6-гранного кубика, или20-гранного кубика, или даже100-гранного кубика.
// Это также можно сделать через GKRandomDistribution.d6() letПохожие статьи:Злам Центробанку рф українською IT-армією, Twitter за платною підпискою, запуск українського безпілотника, бронювання від мобілізації —...Эта статья для всех, кого интересует интеграция голосового интерфейса управления разнообразными устройствами в собственный...Компания WEXLER сообщила о начале продаж сразу двух своих новых моделей планшетов А-серии, отличающихся, с её слов,...Южнокорейская компания LG Electronics объявила о пополнении своей линейки беспроводных Bluetooth гарнитур LG TONE новым...