WPF 星空动画效果 星星连线
测试WPF的性能,做了这样一个动画效果。实际测试感觉性能还可以,动画效果也还不错,分享一下
效果图在此:
- 先生成随机位置的圆形;
- 将圆形依次连接成线,将线的起始点和结束点绑定在圆的位置点;
- 生成随机的运动偏移点;
- 根据生成的随机偏移点进行计算,算出每个点运动到超出边界的目标位置;
- 开始圆形的动画,动画设置为自动回放模式;
- 设置一个定时器计算线的长度,超出一定长度时,使线段透明。
XAML:
<Window x:Class="AutoStar.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:AutoStar"
mc:Ignorable="d"
Title="MainWindow" Background="#1B1D26" WindowState="Normal" Height="450" Width="800" Loaded="Window_Loaded">
<Window.Resources>
<Style TargetType="Line">
<Setter Property="Stroke" Value="#FFD8F4E9"/>
<Setter Property="StrokeThickness" Value="1"/>
</Style>
<Style TargetType="Ellipse">
<Setter Property="Stroke" Value="#53257DD9"/>
<Setter Property="StrokeThickness" Value="1"/>
<Setter Property="Fill" Value="#95FAE6"/>
<Setter Property="Width" Value="8"/>
<Setter Property="Height" Value="8"/>
</Style>
</Window.Resources>
<Grid>
<Canvas x:Name="canvas">
</Canvas>
</Grid>
</Window>
C#:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;
namespace AutoStar
{
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
Random random = new Random();
Point range = new Point(800, 450);
int starNum = 200;
Dictionary<Ellipse, Point> ellipsePoints = new Dictionary<Ellipse, Point>();
List<Line> lines = new List<Line>();
private void Window_Loaded(object sender, RoutedEventArgs e)
{
range = new Point(ActualWidth, ActualHeight);
Ellipse lastEllipse = default(Ellipse);
for (int i = 0; i < starNum; i++)
{
Point point = new Point(random.Next((int)range.X), random.Next((int)range.Y));
Ellipse ellipse = new Ellipse();
Canvas.SetLeft(ellipse, point.X);
Canvas.SetTop(ellipse, point.Y);
canvas.Children.Add(ellipse);
ellipsePoints[ellipse] = new Point(random.Next(-5, 5), random.Next(-5, 5));
while (ellipsePoints[ellipse] == default)
{
ellipsePoints[ellipse] = new Point(random.Next(-5, 5), random.Next(-5, 5));
}
// 连线计算
if (lastEllipse != default)
{
Line line = new Line();
lines.Add(line);
line.SetBinding(Line.X1Property, new Binding("(Canvas.Left)") { Source = lastEllipse, Mode = BindingMode.OneWay });
line.SetBinding(Line.Y1Property, new Binding("(Canvas.Top)") { Source = lastEllipse, Mode = BindingMode.OneWay });
line.SetBinding(Line.X2Property, new Binding("(Canvas.Left)") { Source = ellipse, Mode = BindingMode.OneWay });
line.SetBinding(Line.Y2Property, new Binding("(Canvas.Top)") { Source = ellipse, Mode = BindingMode.OneWay });
Canvas.SetLeft(line, 4);
Canvas.SetTop(line, 4);
canvas.Children.Add(line);
}
lastEllipse = ellipse;
// 动画计算
int countTime = 1;
Point offset = ellipsePoints[ellipse];
while (point.X + offset.X > 0 && point.X + offset.X < range.X
&& point.Y + offset.Y > 0 && point.Y + offset.Y < range.Y)
{
point = new Point(point.X + offset.X, point.Y + offset.Y);
countTime++;
}
point = new Point(point.X + offset.X, point.Y + offset.Y);
Storyboard storyboard = new Storyboard();
storyboard.AutoReverse = true;
storyboard.RepeatBehavior = RepeatBehavior.Forever;
DoubleAnimation doubleAnimation = new DoubleAnimation() { To = point.X, Duration = new Duration(TimeSpan.FromMilliseconds(1000 * countTime)) };
DoubleAnimation doubleAnimationY = new DoubleAnimation() { To = point.Y, Duration = new Duration(TimeSpan.FromMilliseconds(1000 * countTime)) };
storyboard.Children.Add(doubleAnimation);
storyboard.Children.Add(doubleAnimationY);
Storyboard.SetTarget(doubleAnimation, ellipse);
Storyboard.SetTarget(doubleAnimationY, ellipse);
Storyboard.SetTargetProperty(doubleAnimation, new PropertyPath("(Canvas.Left)"));
Storyboard.SetTargetProperty(doubleAnimationY, new PropertyPath("(Canvas.Top)"));
storyboard.Begin(ellipse);
}
DispatcherTimer dispatcherTimerLine = new DispatcherTimer(TimeSpan.FromMilliseconds(50), DispatcherPriority.Normal, OnTimeTickLineOpacity, Dispatcher);
dispatcherTimerLine.Start();
}
private void OnTimeTickLineOpacity(object sender, EventArgs e)
{
int index = 0;
foreach (var item in ellipsePoints)
{
if (index > 0)
{
var ellpses = ellipsePoints.Keys.ToList();
var firstPoint = new Point(Canvas.GetLeft(ellpses[index - 1]), Canvas.GetTop(ellpses[index - 1]));
var secPoint = new Point(Canvas.GetLeft(ellpses[index]), Canvas.GetTop(ellpses[index]));
double dist = Math.Sqrt(Math.Pow(firstPoint.X - secPoint.X, 2) + Math.Pow(firstPoint.Y - secPoint.Y, 2));
var currentLine = lines[index - 1];
if (dist > 200)
{
currentLine.Opacity = 0;
}
else
{
currentLine.Opacity = 1 - (dist / 200);
}
}
index++;
}
}
}
}