Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Move element like falling snow flake

Tags:

vb.net

wpf

I found a fun program that allows you to overlay snowflakes over your desktop and windows. As a programming challenge I am interested in trying to figure out how to do this myself. Not to mention that this program is a bit of a memory hog (if it doesn't have a memory leak). Below is the start I have. I am trying to get the basics down with one image and then will expand.

What I would really like help on is making the image move more smoothly and naturally.


Edit:

I posted a solution down below in the answers section but it is more CPU intensive than I would like, any thoughts?


WPF XAML code:

<Window x:Class="MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    AllowsTransparency="True"
        WindowStyle="None"
    Title="MainWindow" Height="350" Width="525" Background="Transparent" Topmost="True" WindowState="Maximized" ResizeMode="NoResize">
    <Grid Name="grid1">
        <Image Height="26" HorizontalAlignment="Left" Margin="{Binding flakeMargin}" Name="Image1" Stretch="Fill" VerticalAlignment="Top" Width="28" Source="/snowTest;component/Images/blue-pin-md.png" />
    </Grid>
</Window>

VB Code:

Imports System.ComponentModel

    Class MainWindow
        Dim bw As BackgroundWorker = New BackgroundWorker
        Dim flake0 As New flake

        Private Sub Window_Loaded(sender As System.Object, e As System.Windows.RoutedEventArgs) Handles MyBase.Loaded
            grid1.DataContext = flake0
            AddHandler bw.DoWork, AddressOf backgroundMover
            bw.RunWorkerAsync()
        End Sub

        Private Sub backgroundMover(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs)
            While (True)
                flake0.move()
                System.Threading.Thread.Sleep(100)
            End While
        End Sub
    End Class

Flake Class:

Imports System.ComponentModel

Public Class flake
    Implements INotifyPropertyChanged

    Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged

    Private Sub NotifyPropertyChanged(ByVal info As String)
        RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(info))
    End Sub

    Private Property startLeft As Integer = 300
    Private Property left As Integer = left
    Private Property top As Integer = 100
    Private Property speed As Integer = 1

    Public ReadOnly Property flakeMargin As Thickness
        Get
            Return New Thickness(left, top, 0, 0)
        End Get
    End Property

    Public Sub move()
        top += speed
        left = (Math.Cos(top - 100)) * 6 + startLeft
        NotifyPropertyChanged("flakeMargin")
    End Sub
End Class
like image 926
volderArt Avatar asked Dec 03 '12 23:12

volderArt


People also ask

How do you make falling snow in PowerPoint?

To find these snowflakes, use PowerPoint's Online Pictures option on the Insert tab in the Images group. In the search control, enter snowflake and press Enter. Make sure to check the Creative Commons only option and start inserting snowflake images.

How do you add falling snow to Google Slides?

Go to Giphy.com and search for “snow transparent”, choose the GIF you like the most and select it. Go to copy link and get it, once you have it copied to your clipboard, go to your Google Slide and select Insert > Image > By URL and paste the link.


2 Answers

Here is my currently proposed solution: What ended up being the biggest correcting factors were that I used the canvas, which allowed me to move in non-integer increments and I also used the cos function more effectively. It is more CPU intensive than I would like (25-30%). Does any one have any ideas on reducing the impact on the CPU?

WPF/XAML:

<Window x:Class="MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    AllowsTransparency="True"
        WindowStyle="None"
    Title="MainWindow" Height="350" Width="525" Background="Transparent" Topmost="True" WindowState="Maximized" ResizeMode="NoResize">
    <Canvas Name="canvas1">

    </Canvas>
</Window>

VB.NET Main Window:

Imports System.ComponentModel

Class MainWindow

    Dim bw As New BackgroundWorker
    Dim flakes(17) As flake

    Private Sub Window_Loaded(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles MyBase.Loaded
        For i = 0 To flakes.Count - 1
            flakes(i) = New flake
            flakes(i).image.DataContext = flakes(i)
            flakes(i).image.SetBinding(Canvas.LeftProperty, "left")
            flakes(i).image.SetBinding(Canvas.TopProperty, "top")
            canvas1.Children.Add(flakes(i).image)
        Next

        AddHandler bw.DoWork, AddressOf backgroundMover
        bw.RunWorkerAsync()
    End Sub


    Private Sub backgroundMover()
        While (True)
            For Each f In flakes
                f.move()
            Next
            System.Threading.Thread.Sleep(50)
        End While
    End Sub
End Class

VB.Net flake class:

Imports System.ComponentModel

Public Class flake
    Implements INotifyPropertyChanged

    Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged

    Private Sub NotifyPropertyChanged(ByVal info As String)
        RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(info))
    End Sub

    Private Property startLeft As Double
    Private Property _left As Double
    Private Property _top As Double
    Private Property speed As Double
    Private Property amplitude As Double
    Private Property period As Double
    Public Property image As New Image
    Private Shared Property r As New Random

    Public Sub New()
        _image.Width = 28
        _image.Height = 26
        _image.Source = New System.Windows.Media.Imaging.BitmapImage(New Uri("/snowTest;component/Images/blue-pin-md.png", UriKind.Relative))
        startFresh()
    End Sub

    Public ReadOnly Property left As Double
        Get
            Return _left
        End Get
    End Property

    Public ReadOnly Property top As Double
        Get
            Return _top
        End Get
    End Property

    Public Sub startFresh()
        _top = -30
        amplitude = r.Next(5, 35)
        period = 1 / r.Next(20, 60)
        speed = r.Next(15, 25) / 10
        startLeft = r.Next(0, System.Windows.SystemParameters.PrimaryScreenWidth)
    End Sub

    Public Sub move()
        If _top > System.Windows.SystemParameters.PrimaryScreenHeight Then
            startFresh()
        Else
            _top += speed
            _left = amplitude * Math.Cos(period * _top) + startLeft
        End If

        NotifyPropertyChanged("top")
        NotifyPropertyChanged("left")
    End Sub
End Class
like image 165
volderArt Avatar answered Sep 25 '22 11:09

volderArt


Why are you moving it yourself as opposed to using an animation?

If you use WPF's Animation (which is really easy to do in Expression Blend), I think you will get the smoothness you are looking for and you can get some variation in movement, making it more real.

WPF Expression Blend Videos

Basic Animation

like image 31
Rhyous Avatar answered Sep 26 '22 11:09

Rhyous