Introduction
First of all, I have to say that this isn't my idea, it is more a portation of a C++ example to C# using a different way. If you want to get to the original article, click here. (Thanks to Igor Tolmachev for the nice idea.) I changed the way it works (from multiple dialogs to a single form) and added some new features (e.g. Rotation, Scaling, etc.).
Using the Program
Simply run the executable. To close the program, double click on the tray icon representing a snow flake.
Using the Code
The program itself uses a non-bordered form (which is resized to match screen resolution) with a transparent background color for drawing the snow flakes. Instead of using several forms/dialogs (I hate this idea), I just use one form on which I draw using GDI+.
public MainForm() {
InitializeComponent();
SetStyle(
ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint |
ControlStyles.DoubleBuffer, true);
Location = new Point(Screen.PrimaryScreen.Bounds.X,
Screen.PrimaryScreen.Bounds.Y);
Width = Screen.PrimaryScreen.Bounds.Width;
Height = Screen.PrimaryScreen.Bounds.Height;
}
The snowflakes themselves are saved in a List<SnowFlake>
. Snowflake
is a container class containing the current Data/Positions of the snowflake (X
, Y
, Rot
, Scale
) and the Velocities/Changes (XVel
, YV
el
, RotVel
)
The main function is the OnTick
method, which is divided into several steps:
- Increasing the tick count (e.g. Adding snow flakes every tick would be a bit too much)
- Spawning new flakes (If appropriate conditions are given)
- Moving all flakes (by adding the velocities to the data values)
- Deleting flakes which are below the screen/taskbar
- Rendering the flakes
The flakes are drawn by defining a userpaint
method MainForm_Paint
and calling Refresh()
to cause the form to invalidate itself. Refresh()
is required, as it supports double buffers, which MainForm_Paint(CreateGraphics())
would not. In this case, I used the Matrix capabilities of GDI+ to rotate and scale the snowflakes.
foreach (SnowFlake s in SnowFlakes) {
g.ResetTransform();
g.TranslateTransform(-16, -16, MatrixOrder.Append);
g.ScaleTransform(s.Scale, s.Scale, MatrixOrder.Append);
g.RotateTransform(s.Rotation, MatrixOrder.Append);
g.TranslateTransform(s.X, s.Y, MatrixOrder.Append);
g.DrawImage(Snow, 0, 0);
}
The snowflake image is drawn by using the GDI+ functions and then cached at a 32x32 pixel size for performance reasons. (GDI+ is slow when you draw lots of lines.)
Customize!
You could get some pretty nice results by just increasing the snow flake spawn count/the velocities. But note that GDI+ is not as fast at it may look and it increases CPU usage (especially when using matrices).
History
- 3rd October, 2007: Initial post