SkiaSharp 自繪彈幕效果

?SkiaSharp 自繪彈幕效果

控件名:SkiaSharpBarrage

作者: 驚鏵

原文鏈接: ? ?https://github.com/yanjinhuagood/SkiaSharpBarrage

  • 框架使用.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 彈幕消息類如下:

using?System;
using?SkiaSharp;namespace?SkiaSharpBarrage
{///?<summary>///?????msg?info///?</summary>public?class?MsgInfo{private?string?_msg;public?string?GUID;public?MsgInfo(string?msg,?SKTypeface?_font,?float?windowsWidth){_msg?=?msg;var?_random?=?new?Random();var?skColor?=?new?SKColor((byte)?_random.Next(1,?255),(byte)?_random.Next(1,?255),?(byte)?_random.Next(1,?233));using?var?paint?=?new?SKPaint{Color?=?skColor,Style?=?SKPaintStyle.Fill,IsAntialias?=?true,StrokeWidth?=?2};paint.Shader?=?SKShader.CreateLinearGradient(new?SKPoint(0,?0),new?SKPoint(1,?1),new[]?{SKColors.Transparent,?skColor},new?float[]?{0,?1},SKShaderTileMode.Repeat);using?var?paintText?=?new?SKPaint{Color?=?SKColors.White,IsAntialias?=?true,Typeface?=?_font,TextSize?=?24};var?textBounds?=?new?SKRect();paintText.MeasureText(msg,?ref?textBounds);var?width?=?textBounds.Width?+?100;SKImage?skImage;using?(var?bitmap?=?new?SKBitmap((int)?width,?40,?true))using?(var?canvas?=?new?SKCanvas(bitmap)){canvas.DrawRoundRect(0,?0,?width,?40,?20,?20,?paint);canvas.DrawText(msg,?width?/?2?-?textBounds.Width?/?2,?bitmap.Height?/?2?+?textBounds.Height?/?2,paintText);var?image?=?SKImage.FromBitmap(bitmap);skImage?=?image;}SKImage?=?skImage;Width?=?width;X?=?windowsWidth?+?Width;CanvasWidth?=?windowsWidth;CostTime?=?TimeSpan.FromMilliseconds(Width);GUID?=?Guid.NewGuid().ToString("N");}public?float?X?{?get;?set;?}public?float?Y?{?get;?set;?}public?float?Width?{?get;?set;?}public?float?CanvasWidth?{?get;?set;?}public?SKImage?SKImage?{?get;?set;?}public?float?MoveNum?=>?CanvasWidth?/?(float)?CostTime.TotalMilliseconds;public?TimeSpan?CostTime?{?get;?set;?}///?<summary>///?????定時調用,移動指定距離///?</summary>public?void?Move(out?string?guid){guid?=?string.Empty;X?=?X?-?MoveNum;if?(X?<=?-Width)guid?=?GUID;}}
}

2) 新建 Barrage.cs 類如下:

using?System.Collections.Generic;
using?System.Linq;
using?SkiaSharp;namespace?SkiaSharpBarrage
{public?class?Barrage{private?readonly?SKTypeface?_font;private?readonly?List<MsgInfo>?_MsgInfo;private?int?_num,?_index;private?double?_right,?_top;private?float?_width;private?readonly?float?_height;public?Barrage(SKTypeface?font,?float?width,?float?height,?List<string>?strList){_width?=?width;_height?=?height;_font?=?font;_num?=?(int)?height?/?40;_MsgInfo?=?new?List<MsgInfo>();foreach?(var?item?in?strList)?BuildMsgInfo(item);}private?void?BuildMsgInfo(string?text){_index++;if?(_right?!=?0)_width?=?(float)?_right;var?model?=?new?MsgInfo(text,?_font,?_width);_right?=?_right?==?0???_height?+?model.Width?:?_right;var?y?=?_height?-?40;_top?=?_top?+?40?>=?y???40?:?_top;model.Y?=?(float)?_top;_MsgInfo.Add(model);_top?+=?60;}public?void?AddBarrage(string?text){BuildMsgInfo(text);}public?void?Render(SKCanvas?canvas,?SKTypeface?font,?int?width,?int?height,?List<string>?strList){for?(var?i?=?0;?i?<?_MsgInfo.Count;?i++){var?info?=?_MsgInfo[i];var?guid?=?string.Empty;info.Move(out?guid);if?(!string.IsNullOrEmpty(guid)){var?model?=?_MsgInfo.FirstOrDefault(x?=>?x.GUID?==?guid);_MsgInfo.Remove(model);}canvas.DrawImage(info.SKImage,?info.X,?info.Y);}}}
}

3) MainWindow.xaml.cs 如下:

<wpfdev:Window?x: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"><Grid?Margin="4"><Grid.RowDefinitions><RowDefinition?/><RowDefinition?Height="Auto"?/></Grid.RowDefinitions><MediaElement?Stretch="Uniform"?Grid.RowSpan="2"Name="myMediaElement"?/><skia:SKElement?x:Name="skElement"?/><Grid?Grid.Row="1"?Name="MyGrid"><Grid.ColumnDefinitions><ColumnDefinition?/><ColumnDefinition?Width="Auto"?/></Grid.ColumnDefinitions><TextBox?wpfdev:ElementHelper.IsWatermark="True"x:Name="tbBarrage"wpfdev:ElementHelper.Watermark="請彈幕內容"?/><Button?Grid.Column="1"?Style="{StaticResource?PrimaryButton}"Content="發射彈幕"?Margin="4,0,0,0"Click="ButtonBase_OnClick"?/></Grid></Grid>
</wpfdev:Window>

3) 邏輯 MainWindow.xaml.cs 如下:

using?System;
using?System.Collections.Generic;
using?System.IO;
using?System.Linq;
using?System.Threading;
using?System.Threading.Tasks;
using?System.Windows;
using?SkiaSharp;
using?SkiaSharp.Views.Desktop;namespace?SkiaSharpBarrage
{///?<summary>///?????Interaction?logic?for?MainWindow.xaml///?</summary>public?partial?class?MainWindow{private?readonly?Barrage?_barrage;private?readonly?SKTypeface?_font;private?readonly?List<string>?list?=?new?List<string>();public?MainWindow(){list.Add("2333");list.Add("測試彈幕公眾號:WPF開發者");list.Add("很難開心");list.Add("LOL~");list.Add("青春記憶");list.Add("bing");list.Add("Microsoft");InitializeComponent();var?index?=?SKFontManager.Default.FontFamilies.ToList().IndexOf("微軟雅黑");_font?=?SKFontManager.Default.GetFontStyles(index).CreateTypeface(0);_barrage?=?new?Barrage(_font,?(float)?Width,?(float)?Height?-?(float)?MyGrid.ActualHeight,?list);skElement.PaintSurface?+=?SkElement_PaintSurface;Loaded?+=?delegate{myMediaElement.Source?=new?Uri(Path.Combine(AppDomain.CurrentDomain.BaseDirectory,?"Leagueoflegends.mp4"));};_?=?Task.Run(()?=>{try{while?(true){Dispatcher.Invoke(()?=>?{?skElement.InvalidateVisual();?});_?=?SpinWait.SpinUntil(()?=>?false,?1000?/?60);?//每秒60幀}}catch?(Exception?e){}});}private?void?SkElement_PaintSurface(object??sender,?SKPaintSurfaceEventArgs?e){var?canvas?=?e.Surface.Canvas;canvas.Clear();_barrage.Render(canvas,?_font,?e.Info.Width,?e.Info.Height,?list);}private?void?ButtonBase_OnClick(object?sender,?RoutedEventArgs?e){_barrage.AddBarrage(tbBarrage.Text);}}
}
249f047005f0a31ecdf3d8c7be90ccd7.gif

Github|SkiaSharpBarrage[1]
Gitee|SkiaSharpBarrage[2]

參考資料

[1]

Github|SkiaSharpBarrage: https://github.com/yanjinhuagood/SkiaSharpBarrage

[2]

Gitee|SkiaSharpBarrage: https://gitee.com/yanjinhua/SkiaSharpBarrage

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/282473.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/282473.shtml
英文地址,請注明出處:http://en.pswp.cn/news/282473.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

JavaScript中this指向

一.重點來了&#xff0c;this指向問題&#xff1a;1.this指向之普通函數。 2.this指向之對象 3.this指向之構造函數 4.this指向之&#xff08;call,apply&#xff09;動態更改this指向。 二.具體分析如下 1.普通函數 // 第23行的調用者為null,this指向也為null,// 所以這時js把…

【python】python中的定義類屬性和對像屬性

python中變量是沒有類型的可以綁定任意類型&#xff0c;但是在語法上不能聲明變量。 那我們怎麼來聲名一個變量呢&#xff1f; fNone 這樣我們給著個變量綁定了以各None類型&#xff0c;我們隨時可用重新綁定其它類型。這樣我們起到了預先聲名變量的效果。 類中如何去定義類的…

提交Form表單,submit之前做js判斷處理

效果:在點擊提交按鈕時,首先進行js判斷, 如果不符合條件,則alert出提示信息,并return false. 主要點就在于給form表單添加一個onsubmit事件. 在onsubmit事件中定義的函數里進行js驗證處理.代碼 : <!DOCTYPE html> <html lang"en"> <head><meta …

如何在Windows上一鍵部署PaddleOCR的WebAPI服務

PaddleOCR旨在打造一套豐富、領先、且實用的OCR工具庫&#xff0c;助力開發者訓練出更好的模型&#xff0c;并應用落地。官方開源項目地址&#xff1a;https://github.com/PaddlePaddle/PaddleOCR一定會有小伙伴們看完不知道如何部署與應用&#xff0c;怎么才能融入到自己的產品…

微軟為 Visual Studio 擴展添加對 Arm64 的支持

微軟在 6 月份推出了支持 Arm64 架構的 Visual Studio&#xff0c;這是第一個原生支持在基于 Arm 的處理器上構建和調試 Arm64 應用程序的 Visual Studio 版本。近日&#xff0c;他們宣布為 Visual Studio 擴展也添加了對 Arm64 的支持&#xff0c;因此開發者可在 Arm64 Visual…

WIN10 查看已經連接的wifi的密碼

命令行: 1. 顯示以前連接過的wifi2. 將wifi配置存入文件中3. 查看剛剛保存的wifi配置的文件這樣,我們就可以看到連接的wifi名稱和wifi密碼了.

ubantu 重啟mysql

如何啟動/停止/重啟MySQL一、 啟動方式1、使用 service 啟動&#xff1a;service mysql start2、使用 mysqld 腳本啟動&#xff1a;/etc/inint.d/mysql start3、使用 safe_mysqld 啟動&#xff1a;safe_mysql&二、停止1、使用 service 啟動&#xff1a;service mysql stop2…

C++ 反射機制的簡單實現

C并不支持反射機制&#xff0c;只能自己實現。 如果需要實現字字符串到函數到映射&#xff0c;一定要使用到函數指針。 簡單實現反射機制&#xff0c;根據字符串來構造相應到類。主要有以下幾點&#xff1a; (1) 可以使用map保存字符從到函數指針到映射。 (2) 工廠類提供字符串…

微軟與 Canonical 合作,將 systemd 引入 WSL

微軟和 Canonical 聯合宣布&#xff0c;systemd 現在可以在 Windows Subsystem for Linux&#xff08;WSL2&#xff09;中運行了&#xff0c;此舉可以讓用戶在 Windows 設備上獲得更加全面的 Linux 體驗。systemd 的作者 Lennart Poettering 在 7 月份離開紅帽并加入了微軟&…

vsftpd配置

1.) yum install -y vsftpd 2.) useradd -g ftp -s /sbin/nologin afcupload (默認生成/home/afcupload, 可使用 -d參數自定義主目錄生成位置) 3.) passwd afcupload 4.) chgrp -R ftp afcupload 5.) chown -R afcupload:ftp afcupload 6.) chmod -R 700 afcupload 4.) 修…

2017.9.6數學

集合&#xff1a;一個可以代表一類事物或數據的代詞。&#xff08;個人定義&#xff09; &#xff08;其內容帶有輔助功效【個人記不下來】&#xff09;自然數&#xff1a;所有的非負整數。 有理數&#xff1a;是可以用正數和分數代表的數。實數&#xff1a;包括有理數和無理數…

.NET 反向代理-YARP 根據域名轉發

編者&#xff1a;fastgithub 就是基于YARP使用域名做轉發邏輯的。 前段時間發布過一個關于 YARP 的簡單介紹&#xff0c;感興趣的小伙伴恭請移步看看 .NET 反向代理-YARP 作為反向代理&#xff0c;必不可少的當然是根據域名代理轉發啦&#xff0c;毫無疑問&#xff0c;YARP…

第一個python小游戲

guess int(input("猜一猜寶寶心目中的數字是多少:")) secret 8 while guess !secret:guess int(input("哎呀猜錯了,重新猜一猜寶寶心目中的數字是多少:"))if guess secret:print("你真厲害,居然猜對了")print("哼,猜對了也不給你獎勵&q…

理論實踐:循序漸進理解AWR細致入微分析性能報告

1. AWR 概述 Automatic Workload Repository(AWR) 是10g引入的一個重要組件。在里面存貯著近期一段時間內&#xff08;默認是7天&#xff09;數據庫活動狀態的詳細信息。 AWR 報告是對 AWR 視圖進行查詢而得到的一份自動生成的報告。可以通過下面的腳本手工得到一份 AWR 報告。…

java 動態代理

動態代理 Proxy動態代理是基于實現接口的,被代理類實現了某個功能接口, 代理類實現invocationHandler 接口重寫invoke(Object proxy, Method method , class 代理類) 用Proxy.newProxyInstance(類加載器, 被代理類實現的接口的集合, invocationhandler 的實現類)來創建代理類對…

mysql sql語句書寫之面試部分

要求一 :查詢時,將用戶的手機號碼(比如1331234567)顯示為133***4567 這是在交流群里看到別人發的一個面試題,我本人非常反感直接在查詢時進行處理數據的,查詢出來再處理不好嗎,但是面試題要求是這樣. 這里,簡單的寫了兩個表關聯查詢,然后把手機號碼進行處理顯示出來select a.ui…

Linux中寫入ISO鏡像

1、查看U盤標識 fdisk -l2、寫入鏡像到U盤 sudo dd if/home/***.iso of/dev/sdb轉載于:https://www.cnblogs.com/katzepunk/p/7492813.html

Linux上用戶之間對話

Linux上用戶之間對話 昨天想在CentOS7上與另外一個用戶對話&#xff0c;但把命令忘記了&#xff0c;特此記錄下來。 Write命令 write命令是單向發送一條消息給同機器的Linux用戶。首先通過who命令查看誰在線。 root tty7 2017-03-15 14:38 (:0) root pts/20 …

Redis --數據類型 [1]

一 string 類型 (最簡單常用的類型) string是redis最基本的類型&#xff0c;你可以理解成與Memcached一模一樣的類型&#xff0c;一個key對應一個value。二 Hash類型(哈希) Redis hash是一個string類型的field和value的映射表&#xff0c;hash特別適合用于存儲對象。三 List(列…