如何更新 SceneKit 节点以'automatically'反映底层模型?



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

我不知道如何最好地表达这个问题,所以可能更容易有一个最小的例子:

我有一些东西,比如说一组彩色物体,我可能想用Quartz二维表示为正方形,或者用SceneKit三维表示。由于这两种情况下的底层数据都是相同的,因此抽象掉模型并定义如下内容似乎更合适:

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

然后我有:

var collectionOfFoo: [Foo]

然后我可以通过在我的CCD_ 1上循环并为每个CCD_

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

我目前的方法是:给与给定Foo对应的SceneKit节点一个与Foouid匹配的名称,然后使用collectionOfFoo0手动搜索节点层次结构。然而,这确实不能很好地扩展(低帧率),而且感觉"错误",好像有一种更容易/更习惯的方法可以做到这一点。我一直在研究像ReactiveCocoa这样的东西,因为它似乎解决了这类问题,但我不确定这是否使事情过于复杂。

如果我使用Objective-C,我可能会尝试创建一个Foo类,其中每个实例只包含一个指向相关SceneKit节点的指针;这不会很优雅,但至少会很有效,并会产生所需的结果。我只是在寻找一种更好的方法,一种在Swift中有效的方法。

建议非常受欢迎,也非常感谢——我仍在开发我的第一个应用程序,仍然认为自己是这方面的初学者。

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

他们建议使用NSNotification提醒您的控制器(在您的情况下可能是您的SCNScene)您的型号发生了变化。然后,控制器转到并更改其视图(在您的情况下为SCNNodes)。这里有一个例子:

1.您的模型中发生了一些事情-创建了一个新的Foo!因此,张贴NSNotification:

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

(为了能够在这里传递Foo的实例,Foo需要是一个类,因为SCNBox0 s不能添加到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是盲通信。因此,您的控制器和节点可以是您想要的任何对象,而无需更改模型。

希望能有所帮助。

我对Swift了解不多,所以大部分内容可能都是错误的,但这里有一个疯狂的猜测:

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

如果这不可能,那用一本单独的词典怎么样?只需将SCNNode与已有的uid一起存储即可:

var nodes = [String: SCNNode]()
...
nodes[current.uid] = aNewNode

您也可以随时在场景中添加和删除节点,而无需"销毁和重建"。如果我们保留我之前的例子,你可以简单地做:

nodes[uidToDelete].removeFromParentNode()

顺便说一句,帧速率低可能与添加/删除节点的方式无关。试着在你的场景中启用统计数据,看看你在哪里浪费了时间。

最新更新