<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          大力教育:教具游戲原理公開,你想知道的一切都在這里

          共 8930字,需瀏覽 18分鐘

           ·

          2020-12-25 22:07

          在兩周前舉辦的 Cocos 十周年系列沙龍」北京,來自字節(jié)跳動的高級軟件工程師林良喜、渲染引擎開發(fā)工程師黃俊銘、高級算法工程師郭冠軍為現(xiàn)場開發(fā)者分享了大力教育教具游戲聯(lián)合團(tuán)隊制作的教具游戲技術(shù)實現(xiàn)方案,深受開發(fā)者喜愛。


          在征得同意后,我們將通過本文對幾位的演講進(jìn)行梳理總結(jié),從 AI 識別原理、定制化渲染引擎以及游戲?qū)崿F(xiàn)三個方面進(jìn)行分享,把他們寶貴的技術(shù)經(jīng)驗分享給因為各種原因沒能去到沙龍現(xiàn)場的開發(fā)者伙伴們!


          字節(jié)跳動布局線上教育成立大力教育品牌,旗下有多款已公開的產(chǎn)品,其中瓜瓜龍啟蒙是專為 2-8 歲孩子打造的在線教育產(chǎn)品,內(nèi)容涵蓋英語、思維和語文等多學(xué)科的趣味 AI 互動課程,多維度體系化教學(xué),全面助力孩子成長。


            3-6 歲兒童正處于動手敏感期,孩子數(shù)學(xué)思維的啟蒙須高效把握好這個時期,充分調(diào)動起他們的多重感官,才能更好地培養(yǎng)孩子的數(shù)感。與市面上傳統(tǒng)的 AI 啟蒙課程相比,瓜瓜龍教具游戲玩法更加新穎,一改屏幕點選、拖動等課程交互形式,升級為結(jié)合實體智能教具動手實操。


            通過瓜瓜龍啟蒙的獨(dú)家“黑科技”,孩子邊聽課邊將題目的正確答案從教具中挑選出來擺放在“底座”上,iPad 和手機(jī)上方的“棱鏡”均可進(jìn)行智能識別立即判斷答案是否正確,給到孩子及時反饋。那么這些是如何實現(xiàn)的呢?



            AI?教具識別


            AI 教具識別的原理簡單而言分為三步:

            1. 攝像頭拍攝原始的鏡頭數(shù)據(jù),原始數(shù)據(jù)傳給 AI 識別模塊;

            1. 通過 AI 模塊進(jìn)行算法識別,對攝像頭原始數(shù)據(jù)處理生成結(jié)構(gòu)化的數(shù)據(jù);

            1. 結(jié)構(gòu)化的數(shù)據(jù)通過客戶端傳給游戲 JS 運(yùn)行環(huán)境。



            教具游戲設(shè)計的挑戰(zhàn)在于配套了 28 類卡牌,每類卡牌又由幾十個卡牌組成,需要對這 28 類卡牌進(jìn)行識別和定位,同時讓卡牌定位算法的召回率高于 99% 和識別算法的精度大于 99%。

            AI 識別這里的原理概括就是通過輸入原始的圖片數(shù)據(jù),經(jīng)過兩類的神經(jīng)網(wǎng)絡(luò):分類和定位對卡牌進(jìn)行定位和分類。


            我們 AI 算法識別第一個面臨的難點就是數(shù)據(jù)采集成本高,原始數(shù)據(jù)會出現(xiàn)目標(biāo)阻擋、卡牌破損、多余卡牌、以及其他極端環(huán)境等問題。


            為了解決這個困難,我們采用了數(shù)據(jù)合成策略的方法,也就是在理想的情況下采集了卡牌的數(shù)據(jù)和計算出了卡牌的定位和分類信息,然后把這些卡牌通過一定的變形合成之后,與隨機(jī)背景合成形成新的訓(xùn)練樣本,從而提升了神經(jīng)網(wǎng)絡(luò)的效果(召回率)。


            AI 算法識別遇到的第二個難點就是識別結(jié)果的“晃動”,前后兩幀的定位框晃動導(dǎo)致識別的類別會晃動,由于識別結(jié)果會實時地顯示在游戲中,識別結(jié)果晃動會讓用戶體驗變差。


            解決這個問題的方法比較簡單,我們通過串聯(lián)前后幀的信息來抹平前后幀晃動的情況,具體是通過緩存前一幀的灰度圖和框信息來實現(xiàn)的。

            幀差法檢測上一幀卡牌位置是否發(fā)生變化,如果沒發(fā)生變化,保留框,同時合并上一幀剩余檢測框和當(dāng)前幀檢測框,做 nms 進(jìn)行過濾 。


            AI 算法識別遇到的第三個難點是檢測模型性能要求高的問題,我們的檢測模型需要達(dá)到 60 FPS 的標(biāo)準(zhǔn)且內(nèi)存占用在 10M 以下。


            我們這里采用的解決方案是用了學(xué)術(shù)界性能和效果都不錯的、一個比較小型的網(wǎng)絡(luò) ShuffleNet V2,同時通過神經(jīng)網(wǎng)絡(luò)結(jié)構(gòu)搜索(NAS)和對網(wǎng)絡(luò)權(quán)重的 INT8 量化使得單幀耗時在 17ms 以下同時召回率在 99.5% 以上。

            AI 算法遇到的第四個難點是除了提升召回率之外,如何提升類別識別的精度,且精度需要在 99% 以上。

            我們同樣把采集的數(shù)據(jù)貼在各種背景上后合成了各種分類數(shù)據(jù)。另外也會針對手遮擋、環(huán)境光等各種 badcase 單獨(dú)采集分類數(shù)據(jù)進(jìn)行模型迭代。在模型充分迭代 10 次左右以及在各種極端光線下測試通過后才會上線使用。

            AI 算法遇到的第五個難點是減少其他卡牌識別結(jié)果的干擾。由于用戶無法直接看到攝像頭的視野,因此視野內(nèi)很容易出現(xiàn)非目標(biāo)的卡牌,進(jìn)而被識別。我們這里采用環(huán)境監(jiān)測的方法來分割出用戶的桌墊,把桌墊外的卡牌識別結(jié)果過濾掉。


            同樣其他環(huán)境問題,比如光線、棱鏡遮擋有無桌墊環(huán)境問題也是通過采集對應(yīng)的數(shù)據(jù)訓(xùn)練不同的分類模型,當(dāng)環(huán)境出現(xiàn)異常時把實時的環(huán)境監(jiān)測結(jié)果反饋給游戲,讓游戲提示用戶調(diào)整識別環(huán)境。



            渲染引擎


            在教具游戲場景下,底層游戲渲染引擎也扮演著一個重要的角色,支持游戲在教育業(yè)務(wù)場景下高效開發(fā)以及高性能運(yùn)行。

            MiniGameLite 是教具業(yè)務(wù)場景下使用的快速游戲集成解決方案,我們將從方案背景、技術(shù)原理、部分技術(shù)問題優(yōu)化以及未來展望幾個方面給大家介紹。


            第一部分是方案背景,首先我們提出一個問題,游戲如何與業(yè)務(wù)快速結(jié)合?

            業(yè)務(wù)方會提出以下幾點訴求:

            • 需要將游戲嵌入到業(yè)務(wù)中,業(yè)務(wù)可以隨意放在任意位置;

            • 需要快速地開發(fā)游戲,有一套完整的工具鏈路,可以快速集成到業(yè)務(wù)中;

            • 需要定制游戲的接口去滿足業(yè)務(wù)的需求,比如教具場景下要通知游戲消息去做一些互動;

            • 需要更高性能、占用內(nèi)存更小的游戲。


            MiniGameLite 快速小游戲集成解決方案就解決了以上訴求:

            • 提供 View 視圖級別接入,快速嵌入業(yè)務(wù);

            • 支持運(yùn)行小游戲,對接小游戲生態(tài),具有完整的工具鏈路;

            • 提供業(yè)務(wù)方定制小游戲通道的能力,定制業(yè)務(wù)接口;

            • 使用自研的渲染引擎,渲染鏈路更短更高效。



            第二部分想跟大家分享背后的技術(shù)原理,首先從整體架構(gòu)圖看 MiniGameLite 方案部分實現(xiàn)的功能以及位置。

            最上層是 Cocos 等游戲引擎承載的小游戲,與小游戲生態(tài)對接;向下是對接 Android 、 iOS 業(yè)務(wù)方;中間就是 MiniGameLite 整體的解決方案,從上往下看,最上方是支持字節(jié)小游戲接口(比如 tt.createCanvas、tt.getSystemInfoSync、gl.clearColor 等),并支持 MiniGameLite 定制的消息通道接口,往下是 JS 引擎,Android 使用 V8 引擎, iOS 使用 JavaScriptCore 引擎,再往下是 JavaScript Binding,連接底層核心實現(xiàn),比如很重要的一部分 WebGL 到 OpenGL 的 Binding,緊接是 MiniGameLite 的核心模塊,包含核心小游戲渲染層、音頻模塊、文件系統(tǒng)、網(wǎng)絡(luò)等,接下來是 ?MiniGameLite 平臺接口層,提供給業(yè)務(wù)方簡單易用的接口,比如開始游戲、暫?;謴?fù)游戲等。

            我們拆解以上的幾個技術(shù)特點簡單講解,首先是 MiniGameLite 的視圖級別接入。

            MiniGameLite 提供簡單的接口,指定游戲 ID 以及游戲視圖,游戲?qū)嬅驿秩镜綄?yīng)的視圖上,不同于普通單進(jìn)程全屏小游戲,MiniGameLite 支持任意進(jìn)程指定視圖渲染,支持快速嵌入到業(yè)務(wù)中。

            游戲?qū)嬅驿秩镜?Canvas 中,然后在 Android 繪制到 SurfaceView 或者 TextureView 上,iOS 繪制到 CAEAGLLayer 上,最后嵌入到業(yè)務(wù)中。

            接下來講一下定制消息通道。背后的技術(shù)原理也比較簡單,MiniGameLite 提供了游戲?qū)右约皹I(yè)務(wù)層的消息通道,平臺層假如要通知游戲業(yè)務(wù)層消息,就是平臺層調(diào)用 JS 方法通知游戲方,游戲方通過暴露的消息通道接口監(jiān)聽函數(shù)收到消息,游戲業(yè)務(wù)需要通知平臺層消息時,平臺層預(yù)先注入實現(xiàn)好的 JS 方法,游戲方通過調(diào)用 JS 方法通知平臺層。

            關(guān)于 MiniGameLite 高性能渲染的部分,我們可以對比下瀏覽器渲染鏈路,瀏覽器支持了其他 DOM 元素的渲染,整體渲染鏈路比較復(fù)雜,包含樣式計算、重繪、重排等。

            MiniGameLite 專注于支持小游戲 Canvas 的渲染,整體渲染鏈路比較簡單,主要的工作是做了 WebGL 到 OpenGL 的 Binding 工作,減少了不必要的開銷,在某些 API 的使用上鏈路更短,避免了 DOM 元素帶來的消耗(比如 DrawImage API 等)。

            在 MiniGameLite 高性能渲染鏈路以外,我們還可以介紹下 MiniGameLite 在調(diào)用 WebGL 方面使用共享內(nèi)存的優(yōu)化。


            舉一個很簡單的例子,比如創(chuàng)建一個 canvas 使用 clearColor 將它染成紅色,這里的 clearColor 就是一個很常見的 WebGL 狀態(tài)。

            我們是不是需要在每次調(diào)用的時候直接調(diào)用到底層的 OpenGL 函數(shù)呢?答案不是的,我們使用共享內(nèi)存的方式維護(hù)了 GL 的狀態(tài),不會每次調(diào)用 clearColor 的時候調(diào)用 OpenGL 函數(shù),而是在真正繪制時對比當(dāng)前上下文狀態(tài)是否與對應(yīng)上下文狀態(tài)是否有更新,假如有更新再去應(yīng)用更新,這樣也高效地維護(hù)了 WebGL 狀態(tài),減少無用的更新。

            不過對于游戲開發(fā)者而言,引擎底層的優(yōu)化是一方面,游戲開發(fā)者需要更關(guān)注 drawcall 的使用,比如可以采用批處理等方式進(jìn)行優(yōu)化。
            第三部分我們講述下我們遇到的幾個技術(shù)問題以及優(yōu)化的方式。

            由于我們面向的是小游戲開發(fā)者,假如小游戲開發(fā)者沒有及時釋放 GL 資源,GL 資源將成為內(nèi)存殺手,這時候?qū)τ谝鎸有枰趺醋瞿?/strong>?


            我們知道 JS 引擎有垃圾回收機(jī)制,利用這一點我們也可以完成 GL 資源的垃圾回收,比如 V8 引擎,我們可以使用它的 SetWeak 方法,它將在對象引用只剩下一個弱持久引用時調(diào)用回調(diào)函數(shù)。

            利用這一點我們就可以對我們的 WebGL 資源掛載上 finalize,當(dāng)對象不再被引用時,我們自動調(diào)用析構(gòu),釋放 GL 資源。

            再分享我們遇到的一個技術(shù)問題,在某些機(jī)型上,底層 OpenGL 紋理異步釋放速度很慢,在某些場景下某些游戲頻繁地申請紋理資源(并且調(diào)用了釋放),但是由于釋放速度較慢,申請紋理資源過快就會導(dǎo)致 GL OOM 的問題。懶加載、復(fù)用緩存是優(yōu)化的常見手段,為了解決這個問題,我們針對特定場景下嘗試了以下優(yōu)化:


            首先,我們延遲了創(chuàng)建紋理的調(diào)用,createTexture 不立即創(chuàng)建紋理而是等到 Bind 使用時。

            其次,我們在釋放紋理時不會真正地調(diào)用底層紋理的釋放,而是將紋理放置于紋理池中,供下次創(chuàng)建循環(huán)使用,這樣也就解決了頻繁申請紋理的問題。

            不過對于游戲而言,關(guān)于內(nèi)存的使用,引擎層需要關(guān)注,游戲開發(fā)者也需要更多的關(guān)注:游戲可以優(yōu)化紋理使用,可以使用壓縮、合圖或者使用壓縮紋理的方式進(jìn)行優(yōu)化;游戲可以提早及時釋放游戲資源,防止達(dá)到內(nèi)存峰值。


            最后一部分我們講述 MiniGameLite 快速小游戲集成方案的未來展望。

            首先我們會打造更高性能、更小體積的業(yè)務(wù) SDK,其次我們在嘗試打造更強(qiáng)大的物理引擎,目前也與 Cocos 合作,下沉物理引擎到 Native 層增強(qiáng)小游戲的性能。

            最后是字節(jié)能力賦能,我們將結(jié)合字節(jié)跳動內(nèi)部特效、算法生態(tài),游戲結(jié)合攝像頭特效、攝像頭 AR 等能力賦能更多業(yè)務(wù)場景。


            游戲?qū)崿F(xiàn)


            我們提供線上教育服務(wù),游戲跟隨課程上線,隨著課程開展,游戲需求量越來越大。

            為了適應(yīng)不同教學(xué)情況和滿足小朋友好奇心,我們需要豐富游戲玩法,為了更吸引小朋友,滿足小朋友動手需求,我們接入了教具識別。因此,我們需要解決的問題是,大量的、不同種類的教具游戲開發(fā)。

            我們統(tǒng)計了現(xiàn)有游戲玩法,把它們組合起來,抽出可以被復(fù)用的部分,設(shè)計游戲模板。在游戲模版中,根據(jù)功能不同分成三塊,分別是狀態(tài)機(jī),適配器和教具識別。
            為了大家更好理解,首先從這三張圖出發(fā),這里用點數(shù)游戲-抓老鼠的三張圖作為示例。

            第一張圖是關(guān)卡地圖,游戲以闖關(guān)的模式進(jìn)行,通過關(guān)卡后才能進(jìn)行下一關(guān)。

            第二張圖是進(jìn)入關(guān)卡后,開始游戲,這個游戲的玩法是,使用對應(yīng)點數(shù)卡牌回答問題,回答正確可以阻止老鼠進(jìn)入屋子,根據(jù)回答狀態(tài),我們可以分為未回答、回答正確、回答錯誤一次、回答錯誤兩次、回答錯誤三次、超時未回答等,每個狀態(tài)都有對應(yīng)邏輯。

            例如在未回答時,老鼠從主路走向中間的岔路,這時游戲開啟攝像頭,接收教具數(shù)據(jù),等待用戶答題。當(dāng)識別到正確教具,用戶回答正確,游戲狀態(tài)變?yōu)榛卮鹫_,這時游戲中出現(xiàn)了一只道具手拍向老鼠,結(jié)束當(dāng)前題目,開啟下一道題。

            我們把游戲中的每一個流程都當(dāng)成一種狀態(tài),為此設(shè)計了游戲狀態(tài)機(jī),用來管理游戲中的狀態(tài) ,狀態(tài)流轉(zhuǎn)類似 JS 中的 Promise,狀態(tài)只會正向流轉(zhuǎn),一旦發(fā)生改變,狀態(tài)將不可逆。

            用狀態(tài)機(jī)管理游戲有一個好處,可以使抽象邏輯更加清晰。因為游戲玩法太多了,每個流程對應(yīng)的功能可能都不一樣,那么我們可以把它理解為一個狀態(tài),規(guī)定這個狀態(tài)的輸入輸出,而中間是如何處理的,我們可以先不管,由具體邏輯負(fù)責(zé),下面會講到相關(guān)內(nèi)容。
            圍繞模板,分析玩法,我們把核心邏輯抽離出來,設(shè)計關(guān)卡管理器,根據(jù)游戲狀態(tài),設(shè)計了狀態(tài)機(jī)。

            如圖所示,游戲開始,我們進(jìn)入關(guān)卡,關(guān)卡開始、讀取狀態(tài)機(jī)、狀態(tài)機(jī)開始,開始接收識別數(shù)據(jù),狀態(tài)機(jī)根據(jù)識別數(shù)據(jù)改變狀態(tài),游戲處理對應(yīng)狀態(tài),狀態(tài)機(jī)達(dá)到退出條件,狀態(tài)機(jī)結(jié)束,銷毀當(dāng)前狀態(tài)機(jī),查詢是否有下一個狀態(tài)機(jī)。

            如果有,繼續(xù)執(zhí)行下一個狀態(tài)機(jī),游戲進(jìn)度加一;如果沒有下一個狀態(tài)機(jī),結(jié)束當(dāng)前關(guān)卡,游戲跳轉(zhuǎn)至下一關(guān)卡,根據(jù)關(guān)卡類型,執(zhí)行對應(yīng)狀態(tài)機(jī),游戲重新走一遍關(guān)卡流程;如果沒有下一個關(guān)卡,游戲通關(guān),通關(guān)后,結(jié)束游戲。

            在這一過程中,狀態(tài)機(jī)承擔(dān)了主要的游戲邏輯,由狀態(tài)機(jī)控制狀態(tài)流轉(zhuǎn),狀態(tài)流轉(zhuǎn)時控制狀態(tài)功能。

            這個流程的基本思路是,從玩法出發(fā),定義需要用到的狀態(tài),根據(jù)用戶的輸入,改變狀態(tài),流轉(zhuǎn)狀態(tài),最終達(dá)到退出游戲條件。而模板開發(fā)在這一過程中,只需要去實現(xiàn)對應(yīng)狀態(tài)功能。

            由于有多種玩法,因此在設(shè)計狀態(tài)機(jī)時,我們只需要確定核心狀態(tài),然后在適配器上實現(xiàn)新玩法帶來的新狀態(tài),就可以在同一份模板上實現(xiàn)不同游戲種類玩法。
            游戲玩法多樣性由適配器完成,根據(jù)狀態(tài)機(jī)核心流程,我們定義了一個基礎(chǔ)適配器,玩法適配器繼承了基礎(chǔ)適配器,在基礎(chǔ)適配器上開發(fā)。

            當(dāng)我們要開發(fā)一個新的玩法時,只需要開發(fā)新的適配器,實現(xiàn)對應(yīng)玩法,即可快速生成一套玩法模板。

            由于新玩法往往與其他游戲不同,我們需要根據(jù)玩法的特性,重寫狀態(tài)接口,使游戲狀態(tài)滿足游戲玩法。因為狀態(tài)接口和游戲狀態(tài)一一對應(yīng),因此,當(dāng)狀態(tài)發(fā)生流轉(zhuǎn)時,對應(yīng)的游戲玩法也隨之發(fā)生改變。

            在一些玩法里面,可能存在別的玩法不需要的能力,例如編程題中需要把教具信息轉(zhuǎn)化成程序指令、教具拖拽題需要拖動指定教具到正確區(qū)域,實現(xiàn)玩法時,我們需要增加 feature 能力完成對應(yīng)功能,feature 是指特定玩法功能,程序一般在狀態(tài)執(zhí)行時調(diào)用對應(yīng)的 feature,或者預(yù)留在代碼里,根據(jù)用戶輸入觸發(fā)對應(yīng) feature,通過 bridge 動態(tài)調(diào)用。
            我們所處業(yè)務(wù)的時間很緊張,每周都有大量游戲上線,行業(yè)和業(yè)務(wù)發(fā)展十分迅猛,過不了多久就會有大量線上游戲。量變形成質(zhì)變,怎么管理大量線上游戲成為一個難題,bridge 在這個背景下誕生。

            我們把游戲分成三大模塊,狀態(tài)機(jī)、適配器和教具識別,其中狀態(tài)機(jī)代表視圖層,控制游戲表現(xiàn),適配器代表控制層,控制游戲邏輯,教具識別代表數(shù)據(jù)層,表示用戶輸入。

            我們把適配器和教具識別單獨(dú)抽離出來,創(chuàng)建一個新工程,用來維護(hù)birdge。控制邏輯被抽離之后,可以簡化狀態(tài)機(jī)代碼,同時游戲邏輯更加清晰。

            狀態(tài)機(jī)只處理對應(yīng)視圖層,完成對應(yīng)狀態(tài)表現(xiàn),視圖層由邏輯層控制,開發(fā)者不用過多關(guān)注視圖層,可以更加專注游戲邏輯開發(fā)。

            為了能更好地管理游戲,抽離出來的 bridge 單獨(dú)維護(hù),所有游戲共用一份 bridge,通過 bridge 管理海量線上游戲。這樣,如果遇到邏輯變更或者修復(fù),我們只需要維護(hù)一份 birdge,即可影響所有游戲。

            那么,birdge怎么和狀態(tài)機(jī)結(jié)合呢?

            考慮游戲會和多端通信(minigamelite、AI lab 等),我們最終使用事件派發(fā)驅(qū)動游戲。

            根據(jù)模塊劃分,bridge 需要對接狀態(tài)機(jī)和 AI lab,AI lab 通過派發(fā)事件與 bridge 通信、傳輸教具信息,bridge 處理信息后通過事件驅(qū)動狀態(tài)機(jī)流轉(zhuǎn)狀態(tài),從而控制游戲邏輯。使用事件驅(qū)動,我們可以很方便在模塊之間通信,開發(fā)者只需要根據(jù)用戶輸入和當(dāng)前狀態(tài)判斷下一個狀態(tài),通過指定事件控制狀態(tài)流轉(zhuǎn)。
            遇到難題,假設(shè)我們有個通用組件叫瓜瓜幣,是游戲內(nèi)的積分,產(chǎn)品覺得這個組件不夠 Q,需要把它改得更加適合小朋友,這個時候我們的麻煩來了,怎么解決游戲更新?

            我們預(yù)留了解決方案,組件開發(fā)和動態(tài)下發(fā)。

            下面向大家分享我們組件倉庫的開發(fā)歷史,一開始我們也經(jīng)歷 copy 代碼的過程,但相信大家也知道這樣的痛苦。當(dāng)時還沒規(guī)劃組件倉庫、結(jié)合 Cocos,我們尋找市面上能夠滿足組件開發(fā)的技術(shù),后來我們選擇了 git subModule,一定程度上緩解 copy 代碼帶來的不便。

            但是因為子模塊維護(hù)操作比較麻煩,容易被誤修改等,我們后來開發(fā)組件倉庫時,最終使用了 @byted/cetus 管理組件倉庫。

            cetus 是我們的一個工具包,它是一個基于 git 的團(tuán)隊項目代碼管理工具,它適合內(nèi)部的包管理,它可以直接使用 git 倉庫作為依賴,cetus 僅需要很少的配置就可以實現(xiàn)倉庫的管理,在配置中,mode 表示組件開發(fā)模式,我們選擇克隆模式拉取整個倉庫,方便修改和提交,path 表示組件存放路徑,remoteUrl 表示拉取的組件倉庫地址,version 表示拉取版本的代碼,可以使用分支名或 commit hash,配置完成后,執(zhí)行 ct,空格 i,即可在對應(yīng)目錄下看到相應(yīng)的組件文件。通過 cetus,我們可以很便捷開發(fā)和維護(hù)組件。


            組件開發(fā)完后,我們會把通過測試的組件打包,發(fā)布到 CDN,提供游戲使用。
            游戲通過組件倉庫 id 加載倉庫下的 uuid-to-mtime.json 文件,這個文件比較特殊,存放了倉庫下面所有資源,包含了 uuid 與資源路徑映射關(guān)系,我們可以根據(jù)它獲取對應(yīng)倉庫所有資源。

            拿到 uuid-to-mtime.json 文件后,我們還需要改造數(shù)據(jù),由 relativePath 映射 uuid。因為一個倉庫里面包含很多組件,對于開發(fā)者而言,相對路徑對我們來說會更清晰些,我們通過相對路徑獲取遠(yuǎn)程倉庫內(nèi)指定組件。

            當(dāng)請求的組件路徑命中 relativePath 時,我們可以獲取到對應(yīng)組件的 uuid,根據(jù) Cocos 項目結(jié)構(gòu),我們可以很容易通過 uuid 解析出資源存放在 library 中的路徑,再通過路徑加載指定組件的資源。至此,游戲完成動態(tài)加載。

            至此,教育游戲的痛點難點我們都解決了,下面簡單介紹下我們用到的優(yōu)化手段。

            關(guān)于性能優(yōu)化,我們主要從包大小、內(nèi)存、drawCall 入手。

            優(yōu)化包大小的手段有很多,我們主要從資源入手,圖片、音頻壓縮,優(yōu)化合圖空白區(qū)域,優(yōu)化圖片像素格式,使用 jpg 格式,使用九宮格、平鋪或拉伸方式滿足大圖需求。

            對于字體文件,優(yōu)先考慮使用位圖,如果需要引入字體文件,使用 fontmin 去除未被使用的字符。在這么多資源中,setting.js 文件大小最容易被忽略,如果不注意資源放置,setting.js 文件可以增大很大,為了減少 setting.js 文件大小,避免在 resources 放置不需要動態(tài)加載的資源,碎圖合并成一張。

            除了業(yè)務(wù)相關(guān)資源,引擎中不需要引用的模塊也可以適當(dāng)刪減,去掉未使用的引擎模塊不單能夠減少包體積,還可以加快構(gòu)建速度。

            內(nèi)存優(yōu)化這里主要做了 3 個操作,對于靜態(tài)資源,可以勾選自動釋放資源讓引擎處理。針對動態(tài)資源,需要計算動態(tài)資源引用次數(shù),當(dāng)資源引用次數(shù)為 0 時釋放資源。

            圖片的分辨率盡量滿足 2 的冪次方,Cocos的渲染方式基于 OpenGL 的,OpenGL 載入紋理圖片時,所用內(nèi)存會自動擴(kuò)張到 2 的 N 次方,圖片分辨率滿足 2 的冪次方,可以避免因擴(kuò)張內(nèi)存導(dǎo)致內(nèi)存浪費(fèi),在分辨率滿足 2 的冪次方下,碎圖鋪滿合圖可以更有效利用內(nèi)存。

            進(jìn)行 drawCall 優(yōu)化前我們需要明白 drawCall 是什么,drawCall 是 cpu 對圖形繪制接口的調(diào)用,CPU 通過調(diào)用圖形庫接口,命令 GPU 進(jìn)行渲染操作。每一次繪制 CPU 都要調(diào)用 DrawCall,而在調(diào)動 DrawCall 前,CPU 還要進(jìn)行很多準(zhǔn)備工作:檢測渲染狀態(tài)、提交渲染所需要的數(shù)據(jù)、提交渲染所需要的狀態(tài)。

            而 GPU 本身具有很強(qiáng)大的計算能力,可以很快就處理完渲染任務(wù)。當(dāng) DrawCall 過多,CPU 就會很多額外開銷用于準(zhǔn)備工作,CPU 本身負(fù)載,而這時 GPU 可能閑置了。由于 drawCall 過高,導(dǎo)致 frame time 過高,fps 變低,用戶感覺體驗是游戲變卡了,甚至掉幀,那么我們優(yōu)化的時候就是減少 drawCall,盡量把小的 drawCall 合并到一個大的 drawCall 中,渲染合批。

            我們主要的方法是合圖,把紋理狀態(tài),材質(zhì),混合模式一致的圖片合張一張大圖,減少渲染次數(shù),使用位圖代替 Label,避免 Label 和 Sprite 相互打斷。
            還有一些常用的優(yōu)化,如使用對象池,設(shè)置合適的游戲幀率,降低物理引擎步長等,可以根據(jù)項目需要設(shè)置,通過比較小的改動帶來比較明顯的優(yōu)化。

            以上就是大力教育所有關(guān)于教具的原理介紹喔,字節(jié)跳動布局線上教育成立大力教育品牌,旗下有多款已公開的產(chǎn)品。


            教具游戲是大力教育綜合字節(jié)內(nèi)部各種技術(shù)積累進(jìn)行的一個項目,大力教育結(jié)合 Cocos 還有很多應(yīng)用場景,對 Cocos 開發(fā)者也提供了很多非常不錯的機(jī)會,對教育行業(yè)感興趣同學(xué)可以聯(lián)系 [email protected] 投遞簡歷喔。



            最后,再次感謝林良喜、黃俊銘、郭冠軍三位大大的傾情分享,「十周年系列沙龍」仍在繼續(xù)前進(jìn),12 月 26 日廣州站已經(jīng)在路上,尚未報名的童鞋戳鏈接沖鴨!
            瀏覽 71
            點贊
            評論
            收藏
            分享

            手機(jī)掃一掃分享

            分享
            舉報
            評論
            圖片
            表情
            推薦
            點贊
            評論
            收藏
            分享

            手機(jī)掃一掃分享

            分享
            舉報
            <kbd id="afajh"><form id="afajh"></form></kbd>
            <strong id="afajh"><dl id="afajh"></dl></strong>
              <del id="afajh"><form id="afajh"></form></del>
                  1. <th id="afajh"><progress id="afajh"></progress></th>
                    <b id="afajh"><abbr id="afajh"></abbr></b>
                    <th id="afajh"><progress id="afajh"></progress></th>
                    久久在线播放 | 精品卡一卡2卡3卡4卡在线 | 学生妹一区二区三区 | 无码人妻精品一区二区 | 亚洲AV成人一区二区三区不卡 |