如何使用 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)
请帮助我理解,我做错了什么。
我可以看到三个问题:
不保留委托,因此您必须通过将 MyRender
实例分配给某处的强变量(例如实例变量)来保持 MyRender
实例处于活动状态
rendererDelegate
声明为 assign
而不是 weak
因此当委托被释放时它不会自动设置为 nil
(这是一个SceneKit 中的弱点)所以你必须明确地将它设置为 nil
。在这里,当 MyRender
实例被释放时,SceneKit 仍然认为 boxNode
有一个委托并向一个释放的对象发送消息(EXC_BAD_ACCESS 崩溃)
看来你会陷入死循环。您的委托方法正在调用自身。
会试一试,首先你必须定义你的 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 标记当然不是必需的。
希望这有帮助
我是 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) 请帮助我理解,我做错了什么。
我可以看到三个问题:
不保留委托,因此您必须通过将
MyRender
实例分配给某处的强变量(例如实例变量)来保持MyRender
实例处于活动状态rendererDelegate
声明为assign
而不是weak
因此当委托被释放时它不会自动设置为nil
(这是一个SceneKit 中的弱点)所以你必须明确地将它设置为nil
。在这里,当MyRender
实例被释放时,SceneKit 仍然认为boxNode
有一个委托并向一个释放的对象发送消息(EXC_BAD_ACCESS 崩溃)看来你会陷入死循环。您的委托方法正在调用自身。
会试一试,首先你必须定义你的 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 标记当然不是必需的。 希望这有帮助