Scenekit:为什么SCNNode不应该被子类化?

时间:2018-05-04 01:30:48

标签: ios swift 3d scenekit arkit

我继续在StackOverflow中读到我们不应该将SCNNode子类化,有人可以指出我正确的方向进行Scenekit最佳实践吗?

我觉得继承SCNNode将帮助我使用不同类型的子类的特殊方法。遵循面向对象的编程......也许3D车是SCNNode的子类,可以有启动引擎,移动,打开门等的方法。

如果这不是正确的方法..如何将SCNNode耦合到额外的属性和方法?而且,如何区分汽车的SCNNode,卡车或AirPlanes或其他任何东西的SCNNode?

1 个答案:

答案 0 :(得分:3)

我个人认为子类化SCNNode没有任何问题,具体取决于您需要这样做的原因。

这里的关键考虑因素如下:

  

如果您要添加应具有的通用功能   可用于每个SCNNode,然后进行扩展。

     

然后,所有SCNNode实例都可以调用这些新方法。

另一方面:

  

如果要添加应限制为特殊功能的功能   SCNNode的实例,你需要具体识别它们:然后   创建一个子类,因为只有这些实例可以使用你的新类   方法

如果您选择使用SCNNode的扩展名,则表示您创建的所有功能都可以应用于任何SCNNode

例如,让我们说,您希望允许任何SCNNode增长和缩小,然后extension将是您最好的选择,例如:

extension SCNNode{

    /// Doubles The Size Of The SCNNode & Then Returns It To Its Original Size
    func growAndShrink(){

        //1. Create An SCNAction Which Will Double The Size Of Our Node
        let growAction = SCNAction.scale(by: 2, duration: 5)

        //2. Create Another SCNAction Wjich Will Revert Our Node Back To It's Original Size
        let shrinkAction = SCNAction.scale(by: 0.5, duration: 5)

        //3. Create An Animation Sequence Which Will Store Our Actions
        let animationSequence = SCNAction.sequence([growAction, shrinkAction])

        //4. Run The Sequence
        self.runAction(animationSequence)

    }

}

但是,如果您想要创建一个SCNNode,其中包含仅适用于该实例的功能,那么创建subclass可能就是前进的方向。

然后我们说我们需要创建一个带有SCNNode的{​​{1}},它为我们提供了有关该节点的具体信息,然后我们可以创建一个类似的子类:

SCNPlaneGeometry

在您的情况下,似乎您计划拥有非常具体的实例,例如卡车,飞机等,每个都有自己的特定功能,然后使用class PlaneNode: SCNNode { let DEFAULT_IMAGE: String = "defaultGrid" let NAME: String = "PlaneNode" var planeGeometry: SCNPlane var planeAnchor: ARPlaneAnchor var widthInfo: String! var heightInfo: String! var alignmentInfo: String! //--------------- //MARK: LifeCycle //--------------- /// Inititialization /// /// - Parameters: /// - anchor: ARPlaneAnchor /// - node: SCNNode /// - node: Bool init(anchor: ARPlaneAnchor, node: SCNNode, image: Bool, identifier: Int, opacity: CGFloat = 0.25){ //1. Create The SCNPlaneGeometry self.planeAnchor = anchor self.planeGeometry = SCNPlane(width: CGFloat(anchor.extent.x), height: CGFloat(anchor.extent.z)) let planeNode = SCNNode(geometry: planeGeometry) super.init() //2. If The Image Bool Is True We Use The Default Image From The Assets Bundle let planeMaterial = SCNMaterial() if image{ planeMaterial.diffuse.contents = UIImage(named: DEFAULT_IMAGE) }else{ planeMaterial.diffuse.contents = UIColor.cyan } //3. Set The Geometries Contents self.planeGeometry.materials = [planeMaterial] //4. Set The Position Of The PlaneNode planeNode.simdPosition = float3(self.planeAnchor.center.x, 0, self.planeAnchor.center.z) //5. Rotate It On It's XAxis planeNode.eulerAngles.x = -.pi / 2 //6. Set The Opacity Of The Node planeNode.opacity = opacity //7. Add The PlaneNode node.addChildNode(planeNode) //8. Set The Nodes ID node.name = "\(NAME) \(identifier)" } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } /// Updates The Size Of The Plane As & When The ARPlaneAnchor Has Been Updated /// /// - Parameter anchor: ARPlaneAnchor func update(_ anchor: ARPlaneAnchor) { self.planeAnchor = anchor self.planeGeometry.width = CGFloat(anchor.extent.x) self.planeGeometry.height = CGFloat(anchor.extent.z) self.position = SCNVector3Make(anchor.center.x, 0.01, anchor.center.z) returnPlaneInfo() } //----------------------- //MARK: Plane Information //----------------------- /// Returns The Size Of The ARPlaneAnchor & Its Alignment func returnPlaneInfo(){ let widthOfPlane = self.planeAnchor.extent.x let heightOfPlane = self.planeAnchor.extent.z var planeAlignment: String! switch planeAnchor.alignment { case .horizontal: planeAlignment = "Horizontal" case .vertical: planeAlignment = "Vertical" } #if DEBUG print(""" Width Of Plane = \(String(format: "%.2fm", widthOfPlane)) Height Of Plane = \(String(format: "%.2fm", heightOfPlane)) Plane Alignment = \(planeAlignment) """) #endif self.widthInfo = String(format: "%.2fm", widthOfPlane) self.heightInfo = String(format: "%.2fm", heightOfPlane) self.alignmentInfo = planeAlignment } } 子类可能是前进的方向。

希望它有所帮助...

更新:根据您的要求,例如:在使用SCNNode的情况下,这将如何工作?

有些.scn file可能如此:

pseudo code

然后您可以初始化和管理这些功能:

/// Creates & Manages The Car Model
class Car: SCNNode {

    let MODEL_SCALE = SCNVector3(0.5, 0.5, 0.5)
    let MODEL_POSITION = SCNVector3(1, 0, -2.5)
    let MODEL_ROTATION: CGFloat = 30.45
    let TURN_DURATION: Double = 1

    var leftFrontWheel: SCNNode!
    var rightFrontWheel: SCNNode!
    var leftBackWheel: SCNNode!
    var rightBackWheel: SCNNode!

    //--------------------
    //MARK: Initialization
    //--------------------

    override init() {

        super.init()

        //1. Get The Car Model From The Assetts Bundle
        guard let carModel = SCNScene(named: "StackOverflow.scnassets/Models/Car.scn"),
            let modelNode = carModel.rootNode.childNode(withName: "Root", recursively: false),
            let frontLeftWheel = modelNode.childNode(withName: "leftFront", recursively: false),
            let frontRightWheel = modelNode.childNode(withName: "rightFront", recursively: false),
            let rearLeftWheel = modelNode.childNode(withName: "leftRear", recursively: false),
            let rearRightWheel = modelNode.childNode(withName: "rightRear", recursively: false) else { return }


        //2. Scale, Rotate & Position The Car
        self.scale = MODEL_SCALE
        self.simdRotation = simd_float4 (0, 1, 0, Float(MODEL_ROTATION.degreesToRadians))
        self.position = MODEL_POSITION

        //2. Create A Reference To Each Wheel
        self.leftFrontWheel = frontLeftWheel
        self.rightFrontWheel = frontRightWheel
        self.leftBackWheel = rearLeftWheel
        self.rightBackWheel = rearRightWheel


        //3. Add The Car To The Root Node
        self.addChildNode(modelNode)

        print("""
            Loaded Car Model
            Scale = \(MODEL_SCALE)
            Rotation = \(MODEL_ROTATION)
            Position = \(MODEL_POSITION)
            """)

    }

    required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") }

    //---------------
    //MARK: Animation
    //---------------

    /// Runs The Wheel Animation
    func animateWheels(){

        let wheelTurnAnimationOut = SCNAction.rotate(toAxisAngle:  SCNVector4(0 , 0 , 1, CGFloat(45).degreesToRadians), duration: TURN_DURATION)
        let wheelTurnAnimationIn = SCNAction.rotate(toAxisAngle:  SCNVector4(0 , 0 , 1, CGFloat(0).degreesToRadians), duration: TURN_DURATION)
        let turningSequence = SCNAction.sequence([wheelTurnAnimationOut, wheelTurnAnimationIn])
        let turningAction = SCNAction.repeatForever(turningSequence)
        leftFrontWheel.runAction(turningAction)
        rightFrontWheel.runAction(turningAction)
        leftBackWheel.runAction(turningAction)
        rightBackWheel.runAction(turningAction)

    }

}

希望它有所帮助...