Option Explicit On
Option Strict On
Option Infer Off
Imports System.ComponentModel
Imports System.Drawing.Drawing2D
Public Class SnowBaseForm
Private Shared ReadOnly Random As New Random()
Private Shared ReadOnly m_SnowFlakes As New List(Of SnowFlake)
Private WithEvents Timer1 As System.Windows.Forms.Timer
Private m_Tick As Integer = 0I
Private m_Snow As Bitmap
#Region " Constructor "
Public Sub New()
' This call is required by the Windows Form Designer.
Call InitializeComponent()
' Add any initialization after the InitializeComponent() call.
'We paint our control ourself and need a double buffer to prevent flimmering
Me.SetStyle(ControlStyles.UserPaint Or ControlStyles.AllPaintingInWmPaint Or ControlStyles.DoubleBuffer, True)
Timer1 = New System.Windows.Forms.Timer
Timer1.Interval = 20I
End Sub
#End Region
#Region " BaseForm: Paint, Dispose "
'Form overrides dispose to clean up the component list.
<System.Diagnostics.DebuggerNonUserCode()> _
Protected Overrides Sub Dispose(ByVal disposing As Boolean)
Try
If disposing AndAlso components IsNot Nothing Then
components.Dispose()
End If
If disposing Then
Timer1.Enabled = False
Timer1.Dispose()
End If
Finally
MyBase.Dispose(disposing)
End Try
End Sub
<System.Diagnostics.DebuggerNonUserCode()> _
Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
MyBase.OnPaint(e)
Dim g As Graphics = e.Graphics
g.SmoothingMode = SmoothingMode.HighSpeed
'other things may be to slow
For Each s As SnowFlake In m_SnowFlakes
g.ResetTransform()
g.TranslateTransform(-16I, -16I, 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..
g.TranslateTransform(s.X, s.Y, MatrixOrder.Append)
'Move them to their appropriate location
'draw them
g.DrawImage(Snow, 0I, 0I)
Next s
End Sub
#End Region
#Region " Properties "
Private ReadOnly Property Snow() As Bitmap
Get
If m_Snow Is Nothing Then
'First Time - Create Image
m_Snow = New Bitmap(32I, 32I)
Using g As Graphics = Graphics.FromImage(m_Snow)
g.SmoothingMode = SmoothingMode.AntiAlias
g.Clear(Color.Transparent)
g.TranslateTransform(16.0F, 16.0F, MatrixOrder.Append)
Dim black As Color = Color.FromArgb(1I, 1I, 1I)
Dim white As Color = Color.FromArgb(255I, 255I, 255I)
DrawSnow(g, New SolidBrush(black), New Pen(black, 3.0F))
DrawSnow(g, New SolidBrush(white), New Pen(white, 2.0F))
g.Save()
End Using
End If
Return m_Snow
End Get
End Property
<Category("Snow"), DefaultValue("True")> _
Public Property Snowing() As Boolean
Get
Return Timer1.Enabled
End Get
Set(ByVal value As Boolean)
If value <> Timer1.Enabled Then Timer1.Enabled = value
End Set
End Property
<Category("Snow"), DefaultValue(20)> _
Public Property SnowSpeed() As Integer
Get
Return IntervalToSnowSpeed(Timer1.Interval)
End Get
Set(ByVal value As Integer)
Select Case value
Case Is > 41I : value = 41I
Case Is < 1I : value = 1I
End Select
Timer1.Interval = SnowSpeedToInterval(value)
End Set
End Property
#End Region
#Region " Methods "
Public Sub StartSnow()
Timer1.Start()
End Sub
Public Sub StopSnow()
Timer1.Stop()
End Sub
Public Sub ClearSnow()
m_SnowFlakes.Clear()
m_Tick = 0I
Me.Refresh()
End Sub
#End Region
#Region " Conversion Functions "
Private Function SnowSpeedToInterval(ByVal Speed As Integer) As Integer
Dim output As Integer = 10I
Select Case Speed
Case 0I : output = 50I
Case 1I : output = 49I
Case 2I : output = 48I
Case 3I : output = 47I
Case 4I : output = 46I
Case 5I : output = 45I
Case 6I : output = 44I
Case 7I : output = 43I
Case 8I : output = 42I
Case 9I : output = 41I
Case 10I : output = 40I
Case 11I : output = 39I
Case 12I : output = 38I
Case 13I : output = 37I
Case 14I : output = 36I
Case 15I : output = 35I
Case 16I : output = 34I
Case 17I : output = 33I
Case 18I : output = 32I
Case 19I : output = 31I
Case 20I : output = 30I
Case 21I : output = 29I
Case 22I : output = 28I
Case 23I : output = 27I
Case 24I : output = 26I
Case 25I : output = 25I
Case 26I : output = 24I
Case 27I : output = 23I
Case 28I : output = 22I
Case 29I : output = 21I
Case 30I : output = 20I
Case 31I : output = 19I
Case 32I : output = 18I
Case 33I : output = 17I
Case 34I : output = 16I
Case 35I : output = 15I
Case 36I : output = 14I
Case 37I : output = 13I
Case 38I : output = 12I
Case 39I : output = 11I
Case 40I : output = 10I
End Select
Return output
End Function
Private Function IntervalToSnowSpeed(ByVal Interval As Integer) As Integer
Dim output As Integer = 1I
Select Case Interval
Case 50I : output = 0I
Case 49I : output = 1I
Case 48I : output = 2I
Case 47I : output = 3I
Case 46I : output = 4I
Case 45I : output = 5I
Case 44I : output = 6I
Case 43I : output = 7I
Case 42I : output = 8I
Case 41I : output = 9I
Case 40I : output = 10I
Case 39I : output = 11I
Case 38I : output = 12I
Case 37I : output = 13I
Case 36I : output = 14I
Case 35I : output = 15I
Case 34I : output = 16I
Case 33I : output = 17I
Case 32I : output = 18I
Case 31I : output = 19I
Case 30I : output = 20I
Case 29I : output = 21I
Case 28I : output = 22I
Case 27I : output = 23I
Case 26I : output = 24I
Case 25I : output = 25I
Case 24I : output = 26I
Case 23I : output = 27I
Case 22I : output = 28I
Case 21I : output = 29I
Case 20I : output = 30I
Case 19I : output = 31I
Case 18I : output = 32I
Case 17I : output = 33I
Case 16I : output = 34I
Case 15I : output = 35I
Case 14I : output = 36I
Case 13I : output = 37I
Case 12I : output = 38I
Case 11I : output = 39I
Case 10I : output = 40I
End Select
Return output
End Function
#End Region
#Region " Timer1_Tick "
Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
'Tick..
If m_Tick = Integer.MaxValue Then m_Tick = 0I
m_Tick += 1I
'Spawn new Flakes
If m_Tick Mod 3I = 0I AndAlso Random.NextDouble() < 0.7R Then
Dim s As New SnowFlake()
s.X = Random.Next(-50I, Width + 50I)
'All over the screen...
s.Y = Random.Next(-20I, -7I)
'Customize height further
s.XVelocity = CSng((Random.NextDouble() - 0.5F)) * 2.0F
s.YVelocity = CSng((Random.NextDouble() * 3.0F)) + 1.0F
s.Rotation = Random.Next(0I, 359I)
s.RotVelocity = Random.Next(-3I, 3I) * 2.0F
If s.RotVelocity.Equals(0.0F) Then s.RotVelocity = 3.0F
s.Scale = CSng((Random.NextDouble() / 2I)) + 0.75F
m_SnowFlakes.Add(s)
End If
'Move current flakes (and add them to del list, if they exceed the screen)
Dim del As New List(Of SnowFlake)
For Each s As SnowFlake In m_SnowFlakes
s.X += s.XVelocity
s.Y += s.YVelocity
s.Rotation += s.RotVelocity
'Make them move snowflake like
s.XVelocity += (CSng(Random.NextDouble()) - 0.5F) * 0.7F
s.XVelocity = Math.Max(s.XVelocity, -2.0F)
s.XVelocity = Math.Min(s.XVelocity, 2.0F)
If s.YVelocity > Me.Height + 10I Then
'Out of Screen
del.Add(s)
End If
Next s
'Delete them
For Each s As SnowFlake In del
m_SnowFlakes.Remove(s)
Next s
'Redraw our control
Me.Refresh()
End Sub
#End Region
#Region " Helpers "
''' <summary>
''' Draws a snow flake on the specified graphics object
''' </summary>
''' <param name="g">Graphics object to draw on</param>
''' <param name="b">Brush (Color) of the middle part</param>
''' <param name="p">Pen (Color, Size) of the lines</param>
Private Shared Sub DrawSnow(ByVal g As Graphics, ByVal b As Brush, ByVal p As Pen)
Const a As Integer = 6I
Const a2 As Integer = a + 2I
Const r As Integer = 2I
g.DrawLine(p, -a, -a, +a, +a)
g.DrawLine(p, -a, +a, +a, -a)
g.DrawLine(p, -a2, 0I, +a2, 0I)
g.DrawLine(p, 0I, -a2, 0I, +a2)
g.FillEllipse(b, -r, -r, r * 2I, r * 2I)
End Sub
#End Region
#Region " Classes "
''' <summary>
''' This Container class represents the snowflake falling and rendered to the screen
''' </summary>
Private Class SnowFlake
Public Rotation As Single
Public RotVelocity As Single
Public Scale As Single
Public X As Single
Public XVelocity As Single
Public Y As Single
Public YVelocity As Single
End Class
#End Region
End Class