前言
之前在知乎閒逛看有意思的專案的時候,發現一個前輩曾做過一個在滑鼠周圍隨機生成愛心的小程式,閒來無聊實現了一版隨機生成彩色小球的(因為沒有女朋友,只是練練手)。最近疫情在網上撩了一個小妹妹,她知道這個程式之後,讓我給她做一個“格桑花”版的。我想著應該差不多,就改了改程式碼。好感度+1(不一定有),但是妹汁送我一杯奶茶,嘻嘻。話不多說,下面介紹一下。
實現
總的思路很簡單,就是獲取滑鼠的位置,然後再滑鼠周圍隨機進行動畫。實現主要分為這幾個函式。
InitProperty(); //初始化動畫配置,放到多大,透明度多少,持續時間
InitGraph(); //初始化需要放大的樣式,只要繼承FrameworkElement類就可以了
MaxmizeAndTransparenceWindow(); //視窗設定,設定全屏,還有一個坑(放大比)
StartMarvellousMouse(); //核心程式碼,隨機生成小球
1.初始化屬性
這裡動畫主要是樣式放大的一些設定:長寬,透明度。是WPF比較基礎的類FrameworkElement的屬性。
private void InitProperty()
{
MyStoryBoard = new Storyboard();
//MyStoryBoard.RepeatBehavior = RepeatBehavior.Forever;
DAWidth = new DoubleAnimation();
DAWidth.From = 0;
DAWidth.To = 2 * Radius;
DAWidth.Duration = new Duration(TimeSpan.FromMilliseconds(DurationTime));
DAHeight = new DoubleAnimation();
DAHeight.From = 0;
DAHeight.To = 2 * Radius;
DAHeight.Duration = new Duration(TimeSpan.FromMilliseconds(DurationTime));
DAOpacity = new DoubleAnimation();
DAOpacity.From = 0;
DAOpacity.To = 0.7;
DAOpacity.Duration = new Duration(TimeSpan.FromMilliseconds(DurationTime));
MyStoryBoard.Children.Add(DAWidth);
MyStoryBoard.Children.Add(DAHeight);
MyStoryBoard.Children.Add(DAOpacity);
}
2.初始化樣式
這裡一開始是使用WPF的自定義控制元件比如ellipse,等。後來給妹汁做格桑花的時候,突然想到:圖片不就是天然的FrameworkElement嘛,所以理論上啥樣式都已放進圖片並顯示。順帶說一句,圖片資源獲取網上搜一下,然後在Google活bing的識圖裡面找類似的。
很難找到背景透明的圖(比如帶白底),可以用ps工具,或者網上的去底色工具或網址(我直接百度搜了個網址就可以用)。反正圖片放大的也不大,略微丟失一點邊邊角角無傷大雅。
private void InitGraph()
{
var elements =ElementProvider.GetElements<MyImage>();
if (elements != null)
{
foreach (var item in elements)
{
this.canvas.Children.Add(item);
}
}
NumofGrap = this.canvas.Children.Count;
}
3.螢幕最大化及一些設定
這裡的一個坑就是,不是所有的螢幕都是100%放大,在一些筆記本上可能解析度調的超級高,然偶後放大到200%,所以滑鼠位置會有問題。這裡計算了下放大比,然後滑鼠的XY乘以係數。
private void MaxmizeAndTransparenceWindow()
{
this.Width = SystemParameters.PrimaryScreenWidth;
this.Height = SystemParameters.PrimaryScreenHeight;
var hdc = GetDC(GetDesktopWindow());
int ResolutionHeight = GetDeviceCaps(hdc, 10); //高
int ResolutionWidth = GetDeviceCaps(hdc, 8); //寬
ScaleX = (double)(ResolutionWidth / Width);
ScaleY = (double)(ResolutionHeight / Height);
this.Top = 0;
this.Left = 0;
this.WindowStyle = WindowStyle.None;
this.ResizeMode = ResizeMode.NoResize;
this.Topmost = true;
}
4.核心顯示
就是不停地獲取滑鼠位置,然後隨機再滑鼠周圍生成圖案。這裡因為是死迴圈瘋狂更新,所以記憶體會爆炸。所以設定執行緒需要休息一會會再傳送(及時1ms也足夠了)。
private void StartMarvellousMouse()
{
POINT lpPoint;
var widthProperty = new PropertyPath("Width");
var heightProperty = new PropertyPath("Height");
var opacityProperty = new PropertyPath("Opacity");
new Thread(() =>
{
while (true)
{
for (int i = 0; i < NumofGrap; i++)
{
GetCursorPos(out lpPoint);
Dispatcher.BeginInvoke(new Action(() =>
{
if (i == NumofGrap) return; //防止迴圈i=NumofGrap的時候,ui執行緒正好訪問
var item = (FrameworkElement)this.canvas.Children[i];
Canvas.SetLeft(item, (lpPoint.X - Radius + RandomDistance) / ScaleX);
Canvas.SetTop(item, (lpPoint.Y - Radius + RandomDistance) / ScaleY);
//item.Fill = RandomColor;
Storyboard.SetTarget(DAWidth, item);
Storyboard.SetTargetProperty(DAWidth, widthProperty);
Storyboard.SetTarget(DAHeight, item);
Storyboard.SetTargetProperty(DAHeight, heightProperty);
Storyboard.SetTarget(DAOpacity, item);
Storyboard.SetTargetProperty(DAOpacity, opacityProperty);
MyStoryBoard.Begin();
}));
Thread.Sleep((int)DurationTime / NumofGrap);
}
}
}).Start();
}