基于聲網(wǎng)Flat實現(xiàn)“成語解謎”的Web小游戲-創(chuàng)新互聯(lián)

前言

成都創(chuàng)新互聯(lián)主營宣城網(wǎng)站建設(shè)的網(wǎng)絡(luò)公司,主營網(wǎng)站建設(shè)方案,成都app開發(fā),宣城h5小程序制作搭建,宣城網(wǎng)站營銷推廣歡迎宣城等地區(qū)企業(yè)咨詢

本文作者趙杭天。他參加了“2022 RTE(Real-time Engagement,實時互動) 編程挑戰(zhàn)賽”——“賽道二 場景化白板插件應(yīng)用開發(fā)” , 并憑借作品“成語解謎”獲獎?!俺烧Z解謎”是一個基于互動白板 SDK 的互動小游戲應(yīng)用。通過前端編碼、調(diào)用白板 API 能力、定制化后端邏輯等,實現(xiàn)了一個老少咸宜、寓教于樂的成語解謎游戲。其中的流程、步驟與相關(guān)的技術(shù)棧在白板互動應(yīng)用開發(fā)上具有一定的通用性。本文將分享該項目的開發(fā)過程,包括一些關(guān)鍵功能的實現(xiàn),希望與各位同學(xué)一起交流,共同進(jìn)步。大家可以訪問 game.willtian.cn/idiom2/,在線體驗該作品。

01 選題

為什么要做這樣一款小游戲?有幾個原因。

零幾年剛上小學(xué)的時候,第一次接觸到電腦和教育軟件,里面有一些小游戲,真的會被引導(dǎo)去學(xué)習(xí)到一些東西,比如一些名詞概念、科學(xué)常識,對小孩子挺有幫助。

“白板”兩個字,給我的第一感覺是回到了校園。在學(xué)校里都能遇到很好的同學(xué)和老師,有很多美好的回憶。小時候喜歡讀成語字典,就像看故事書,然后在教室里也會玩一些類似成語解謎這樣的字謎游戲。

20 年疫情在家會玩一些益智休閑游戲,能玩到自己做的游戲,感覺很開心。另外,這類游戲很適合碎片化的時間,并且能讓用戶學(xué)習(xí)到一些東西。尤其適合小朋友和喜歡休閑游戲的大朋友;對于長輩,操作上比較友好,內(nèi)容也容易引起共鳴。從市場和社會上看,都是有價值的。

02 什么是互動白板 SDK

互動白板的正式名稱叫聲網(wǎng) Flat,官方的解釋是:“個人老師可直接使用的在線授課軟件,開箱即用,前后端完全開源,快速搭建簡約美觀的在線教室”。它運行起來初始界面長這樣子:

圖片

互動白板初始界面

左側(cè)工具欄圖標(biāo)告訴我們,這是一個可以在上面寫寫畫畫的東西。它具有這些特點:

1.互動性,每個房間對應(yīng)一個互動白板,默認(rèn)情況下,房間內(nèi)所有人都可以操作白板,并且交互效果所有人可見的;

2.擴(kuò)展性,除基本的書寫、涂鴉功能外,互動白板支持自定義應(yīng)用(點擊工具欄最下面的“田”字型圖標(biāo)查看所有應(yīng)用);

個人認(rèn)為支持各種 APPs 是 Flat 互動白板最強(qiáng)大的功能,通過 Flat 提供的 SDK 能力,我們可以實現(xiàn)許多復(fù)雜的功能的白板應(yīng)用。

圖片

每個房間對應(yīng)一個白板

互動白板的內(nèi)容,包括文字、涂鴉以及 App,可由 SDK 中的 Window Manager 對象來控制。可以通過官方提供的 demo 來快速熟悉一個App開發(fā)流程。利用 Window Manager 的 API 接口,我們可以完成應(yīng)用實例通信等操作,具體例子請見后文。

03 架構(gòu)規(guī)劃

在展開具體例子前,先介紹“成語解謎“項目的整體框架。如下圖,我們將前后端分離的方式,前端專注頁面繪制與互動,后端專注題目生成與結(jié)果判斷。用戶訪問前端頁面無需下載全量詞庫,大幅提高訪問速度。前端利用 Window Manager 的 context API 接口,在聲網(wǎng)服務(wù)器上進(jìn)行 App 實例的同步與廣播。

圖片

前端 App 實例與聲網(wǎng)服務(wù)、游戲后端的通信

04 界面設(shè)計

我們采用“設(shè)計驅(qū)動”的開發(fā)模式,首先畫出設(shè)計圖,然后一步一步的把腦海里的畫面通過代碼變成現(xiàn)實 :

圖片

設(shè)計草圖

游戲主界面設(shè)計圖如上,交互設(shè)計如下:

1.謎面隨機(jī)出現(xiàn)若干個成語,這些成語由公共字進(jìn)行關(guān)聯(lián),作為生成的約束條件;

2.成語間關(guān)聯(lián)的公共字被挖走并隨機(jī)排列,作為候選字;

3.用戶通過“觸摸->拖拽->放置” 交互操作候選字的完成對謎面的補(bǔ)全;

4.“提交”得到對用戶謎面的判斷結(jié)果,分別對應(yīng)通關(guān)與未通過的場景;

5.“重置”將謎面和候選字恢復(fù)到游戲初始狀態(tài);

6.“答案”通過彈窗展示謎面包含成語的信息,包括字型、字音、釋義、出處以及用例;

(對于比較復(fù)雜的場景,建議把場景直接切換的邏輯都畫出來,形成一個比較完成的需求文檔)

抓住主要矛盾,優(yōu)先完成核心功能的開發(fā),實現(xiàn)產(chǎn)品原型后,再繼續(xù)打磨,解決次要矛盾。

05 前端開發(fā)

完成游戲基本界面設(shè)計后,我們開始選擇前端框架并完成界面開發(fā)。

適合游戲開發(fā)的前端框架很多,Three.js、Phaser、Cocos2d-js等,針對具體需求選擇。個人感覺 Three.js 比較底層,用來寫游戲代碼量可能比較大。Cocos2d-js 封裝程度較高,需要熟悉Cocos的工具鏈,對于非專業(yè)做游戲的同學(xué)而言,上手難度不低而且技術(shù)可遷移性不高。

這里選擇的是 PixiJS,PixiJS 是一個基于 2D WebGL 的渲染引擎,兼容HTML5 Canvas。它有一系列合理、整潔的 APIs,支持 Sprite,將對象抽象為各種層級的 Container。類似 React/Vue 數(shù)據(jù)驅(qū)動的設(shè)計,在 PixiJS 中,通過修改 Container 的參數(shù),即可產(chǎn)生用戶界面的變化。Pixi 的 API 實際上是 Flash 率先使用的,經(jīng)過反復(fù)改進(jìn),有 Flash 經(jīng)驗的同學(xué)極易上手。

入口

以“成語解謎”為例,我們來介紹編碼的一些細(xì)節(jié)。首先我們找到自己代碼的掛載點,根據(jù)文檔給出的 demo 或者本文提供的例子,找到這個入口文件:

圖片

自定義應(yīng)用的入口(src/index.js)

注意到const box = context.getBox();這一行,box 對應(yīng)這個應(yīng)用打開的窗口。我們通過box.mountContent向窗口掛載了包含我們的 App 實例的 div 容器$content。

App 類

接下來,我們定義 App 類。關(guān)鍵代碼如下。

圖片

App 類(src/app.js)App 類中持有一個PIXI.Application實例,此外 App 類還持有一些相對 App 維度上的變量與方法,例如:從setup(見 src/index.js)里透傳的過來的context(用于調(diào)用 Window Manager 的 API)、App 實例的 id(用于前端區(qū)分 App 實例)、layers(圖層)、resizeObserver(用于監(jiān)聽界面變化并自適應(yīng)布局)getRandomString(生成每局游戲的 token,用于后端交互)、storage(用于在聲網(wǎng)服務(wù)器上存取App的狀態(tài))等。

Scene類

我們?yōu)槊總€場景寫一個 Scene 類,這里只有一個場景。App 類實例化了 Scene 類,并使用addChildscene實例加入渲染。接下來我們?yōu)橹鹘缑鎸懸粋€ Scene。關(guān)鍵代碼如下:

圖片

Scene 類(src/scene.js)

在 Scene 的構(gòu)造函數(shù)里實例化了“提交”、“重置”和“答案”三個按鍵,并定義了對應(yīng)事件。我們在 Scene 里實例化了類 Idiom,一個 Idiom 實例對應(yīng)一套字謎與候選字,Idiom 又有子對象 Piece,Piece 對應(yīng)具體的每一個字塊。由于 Scene 的按鍵事件函數(shù)的需要,我們把Piece 狀態(tài)的保存/讀取方法寫在了 Scene 類里。

Idiom 類 & Piece 類

我們在 Idiom 類里定義了謎面與候選字的(Piece)字塊生成方法、重置方法、拖拽生效方法。在 Piece 類中實現(xiàn)拖拽時的外觀行為。

圖片

Idiom 類(src/idiom.js)

圖片

Piece 類(src/piece.js)

整體效果圖片

主界面運行效果

06 后端開發(fā) 實例關(guān)聯(lián)與隔離

由于詞庫比較大,用戶每次加載完整詞庫會消耗較多的帶寬和時間,對用戶體驗影響較大。我們通過搭建后端將謎面的獲取、提交結(jié)果的驗證、答案的獲取,進(jìn)行服務(wù)化,提升用戶體驗。

如上文“架構(gòu)規(guī)劃”所述,我們和每個 App 實例均持有一個 token,用于與后端通信時,對應(yīng)上后端的游戲?qū)嵗龑ο?。UserGames 的 key 即為 token,在接受到瀏覽器發(fā)來的請求后,后端會在 UserGames 中查找相應(yīng)的游戲?qū)嵗?BoardGame,并得到當(dāng)前的游戲狀態(tài),包括謎面 table、答案 answers、答案解析 answerDetail 等。

圖片

使用 UserGames 的 key(token) 來隔離游戲?qū)嵗?,并與前端 App 實例關(guān)聯(lián)

謎面生成

謎面是怎么生成的呢,基本的算法思路是:

1.預(yù)處理成語庫,建立所有成語的字索引NthOfChar *[]map[rune][][]rune,保存第 n 個字為 m 的信息;

2.使用 DFS 遞歸搜索謎面。在當(dāng)前成語找一個字 k 作為下一個生成開始的節(jié)點,根據(jù)約束條件,選定新成語以及新成語擺放位置:

a. k 必須出現(xiàn)在新成語中;

b. 新成語放置后須保證當(dāng)前謎面不被破壞;

搜索的過程中使用索引NthOfChar實現(xiàn)剪枝;

多解兼容

我們通過生成算法形成的謎面同時會產(chǎn)生 1 個唯一的答案。但實際上可能答案并不唯一,尤其是在成語較多時,交換某幾個字,亦可生成合理的答案。針對這種情況,我需要逐個校驗用戶提交的成語。若成語庫里總共有 N 個成語,對成語庫的成語生成字典樹 Trie,可以將查找時間復(fù)雜度從 O(N) 下降到 O(1),最多 4 次搜索。

全局單例

負(fù)責(zé)游戲?qū)嵗傻慕Y(jié)構(gòu)體 GlobalBoard 儲存了全量成語以及中間數(shù)據(jù)信息,作為全局單例,減少內(nèi)存拷貝;對于每個問題(謎面)獲取的請求,直接返回 GlobalBoard 生成結(jié)果的拷貝。

圖片

使用全局單例與狀態(tài)拷貝的方式優(yōu)化內(nèi)存使用

07 App 實例通信 實例狀態(tài)的同步

到目前為止,我們基本實現(xiàn)單用戶的游戲。但是當(dāng)我們打開兩個瀏覽器 tab 模擬多用戶操作時會發(fā)現(xiàn),App 的交互僅對當(dāng)前用戶生效,其他用戶是無感知的。表現(xiàn)為,A 用戶打開 App,拖拽到 App 窗口合適的位置,開始游戲,將候選詞與空字塊交換,然后提交;同時,B 用戶在同一房間,卻只看到了 A 打開 App,拖拽 App,看到的 App 內(nèi)容與 A 的 App 展示內(nèi)容并不同步,也感知不到 A 對 App 做的操作(能看到 A 鼠標(biāo)光標(biāo)運動,這是 Flat 兜底的同步邏輯)。

針對當(dāng)前問題,我們可以自然想到必須有某種機(jī)制,使用戶在本地對 App 實例操作后,同步狀態(tài)到某個所有用戶可訪問的遠(yuǎn)端服務(wù)里,然后通知所有用戶將遠(yuǎn)端服務(wù)儲存的狀態(tài)同步到本地 App 實例中,重新渲染 App 畫面,這樣才可以實現(xiàn)多用戶的互動。

談到這里,大家可能會想到,那我們是否可以在自己寫的后端服務(wù)中加入同步功能呢?讓我們構(gòu)思一下做這樣的同步功能需要做哪些事:

1.設(shè)計一套通信機(jī)制,本地實例能夠主動感知遠(yuǎn)端狀態(tài)的更新;

2.處理好超時、重連、弱網(wǎng)等問題;

3.延遲足夠低,能接受業(yè)務(wù)波動的負(fù)載;

4.服務(wù)經(jīng)過充分的測試,足夠穩(wěn)定;

仔細(xì)思考會發(fā)現(xiàn),穩(wěn)定可靠的實時通信其實是一個比較大的課題,并不應(yīng)該成為實現(xiàn)業(yè)務(wù)、產(chǎn)生業(yè)務(wù)價值的一個主要工作,換言之,自己造輪子的投入產(chǎn)出并不高。聲網(wǎng)在實時網(wǎng)絡(luò)通信領(lǐng)域耕耘多年,基于其技術(shù)積累,在 Flat 項目中提供一系列非常有用的通信 APIs,這些 APIs 設(shè)計與 React 很像,比較容易上手。下面我們通過這些 APIs 進(jìn)行同步與廣播,解決互動性的問題。

讓我們回到前端代碼里,在 app.js 的 App 類做一些修改:

圖片

初始化實例的storage

我們給每個 App 實例持有一份storage對象,storage對象來自白板應(yīng)用創(chuàng)建時得到的 context。這里的storage.ensureState用以確保storage.state包含某些初始值。context.storage實際上關(guān)聯(lián)了遠(yuǎn)端服務(wù)的一個存儲實例,它實時監(jiān)聽到本地 storage 的變化,當(dāng)變化發(fā)生時,將自動同步最新的 storage 到服務(wù)端。即使是不同的用戶,同一房間相同的應(yīng)用實例,實際上會對應(yīng)到同一個遠(yuǎn)端 storage,畫一張圖直觀一些:

圖片

storage關(guān)聯(lián)關(guān)系圖

弄明白 storage 的同步特性,我們要做的就是在游戲狀態(tài)發(fā)生變化的時候更新 context.storage,以及增加監(jiān)聽 context.storage 變化的回調(diào)事件,將遠(yuǎn)端 context.storage 同步到游戲(應(yīng)用實例)中。

我們將狀態(tài)的 push/pull 方法做封裝,使代碼更利于維護(hù)。這里的storage.setState和 React 的 setState 類似,更新storage.state并同步到所有客戶端。

圖片

圖片

游戲狀態(tài) ->遠(yuǎn)端storage

增加監(jiān)聽事件,addStateChangedListener在有人調(diào)用storage.setState()后觸發(fā) (包含當(dāng)前storage) ,在這里我們編寫將遠(yuǎn)端storage同步到游戲狀態(tài)的邏輯。

圖片

遠(yuǎn)端 storage ->游戲狀態(tài)

分布式鎖

設(shè)想這么一個場景,我們的用戶需要共同操作同一個 App 實例,比如共同完成一場解謎游戲,用戶 A、B 幾乎同時點擊了“提交”,后端接到提交請求,判斷答案正確,然后為游戲?qū)嵗职l(fā)新的題目,此時,若后端在為 A 分發(fā)題目的過程中 B 的請求到達(dá),且也給 B 分發(fā)新的題目,會導(dǎo)致 A、B 前端收到不一致的新題目。此外,還有一種場景,用戶 C 因為弱網(wǎng)或其他原因,提交后未馬上收到反饋,重復(fù)頻繁地點擊提交,將導(dǎo)致發(fā)起重復(fù)請求,用戶較多且請求時間集中時,容易導(dǎo)致負(fù)載波動,影響服務(wù)質(zhì)量。

因此,我們有必要為“提交”增加一個分布式的鎖,使在某個 App 實例里,所有時間里,只能由一個用戶提交。

圖片

通過 context.storage 實現(xiàn)分布式鎖

實例廣播

當(dāng)對于某個 App 實例,某個用戶提交通過得到新的游戲狀態(tài)(新的謎面與候選詞等)后,需要將狀態(tài)同步給其他用戶。實際上我們可以將獲取新游戲與狀態(tài)寫入本地游戲這兩步分離,在進(jìn)行廣播時自己也會接收到,所有包括自己在內(nèi)的用戶監(jiān)聽到廣播立即寫入本地游戲。如圖所示:

圖片

先獲取新狀態(tài)再通過廣播進(jìn)行狀態(tài)同步的流程

我們可以利用廣播與監(jiān)聽API context.dispatchMagixEvent(event, payload)context.addMagixEventListener(event, listener)上述功能:

圖片

圖片

在游戲狀態(tài)發(fā)生變化(提交成功和重置)時廣播

圖片

監(jiān)聽廣播發(fā)生,并根據(jù)具體事件做不同操作

至此,我們的跨越前后端的實例通信部分也完成了,實現(xiàn)了用戶對 App 實例操作時交互的同步,并處理了如同時、重復(fù)提交這類的并發(fā)問題。此類問題在其他互動應(yīng)用的開發(fā)中也普遍存在,這里提供了一些參考。

08 小結(jié)

聲網(wǎng) Flat 開源項目提供了白板 SDK,支持開發(fā)自定義 App,為在線教育和白板應(yīng)用提供了巨大的想象空間。本次分享從一個初次接觸 Flat 開發(fā)者的視角,介紹了互動白板的特點,并從基于實際例子——完成一款互動小游戲,分享了小游戲前端框架的選擇與使用、整體架構(gòu)設(shè)計思路、后端開發(fā)流程等。同時介紹一些實用的 window-manager API,并在實戰(zhàn)中如何使用這些 APIs 來快速解決一些原本比較復(fù)雜的問題。希望能對大家開發(fā)Flat白板自定義應(yīng)用、在線互動小游戲中提供一些參考和幫助。由于時間倉促,仍存在許多有待完善和優(yōu)化的點,請大家不吝指出。拋磚引玉,互動教育、教育游戲等在國內(nèi)外仍有較大的市場前景,希望與大家有更多的交流與合作,謝謝大家。

參考
  • https://github.com/netless-io/window-manager/blob/master/docs/develop-app.md

  • https://github.com/netless-io/window-manager/blob/master/docs/app-context.md

成語解謎:

  • https://github.com/Zhao-hangtian/happy-star

大賽作品倉庫:

https://github.com/AgoraIO-Community/RTE-2022-Innovation-Challenge

你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機(jī)房具備T級流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級服務(wù)器適合批量采購,新人活動首月15元起,快前往官網(wǎng)查看詳情吧

分享題目:基于聲網(wǎng)Flat實現(xiàn)“成語解謎”的Web小游戲-創(chuàng)新互聯(lián)
分享鏈接:http://muchs.cn/article0/cddioo.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供小程序開發(fā)、面包屑導(dǎo)航、網(wǎng)站收錄、關(guān)鍵詞優(yōu)化、外貿(mào)網(wǎng)站建設(shè)ChatGPT

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

綿陽服務(wù)器托管