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
}
}