Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Make an object orbit another in SceneKit

Say I have 2 nodes in my SceneKit scene. I want one to rotate around or orbit (like a planet orbiting a star), the other node once in a certain time interval. I know I can set up animations like so:

let anim = CABasicAnimation(keyPath: "rotation")
anim.fromValue = NSValue(scnVector4: SCNVector4(x: 0, y: 1, z: 0, w: 0))
anim.toValue = NSValue(scnVector4: SCNVector4(x: 0, y: 1, z: 0, w: Float(2 * Double.pi)))
anim.duration = 60     
anim.repeatCount = .infinity
parentNode.addAnimation(aim, forKey: "spin around")

Is there an animation for "orbiting", and a way to specify the target node?

like image 473
Timestretch Avatar asked Mar 28 '17 15:03

Timestretch


1 Answers

The way to do this is by using an additional (helper) SCNNode. You'll use the fact that it adds its own coordinate system and that all of its Child Nodes will move together with that (helper) coordinate system. The child nodes that are off-centre will effectively be orbiting if you view them from the world coordinate system.

  1. You add the HelperNode at the centre of your FixedPlanetNode (orbited planet), perhaps as its child, but definitely at the same position

  2. You add your OrbitingPlanetNode as a child to the HelperNode, but with an offset on one of the axes, e.g. 10 points on the X axis

  3. You start the HelperNode rotating (together with its coordinate system) around a different axis, e.g. the Y axis

  4. This will result in the OrbitingPlanetNode orbiting around the Y axis of HelperNode with an orbit radius of 10 points.

EXAMPLE

earthNode - fixed orbited planet

moonNode - orbiting planet

helperNode - helper node added to provide coordinate system

// assuming all planet geometry is at the centre of corresponding nodes
// also helperNode.position is set to (0, 0, 0)
[earthNode addChildNode:helperNode];
moonNode.position = SCNVector3Make(10, 0, 0);
[helperNode addChildNode:moonNode];

// set helperNode to rotate forever
SCNAction * rotation = [SCNAction rotateByX:0 y:3 z:0];
SCNAction * infiniteRotation = [SCNAction repeatActionForever:rotation];
[helperNode runAction:infiniteRotation];

I used actions and objective-c as this is what I am familiar with, but should be perfectly doable in Swift and with animations.

like image 145
Sulevus Avatar answered Nov 14 '22 08:11

Sulevus