2015-05-05 11 views
6

Mam węzeł skrzynkiSceneKit ożywione węzeł wzdłuż ścieżki

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

Mam ścieżkę

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

chcę mieć moje pudełko podróż wzdłuż mojej ścieżce raz.

Jak to zrobić w SceneKit?

Chciałbym zrobić metodę, która będzie wyglądać

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

Co cię powstrzymuje przed uruchomieniem wyszukiwania? Już wcześniej widziałem podobny temat. –

+0

Zrobiłem to już wcześniej z CAKeyAnimation. SceneKit nie ma wbudowanego interfejsu API do poruszania się po ścieżce. Moje działające twory są w najlepszym wypadku nieporęczne i zbyt skomplikowane. Zastanawiam się, czy ktoś ma proste rozwiązanie. –

+0

nie dodaje, że animacja CoreAnimation do węzła działa? – mnuages

Odpowiedz

5

natknąłem tej kwestii, jak również i napisałem mały plac zabaw. Animacja działa dobrze. Jedna rzecz musi zostać zrobiona. Odległość między każdym punktem musi być obliczona, aby czas mógł być skalowany w celu uzyskania płynnej animacji. Wystarczy skopiować & wkleić kod na plac zabaw. Kod jest w Swift 3.

Oto moje rozwiązanie (rozszerzenie BezierPath nie jest ode mnie, znaleziono go tutaj):

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