日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > asp.net >内容正文

asp.net

.NET斗鱼直播弹幕客户端(下)

發(fā)布時(shí)間:2023/12/4 asp.net 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 .NET斗鱼直播弹幕客户端(下) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

前言

在上篇文章中,我們提到了如何使用 .NET連接斗魚TV直播彈幕的基本操作。然而想要做得好,做得容易擴(kuò)展,就需要做進(jìn)一步的代碼整理。

本文將涉及以下內(nèi)容:

  • 介紹如何使用?ReactiveExtensions(?Rx),演示這一系列操作用起來,就像寫?HelloWorld一樣簡(jiǎn)單;

  • 用我自制的“準(zhǔn)游戲引擎”?FlysEngine,只需少量代碼,即可實(shí)現(xiàn)桌面彈幕的效果;

  • 最后提供一波“伸手黨”福利,文中所有可運(yùn)行、完整代碼,將按原樣奉上。

Rx.NET

Rx,是 ReactiveExtensions的縮寫,據(jù)說 Rx發(fā)明于 .NET2.0時(shí)代的微軟。那時(shí)候還沒有 async/await。后來,也許由于 RX對(duì)編程語言要求不高(如不要求內(nèi)置 協(xié)程- coroutine), RX反倒在 .NET之外的其它編程語言中大行其道。如 rx.jsRxJava等等。

C#.NET2.0就提供了 yield關(guān)鍵字,然后 3.0提供了 LINQ5.0提供了 async/await,因此很多時(shí)候 RX的意義不大。但在某些情況下(如這種情況),就有意義了,原因請(qǐng)見下圖:

-單數(shù)據(jù)多數(shù)據(jù)
同步TIEnumerable<T>
異步Task<T>Observable<T>/?IAsyncEnumerable<T>

C#協(xié)程支持同步多數(shù)據(jù),異步單數(shù)據(jù),但不支持同步多數(shù)據(jù)( C# 8.0現(xiàn)在已經(jīng)支持 IAsyncEnumerable<T>),本文將使用 Rx來包裝上一篇文章的斗魚TV直播彈幕客戶端。

來先看一波老代碼:

注意剪頭所指的位置,那是基礎(chǔ)代碼“出口”,或者業(yè)務(wù)邏輯“入口”,基礎(chǔ)代碼不能簡(jiǎn)單地 return打斷,因?yàn)樗煌5剌敵鰯?shù)據(jù),這時(shí)就需要像 協(xié)程等編程語言功能,或者 Rx的支持。

Rx-Hello World

首先引入 NuGetSystem.Reactive,一個(gè)簡(jiǎn)單的“異步多值返回”的 Rx示例代碼如下:

Observable.Create<int>(async (o, cancellationToken) => { for (var i = 0; i < 5; ++i) { await Task.Delay(1000); o.OnNext(i); } o.OnCompleted(); })

麻雀雖小,五臟俱全,如代碼所示,幾乎只需在正常代碼外包一層 Rx,即可享受 Rx的好處。

使用?Rx

使用起來就更簡(jiǎn)單了,上篇展示的長(zhǎng)達(dá) 252行代碼的 demo,現(xiàn)在只需一行代碼,即可無侵入式地調(diào)用:

DouyuBarrage.ChatMessageFromUrl("https://www.douyu.com/scboy")

調(diào)用結(jié)果如下(和昨天效果完全一樣):

Rx的其它好處

除了調(diào)用簡(jiǎn)單之外, Rx的擴(kuò)展也非常非常簡(jiǎn)單,比如完成以下操作,以前可能非常麻煩,需要改多處代碼,而使用 Rx,只需像 LINQ一樣加幾個(gè)指令即可:

同時(shí)抓多個(gè)直播間的彈幕

#load ".\barrage.linq" DouyuBarrage.ChatMessageFromUrl("https://www.douyu.com/scboy") .Select(x => new { Room = "scboy", Message = x.Message }) .Merge(DouyuBarrage.ChatMessageFromUrl("https://www.douyu.com/topic/lscs?rid=633019") .Select(x => new { Room = "lalala", Message = x.Message}))

效果如下:

只需一個(gè) Merge指令即可合并兩個(gè)直播間的彈幕( Observable<T>

擴(kuò)展簡(jiǎn)單

比如只想提取特殊的彈幕,或者數(shù)據(jù)之前想做一些轉(zhuǎn)換,可以使用 WhereSelect等數(shù)據(jù)過濾和轉(zhuǎn)換操作符,符合 LINQ的習(xí)慣,非常好用。比如我正常彈幕的提取,其實(shí)是從 JObjectFromUrl轉(zhuǎn)換而來, JObjectFromUrl,又是從 RawFromUrl轉(zhuǎn)換而來,這提高了擴(kuò)展性,又無需修改老代碼,正是所謂“對(duì)擴(kuò)展開放,對(duì)修改封閉”的開放-封閉原則:

public IObservable<JToken> JObjectFromUrl(string url) => RawFromUrl(url).Select(MsgTool.DecodeStringToJObject); public IObservable<Barrage> ChatMessageFromUrl(string url) => JObjectFromUrl(url) .Where(x => x["type"].Value<string>() == "chatmsg") .Select(Barrage.FromJToken);

又比如可能我只想提取彩色彈幕,我只需 ChatMessageFromUrl().Where(x=>x.Color!=0xffffff)即可,非常方便。

桌面彈幕

這可能是另一個(gè)主題——實(shí)時(shí)渲染,用到了我自己寫的“準(zhǔn)游戲引擎” FlysEngine,因此需要安裝 NuGet包:FlysEngine.Desktop

桌面彈幕不同于 網(wǎng)頁彈幕,只能在網(wǎng)頁中顯示,而 桌面彈幕可以直接顯示在屏幕最上方。有些公司年會(huì)可能用到了 桌面彈幕,這無疑增加了主持人與觀眾們的互動(dòng),提高了群眾參與的積極性。

注意:本文中所說 FlysEngine的實(shí)質(zhì)是 Direct2DWindowsAPI- UpdateLayeredWindowIndirect函數(shù)。如果不想使用 FlysEngine,完全可以使用其它方式代替。最簡(jiǎn)單的方式是使用 WPF,然后設(shè)置 AllowsTransparency=true,但這樣性能會(huì)差一些。本文介紹的方法, CPU使用率將保持在 0%左右!

桌面彈幕的要點(diǎn)

  • 渲染文字?DirectWrite

  • 文字移動(dòng)?將文字從屏幕右邊移動(dòng)到左邊;

  • 檢測(cè)是否離開屏幕?如果屏幕上不顯示彈幕,即可將彈幕刪除;

  • 初始位置確定?如果一行顯示不下,則將彈幕放在下一行。

渲染文字

渲染文字一般是通過 DirectWrite,它性能很好,功能也強(qiáng)大。FlysEngineDirectWrite封裝了,因此直接用便是。

注意:DirectWrite不僅渲染文字,還提供了 .Metrics屬性,可以計(jì)算文字渲染之后的大小,這會(huì)讓事情變得容易很多。

文字移動(dòng)

文字移動(dòng)首先需要一個(gè)位置,隨著時(shí)間變化,將該位置的 X坐標(biāo)不段減少即可。這可以通過 FlysEngine中的 UpdateLogic事件實(shí)現(xiàn),它會(huì)定期調(diào)用,傳入一個(gè) floatdt,代碼離上一次調(diào)用 UpdateLogic的時(shí)間間隔。因此可以利用這個(gè) dt變量,計(jì)算是彈幕的新位置:

public void MoveLeft(float dt, float speed) { Position.X -= dt * speed; }

檢測(cè)是否離開屏幕

由于我們已知彈幕是矩形,(很顯然屏幕也是矩形)因此這個(gè)檢測(cè)比較簡(jiǎn)單,直接判斷文字的 右邊緣是否 大于0即可。

也由于需要經(jīng)常/頻繁地刪除在屏幕上的彈幕對(duì)象,因此最好儲(chǔ)存彈幕的數(shù)據(jù)結(jié)構(gòu)別使用 O(n)的集合,如最好別使用 List<T>,它是線性表。我這里使用的是 鏈表.NET的鏈表實(shí)現(xiàn)是 LinkedList<T>(很多人以為是 List<T>)。

多說一句,鏈接的遍歷算法如下( while循環(huán)):

var node = barrages.First; while (node != null) { var next = node.Next; // do work here node = next; }

之所以不使用 foreach來遍歷,因?yàn)檫@樣遍歷可以實(shí)現(xiàn)高性能的“邊遍歷、邊刪除”的實(shí)現(xiàn)。

初始位置確定

這一點(diǎn)思想需要多想想,需要從第一行開始,從后往前看,看最后那一邊彈幕是否大于屏幕右邊。只要想清楚了,代碼很容易:

float GetNewY() { float y = 0; while (barrages.Reverse().Where(x => x.Position.Y == y).Select(x => x.Rect.Right).FirstOrDefault() > form.Width) { y += FontSize; } return y; }

有了這些,就可以愉快地感受屏幕彈幕啦!

彩色?emoji表情

Direct2D支持——但默認(rèn)不顯示彈幕 emoji表情:

要多加一個(gè)枚舉讓其支持:

target.DrawText("????????????", res.TextFormats[36], rectangle, res.GetColor(Color.Blue), Direct2D.DrawTextOptions.EnableColorFont); // 重點(diǎn)

支持彩色 emoji表情后,效果如下:

結(jié)

最終效果昨天已經(jīng)見過了,如下:

本文(包括上文)所用的代碼如下:

id鏈接
老式代碼https://github.com/sdcb/blog-data/blob/master/2019/20191013-douyu-barrage-with-dotnet-2/barrage_tranditional.linq
新式代碼https://github.com/sdcb/blog-data/blob/master/2019/20191013-douyu-barrage-with-dotnet-2/barrage.linq
合并彈幕https://github.com/sdcb/blog-data/blob/master/2019/20191013-douyu-barrage-with-dotnet-2/barrage-combine.linq
桌面彈幕https://github.com/sdcb/blog-data/blob/master/2019/20191013-douyu-barrage-with-dotnet-2/desktop-barrage.linq

喜歡的朋友請(qǐng)“刷一波666???”,并關(guān)注我的微信公眾號(hào):【DotNet騷操作】

總結(jié)

以上是生活随笔為你收集整理的.NET斗鱼直播弹幕客户端(下)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。