当前位置:网站首页>WPF achieves star effect
WPF achieves star effect
2022-06-22 03:46:00 【Dotnet cross platform】
This article is authorized by the original author to share it twice in an original way , Welcome to reprint 、 Share .
Original author : Ordinary earthman
Original address :https://www.cnblogs.com/tsliwei/p/6282183.html
Github Address :https://github.com/WPFDevelopersOrg/WPFDevelopers
effect
I saw... A while ago ay Spider web effect and landing page background , I think the effect is very cool . I also want to write a . So the writing became like this . The girl's dream is to catch up with her feet . I am a stingy man with a girlish heart ;
The realization idea is divided into two parts :
1) The stars roam endlessly ;
2) The line between the stars ;
Don't put stars and wires in two containers , For separate operation ;
The stars
Decompose the motion of the stars into
XAxis andYTwo incoherent motions of an axis , Separate operation . Operation is to randomly generate a speed , Randomly generate a time . After the movement, a random speed is generated , Randomly generate a time ...... Infinite loop ;The same is true of the rotation of stars ;
attachment
First, explain the rules of connection . A line between two stars , Each star has a wired sphere of influence , Is the width times the line magnification , This connection ratio can be set in the window . When two spheres of influence intersect , Just connect ;
example :
star 1 Width 5,star 2 Width 10,Connection magnification is 3, Then the distance between the two stars is less than5*3+10*3=45Connect as soon as possible , Greater than45Disconnect when . If the connection magnification is set to4, Then the distance between the two stars is less than5*4+10*4=60Time connection , Greater than60Disconnect when ;
Realization and resource occupancy
There are two ways to realize the motion of stars :
1) be based on Grid and TranslateTransform use DoubleAnimation Animation controls the displacement of stars .
2) be based on Canvas Control through frame animation Canvas Of X,Y.
There are also two ways to implement the connection :
1) Simple and crude . Empty the connection container at each frame . And then double circle the stars , Reconnect all stars ( Conform to the connection rules ).
2) Loop the line at each frame , Judge the connection rules . Match the... That changes this connection X1,Y1,X2,Y2 Instead of trying again new attachment . Those that do not conform to the rules are removed . And then there's still a double circle of stars , See if there is a line between the two stars that conform to the rules , If you don't have it, just new One .
as everyone knows ,WPF The share of animation resources is still high , Written so many implementations , It's also because of this .
Basically, it is based on Canvas The implementation of takes a little less resources . But there's a problem , If you add a blur effect to the stars , be based on Canvas The realized resource share will not soar , Instead, the number of frames is significantly reduced .( It may also be the reason for my computer environment )
It can not be said that the realization is good or bad , The specific operating environment may be different , Parameter settings are different , Each implementation has a different representation .
Then on the question of resource occupancy , At my current level , That's the end of it . Bloggers can choose for themselves .
Source code is as follows
1)StarrySky.cs The code is as follows ;
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
namespace WPFDevelopers.Controls
{
[TemplatePart(Name = GridTemplateName, Type = typeof(Grid))]
[TemplatePart(Name = CanvasTemplateName, Type = typeof(Canvas))]
public class StarrySky : Control
{
private const string GridTemplateName = "PART_GridLineContainer";
private const string CanvasTemplateName = "PART_CanvasStarContainer";
private Grid _grid;
private Canvas _canvas;
public static readonly DependencyProperty StarCountProperty =
DependencyProperty.Register("StarCount", typeof(int), typeof(StarrySky), new UIPropertyMetadata(10));
public static readonly DependencyProperty StarSizeMinProperty =
DependencyProperty.Register("StarSizeMin", typeof(int), typeof(StarrySky), new UIPropertyMetadata(5));
public static readonly DependencyProperty StarSizeMaxProperty =
DependencyProperty.Register("StarSizeMax", typeof(int), typeof(StarrySky), new UIPropertyMetadata(20));
public static readonly DependencyProperty StarVMinProperty =
DependencyProperty.Register("StarVMin", typeof(int), typeof(StarrySky), new UIPropertyMetadata(10));
public static readonly DependencyProperty StarVMaxProperty =
DependencyProperty.Register("StarVMax", typeof(int), typeof(StarrySky), new UIPropertyMetadata(20));
public static readonly DependencyProperty StarRVMinProperty =
DependencyProperty.Register("StarRVMin", typeof(int), typeof(StarrySky), new UIPropertyMetadata(90));
public static readonly DependencyProperty StarRVMaxProperty =
DependencyProperty.Register("StarRVMax", typeof(int), typeof(StarrySky), new UIPropertyMetadata(360));
public static readonly DependencyProperty LineRateProperty =
DependencyProperty.Register("LineRate", typeof(int), typeof(StarrySky), new UIPropertyMetadata(3));
private readonly Random _random = new Random();
private StarInfo[] _stars;
static StarrySky()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(StarrySky),
new FrameworkPropertyMetadata(typeof(StarrySky)));
}
public StarrySky()
{
Loaded += delegate
{
CompositionTarget.Rendering += delegate
{
StarRoamAnimation();
AddOrRemoveStarLine();
MoveStarLine();
};
};
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
_grid = GetTemplateChild(GridTemplateName) as Grid;
_canvas = GetTemplateChild(CanvasTemplateName) as Canvas;
}
public int StarCount
{
get => (int)GetValue(StarCountProperty);
set => SetValue(StarCountProperty, value);
}
public int StarSizeMin
{
get => (int)GetValue(StarSizeMinProperty);
set => SetValue(StarSizeMinProperty, value);
}
public int StarSizeMax
{
get => (int)GetValue(StarSizeMaxProperty);
set => SetValue(StarSizeMaxProperty, value);
}
public int StarVMin
{
get => (int)GetValue(StarVMinProperty);
set => SetValue(StarVMinProperty, value);
}
public int StarVMax
{
get => (int)GetValue(StarVMaxProperty);
set => SetValue(StarVMaxProperty, value);
}
public int StarRVMin
{
get => (int)GetValue(StarRVMinProperty);
set => SetValue(StarRVMinProperty, value);
}
public int StarRVMax
{
get => (int)GetValue(StarRVMaxProperty);
set => SetValue(StarRVMaxProperty, value);
}
public int LineRate
{
get => (int)GetValue(LineRateProperty);
set => SetValue(LineRateProperty, value);
}
public void InitStar()
{
// Empty the star container
_stars = new StarInfo[StarCount];
_canvas.Children.Clear();
_grid.Children.Clear();
// Make stars
for (var i = 0; i < StarCount; i++)
{
double size = _random.Next(StarSizeMin, StarSizeMax + 1); // Star size
var starInfo = new StarInfo
{
X = _random.Next(0, (int)_canvas.ActualWidth),
XV = (double)_random.Next(-StarVMax, StarVMax) / 60,
XT = _random.Next(6, 301), // frame
Y = _random.Next(0, (int)_canvas.ActualHeight),
YV = (double)_random.Next(-StarVMax, StarVMax) / 60,
YT = _random.Next(6, 301), // frame
StarLines = new Dictionary<StarInfo, Line>()
};
var star = new Path
{
Data = Application.Current.Resources["PathStarrySky"] as Geometry,
Width = size,
Height = size,
Stretch = Stretch.Fill,
Fill = GetRandomColorBursh(),
RenderTransformOrigin = new Point(0.5, 0.5),
RenderTransform = new RotateTransform { Angle = 0 }
};
Canvas.SetLeft(star, starInfo.X);
Canvas.SetTop(star, starInfo.Y);
starInfo.StarRef = star;
// Animate star rotation
SetStarRotateAnimation(star);
// Add to container
_stars[i] = starInfo;
_canvas.Children.Add(star);
}
}
private void SetStarRotateAnimation(Path star)
{
double v = _random.Next(StarRVMin, StarRVMax + 1); // Speed
double a = _random.Next(0, 360 * 5); // angle
var t = a / v; // Time
var dur = new Duration(new TimeSpan(0, 0, 0, 0, (int)(t * 1000)));
var sb = new Storyboard
{
Duration = dur
};
// Animation completion event Animate this again
sb.Completed += (S, E) => { SetStarRotateAnimation(star); };
var da = new DoubleAnimation
{
To = a,
Duration = dur
};
Storyboard.SetTarget(da, star);
Storyboard.SetTargetProperty(da, new PropertyPath("(UIElement.RenderTransform).(RotateTransform.Angle)"));
sb.Children.Add(da);
sb.Begin(this);
}
private SolidColorBrush GetRandomColorBursh()
{
var r = (byte)_random.Next(128, 256);
var g = (byte)_random.Next(128, 256);
var b = (byte)_random.Next(128, 256);
return new SolidColorBrush(Color.FromRgb(r, g, b));
}
/// <summary>
/// Star walkthrough animation
/// </summary>
private void StarRoamAnimation()
{
if (_stars == null)
return;
foreach (var starInfo in _stars)
{
//X Axial motion
if (starInfo.XT > 0)
{
// The exercise time is longer than 0, Keep moving
if (starInfo.X >= _canvas.ActualWidth || starInfo.X <= 0)
// Touch the edge , The speed is reversed
starInfo.XV = -starInfo.XV;
// Displacement plus , Less time
starInfo.X += starInfo.XV;
starInfo.XT--;
Canvas.SetLeft(starInfo.StarRef, starInfo.X);
}
else
{
// The exercise time is less than 0, Reset the speed and time
starInfo.XV = (double)_random.Next(-StarVMax, StarVMax) / 60;
starInfo.XT = _random.Next(100, 1001);
}
//Y Axial motion
if (starInfo.YT > 0)
{
// The exercise time is longer than 0, Keep moving
if (starInfo.Y >= _canvas.ActualHeight || starInfo.Y <= 0)
// Touch the edge , The speed is reversed
starInfo.YV = -starInfo.YV;
// Displacement plus , Less time
starInfo.Y += starInfo.YV;
starInfo.YT--;
Canvas.SetTop(starInfo.StarRef, starInfo.Y);
}
else
{
// The exercise time is less than 0, Reset the speed and time
starInfo.YV = (double)_random.Next(-StarVMax, StarVMax) / 60;
starInfo.YT = _random.Next(100, 1001);
}
}
}
/// <summary>
/// Add or remove lines between stars
/// </summary>
private void AddOrRemoveStarLine()
{
// There are no stars Go straight back to
if (_stars == null || StarCount != _stars.Length)
return;
// Create a line between the stars
for (var i = 0; i < StarCount - 1; i++)
for (var j = i + 1; j < StarCount; j++)
{
var star1 = _stars[i];
var x1 = star1.X + star1.StarRef.Width / 2;
var y1 = star1.Y + star1.StarRef.Height / 2;
var star2 = _stars[j];
var x2 = star2.X + star2.StarRef.Width / 2;
var y2 = star2.Y + star2.StarRef.Height / 2;
var s = Math.Sqrt((y2 - y1) * (y2 - y1) + (x2 - x1) * (x2 - x1)); // The distance between two stars
var threshold = star1.StarRef.Width * LineRate + star2.StarRef.Width * LineRate;
if (s <= threshold)
{
if (!star1.StarLines.ContainsKey(star2))
{
var line = new Line
{
X1 = x1,
Y1 = y1,
X2 = x2,
Y2 = y2,
Stroke = GetStarLineBrush(star1.StarRef, star2.StarRef)
};
star1.StarLines.Add(star2, line);
_grid.Children.Add(line);
}
}
else
{
if (star1.StarLines.ContainsKey(star2))
{
_grid.Children.Remove(star1.StarLines[star2]);
star1.StarLines.Remove(star2);
}
}
}
}
/// <summary>
/// Move the line between the stars
/// </summary>
private void MoveStarLine()
{
// There are no stars Go straight back to
if (_stars == null)
return;
foreach (var star in _stars)
foreach (var starLine in star.StarLines)
{
var line = starLine.Value;
line.X1 = star.X + star.StarRef.Width / 2;
line.Y1 = star.Y + star.StarRef.Height / 2;
line.X2 = starLine.Key.X + starLine.Key.StarRef.Width / 2;
line.Y2 = starLine.Key.Y + starLine.Key.StarRef.Height / 2;
}
}
/// <summary>
/// Get the star line color brush
/// </summary>
/// <param name="star0"> Starting star </param>
/// <param name="star1"> The end star </param>
/// <returns>LinearGradientBrush</returns>
private LinearGradientBrush GetStarLineBrush(Path star0, Path star1)
{
return new LinearGradientBrush
{
GradientStops = new GradientStopCollection
{
new GradientStop { Offset = 0, Color = (star0.Fill as SolidColorBrush).Color },
new GradientStop { Offset = 1, Color = (star1.Fill as SolidColorBrush).Color }
}
};
}
}
/// <summary>
/// The stars
/// </summary>
internal class StarInfo
{
/// <summary>
/// X coordinate
/// </summary>
public double X { get; set; }
/// <summary>
/// X Shaft speed ( Unit distance / frame )
/// </summary>
public double XV { get; set; }
/// <summary>
/// X Coordinates to X The time the shaft speed runs ( frame )
/// </summary>
public int XT { get; set; }
/// <summary>
/// Y coordinate
/// </summary>
public double Y { get; set; }
/// <summary>
/// Y Shaft speed ( Unit distance / frame )
/// </summary>
public double YV { get; set; }
/// <summary>
/// Y Coordinates to Y The time the shaft speed runs ( frame )
/// </summary>
public int YT { get; set; }
/// <summary>
/// References to stars
/// </summary>
public Path StarRef { get; set; }
public Dictionary<StarInfo, Line> StarLines { get; set; }
}
}2)StarrySky.xaml The code is as follows ;
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="clr-namespace:WPFDevelopers.Controls">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Basic/ControlBasic.xaml"/>
</ResourceDictionary.MergedDictionaries>
<RadialGradientBrush x:Key="StarrySkyRadialGradientBrush" GradientOrigin="0.5,0" Center="0.5,0.3" RadiusX="0.7">
<GradientStop Color="#FF04040E" Offset="0"/>
<GradientStop Color="#FF24315D" Offset="1"/>
</RadialGradientBrush>
<Style TargetType="{x:Type controls:StarrySky}"
BasedOn="{StaticResource ControlBasicStyle}">
<Setter Property="Background" Value="{StaticResource StarrySkyRadialGradientBrush}"></Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type controls:StarrySky}">
<Grid Background="{TemplateBinding Background}">
<Grid x:Name="PART_GridLineContainer"/>
<Canvas x:Name="PART_CanvasStarContainer"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>3)StarrySkyExample.xaml The code is as follows ;
<UserControl x:Class="WPFDevelopers.Samples.ExampleViews.StarrySkyExample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:wpfdev="https://github.com/WPFDevelopersOrg/WPFDevelopers"
xmlns:ws="https://github.com/WPFDevelopersOrg.WPFDevelopers.Minimal"
xmlns:local="clr-namespace:WPFDevelopers.Samples.ExampleViews"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<UserControl.Resources>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="White"></Setter>
<Setter Property="FontSize" Value="14"></Setter>
<Setter Property="VerticalAlignment" Value="Center"></Setter>
<Setter Property="Margin" Value="2"></Setter>
</Style>
<Style TargetType="{x:Type StackPanel}">
<Setter Property="Margin" Value="2"></Setter>
</Style>
<Style TargetType="{x:Type TextBox}" BasedOn="{StaticResource {x:Type TextBox}}">
<Setter Property="ws:ElementHelper.Watermark" Value=" Input content "></Setter>
<Setter Property="Margin" Value="-30,0"></Setter>
<Setter Property="Width" Value="100"></Setter>
</Style>
</UserControl.Resources>
<Grid>
<!--<wpfdev:StarrySky StarCount="{Binding ElementName=tbx_starCount,Path=Text}"
StarSizeMin="{Binding ElementName=tbx_starSizeMin,Path=Text}"
StarSizeMax="{Binding ElementName=tbx_starSizeMax,Path=Text}"
StarVMin="{Binding ElementName=tbx_starVMin,Path=Text}"
StarVMax="{Binding ElementName=tbx_starVMax,Path=Text}"
StarRVMin="{Binding ElementName=tbx_starRVMin,Path=Text}"
StarRVMax="{Binding ElementName=tbx_starRVMax,Path=Text}"
LineRate="{Binding ElementName=tbx_lineRate,Path=Text}"
Name="myStarrySky">
</wpfdev:StarrySky>-->
<wpfdev:StarrySky Name="myStarrySky">
</wpfdev:StarrySky>
<StackPanel HorizontalAlignment="Left" VerticalAlignment="Top">
<StackPanel Orientation="Horizontal">
<TextBlock Text=" The number of stars :"></TextBlock>
<TextBox x:Name="tbx_starCount" Text="{Binding ElementName=myStarrySky,Path=StarCount}"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text=" The minimum size :"></TextBlock>
<TextBox Name="tbx_starSizeMin" Text="{Binding ElementName=myStarrySky,Path=StarSizeMin}"></TextBox>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text=" Maximum size :"></TextBlock>
<TextBox Name="tbx_starSizeMax" Text="{Binding ElementName=myStarrySky,Path=StarSizeMax}"></TextBox>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text=" Minimum speed :"></TextBlock>
<TextBox Name="tbx_starVMin" Text="{Binding ElementName=myStarrySky,Path=StarVMin}"></TextBox>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text=" Maximum speed :"></TextBlock>
<TextBox Name="tbx_starVMax" Text="{Binding ElementName=myStarrySky,Path=StarVMax}"></TextBox>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text=" Minimum speed :"></TextBlock>
<TextBox Name="tbx_starRVMin" Text="{Binding ElementName=myStarrySky,Path=StarRVMin}"></TextBox>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text=" Maximum speed :"></TextBlock>
<TextBox Name="tbx_starRVMax" Text="{Binding ElementName=myStarrySky,Path=StarRVMax}"></TextBox>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text=" Connection magnification :"></TextBlock>
<TextBox Name="tbx_lineRate" Text="{Binding ElementName=myStarrySky,Path=LineRate}"></TextBox>
</StackPanel>
<Button Name="btn_render" Content=" Generate " Click="btn_render_Click"/>
</StackPanel>
</Grid>
</UserControl>4)StarrySkyExample.xaml.cs The code is as follows ;
using System.Windows.Controls;
namespace WPFDevelopers.Samples.ExampleViews
{
/// <summary>
/// StarrySkyExample.xaml Interaction logic of
/// </summary>
public partial class StarrySkyExample : UserControl
{
public StarrySkyExample()
{
InitializeComponent();
}
private void btn_render_Click(object sender, System.Windows.RoutedEventArgs e)
{
myStarrySky.InitStar();
}
}
}Source code 1[1]Gtihub[2]Gitee[3]
Reference material
[1]
Source code : https://files.cnblogs.com/files/tsliwei/StarrySkyBasedOnCanvasYOUHUA.zip
[2]Gtihub: https://github.com/WPFDevelopersOrg/WPFDevelopers
[3]gitee: https://gitee.com/WPFDevelopersOrg/WPFDevelopers
边栏推荐
- docker 安装redis
- 76. 最小覆盖子串-滑动窗口法
- Sword finger offer 68 - I. nearest common ancestor of binary search tree
- LeetCode --- 1221. Split a String in Balanced Strings 解题报告
- Beifu TwinCAT 3 cylinder action program compilation
- Direct insertion sort of eight sorts
- 二叉树的层次遍历
- MySQL 45 lecture learning notes (II) execution of SQL update statements
- 倍福嵌入式控制器PLC各型号介绍
- 内网穿透
猜你喜欢

Based on logback XML to realize the insensitive operation of saving log information

Cloud native architecture (03) - Architecture

如何快速定位bug和编写测试用例?

When 618 attacks, how to choose between Beibei X3 and Jimi h3s? Take you all-round in-depth analysis

Flutter 性能优化

How to do activities in beauty salons

VIM from dislike to dependence (18) -- advanced search mode

嵌入式软件测试的经验经历和总结

Official competition volume and "answer" of "Cyberspace Security" of secondary vocational group in 2019 national vocational college skills competition

L'avenir est venu: l'âge du nuage
随机推荐
倍福TwinCAT3 Ads错误查询列表
Research on std:: move and std:: forward right value reference
3000 yuan projector comparison and evaluation, dangbei D3x beats Jimi new Z6 x
Fluent rendering Principle & detailed explanation of three trees
Application method and operation of Beifu cx9020 (wince 7) controller
TwinCAT 3 RS232通信的关键程序
C language integer value range - the problem of more than one negative number
Nepal graph learning Chapter 2_ A bug before version v2.6.1 caused OOM
C51的一些日记
How to do activities in beauty salons
Wechat applet ChAT expression
Beifu TwinCAT sets the scanning cycle and operation cycle method of PLC
Shelling of ESP law of reverse crackme
Threejs realizes the fluctuation hot spot effect, fluctuation mark and fluctuation label display
128 traps - source code analysis
SSM住院管理系统
基于SSM的博客系统【带后台管理】
Use of shutter stream
关于在dialog中调用edittext这个件事
Kubernetes 集群日志管理