Deep Background(s)

Lightening Up.

In the real world, as the sun rises and sets, the sky does not uniformly change color and brightness along with it. Instead, it tracks a wide range of colors and shades, from the full(ish) blue of day to the deep black of night.

It would be quite tedious, if not exceedingly difficult, to create multiple static gradient backgrounds, one for every stage of a sky's day, and then swap these throughout. And while this swapping operation wouldn't be tough to conceal, it would both require an inordinate number of images, and most likely, or more importantly, not appear terribly natural.

However, a CGGradient constituted from a host of colors, themselves derived from predetermined RGB values, could be created on the fly, on the minute even, and updated across a day-long continuum.


There's a convenience init for UIColor which gives one access to the RGB values as CGFloat's.

init(red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat)

Using the current time, and with as much granularity as one would like, the individual RGB values could be adjusted, new UIColor's created, then those used to redraw a gradient, and the resulting texture applied to an SKSpriteNode.

The Gradient.

The sky gradient will need a top and bottom color and a transition point between the two, which for starters will be half the height of the scene.

The transition point can change position over time as well, so within the gradient the color mixing would move up and down.

There will need to be a master list of all the forty-eight (twenty-four per section of the gradient) colors and their corresponding red, green, and blue values. The SkyBackground class will eventually need to reference this list to establish its colors at any particular moment.

TOP: UIColor(r:0,g:110,b:0)  
BOTTOM: UIColor(r:0,g:110,b:0)
TOP: UIColor(r:75,g:75,b:100)  
BOTTOM: UIColor(r:200,g:130,b:160)
TOP: UIColor(r:120,g:120,b:190)
BOTTOM: UIColor(r:230,g:175,b:210)
TOP: UIColor(r:30,g:30,b:0) 
BOTTOM: UIColor(r:0,g:110,b:0)
TOP: UIColor(r:60,g:60,b:92)
BOTTOM: UIColor(r:0,g:110,b:0)
and so on...

Ultimately, the master list of hours/colors will be a dictionary of tuples.

typealias RGBValue = (r: CGFloat, g: CGFloat, b: CGFloat)
var topColors: [Int:RGBValue]!

Moving Between.

So, if we have a color, composed of RGB values, assigned to the hour it is, and another color assigned to the hour that it will be, then we've got a start and a finish. Now, each RGB value for either UIColor in the gradient, has some knowable distance to travel during the hour: between its current and next point.

These swatches of topColor and bottomColor, variables which will be used in the gradient creation portion of the function drawSkyTexture, demonstrate the difference between the RGB values at 6:00am and 7:00am.

And this composite shows the two resultant gradients of 6:00am 7:00am.

Arbitrary Example.

To walk through my understanding of the calculations needed, I'll start with some random colors.

thisHoursColor = UIColor(r:20,g:20,b:45)
nextHoursColor = UIColor(r:50,g:60,b:90)

Over the course of the hour, all three values need to increase or decrease so as to arrive at the nextHoursColor.

r: 20 -> 50
g: 20 -> 60
b: 45 -> 90

Starting with red, we'd subtract the currentValue from the targetValue, in this case that would be 50 - 20 = 30. Then divide the difference by the number of minutes in an hour, 30 / 60 = 0.5, which results in the multiplier for any particular currentMinute.

If we take any minute of the hour (I'll use the 24th here), and multiply it by 0.5, then we'll have the correct amount by which to increment the current hour's red value.
24 * 0.5 = 12
20 + 12 = 32
32 / 255 = newRedValue

This will work backwards as well. If the redValue of nextHoursColor happened to be 10 as opposed to 50?

r: 20 -> 10
10 - 20 = -10
-10 / 60 = -.16666667
00:24 -> 24 * -.16666667 = -4
20 + -4 = 16
16 / 255 = newRedValue

Now we'd run it all again with the remaining RGB values for topColor and bottomColor.

Onto the heavy lifting...