Math in the Daytime

Note: The public struct GameTime has a .currentMinute and .currentHour which can be used by any other class.

public struct GameTime {
  static var currentHour: Int { return NSDate().hour }
  static var currentMinute: Int { return NSDate().minute }

The Class.

SkyBackground will handle the visual display of the sky as an SKSpriteNode with an SKTexture. The texture will have been created with the calculations from earlier. All of the time-based evaluation and gradient drawing functionality will be in this class.

The calculations worked out before can be wrapped up in a function and applied to the individual members of a tuple, like so:

func newColorValue(prev: CGFloat, next: CGFloat) -> CGFloat {
    let currentMinute = CGFloat(GameTime.currentMinute)
    return (prev + (currentMinute * ((next - prev) / 60))) / 255
  }

In the class declaration of SkyBackground, typealias allows one to make things a bit easier when dealing with these tuples.

typealias RGBValue = (r: CGFloat, g: CGFloat, b: CGFloat)
typealias RGBList = Dictionary<Int,RGBValue>  
var topColors: RGBList!
var bottomColors: RGBList!

This means that to get the colors we need, we'll pass in whichever section of the gradient we're setting the new color for.

  func updateColor(section: RGBList) -> UIColor {
    var color = UIColor.redColor()
    let hour = GameTime.currentHour
    let thisHoursColor = section[hour]
    var nextHoursColor = section[0]
    if hour <= 22 {
      nextHoursColor = section[hour + 1]
    }
    if let thisHour = thisHoursColor, nextHour = nextHoursColor {
      let redValue = newColorValue(thisHour.r, next: nextHour.r)
      let greenValue = newColorValue(thisHour.g, next: nextHour.g)
      let blueValue = newColorValue(thisHour.b, next: nextHour.b)
      color = UIColor(red: redValue, green: greenValue, blue: blueValue, alpha: 1)
    }
    return color
  }

This function will then be called to set the topColor and bottomColor.

topColor = updateColor(topColors)
bottomColor = updateColor(bottomColors)

Drawing the Gradient.

The gradient drawing function drawSkyTexture() returns an SKTexture, it begins by updating the color for each section of the gradient. After that, it will use those updated colors to create a gradient with CGGradientCreateWithColors. Finally, it will output an image which will be used to init a SKTexture.

func drawSkyTexture() -> SKTexture {
    topColor = updateColor(topColors)
    bottomColor = updateColor(bottomColors)
    UIGraphicsBeginImageContextWithOptions(bounds.size, false, 0)
    let context = UIGraphicsGetCurrentContext()
    gradientColors = [topColor.CGColor, bottomColor.CGColor]
    let gradient = CGGradientCreateWithColors(CGColorSpaceCreateDeviceRGB(), gradientColors, gradientPoints)
    CGContextDrawLinearGradient(context, gradient, startPoint, endPoint, 0)
    skyGradImage = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    skyTexture = SKTexture(image: skyGradImage)
    return skyTexture
  }

Updating.

Finally, SkyBackground will update itself, if it hasn't already done so in the last five seconds, with an SKAction to set the new texture.

  func update() {
    let now = NSDate()
    if lastUpdateTime == nil {
      lastUpdateTime = now
    }
    let timeSinceUpdate = now.timeIntervalSinceDate(lastUpdateTime)
    if timeSinceUpdate >= 5.0 {
      sprite.runAction(SKAction.setTexture(drawSkyTexture()))
      lastUpdateTime = now
    }
  }