此案例基于拖曳和弹动球两个技术功能实现,如有不懂的可以参考之前的相关文章,属于递进式教程。
五环弹动球
好吧,名字是我起的,其实,你可以任意个球进行联动弹动,效果还是很不错的,有很多前端都是基于这个特效,可以搞出一些很有科技感的效果出来。
Wpf 和 SkiaSharp
新建一个WPF项目,然后,Nuget包即可
要添加Nuget包- Install-Package SkiaSharp.Views.WPF -Version 2.88.0
复制代码 其中核心逻辑是这部分,会以我设置的60FPS来刷新当前的画板。- skContainer.PaintSurface += SkContainer_PaintSurface;
- _ = Task.Run(() =>
- {
- while (true)
- {
- try
- {
- Dispatcher.Invoke(() =>
- {
- skContainer.InvalidateVisual();
- });
- _ = SpinWait.SpinUntil(() => false, 1000 / 60);//每秒60帧
- }
- catch
- {
- break;
- }
- }
- });
复制代码 弹球实体代码 (Ball.cs)
- public class Ball
- {
- public double X { get; set; }
- public double Y { get; set; }
- public double VX { get; set; }
- public double VY { get; set; }
- public int Radius { get; set; }
- public bool Dragged { get; set; } = false;
- public SKColor sKColor { get; set; } = SKColors.Blue;
- public bool CheckPoint(SKPoint sKPoint)
- {
- var d = Math.Sqrt(Math.Pow(sKPoint.X - X, 2) + Math.Pow(sKPoint.Y - Y, 2));
- return this.Radius >= d;
- }
- }
复制代码 五环弹动核心类 (FiveRings.cs)
- /// <summary>
- /// 五环弹球
- /// </summary>
- public class FiveRings
- {
- public SKPoint centerPoint;
- public int Radius = 0;
- public int BallLength = 8;
- public double TargetX;
- public double Spring = 0.03;
- public double SpringLength = 200;
- public double Friction = 0.95;
- public List<Ball>? Balls;
- public Ball? draggedBall;
- public void init(SKCanvas canvas, SKTypeface Font, int Width, int Height)
- {
- if (Balls == null)
- {
- Balls = new List<Ball>();
- for (int i = 0; i < BallLength; i++)
- {
- Random random = new Random((int)DateTime.Now.Ticks);
- Balls.Add(new Ball()
- {
- X = random.Next(50, Width - 50),
- Y = random.Next(50, Height - 50),
- Radius = this.Radius
- });
- }
- }
- }
- /// <summary>
- /// 渲染
- /// </summary>
- public void Render(SKCanvas canvas, SKTypeface Font, int Width, int Height)
- {
- centerPoint = new SKPoint(Width / 2, Height / 2);
- this.Radius = 20;
- this.TargetX = Width / 2;
- init(canvas, Font, Width, Height);
- canvas.Clear(SKColors.White);
- //划线
- using var LinePaint = new SKPaint
- {
- Color = SKColors.Green,
- Style = SKPaintStyle.Fill,
- StrokeWidth = 3,
- IsStroke = true,
- StrokeCap = SKStrokeCap.Round,
- IsAntialias = true
- };
- SKPath path = null;
- foreach (var item in Balls)
- {
- if (path == null)
- {
- path = new SKPath();
- path.MoveTo((float)item.X, (float)item.Y);
- }
- else
- {
- path.LineTo((float)item.X, (float)item.Y);
- }
- }
- path.Close();
- canvas.DrawPath(path, LinePaint);
- foreach (var item in Balls)
- {
- if (!item.Dragged)
- {
- foreach (var ball in Balls.Where(t => t != item).ToList())
- {
- SpringTo(item, ball);
- }
- }
- DrawCircle(canvas, item);
- }
- using var paint = new SKPaint
- {
- Color = SKColors.Blue,
- IsAntialias = true,
- Typeface = Font,
- TextSize = 24
- };
- string by = $"by 蓝创精英团队";
- canvas.DrawText(by, 600, 400, paint);
- }
- /// <summary>
- /// 画一个圆
- /// </summary>
- public void DrawCircle(SKCanvas canvas, Ball ball)
- {
- using var paint = new SKPaint
- {
- Color = SKColors.Blue,
- Style = SKPaintStyle.Fill,
- IsAntialias = true,
- StrokeWidth = 2
- };
- canvas.DrawCircle((float)ball.X, (float)ball.Y, ball.Radius, paint);
- }
- public void MouseMove(SKPoint sKPoint)
- {
- if (draggedBall != null)
- {
- draggedBall.X = sKPoint.X;
- draggedBall.Y = sKPoint.Y;
- }
- }
- public void MouseDown(SKPoint sKPoint)
- {
- foreach (var item in Balls)
- {
- if (item.CheckPoint(sKPoint))
- {
- item.Dragged = true;
- draggedBall = item;
- }
- else
- {
- item.Dragged = false;
- }
- }
- }
- public void MouseUp(SKPoint sKPoint)
- {
- draggedBall = null;
- foreach (var item in Balls)
- {
- item.Dragged = false;
- }
- }
- public void SpringTo(Ball b1, Ball b2)
- {
- var dx = b2.X - b1.X;
- var dy = b2.Y - b1.Y;
- var angle = Math.Atan2(dy, dx);
- var targetX = b2.X - SpringLength * Math.Cos(angle);
- var targetY = b2.Y - SpringLength * Math.Sin(angle);
- b1.VX += (targetX - b1.X) * Spring;
- b1.VY += (targetY - b1.Y) * Spring;
- b1.VX *= Friction;
- b1.VY *= Friction;
- b1.X += b1.VX;
- b1.Y += b1.VY;
- }
- }
复制代码 效果如下:

这个特效用的好,也能产生一些神奇的效果。
总结
这次是结合拖曳和弹动效果实现的综合案例,效果还是很不错的,之前也没想到原来还可以这样玩,拓展了玩法啊。
代码地址
https://github.com/kesshei/WPFSkiaFiveRingsDemo.git
https://gitee.com/kesshei/WPFSkiaFiveRingsDemo.git
阅
一键三连呦!,感谢大佬的支持,您的支持就是我的动力!
版权
蓝创精英团队(公众号同名,CSDN同名,CNBlogs同名)
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |