Falling Snowflakes Windows Application C#
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. (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+.
Hide Copy Code
public MainForm() {
InitializeComponent();
//We paint our control ourself
//and need a double buffer to prevent flimmering
SetStyle(
ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint |
ControlStyles.DoubleBuffer, true);
//Resize and relocate form to match Screen settings
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<code>
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
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.
Hide Copy Code
foreach (SnowFlake s in SnowFlakes) {
g.ResetTransform();
g.TranslateTransform(-16, -16, MatrixOrder.Append); //Align our flakes to the center
g.ScaleTransform(s.Scale, s.Scale, MatrixOrder.Append); //Scale them..
g.RotateTransform(s.Rotation, MatrixOrder.Append); //Rotate them..
//Move them to their appropriate location
g.TranslateTransform(s.X, s.Y, MatrixOrder.Append);
g.DrawImage(Snow, 0, 0); //draw them
}
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).
0 Commentaires