You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何存储预计算的SKPhysicsBody数组,避免重复计算提升旧设备性能?

问题:如何持久化SKPhysicsBody数组以避免重复计算?

我在应用首次加载时于后台线程运行代码,提前生成SKPhysicsBody数组供节点加载时使用(参考Stack Overflow中@mfessenden关于SKPhysicsBody纹理动画的实现),以此提升性能。新设备上该操作可在应用intro阶段完成,影响不大,但旧设备可能因计算超时影响性能。我尝试将计算后的数组存储至UserDefaults,却触发NSInvalidArgumentException错误(提示插入非属性列表对象)。请问何种方式可存储该数据,使其仅需计算一次?

代码示例:

var Sat1shapes: [SKPhysicsBody] = []
var Sat1Frames: [SKTexture] = []

for frame in Sat1Frames {
    let node6 = SKSpriteNode()
    node6.physicsBody = SKPhysicsBody(texture: frame, size: CGSize(width: 414 * wR, height: 233 * hR))
    Sat1shapes.append(node6.physicsBody!)
}

let Sat2AnimatedAtlas = SKTextureAtlas(named: "satsmall2")
let numImagesSat2 = Sat2AnimatedAtlas.textureNames.count
for i in 0...numImagesSat2 {
    let Sat2TextureName = "\(i)"
    Sat2Frames.append(Sat2AnimatedAtlas.textureNamed(Sat2TextureName))
}

解决方案

方法1:使用归档(NSKeyedArchiver/NSKeyedUnarchiver)

SKPhysicsBody遵循NSCoding协议,可将数组归档为Data后存储,支持存入UserDefaults或本地文件。

归档存储代码:

// 归档Sat1shapes数组
do {
    let data = try NSKeyedArchiver.archivedData(withRootObject: Sat1shapes, requiringSecureCoding: false)
    UserDefaults.standard.set(data, forKey: "StoredSat1PhysicsBodies")
} catch {
    print("归档失败:\(error)")
}

解归档读取代码:

// 启动时读取已存储的数组
if let data = UserDefaults.standard.data(forKey: "StoredSat1PhysicsBodies") {
    do {
        if let storedShapes = try NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data) as? [SKPhysicsBody] {
            Sat1shapes = storedShapes
            // 无需再重新计算
        }
    } catch {
        print("解归档失败:\(error)")
        generatePhysicsBodies()
    }
} else {
    // 无存储数据时重新计算
    generatePhysicsBodies()
}

// 封装生成物理体的函数
func generatePhysicsBodies() {
    for frame in Sat1Frames {
        let node6 = SKSpriteNode()
        node6.physicsBody = SKPhysicsBody(texture: frame, size: CGSize(width: 414 * wR, height: 233 * hR))
        Sat1shapes.append(node6.physicsBody!)
    }
}

方法2:存储物理体生成参数(更轻量可靠)

若归档出现兼容性问题,可存储生成SKPhysicsBody的关键参数,下次直接重建:

  1. 记录每个物理体对应的纹理名称、尺寸等参数
  2. 启动时读取参数,重新从图集加载纹理并生成物理体

示例代码:

// 存储参数:假设Sat1Frames来自名为"sat1Atlas"的纹理图集
let sat1TextureNames = Sat1Frames.map { $0.name ?? "" }
UserDefaults.standard.set(sat1TextureNames, forKey: "Sat1TextureNames")
UserDefaults.standard.set(["width": 414 * wR, "height": 233 * hR], forKey: "Sat1PhysicsSize")

// 读取并重建
if let textureNames = UserDefaults.standard.array(forKey: "Sat1TextureNames") as? [String],
   let sizeDict = UserDefaults.standard.dictionary(forKey: "Sat1PhysicsSize") as? [String: CGFloat],
   let width = sizeDict["width"], let height = sizeDict["height"] {
    let size = CGSize(width: width, height: height)
    let atlas = SKTextureAtlas(named: "sat1Atlas")
    Sat1shapes = textureNames.compactMap { name in
        let texture = atlas.textureNamed(name)
        return SKPhysicsBody(texture: texture, size: size)
    }
} else {
    generatePhysicsBodies()
}

方法3:本地文件存储(适合大数据量)

若SKPhysicsBody数组较大,可直接将归档数据存入应用Documents目录:

存储代码:

do {
    let data = try NSKeyedArchiver.archivedData(withRootObject: Sat1shapes, requiringSecureCoding: false)
    let documentsDir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
    let fileURL = documentsDir.appendingPathComponent("Sat1PhysicsBodies.data")
    try data.write(to: fileURL)
} catch {
    print("写入文件失败:\(error)")
}

读取代码:

let documentsDir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
let fileURL = documentsDir.appendingPathComponent("Sat1PhysicsBodies.data")
if FileManager.default.fileExists(atPath: fileURL.path) {
    do {
        let data = try Data(contentsOf: fileURL)
        if let storedShapes = try NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data) as? [SKPhysicsBody] {
            Sat1shapes = storedShapes
        }
    } catch {
        print("读取文件失败:\(error)")
        generatePhysicsBodies()
    }
} else {
    generatePhysicsBodies()
}

内容的提问来源于stack exchange,提问作者Guitarman4

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 23:54:28