开发者

WPF+SkiaSharp实现自绘弹幕效果

开发者 https://www.devze.com 2022-12-02 11:09 出处:网络 作者: 驚鏵
SkiaSharp 自绘弹幕效果 框架使用.NET60; Visual Studio 2022; 项目使用 MIT 开源许可协议;

SkiaSharp 自绘弹幕效果

框架使用.NET60

Visual Studio 2022;

项目使用 MIT 开源许可协议;

接着上一篇 wpF 弹幕

上期有网友建议使用Skia实现弹幕。

  • 弹幕消息使用SKElement做弹幕展现,然后在SKCanvas进行绘制弹幕。
  • 由于需要绘制矩形与文本所以需要使用到SKBitmap进行绘制弹幕类。
  • 创建SKBitmap设置宽(根据文本的长度定义宽度)与高度40
  • 创建对象SKCanvas并实例化的时候将SKBitmap传入,然后对SKCanvas进行绘制背景DrawRoundRect 与文本DrawText ,使用属性记录XY的值方便在动画的时候让弹幕动起来。
  • BarrageRender的时候进行绘制弹幕图片DrawImage(SKBitmap,x,y) 。
  • 弹幕每次移动多少值 等于SKCanvas的宽除以弹幕的
  • 当弹幕移动Move()时如超过-Width则通过out返回GUID 就移除弹幕对象。

实现代码

1) 准备 MsgInfo 弹幕消息类如下:

usingSystem;
usingSkiaSharp;

namespaceSkiaSharpBarrage
{
///<summary>
///msginfo
///</summary>
publicclassMsgInfo
{
privatestring_msg;

publicstringGUID;

publicmsgInfo(stringmsg,SKTypeface_font,floatWindowsWidth)
{
_msg=msg;
var_random=newRandom();
varskColor=newSKColor((byte)_random.Next(1,255),
(byte)_random.Next(1,255),(byte)_random.Next(1,233));
usingvarpaint=newSKPaint
{
Color=skColor,
Style=SKPaintStyle.Fill,
IsAntialias=true,
StrokeWidth=2
};
paint.Shader=SKShader.CreateLinearGradient(
newSKPoint(0,0),
newSKPoint(1,1),
new[]{SKColors.Transparent,skColor},
newfloat[]{0,1},
SKShaderTileMode.Repeat);

usingvarpaintText=newSKPaint
{
Color=SKColors.White,
IsAntialias=true,
Typeface=_font,
TextSize=24
};
vartextBounds=newSKRect();
paintText.MeasureText(msg,reftextBounds);
varwidth=textBounds.Width+100;
SKImageskImage;
using(varbitmap=newSKBitmap((int)width,40,true))
using(varcanvas=newSKCanvas(bitmap))
{
canvas.DrawRoundRect(0,0,width,40,20,20,paint);
canvas.DrawText(msg,width/2-textBounds.Width/2,bitmap.Height/2+textBounds.HeigampRUht/2,
paintText);
varimage=SKImage.FromBitmap(bitmap);
skImage=image;
}

SKImage=skImage;
Width=width;
X=windowsWidth+Width;
CanvasWidth=windowsWidth;
CostTime=TimeSpan.FromMilliseconds(Width);
GUID=Guid.NewGuid().ToString("N");
}

publicfloatX{get;set;}
publicfloatY{get;set;}
publicfloatWidth{get;set;}
publicfloatCanvasWidth{get;set;}
publicSKImageSKImage{get;set;}
publicfloatMoveNum=>CanvasWidth/(float)CostTime.TotalMilliseconds;
publicTimeSpanCostTime{get;set;}

///<summary>
///定时调用,移动指定距离
///</summary>
publicvoidMove(outstringguid)
{
guid=string.Empty;
X=X-MoveNum;
if(X<=-Width)
guid=GUID;
}
}
}

2) 新建 Barrage.cs 类如下:

usingSystem.Collections.Generic;
usingSystem.Linq;
usingSkiaSharp;

namespaceSkiaSharpBarrage
{
publicclassBarrage
{
privatereadonlySKTypeface_font;
privatereadonlyList<MsgInfo>_MsgInfo;
privateint_num,_index;
privatedouble_right,_top;
privatefloat_width;
privatereadonlyandroidfloat_height;

publicBarrage(SKTypefacefont,floatwidth,floatheight,List<string>strList)
{
_width=width;
_height=height;
_font=font;
_num=(int)height/40;
_MsgInfo=newList<MsgInfo>();
foreach(variteminstrList)BuildMsgInfo(item);
}

privatevoidBuildMsgInfo(stringtext)
{
_index++;
if(_right!=0)
_width=(float)_right;
varmodel=newMsgInfo(text,_font,_width);
_right=_right==0?_height+model.Width:_right;
vary=_height-40;
_top=_top+40>=y?40:_top;
model.Y=(float)_top;
_MsgInfo.Add(model);
_top+=60;
}

publicvoidAddBarrage(stringtext)
{
BuildMsgInfo(text);
}

publicvoidRender(SKCanvascanvas,SKTypefacefont,intwidth,intheight,List<string>strList)
{
for(vari=0;i<_MsgInfo.Count;i++)
{
varinfo=_MsgInfo[i];
varguid=string.Empty;
info.Move(outguid);
if(!string.IsNullOrEmpty(guid))
{
varmodel=_MsgInfo.FirstOrDefault(x=>x.GUID==guid);
_MsgInfo.Remove(model);
}

canvas.DrawImage(info.SKImage,info.X,info.Y);
}
}
}
}

3) MainWind开发者_开发入门ow.xaml.cs 如下:

<wpfdev:Windowx:Class="SkiaSharpBarrage.MainWindow"
XMLns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:wpfdev="https://github.com/WPFDevelopersOrg/WPFDevelopers"
xmlns:skia="clr-namespace:SkiaSharp.Views.WPF;assembly=SkiaSharp.Views.WPF"
mc:Ignorable="d"WindowStartupLocation="CenterScreen"
ResizeMode="CanMinimize"
Title="SkiaSharpBarrage-弹幕篇"Height="450"Width="800">
<GridMargin="4">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinitionHeight="Auto"/>
</Grid.RowDefinitions>
<MediaElementStretch="Uniform"Grid.RowSpan="2"
Name="myMediaElement"/>
<skia:SKElementx:Name="skElement"/>
<GridGrid.Row="1"Name="MyGrid">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinitionWidth="Auto"/>
</Grid.ColumnDefinitions>
<TextBoxwpfdev:ElementHelper.IsWatermark="True"
x:Name="tbBarrage"
wpfdev:ElementHelper.Watermark="请弹幕内容"/>
<ButtonGrid.Column="1"Style="{StaticResourcePrimaryButton}"
Content="发射弹幕"Margin="4,0,0,0"
Click="ButtonBase_OnClick"/>
</Grid>
</Grid>
</wpfdev:Window>

3) 逻辑 MainWinandroiddow.xaml.cs 如下:

usingSystem;
usingSystem.Collections.Generic;
usingSystem.IO;
usingSystem.Linq;
usingSystem.Threading;
usingSystem.Threading.Tasks;
usingSystem.Windows;
usingSkiaSharp;
usingSkiaSharp.Views.Desktop;

namespaceSkiaSharpBarrage
{
///<summary>
///InteractionlogicforMainWindow.xaml
///</summary>
publicpartialclassMainWindow
{
privatereadonlyBarrage_barrage;
privatereadonlySKTypeface_font;
privatereadonlyList<string>list=newList<string>();

publicMainWindow()
{
list.Add("2333");
list.Add("测试弹幕公众号:WPF开发者");
list.Add("很难开心");
list.Add("LOL~");
list.Add("青春记忆");
list.Add("bing");
list.Add("Microsoft"python);
InitializeComponent();
varindex=SKFontManager.Default.FontFamilies.ToList().IndexOf("微软雅黑");
_font=SKFontManager.Default.GetFontStyles(index).CreateTypeface(0);
_barrage=newBarrage(_font,(float)Width,(float)Height-(float)MyGrid.ActualHeight,list);
skElement.PaintSurface+=SkElement_PaintSurface;
Loaded+=delegate
{
myMediaElement.Source=
newUri(Path.Combine(AppDomain.CurrentDomain.BaseDirectory,"Leagueoflegends.mp4"));
};
_=Task.Run(()=>
{
try
{
while(true)
{
www.devze.comDispatcher.Invoke(()=>{skElement.InvalidateVisual();});
_=SpinWait.SpinUntil(()=>false,1000/60);//每秒60帧
}
}
catch(Exceptione)
{
}
});
}


privatevoidSkElement_PaintSurface(object?sender,SKPaintSurfaceEventArgse)
{
varcanvas=e.Surface.Canvas;
canvas.Clear();
_barrage.Render(canvas,_font,e.Info.Width,e.Info.Height,list);
}

privatevoidButtonBase_OnClick(objectsender,RoutedEventArgse)
{
_barrage.AddBarrage(tbBarrage.Text);
}
}
}

实现效果

WPF+SkiaSharp实现自绘弹幕效果

到此这篇关于WPF+SkiaSharp实现自绘弹幕效果的文章就介绍到这了,更多相关WPF SkiaSharp弹幕内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号