ToB企服应用市场:ToB评测及商务社交产业平台

标题: SkiaSharp 之 WPF 自绘 五环弹动球(案例版) [打印本页]

作者: 金歌    时间: 2022-9-4 21:52
标题: SkiaSharp 之 WPF 自绘 五环弹动球(案例版)
此案例基于拖曳和弹动球两个技术功能实现,如有不懂的可以参考之前的相关文章,属于递进式教程。
五环弹动球

好吧,名字是我起的,其实,你可以任意个球进行联动弹动,效果还是很不错的,有很多前端都是基于这个特效,可以搞出一些很有科技感的效果出来。
Wpf 和 SkiaSharp

新建一个WPF项目,然后,Nuget包即可
要添加Nuget包
  1. Install-Package SkiaSharp.Views.WPF -Version 2.88.0
复制代码
其中核心逻辑是这部分,会以我设置的60FPS来刷新当前的画板。
  1. skContainer.PaintSurface += SkContainer_PaintSurface;
  2. _ = Task.Run(() =>
  3. {
  4.     while (true)
  5.     {
  6.         try
  7.         {
  8.             Dispatcher.Invoke(() =>
  9.             {
  10.                 skContainer.InvalidateVisual();
  11.             });
  12.             _ = SpinWait.SpinUntil(() => false, 1000 / 60);//每秒60帧
  13.         }
  14.         catch
  15.         {
  16.             break;
  17.         }
  18.     }
  19. });
复制代码
弹球实体代码 (Ball.cs)
  1. public class Ball
  2. {
  3.     public double X { get; set; }
  4.     public double Y { get; set; }
  5.     public double VX { get; set; }
  6.     public double VY { get; set; }
  7.     public int Radius { get; set; }
  8.     public bool Dragged { get; set; } = false;
  9.     public SKColor sKColor { get; set; } = SKColors.Blue;
  10.     public bool CheckPoint(SKPoint sKPoint)
  11.     {
  12.         var d = Math.Sqrt(Math.Pow(sKPoint.X - X, 2) + Math.Pow(sKPoint.Y - Y, 2));
  13.         return this.Radius >= d;
  14.     }
  15. }
复制代码
五环弹动核心类 (FiveRings.cs)
  1. /// <summary>
  2. /// 五环弹球
  3. /// </summary>
  4. public class FiveRings
  5. {
  6.     public SKPoint centerPoint;
  7.     public int Radius = 0;
  8.     public int BallLength = 8;
  9.     public double TargetX;
  10.     public double Spring = 0.03;
  11.     public double SpringLength = 200;
  12.     public double Friction = 0.95;
  13.     public List<Ball>? Balls;
  14.     public Ball? draggedBall;
  15.     public void init(SKCanvas canvas, SKTypeface Font, int Width, int Height)
  16.     {
  17.         if (Balls == null)
  18.         {
  19.             Balls = new List<Ball>();
  20.             for (int i = 0; i < BallLength; i++)
  21.             {
  22.                 Random random = new Random((int)DateTime.Now.Ticks);
  23.                 Balls.Add(new Ball()
  24.                 {
  25.                     X = random.Next(50, Width - 50),
  26.                     Y = random.Next(50, Height - 50),
  27.                     Radius = this.Radius
  28.                 });
  29.             }
  30.         }
  31.     }
  32.     /// <summary>
  33.     /// 渲染
  34.     /// </summary>
  35.     public void Render(SKCanvas canvas, SKTypeface Font, int Width, int Height)
  36.     {
  37.         centerPoint = new SKPoint(Width / 2, Height / 2);
  38.         this.Radius = 20;
  39.         this.TargetX = Width / 2;
  40.         init(canvas, Font, Width, Height);
  41.         canvas.Clear(SKColors.White);
  42.         //划线
  43.         using var LinePaint = new SKPaint
  44.         {
  45.             Color = SKColors.Green,
  46.             Style = SKPaintStyle.Fill,
  47.             StrokeWidth = 3,
  48.             IsStroke = true,
  49.             StrokeCap = SKStrokeCap.Round,
  50.             IsAntialias = true
  51.         };
  52.         SKPath path = null;
  53.         foreach (var item in Balls)
  54.         {
  55.             if (path == null)
  56.             {
  57.                 path = new SKPath();
  58.                 path.MoveTo((float)item.X, (float)item.Y);
  59.             }
  60.             else
  61.             {
  62.                 path.LineTo((float)item.X, (float)item.Y);
  63.             }
  64.         }
  65.         path.Close();
  66.         canvas.DrawPath(path, LinePaint);
  67.         foreach (var item in Balls)
  68.         {
  69.             if (!item.Dragged)
  70.             {
  71.                 foreach (var ball in Balls.Where(t => t != item).ToList())
  72.                 {
  73.                     SpringTo(item, ball);
  74.                 }
  75.             }
  76.             DrawCircle(canvas, item);
  77.         }
  78.         using var paint = new SKPaint
  79.         {
  80.             Color = SKColors.Blue,
  81.             IsAntialias = true,
  82.             Typeface = Font,
  83.             TextSize = 24
  84.         };
  85.         string by = $"by 蓝创精英团队";
  86.         canvas.DrawText(by, 600, 400, paint);
  87.     }
  88.     /// <summary>
  89.     /// 画一个圆
  90.     /// </summary>
  91.     public void DrawCircle(SKCanvas canvas, Ball ball)
  92.     {
  93.         using var paint = new SKPaint
  94.         {
  95.             Color = SKColors.Blue,
  96.             Style = SKPaintStyle.Fill,
  97.             IsAntialias = true,
  98.             StrokeWidth = 2
  99.         };
  100.         canvas.DrawCircle((float)ball.X, (float)ball.Y, ball.Radius, paint);
  101.     }
  102.     public void MouseMove(SKPoint sKPoint)
  103.     {
  104.         if (draggedBall != null)
  105.         {
  106.             draggedBall.X = sKPoint.X;
  107.             draggedBall.Y = sKPoint.Y;
  108.         }
  109.     }
  110.     public void MouseDown(SKPoint sKPoint)
  111.     {
  112.         foreach (var item in Balls)
  113.         {
  114.             if (item.CheckPoint(sKPoint))
  115.             {
  116.                 item.Dragged = true;
  117.                 draggedBall = item;
  118.             }
  119.             else
  120.             {
  121.                 item.Dragged = false;
  122.             }
  123.         }
  124.     }
  125.     public void MouseUp(SKPoint sKPoint)
  126.     {
  127.         draggedBall = null;
  128.         foreach (var item in Balls)
  129.         {
  130.             item.Dragged = false;
  131.         }
  132.     }
  133.     public void SpringTo(Ball b1, Ball b2)
  134.     {
  135.         var dx = b2.X - b1.X;
  136.         var dy = b2.Y - b1.Y;
  137.         var angle = Math.Atan2(dy, dx);
  138.         var targetX = b2.X - SpringLength * Math.Cos(angle);
  139.         var targetY = b2.Y - SpringLength * Math.Sin(angle);
  140.         b1.VX += (targetX - b1.X) * Spring;
  141.         b1.VY += (targetY - b1.Y) * Spring;
  142.         b1.VX *= Friction;
  143.         b1.VY *= Friction;
  144.         b1.X += b1.VX;
  145.         b1.Y += b1.VY;
  146.     }
  147. }
复制代码
效果如下:


这个特效用的好,也能产生一些神奇的效果。
总结

这次是结合拖曳和弹动效果实现的综合案例,效果还是很不错的,之前也没想到原来还可以这样玩,拓展了玩法啊。
代码地址

https://github.com/kesshei/WPFSkiaFiveRingsDemo.git
https://gitee.com/kesshei/WPFSkiaFiveRingsDemo.git


一键三连呦!,感谢大佬的支持,您的支持就是我的动力!
版权

蓝创精英团队(公众号同名,CSDN同名,CNBlogs同名)

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4