如何将SceneKit节点自动更新为'反映基础模型?

时间:2015-04-28 23:03:10

标签: swift cocoa-touch scenekit reactive-cocoa

更新该模型时,定位,更新和/或添加或删除与基础模型对应的SceneKit节点的最明智方法是什么?

我不确定如何最好地提出这个问题,所以最简单的例子可能更容易:

我有一些东西,让我们说一个彩色物体的集合,我可能希望使用说法,石英或三维使用SceneKit在二维上表示为正方形。由于底层数据在两种情况下都是相同的,因此抽象模型并定义如下内容似乎更合适:

struct Foo {
    var uid: String
    var color: UIColor
    var position: [Float] // array of 3 floats for x, y, z
}

然后我有:

var collectionOfFoo: [Foo]

然后我可以通过循环collectionOfFoo并为每个具有适当颜色和位置等的SCNBox构建我的SceneKit场景。

问题:用户可能会向Foo添加新的collectionOfFoo,或删除现有的Foo,或更改现有的Foo之一存储的值,然后必须更新SceneKit场景以反映它。摧毁现场并从头开始重建它似乎很浪费,而且速度太慢了。这可能需要每秒调用数百次。

我当前的方法:我给予与给定Foo对应的SceneKit节点一个与Foo' s uid匹配的名称,然后最终手动搜索使用childNodeWithName的节点层次结构。然而,这实际上并没有很好地扩展(帧速率差),并且感觉“错误”#34;好像这可能是一个更容易/更惯用的方式。我一直在寻找像ReactiveCocoa之类的东西,因为它似乎解决了这类问题,但我不确定这是否过于复杂。

如果我使用的是Objective-C,我可能会尝试创建一个Foo类,其中每个实例只保存一个指向相关SceneKit节点的指针;这不会非常优雅,但至少会有效并能产生预期的效果。我只是在寻找一种更好的方法,一种在Swift中运行的方式。

建议非常受欢迎,非常感谢 - 我仍然在制作我的第一个应用程序,并且仍然认为自己是初学者。

2 个答案:

答案 0 :(得分:1)

我对Swift一无所知,所以大部分可能都是错的,但这是一个疯狂的猜测:

为什么不切换到Class而不是Struct?您的代码不会发生太大变化,但它可以帮助您存储SCNNode,以及任何其他图形表示以及您拥有的数据。

如果无法做到这一点,那么使用单独的字典怎么样?只需使用您已有的uid存储您的SCNNode:

var nodes = [String: SCNNode]()

...

nodes[current.uid] = aNewNode

您还可以随时在场景中添加和删除节点,无需"销毁和重建"。如果我们保留上一个示例,您可以执行以下操作:

nodes[uidToDelete].removeFromParentNode()

另一方面,差的帧速率可能与添加/删除节点的方式无关。尝试enable statistics on your scene,看看你在哪里浪费时间。

答案 1 :(得分:1)

我建议你看一下斯坦福大学的这门课程并看一下MVC讲座:https://itunes.apple.com/gb/course/developing-ios-8-apps-swift/id961180099

他们建议您使用NSNotification来提醒您的控制器(在您的情况下可能是您的SCNScene)模型中的更改。然后,您的控制器会进入并更改其视图(或您的情况下为SCNNode)。这是一个例子:

1。您的模型中发生了一些事情 - 创建了新的Foo!因此,发布NSNotification

let notificationCenter = NSNotificationCenter.defaultCenter()
notificationCenter.postNotificationName("FooWasCreatedNotification",
                                        object: nil,
                                        userInfo: ["Foo": fooInstance])

(为了能够在此处传递Foo的实例,Foo需要成为一个类,因为struct无法添加到userInfo

2。SCNScene(或您正在使用的任何其他内容)中,收到NSNotification并更新:

func didRevieveNewFooNotification(notification: NSNotification!) {
    if let info = notification.userInfo as? Dictionary<String,AnyObject>,
       let foo  = info["Foo"] as? Foo {

        //  Create new node using foo's properties...
        //  And add it to the array:
        collectionOfFoo.append(foo)
    }
}

使用NSNotification可使您的模型非常便携,因为NSNotification是盲目沟通。因此,您的控制器和节点可以是您想要的任何内容,而无需更改模型。

希望有所帮助。