如何使用 SCNNodeRendererDelegate?

How to use SCNNodeRendererDelegate?

我是 Swift 和 SceneKit 的新手,正在尝试了解如何使用 SCNNodeRendererDelegate。

我已经声明委托如下

class MyRender: NSObject, SCNNodeRendererDelegate {

  func renderNode(node: SCNNode, renderer: SCNRenderer, arguments: [NSObject : AnyObject]) {
    node.rendererDelegate!.renderNode!(node, renderer: renderer, arguments: arguments)
  }
}

并尝试使用它

class GameViewController: NSViewController {

  @IBOutlet weak var gameView: GameView!

  override func awakeFromNib(){
    // ... some code ....
    let boxNode = SCNNode()
    boxNode.geometry = SCNBox(width: 5, height: 5, length: 5, chamferRadius: 0.1)
    boxNode.geometry?.firstMaterial?.diffuse.contents = NSColor.blueColor()
    boxNode.rendererDelegate = MyRender()
    scene.rootNode.addChildNode(boxNode)
    // ... some code ....

启动后失败 EXC_BAD_ACCESS(code=1, address=0x0) 请帮助我理解,我做错了什么。

我可以看到三个问题:

  1. 不保留委托,因此您必须通过将 MyRender 实例分配给某处的强变量(例如实例变量)来保持 MyRender 实例处于活动状态

  2. rendererDelegate 声明为 assign 而不是 weak 因此当委托被释放时它不会自动设置为 nil (这是一个SceneKit 中的弱点)所以你必须明确地将它设置为 nil。在这里,当 MyRender 实例被释放时,SceneKit 仍然认为 boxNode 有一个委托并向一个释放的对象发送消息(EXC_BAD_ACCESS 崩溃)

  3. 看来你会陷入死循环。您的委托方法正在调用自身。

会试一试,首先你必须定义你的 class

 @interface YourClass : SCNView <SCNPhysicsContactDelegate, SCNSceneRendererDelegate>
 {

 }
 @end

完成后,您的 class 已准备好参与渲染和物理接触,但您仍然必须告诉您的主要 SCNView 和 SCNScene YOURClass 将接管。 你这样做:

 [Myview setDelegate:self];
 [[Myscene physicsWorld] setContactDelegate:self];

您可以在初始化 class 时执行此操作,我个人将 Myscene 和 MYview 创建为单例。

在你完成所有你必须做的之后,在你的实现文件中添加下一行:

pragma 标记 PhysicsDelegate

-(void)physicsWorld:(SCNPhysicsWorld *)world didBeginContact:(SCNPhysicsContact *)contact{}

-(void)physicsWorld:(SCNPhysicsWorld *)world didEndContact:(SCNPhysicsContact *)contact{}

-(void)physicsWorld:(SCNPhysicsWorld *)world didUpdateContact:(SCNPhysicsContact *)contact{}

pragma mark RenderDelegate

-(void)renderer:(id<SCNSceneRenderer>)aRenderer updateAtTime:(NSTimeInterval)time{}
-(void)renderer:(id<SCNSceneRenderer>)aRenderer didApplyAnimationsAtTime:(NSTimeInterval)time{}
-(void)renderer:(id<SCNSceneRenderer>)aRenderer didRenderScene:(SCNScene *)scene atTime:(NSTimeInterval)time{}
-(void)renderer:(id<SCNSceneRenderer>)aRenderer didSimulatePhysicsAtTime:(NSTimeInterval)time{}
-(void)renderer:(id<SCNSceneRenderer>)aRenderer willRenderScene:(SCNScene *)scene atTime:(NSTimeInterval)time{}

现在您可以参与渲染和物理委托。

Pragma 标记当然不是必需的。 希望这有帮助