2015-05-05 15 views
6

ho un nodo scatolaSceneKit nodo animate lungo il percorso

_boxNode = [SCNNode node]; 
_boxNode.geometry = [SCNBox boxWithWidth:1 height:1 length:1 chamferRadius:0]; 
_boxNode.position = SCNVector3Make(0, 0, -2); 
[scene.rootNode addChildNode:_boxNode]; 

Ho un percorso

CGPathRef path = CGPathCreateWithEllipseInRect(CGRectMake(-2, -2, 4, 4), nil); 

voglio avere il mio viaggio di dialogo lungo il mio cammino una volta.

Come si fa in SceneKit?

Mi piacerebbe fare un metodo che sarebbe simile

[_boxNode runAction:[SCNAction moveAlongPath:path forDuration:duration]]; 
+1

Cosa ti impedisce di esecuzione di una ricerca? Ho visto un argomento simile prima. –

+0

L'ho già fatto con un CAKeyAnimation. SceneKit non ha API incorporate per viaggiare lungo un percorso. Le mie creazioni di lavoro sono al massimo ingombranti e complicate. Quindi mi chiedo se qualcuno ha una soluzione semplice. –

+0

non aggiunge l'animazione CoreAnimation al nodo? – mnuages

risposta

5

mi sono imbattuto in questa domanda come bene e ho scritto un piccolo parco giochi. L'animazione funziona bene. Una cosa deve essere fatta. La distanza tra ogni punto deve essere calcolata in modo che il tempo possa essere ridimensionato per ottenere un'animazione fluida. Basta copiare & incollare il codice in un parco giochi. Il codice è a Swift 3.

Qui è la mia soluzione (l'estensione BezierPath non è da me, l'ho trovato qui):

import UIKit 
import SceneKit 
import PlaygroundSupport 

let animationDuration = 0.1 

public extension UIBezierPath { 

    var elements: [PathElement] { 
     var pathElements = [PathElement]() 
     withUnsafeMutablePointer(to: &pathElements) { elementsPointer in 
      cgPath.apply(info: elementsPointer) { (userInfo, nextElementPointer) in 
       let nextElement = PathElement(element: nextElementPointer.pointee) 
       let elementsPointer = userInfo!.assumingMemoryBound(to: [PathElement].self) 
       elementsPointer.pointee.append(nextElement) 
      } 
     } 
     return pathElements 
    } 
} 

public enum PathElement { 

    case moveToPoint(CGPoint) 
    case addLineToPoint(CGPoint) 
    case addQuadCurveToPoint(CGPoint, CGPoint) 
    case addCurveToPoint(CGPoint, CGPoint, CGPoint) 
    case closeSubpath 

    init(element: CGPathElement) { 
     switch element.type { 
     case .moveToPoint: self = .moveToPoint(element.points[0]) 
     case .addLineToPoint: self = .addLineToPoint(element.points[0]) 
     case .addQuadCurveToPoint: self = .addQuadCurveToPoint(element.points[0], element.points[1]) 
     case .addCurveToPoint: self = .addCurveToPoint(element.points[0], element.points[1], element.points[2]) 
     case .closeSubpath: self = .closeSubpath 
     } 
    } 
} 

public extension SCNAction { 

    class func moveAlong(path: UIBezierPath) -> SCNAction { 

     let points = path.elements 
     var actions = [SCNAction]() 

     for point in points { 

      switch point { 
      case .moveToPoint(let a): 
       let moveAction = SCNAction.move(to: SCNVector3(a.x, a.y, 0), duration: animationDuration) 
       actions.append(moveAction) 
       break 

      case .addCurveToPoint(let a, let b, let c): 
       let moveAction1 = SCNAction.move(to: SCNVector3(a.x, a.y, 0), duration: animationDuration) 
       let moveAction2 = SCNAction.move(to: SCNVector3(b.x, b.y, 0), duration: animationDuration) 
       let moveAction3 = SCNAction.move(to: SCNVector3(c.x, c.y, 0), duration: animationDuration) 
       actions.append(moveAction1) 
       actions.append(moveAction2) 
       actions.append(moveAction3) 
       break 

      case .addLineToPoint(let a): 
       let moveAction = SCNAction.move(to: SCNVector3(a.x, a.y, 0), duration: animationDuration) 
       actions.append(moveAction) 
       break 

      case .addQuadCurveToPoint(let a, let b): 
       let moveAction1 = SCNAction.move(to: SCNVector3(a.x, a.y, 0), duration: animationDuration) 
       let moveAction2 = SCNAction.move(to: SCNVector3(b.x, b.y, 0), duration: animationDuration) 
       actions.append(moveAction1) 
       actions.append(moveAction2) 
       break 

      default: 
       let moveAction = SCNAction.move(to: SCNVector3(0, 0, 0), duration: animationDuration) 
       actions.append(moveAction) 
       break 
      } 
     } 
     return SCNAction.sequence(actions) 
    } 
} 



let scnView = SCNView(frame: CGRect(x: 0, y: 0, width: 500, height: 500)) 
scnView.autoenablesDefaultLighting = true 

let scene = SCNScene() 
scnView.scene = scene 

let light = SCNLight() 
light.type = .ambient 
let lightNode = SCNNode() 
lightNode.light = light 
scene.rootNode.addChildNode(lightNode) 

let camera = SCNCamera() 
let cameraNode = SCNNode() 
cameraNode.camera = camera 
cameraNode.position = SCNVector3(0,0,10) 
scene.rootNode.addChildNode(cameraNode) 

let box = SCNBox(width: 1, height: 1, length: 1, chamferRadius: 0) 
let boxNode = SCNNode(geometry: box) 
boxNode.geometry?.firstMaterial?.diffuse.contents = UIColor.red 

scene.rootNode.addChildNode(boxNode) 

let path1 = UIBezierPath(roundedRect: CGRect(x: 1, y: 1, width: 2, height: 2), cornerRadius: 1) 

let moveAction = SCNAction.moveAlong(path: path1) 
let repeatAction = SCNAction.repeatForever(moveAction) 
SCNTransaction.begin() 
SCNTransaction.animationDuration = Double(path1.elements.count) * animationDuration 
boxNode.runAction(repeatAction) 
SCNTransaction.commit() 

PlaygroundPage.current.liveView = scnView 
Problemi correlati