gpt4 book ai didi

ios - Scenekit:为什么不应该对 SCNNode 进行子类化?

转载 作者:行者123 更新时间:2023-11-28 10:09:17 25 4
gpt4 key购买 nike

我一直在 StackOverflow 中读到我们不应该将 SCNNode 子类化,有人可以为我指明 Scenekit 最佳实践的正确方向吗?

我觉得子类化 SCNNode 将帮助我拥有不同类型子类的特殊方法。遵循面向对象编程......也许作为 SCNNode 子类的 3d Car 可以具有启动引擎、移动、打开门等的方法。

如果那不是正确的方法..如何将 SCNNodes 耦合到额外的属性和方法?而且,如何区分汽车 SCNNode 和卡车、飞机或其他任何 SCNNode?

最佳答案

我个人认为子类化 SCNNode 没有任何问题,当然这取决于您为什么需要这样做。

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

If you are adding general purpose functionalities that should be available to every SCNNode, then make an extension.

All SCNNode instances can then call these new methods.

另一方面:

If you are adding functionality that should be restricted to special instances of SCNNode, and you need to identify these specifically: then make a subclass, since only instances of these can use your new methods.

如果您选择使用 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,它具有仅可用于该实例的功能,那么创建一个 子类 可能是前进的方向。

假设我们需要创建一个 SCNNode 和一个 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 文件,这将如何工作?

一些伪代码可能看起来像这样:

/// 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)

}

}

然后您可以像这样初始化和管理函数:

 let car = Car()
self.augmentedRealityView.scene.rootNode.addChildNode(car)
car.animateWheels()

希望对你有帮助

关于ios - Scenekit:为什么不应该对 SCNNode 进行子类化?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50165901/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com