当前位置:网站首页>SkiaSharp 之 WPF 自绘 五环弹动球(案例版)
SkiaSharp 之 WPF 自绘 五环弹动球(案例版)
2022-08-01 20:51:00 【蓝创精英团队】
此案例基于拖曳和弹动球两个技术功能实现,如有不懂的可以参考之前的相关文章,属于递进式教程。
五环弹动球
好吧,名字是我起的,其实,你可以任意个球进行联动弹动,效果还是很不错的,有很多前端都是基于这个特效,可以搞出一些很有科技感的效果出来。
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同名)
边栏推荐
- Wildcard SSL/TLS certificate
- 有用的网站
- Where should I prepare for the PMP exam in September?
- 【多任务模型】Progressive Layered Extraction: A Novel Multi-Task Learning Model for Personalized(RecSys‘20)
- 面试官:大量请求 Redis 不存在的数据,从而打倒数据库,有什么方案?
- 30+的女性测试人面试经验分享
- 线上问题排查常用命令,总结太全了,建议收藏!!
- Failed to re-init queues : Illegal queue capacity setting (abs-capacity=0.6) > (abs-maximum-capacity
- 【节能学院】数据机房中智能小母线与列头柜方案的对比分析
- 有点奇怪!访问目的网址,主机能容器却不行
猜你喜欢
OSG笔记:设置DO_NOT_COMPUTE_NEAR_FAR,手动计算远近平面
技能大赛训练:A部分加固题目
MySQL 中出现的字符编码错误 Incorrect string value: ‘\x\x\x\x‘ for column ‘x‘
虚拟机的IP地址自动变为127.0.0.1
【nn.Parameter()】生成和为什么要初始化
通配符 SSL/TLS 证书
Wildcard SSL/TLS certificate
vant实现Select效果--单选和多选
Get started quickly with MongoDB
Little data on how to learn?Jida latest small learning data review, 26 PDF page covers the 269 - page document small data learning theory, method and application are expounded
随机推荐
Use WeChat official account to send information to designated WeChat users
字符串
[Energy Conservation Institute] Comparative analysis of smart small busbar and column head cabinet solutions in data room
Postman 批量测试接口详细教程
[Multi-task optimization] DWA, DTP, Gradnorm (CVPR 2019, ECCV 2018, ICML 2018)
进行交互或动画时如何选择Visibility, Display, and Opacity
New graduate students, great experience in reading English literature, worthy of your collection
【节能学院】数据机房中智能小母线与列头柜方案的对比分析
KDD2022 | Self-Supervised Hypergraph Transformer Recommendation System
虚拟机的IP地址自动变为127.0.0.1
【Untitled】
Multithreaded producers and consumers
Little data on how to learn?Jida latest small learning data review, 26 PDF page covers the 269 - page document small data learning theory, method and application are expounded
tiup mirror init
Nacos 配置中心
通俗解释:什么是临床预测模型
数据库单字段存储多个标签(位移操作)
WhatsApp群发实战分享——WhatsApp Business API账号
Pytorch框架学习记录9——非线性激活
tiup mirror clone