Celestial Sprites and Swift

Moving the Sun and Moon

The Sun sprite needs to move across the sky, in an arc, at some pace approaching that of its real-life counterpart. At each minute of the day, within the portion of the day in which the Sun would be visible, the sprite should update its location along that arc, eventually depositing itself below the horizon and removing itself from the node tree.

I chose 7AM - 7PM as the "daytime" portion, just to keep it simple. There's 720 minutes in that twelve hour period. 12 x 60 = 720.

There's 180 degrees in the half-circle that I'd like the sun to traverse during the day. And of course, 180 x 4 = 720.

So, at any minute during the 720 minutes that make up the 12 hour period, there should be a degree which correlates, and which can be found by dividing the current minute by 4.

2:21pm = 14hrs 21min
14 - 7 = 7, 7 x 60 = 420 + 21 = 441

To find out what minute we're at in the cycle, we grab the current time, determine whether it's AM or PM, and then multiply by 60 and add the minutes. [1]

  func degreesForSun() -> CGFloat {
    let now = NSDate()
    let degrees = (now.hour - 7) * 60
    return CGFloat((degrees + now.minute) / 4)
  }
Edit:

I needed to check for am/pm, and since I'm just protyping this thing, here's a variable whose getter will check for the time range:

  var shouldAppear: Bool {
    get {
     return now.hour >= 7 && now.hour <= 19 ? true : false
    }
  }

When we've figured out what the degree of the current minute in the cycle should be, we then need to place the sun sprite at that angle and at the correct height and orientation.

let sunSprite = SKSpriteNode(imageNamed: "sunSprite")
var angleForSun: CGFloat = 0.0
var anchorForSun: CGPoint!
var radiusForSun: CGFloat = 360

The radiusForSun determines how far away from the anchorForSun that the sun sprite will appear at the determined angle. I placed the anchor at the scene's bottom middle.

anchorForSun = CGPoint(x: self.viewableArea.width / 2, y: 0.0)

And after I've received the correct angle to use from the updating function. I can use sin/cos to get the right placement.

 let piNumber = CGFloat(M_PI)
 let degreesToRadians = piNumber / 180
 let radiansToDegrees = 180 / piNumber
  func updateSunAngle(dt: CFTimeInterval) {
    let sunAngle = degreesForSun()
    let x = cos(sunAngle * degreesToRadians) * radiusForSun
    let y = sin(sunAngle * degreesToRadians) * radiusForSun
    background.position = CGPoint(x: anchorForSun.x + x, y: anchorForSun.y + y)
  }

And then in the update method of the scene, call for this guy to update himself.

  override func update(currentTime: CFTimeInterval) {
    updateSunAngle(currentTime)
  }


  1. Make sure to add NSDate extension to grab hour/min components. ↩︎