Летом прошлого года я создал несколько приложений на основе Flash, воссоздающих химию роя Хироки Саямы . Я думал, что в продолжение моих недавних экспериментов с NSOperation и threading для iOS, я попробую то же самое в Swift.
Химия роя — еще один замечательный пример морфогенеза. Он моделирует системы гетерогенных частиц, которые имеют геномы, которые описывают простые кинетические правила, такие как разделение и сплоченность, и можно наблюдать возникающие явления, включая самоорганизацию и митоз.
Это вычислительно довольно тяжело. Каждая отдельная частица или член роя опрашивает друг друга. Таким образом, для 100 участников каждое обновление требует 10000 шагов. Одним из методов для оптимизации этого является Bin Lattice Spatial Subdivision, и я постараюсь реализовать его в следующем выпуске.
В моих первых экспериментах использовался набор спрайтов, и каждая частица была небольшим спрайтом, однако быстро стало очевидно, что при большом количестве спрайтов перерисовка становится узким местом производительности. Я решил создать свой собственный точечный рисунок, так же, как я делал это в своем эксперименте по диффузии реакции . Однако Джозеф Лорд любезно пересмотрел этот код, и я реализовал его код для создания экземпляра моего роя в UIImage .
Еще один замечательный совет Джозефа — возвращение к типизированным массивам Swift Arrays, а не к использованию NSMutableArrays классов. Несмотря на то, что в стандартной конфигурации сборки Debug NSMutableArray значительно быстрее, чем Array , переключение на конфигурацию Release оборачивается, и массивы становятся удивительно быстрыми.
Этот код выполняется примерно в секунду в конфигурации отладки, поэтому обязательно отредактируйте конфигурацию и установите для нее Release:
Каждый член роя представлен структурой SwarmMember . Его правила представлены экземпляром класса SwarmGenome . Я решил, что последний является классом, потому что, как класс, его экземпляры передаются по ссылке, а не по значению. Это означает, что когда я редактирую один из параметров правила, например выравнивание, это изменение влияет на каждого члена, реализующего этот геном. Если бы SwarmGenome был структурой, я должен был бы пройтись по каждому члену и обновить свойства его генома.
Одна из приятных вещей в выпуске 6 Xcode 6 — это классовые функции на классах — очень похоже на статические структуры.
Я также избегал NSOperation в этом выпуске и использовал библиотеку Tobias Due Munk ‘s Async . Это предлагает хороший синтаксический сахар для Grand Central Dispatch и делает написание асинхронного кода еще проще. Нет хитрого кода таймера, как в прошлый раз — две мои функции для диспетчеризации задач решения и рендеринга выглядят так:
func dispatchSolve() { Async.background { self.swarmMembers = solveSwarmChemistry(self.swarmMembers); } .main { self.dispatchRender(); self.dispatchSolve(); } } func dispatchRender() { Async.background { self.image = renderSwarmChemistry(self.swarmMembers); } .main { self.uiImageView.image = self.image; } }
Код внутри блока .background выполняется в фоновом режиме, и после его завершения код внутри блока .main выполняется в моем потоке пользовательского интерфейса, поэтому все обновляется хорошо.
Пользовательский интерфейс довольно простой. В этой версии пользователь может редактировать четыре генома (голубой, красный, синий и желтый). Выбрав геном на верхней панели кнопок, а затем выбрав параметр на нижней панели кнопок, ползунок устанавливает значение этого генома / параметра.
Количество членов жестко закодировано до 800 прямо сейчас . Он прекрасно работает под моим симулятором iOS на моем iMac, но немного неуклюже на моем iPad на базе A6X. Я воздерживаюсь от покупки iPad A7, надеясь, что в скором времени будет выпущен новый блестящий A8, но мне было бы очень интересно услышать, как он работает на A7.
Весь исходный код доступен в моем репозитории GitHub здесь .