Click here to Skip to main content
15,887,485 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
hello guys.
I am new to C#. I am trying to simulate snowfall in a window and have been trying to finish it since quite a long time.
I have made a windows form of size 800*600 and set its background color to black.
I have used System.Drawing to draw and ellipse and managed to change its location across the screen using a timer.
Though i have managed to create one snowflake, i have not been able to create multiple snowflakes.
The following is the code. Any help will be grateful.
Thanks in advance.




C#
public partial class MainForm : Form
{
    System.Timers.Timer t = new System.Timers.Timer();
    Graphics f;
    int count = 0;
    int inc;
    Pen myPen = new Pen(Color.White, 2);
    int X = 100;
    int Y = 10;

    public MainForm()
    {
        InitializeComponent();
    }

    private void MainForm_Load(object sender, EventArgs e)
    {
        t.Start();
        t.Interval = 100;
        t.Elapsed += new System.Timers.ElapsedEventHandler(t_Elapsed);
    }

    private void t_Elapsed(object sender, EventArgs e)
    {
        snowMove();
        if (Y == 550)
        {
            t.Stop();
        }
    }

    private void snowMove()
    {
            Random r = new Random();
            //int tc = System.Environment.TickCount;
            f = this.CreateGraphics();
            myPen.Color = Color.White;
            f.DrawEllipse(myPen, X, Y, 2, 2);
            //while (true)
            //{
            //    if (System.Environment.TickCount - tc > 100) break;
            //}
            myPen.Color = Color.Black;
            f.DrawEllipse(myPen, X, Y, 2, 2);
            Y++;
            count++;
            if (count == 5)
            {
                if ((r.Next(10) - 5) > 0)
                {
                    inc = +1;
                }
                else
                {
                    inc = -1;
                }
                X += inc;
                count = 0;
            }
            myPen.Color = Color.White;
            f.DrawEllipse(myPen, X, Y, 2, 2);

        }
    }
}


[edit]Code block added - OriginalGriff[/edit]
Posted
Updated 13-Oct-11 1:29am
v2

Look at the following codeproject article Falling Snow on Your Desktop! The C# Version[^], its nicely done. Should be helpful.


Also, take a look at the code here... snow effect is very nice
http://jobijoy.blogspot.com/2008/11/interactive-silverlight-christmas-card.html[^]

However this is a xaml code, which is great for animations.
 
Share this answer
 
Firstly, move the pen colors out of the method, and have them as private class level variables: myPenWhite and myPenBlack. Since you will need them each time, it makes sense to have them available.
Next, and also at class level, you need to create a List or array (I'd go with a List) of snowflakes, which you can then move individually.
What I would do is create a Snowflake class, with a Paint method taking a Graphics object which draws itself onto the given context. Possibly, I would have a static Random instance within the snowflake class, possibly I would tell it to move via a different method. Depends how I felt - it could be both!
 
Share this answer
 
1. Whenever you want to draw something in Windows, do it in the OnPaint(PaintEventArgs) method.
This will prevent the effect that other windows erase your drawing until it gets repainted during the next Timer.Tick event handler.

2. The OnPaint event can get called at every possible time (you do it via Form.Invalidate() ). You have to build it in such a way that it then draws what it is intended to draw where it is intended to draw. Create a "model" of your snowflake that behaves like a real one, kind of, not depending upon drawing or not, just on physics like starting position, time and so on. Store its data in an object of type SnowFlake (which you have to create).

3. You can then easily create a List<SnowFlake>() that you can .Add(new SnowFlake()). The Form.OnPaint method would then need to iterate over all items of the snow flake list and call their individual Paint(PaintEventArgs e) methods (which you have to create). Use the PaintEventArgs that come with Form.OnPaint. Each flake can process its current position depending on its internal data an the time you called Paint(PaintEventArgs e).

4. Reduce flicker
In the forms constructor, use this.DoubleBuffered = true. Erase your background once every Form.OnPaint() and then let the snow flakes draw themselves. Don't let a flake erase itself like in your second DrawEllipse() call.
 
Share this answer
 
v2
Comments
ARBebopKid 13-Oct-11 15:10pm    
My 5.
Abhishek Durvasula 14-Oct-11 6:01am    
this is what i managed to do..
i am really very new to programming..
i really want to finish this off.plz help further


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace Test1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

int x = 100,y = 10, count = 0, s = 0;
int[] m = new int[10]{10,20,30,40,50,60,10,80,90,100};
Random r = new Random();

public void ellpse(PaintEventArgs e)
{
Pen myPen = new Pen(Color.White, 2);
Graphics g = this.CreateGraphics();
g.DrawEllipse(myPen, x, y, 2, 2);
//g.DrawEllipse(myPen, x+5, y + 10, 2, 2);
y++;
count++;
if (count == 5)
{
if ((r.Next(10) - 5) > 0)
{
s = +1;
}
else
{
s = -1;
}
x = x + s;
count = 0;
}
int tc = System.Environment.TickCount;
while (true)
{
if (System.Environment.TickCount - tc > 50) break;
}
}

protected override void OnPaint(PaintEventArgs e)
{
ellpse(e);
if (y <= 550)
{
Invalidate();
}
}
}
}
lukeer 14-Oct-11 7:07am    
You're using an overridden OnPaint method. That's a good thing to start with. How to proceed?

1. You will be using myPen over and over again without ever changing it. Move the Pen myPen line out of the ellipse method so that it becomes a member of Form1. That way you can still use it in the method but don't need to create and destroy it so many times. This will increase performance.

2. Forget about Graphics g = this.CreateGraphics();. You are given a graphics object already through PaintEventArgs e parameter. Use e.Graphics.DrawEllipse() instead.

3. Move the DrawEllipse() call further down so that all calculations have already been made when it's being executed (That's just a little nicer).

4. Don't use while(true) if(condition) break;. It's called Busy Waiting. It uses 100% power of one processor core without doing much.
Remove if(condition) Invalidate(); from OnPaint() method as well. This is a behaviour only expected from applications that the user knows will use all available cores, memory and such (Doom, Quake, Need for Speed, etc.) In such cases it's considered Ok, but not for a windowed snow simulation.
Instead, place a System.Windows.Forms.Timer _redrawTimer = new System.Windows.Forms.Timer() within Form1. After InitializeComponent(); initialize the timer to _redrawTimer.Interval = 50; _redrawTimer.Tick += new EventHandler(RedrawTimer_Tick);
Create the mentioned event handler method
private void RedrawTimer_Tick(object sender, EventArgs e)
{
this.Invalidate();
}

This will call Invalidate() every 50 millisecons (or 20 times a second).

5. Now you can change flake movement from redraw-based to time-based.
Remember the flake creation time with DateTime _flakeCreationTime = DateTime.Now; (it's a member variable of Form1). Process the flake's y-position depending upon time
DateTime paintTime = DateTime.Now;
TimeSpan flakeFallingTime = paintTime - _flakeCreationTime;
int y_now = y_start + (int)(flakeFallingTime.TotalSeconds * _flakeFallingSpeed);

Of course, you have to create _flakeFallingSpeed as a Form1 member variable.

6. Later on, collect all snow flake related stuff into a SnowFlake class, create several objects thereof, gather them in a List<SnowFlake> but that's for later.
Abhishek Durvasula 14-Oct-11 6:04am    
BTW..
i am very new to programming..
so i need to be explained explicitly..
:(

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900