我继续在StackOverflow中读到我们不应该将SCNNode子类化,有人可以指出我正确的方向进行Scenekit最佳实践吗?
我觉得继承SCNNode将帮助我使用不同类型的子类的特殊方法。遵循面向对象的编程......也许3D车是SCNNode的子类,可以有启动引擎,移动,打开门等的方法。
如果这不是正确的方法..如何将SCNNode耦合到额外的属性和方法?而且,如何区分汽车的SCNNode,卡车或AirPlanes或其他任何东西的SCNNode? p>
答案 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)
}
}
希望它有所帮助...