Это законная проблема, поскольку SceneKit
не предоставляет готового решения для инициализации систем частиц из файлов, которые находятся за пределами основного пакета (единственный метод инициализации SCNParticleSystem.init(named:inDirectory:)
подразумевает, что SCNParticleSystem.scnp
файлы находятся в основном комплекте).
К счастью для нас .scnp
файлы просто кодируются / архивируются SCNParticleSystem
экземпляров, которые мы можем легко декодировать / разархивировать, используя NSKeyedUnarchiver
:
extension SCNParticleSystem {
static func make(fromFileAt url: URL) -> SCNParticleSystem? {
guard let data = try? Data(contentsOf: url),
let object = try? NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data),
let system = object as? SCNParticleSystem else { return nil }
return system
}
}
Если вам не нужно поддерживать iOS 9
и iOS 10
, вы можете использовать NSKeyedUnarchiver.unarchivedObject(ofClass: SCNParticleSystem.self, from: data)
вместо NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(_:)
и приведение типов, которое было введено в iOS 11.0
.
Другая проблема, с которой вы столкнулисьНаиболее вероятная ошибка - отсутствие изображений частиц.Это потому, что по умолчанию SceneKit
будет искать их в основном комплекте.Начиная с текущих версий изображений частиц iOS (iOS 12
) и Xcode (Xcode 10
) в файлах .scnp
(свойство particleImage
) имеют значения String
, которые являются именами текстур восновной пакет (это может измениться, но, вероятно, не изменится, однако мы не сможем использовать больше ничего).
Поэтому я предлагаю взять это имя файла и найти файл текстуры с тем же именем и тем же именем.каталог, в котором находится файл .scnp
:
extension SCNParticleSystem {
static func make(fromFileAt url: URL) -> SCNParticleSystem? {
guard let data = try? Data(contentsOf: url),
let object = try? NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data),
let system = object as? SCNParticleSystem else { return nil }
if let particleImageName = system.particleImage as? String {
let particleImageURL = url
.deletingLastPathComponent()
.appendingPathComponent(particleImageName)
if FileManager.default.fileExists(atPath: particleImageURL.path) {
system.particleImage = particleImageURL
}
}
return system
}
}
Вы можете просто установить URL
файла изображения, и SceneKit
будет обрабатывать его оттуда.
КакНебольшое примечание: рекомендуемый каталог для загружаемого контента - каталог Application Support
, а не Documents
.
Поддержка приложений : Используйте этот каталог для хранения всех файлов данных приложения, кроме тех, которые связаны с документами пользователя.Например, вы можете использовать этот каталог для хранения созданных приложением файлов данных, файлов конфигурации, шаблонов или других фиксированных или изменяемых ресурсов, которыми управляет приложение.Приложение может использовать этот каталог для хранения изменяемой копии ресурсов, изначально содержащихся в комплекте приложения.Игра может использовать этот каталог для хранения новых уровней, приобретенных пользователем и загруженных с сервера.
(из Основы файловой системы )