While taking some time off to enjoy the holidays, I decided to try something new.
While I’ve been working with simple UI animations in Real Studio for some time, I’ve never done anything like this. I’ve seen an awesome fire animation done by my buddy Shawn Rapp, but I never had much of an interest in it personally. Well, tonight, while standing on my back porch in the slowly falling snow, I decided to give it a shot.
What It Is
Essentially, it’s a snowfall generator. You supply it with a background image (or just a color) and it draws falling snow with calculated per-flake drifting. It wasn’t overly difficult, but it was amazingly fun.
How Did You Do It?
Well, to start with, I made a Thread subclass which I named “thdSnowFall”. In in, I placed the following Event Definition:
Update( p as Picture )
And the following Properties:
1 2 3 4 5 6
BGColor as Color = &c000000 BGImage as Picture Drift as Boolean = True Flakes as Integer = 1000 Height as Integer Width as Integer
All of these properties are computed (just so we can make them show up in the window editor propertylist).
From there, I added two methods:
1 2 3 4 5 6 7 8 9
Private Sub InitArray(intPosX() as Integer, intPosY() as Integer, intSpeed() as Integer, intSize() as Integer, ItemCount as Integer) dim intCycle as Integer for intCycle = 0 to ItemCount intPosX.Append( t.InRange( 0, self.Width ) ) intPosY.Append( t.InRange( 0, self.Height ) ) intSpeed.Append( t.InRange( 5, 25 ) ) intSize.Append( (t.InRange( 1, 3 ) * 100 + t.InRange( 50, 100 )) / 100 ) next End Sub
1 2 3 4 5 6
Private Sub DoSnow(intPosX() as Integer, intPosY() as Integer, intSpeed() as Integer, intSize() as Integer, intItem as Integer) intPosX(intItem) = t.InRange( 0, self.Width ) intPosY(intItem) = 0 intSpeed(intItem) = t.InRange( 5, 25 ) intSize(intItem) = (t.InRange( 1, 3 ) * 100 + t.InRange( 50, 100 )) / 100 End Sub
Now, to the meat and potatoes, so to speak. In the Run Event Handler, we place the following bit of code which does all the heavy lifting:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
Dim intPosX(), intPosY(), intSpeed(), intSize(), intWind As Integer Dim rec As Rectangle Dim intItem As Integer dim g as Graphics t = new Random InitArray( intPosX, intPosY, intSpeed, intSize, Flakes - 1 ) while true if IsNull( picSnowfall ) then picSnowfall = new Picture( Width, Height ) if picSnowfall.Width <> Width or picSnowfall.Height <> Height then picSnowfall = new Picture( Width, Height ) g = picSnowfall.Graphics g.ClearRect( 0, 0, g.Width, g.Height ) g.ForeColor = BGColor g.FillRect( 0, 0, g.Width, g.Height ) if not IsNull( BGImage ) then g.DrawPicture( BGImage, 0, 0, g.Width, g.Height, 0, 0, BGImage.Width, BGImage.Height ) for intItem = 0 to Flakes - 1 if Drift then dim strWind as String = "0." + CStr( t.InRange( 0, 2 ) ) + CStr( t.InRange( 0, 5 ) ) if t.InRange( 0, 1 ) = 0 then strWind = "-" + strWind intWind = (intSpeed(intItem) + intSize(intItem)) * CDbl( strWind ) intPosX(intItem) = intPosX(intItem) + intWind end if intPosY(intItem) = intPosY(intItem) + intSpeed(intItem) if intPosY(intItem) > Height then DoSnow( intPosX, intPosY, intSpeed, intSize, intItem ) end if g.ForeColor = rgb( 255, 255, 255, 150 ) g.FillOval( intPosX(intItem), intPosY(intItem), intSize(intItem), intSize(intItem) ) next Update( picSnowfall ) me.Sleep( 50 ) wend
From there, it’s just tossing an instance of thdSnowFall on to the window, adding an image to our project, and hooking everything up. First of all, we need to add a picture buffer property to our window:
picSnowfall As Picture
Next, we need to add some code to our Update event in our thdSnowFall instance:
picSnowfall = p self.Refresh()
Followed by our code in the Open event of our window (where thdS1 is our thdSnowFall instance, and scene1 is our background image):
1 2 3 4 5
thdS1.BGColor = rgb( 0, 0, 0 ) thdS1.BGImage = scene1 thds1.Width = me.Width thds1.Height = me.Height thdS1.Run
And, finally, the code in our paint event to draw the buffer out to the screen:
if not IsNull( picSnowfall ) then g.DrawPicture( picSnowfall, 0, 0, g.Width, g.Height )
If your window is resizable, you need to add the following to window’s Resized event handler:
1 2 3 4
thdS1.Width = me.Width thds1.Height = me.Height thdS1.Kill thdS1.Run
Hit the run button, and enjoy your snowfall scene. Be sure you build for Cocoa on OS X and check App.UseGDIPlus for Windows, but other than that, you should be good. Here’s the result comparison: