SkiaSharp 之 WPF 自繪 五環彈動球(案例版)
此案例基於拖曳和彈動球兩個技術功能實現,如有不懂的可以參考之前的相關文章,屬於遞進式教程。
五環彈動球
好吧,名字是我起的,其實,你可以任意個球進行聯動彈動,效果還是很不錯的,有很多前端都是基於這個特效,可以搞出一些很有科技感的效果出來。
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;
}
}
效果如下:
這個特效用的好,也能產生一些神奇的效果。
總結
這次是結合拖曳和彈動效果實現的綜合案例,效果還是很不錯的,之前也沒想到原來還可以這樣玩,拓展了玩法啊。
程式碼地址
//github.com/kesshei/WPFSkiaFiveRingsDemo.git
//gitee.com/kesshei/WPFSkiaFiveRingsDemo.git
閱
一鍵三連呦!,感謝大佬的支援,您的支援就是我的動力!
版權
藍創精英團隊(公眾號同名,CSDN同名,CNBlogs同名)