scratch3.0 源碼分析

最新一直在做少兒編程方向的創(chuàng)業(yè)寻定,用到了scratch 3.0,在這里簡(jiǎn)單分享一下其原理精耐。

什么是 scratch 3.0狼速?

Scratch是美國(guó)麻省理工學(xué)院的“終身幼兒園團(tuán)隊(duì)”開(kāi)發(fā)的一款圖形化編程工具,通過(guò)點(diǎn)擊并拖拽的方式就能完成編程卦停,可以幫助兒童或成人初學(xué)者更好地學(xué)習(xí)編程的基礎(chǔ)概念等向胡。

Scratch1.0在2007年第一次公開(kāi)發(fā)布,隨后在2012年又推出了Scratch2.0版本惊完,而Scratch3.0則是2019年的1月初正式推出的僵芹。

Scratch 3.0 采用了HTML5和JavaScript技術(shù)來(lái)編寫,支持所有的現(xiàn)代瀏覽器和WebGL小槐,能夠跨平臺(tái)使用拇派。

Scratch 在github上有一系列的開(kāi)源項(xiàng)目,其官方的開(kāi)源scratch 3.0的編程網(wǎng)站的源碼地址為:https://github.com/LLK/scratch-gui.git

系統(tǒng)構(gòu)成

官方網(wǎng)站的主要界面和我們的很類似凿跳,因?yàn)槲覀兙褪腔谒伍_(kāi)發(fā)的:
scratch.png

可以看到件豌,從左到右,依次為代碼塊區(qū)控嗜,編輯區(qū)和展示區(qū)茧彤,對(duì)于其使用,本文就不展開(kāi)了疆栏,重點(diǎn)放在其原理上曾掂。

技術(shù)架構(gòu)

主項(xiàng)目的目錄結(jié)構(gòu)如下:

├── build                    # 默認(rèn)編譯后的文件夾
│   ├── static               # 靜態(tài)資源
│   ├── index.html          
│   ├── gui.js               
│   ├── lib.js               # 編譯后主要的js文件                    
├── src
│   ├── components           # UI組件,負(fù)責(zé)頁(yè)面呈現(xiàn)
│   ├── containers           # 容器組件承边,承載容器組件業(yè)務(wù)邏輯
│   ├── css                  # 全局通用css
│   ├── examples             # 集成測(cè)試用例
│       ├── extensions       # 拓展案例
│   ├── lib                  # 插件及高階組件
│       ├── audio            # 聲音插件
│       ├── backpack         # 背包插件
│       ├── default-project  # 默認(rèn)項(xiàng)目
│       ├── libraries        # 素材庫(kù)相關(guān)
│       ├── video            # 視頻模塊
│   ├── playground           # 編譯后頁(yè)面的模版
│   ├── reducers             # 全局狀態(tài)控制
├── test                     # 測(cè)試用例
├── translations             # 翻譯庫(kù)
├── README.md
└── package.json
└── webpack.consig.js

通過(guò)查看其源碼的package.json遭殉,我們可以看到,它是基于react 技術(shù)棧開(kāi)發(fā)博助,核心依賴包有:

  • scratch-vm:虛擬機(jī)险污,管理狀態(tài)并執(zhí)行業(yè)務(wù)邏輯
  • scratch-blocks:代碼積木塊
  • scratch-l10n:國(guó)際化
  • scratch-paint:繪圖拓展
  • scratch-render:舞臺(tái)渲染,在舞臺(tái)區(qū)域出現(xiàn)的基于WebGL的處理器。
  • scratch-storage:作品存儲(chǔ)加載
  • scratch-svg-renderer:svg處理
  • scratch-audio:聲音拓展

其核心原理就是用scratch-blocks生成語(yǔ)句塊后蛔糯,用scratch-vm 虛擬機(jī)抽象成底層語(yǔ)法拯腮,最后再調(diào)用scratch-render 和scratch-paint渲染到界面,而scratch-audio主要用于音頻的剪輯處理蚁飒。

關(guān)于 scratch-vm

Scratch-VM提供了一套Scratch-Blocks運(yùn)行環(huán)境动壤,因此VM定義很多豐富的外部庫(kù),在初始化時(shí)淮逻,需要對(duì)VM進(jìn)行初始化琼懊,然后再定義Scratch-Blocks,最后對(duì)Blockly和VM進(jìn)行事件綁定和監(jiān)聽(tīng):

  • 定義VirtualMachine爬早,VirtualMachine是Scratch-VM的核心入口類哼丈;
  • 為VirtualMachine設(shè)置ScratchStorage、ScratchSVGRenderer筛严、S- cratchRender醉旦、AudioEngine等輔助工具;
  • 定義工作空間,設(shè)置Blockly桨啃,使用inject方法车胡,加載Scratch-Blocks;
  • 為工作空間設(shè)置相關(guān)事件;
  • 為VirtualMachine設(shè)置相關(guān)事件;
  • 開(kāi)始運(yùn)行VirtualMachine照瘾。

scratch-vm 的一些概念

  • sb2/sb3文件: Scratch VM能解析的文件類型匈棘,sb2為Scratch2.0項(xiàng)目文件,sb3為Scratch3.0項(xiàng)目文件析命;
  • Sprite角色:需要執(zhí)行動(dòng)畫效果的對(duì)象羹饰,對(duì)象可以是svg、圖像碳却;
  • Clone克隆: 有時(shí)候角色動(dòng)畫需要復(fù)制自己本身队秩,會(huì)產(chǎn)生許多虛擬的角色,稱為克轮缙帧馍资;
  • Costume造型:角色會(huì)有多個(gè)外觀,就像人有很多衣服一樣关噪,一個(gè)角色有多個(gè)造型鸟蟹,造型會(huì)讓角色更加生動(dòng);
  • Target目標(biāo):角色屬性信息(基礎(chǔ)信息使兔、腳本信息)建钥,譬如角色的位置、方向虐沥、放大縮小熊经、特效等等泽艘。每個(gè)Clone體對(duì)應(yīng)一個(gè)Target;
  • Stage舞臺(tái):角色在舞臺(tái)上完成動(dòng)畫镐依,舞臺(tái)是一個(gè)特殊的角色匹涮;
  • backdrop舞臺(tái)背景:舞臺(tái)會(huì)有多個(gè)外觀,稱為舞臺(tái)背景
  • Thread線程:角色產(chǎn)生動(dòng)畫槐壳,需要運(yùn)行環(huán)境然低,Thread線程就是角色的運(yùn)行時(shí)環(huán)境;
  • Drawable圖形:每個(gè)角色的Clone體务唐,會(huì)對(duì)應(yīng)一個(gè)Target雳攘,Target目標(biāo)真正的繪圖對(duì)象實(shí)際上是Drawable;
  • Sound聲音:聲音會(huì)讓動(dòng)畫更加生動(dòng)枫笛,Sound角色的屬性来农,由所有Clone體共用;
  • effects特效:角色有很多造型崇堰,使用特效,可以在造型的基礎(chǔ)上涩咖,修改造型外觀海诲,特效有color,fisheye,whirl,pixelate, mosaic,brightness, ghost;
  • IO輸入輸出:Scratch-VM將鍵盤檩互、鼠標(biāo)左右鍵特幔、鼠標(biāo)滾輪、設(shè)備連接等定義為IO闸昨,鍵盤蚯斯、鼠標(biāo)左右鍵、鼠標(biāo)滾輪等提供統(tǒng)一的IO輸入饵较,設(shè)備提供藍(lán)牙和BT連接拍嵌,使用socket與Scratch-link進(jìn)行通信;
  • 刷新率:每秒鐘動(dòng)畫繪制的次數(shù);
  • 時(shí)間片:一次繪制分配給scratch運(yùn)行的時(shí)間循诉,時(shí)間片到期自動(dòng)放棄運(yùn)行等待下一次運(yùn)行横辆,正常情況下,刷新率為每秒60次茄猫,時(shí)間片為1000/60ms狈蚤;
  • StackFrame棧楨:線程運(yùn)行時(shí)棧空間划纽,通常情況下棿辔辏空間只有一個(gè)棧元素,當(dāng)遇到循環(huán)勇劣、事件靖避、函數(shù)時(shí),會(huì)保留當(dāng)前棧楨,新增一個(gè)棧楨筋蓖;
  • ExtensionManager擴(kuò)展積木管理器:擴(kuò)展積木的管理卸耘,Scratch自定義了一種積木的定義方法,將自定義的積木轉(zhuǎn)為json粘咖,供blockly解析蚣抗,所以我們定義積木時(shí),可以在擴(kuò)展中定義瓮下。

vm調(diào)用過(guò)程

  • 加載時(shí)先全局加載虛擬機(jī),初始化虛擬IO翰铡,然后查看網(wǎng)絡(luò)請(qǐng)求中l(wèi)ocation對(duì)象的hash,如果不能識(shí)別,直接在本地新建工程,并為工程賦予唯一ID值;
  • 如果能識(shí)別,從網(wǎng)絡(luò)或從本地加載工程,將舞臺(tái)推入render生成渲染器,再把渲染器推入vm讽坏;
  • 然后調(diào)用Blockly.inject函數(shù)在一個(gè)dom(類似于div#id)上面,初始化workspace和flyoutWorkspace樣式
  • 接著為workspace建立blockListener(在vm/engine/block中定義,為block建立的通用(非特定)動(dòng)作函數(shù),如move,delete,create,click什么的,特定的block動(dòng)作函數(shù)的加載)锭魔;
  • 然后為flyoutWorkspace建立flyoutBlockListener(所以如果需要給所有的block加統(tǒng)一的事件(僅限field和mutation)可以在這里添加 engine/blocks.js)

深入 scratch-vm

  • vm是在containers/gui.jsx中啟動(dòng)的,scratch中components是純函數(shù)組件,而在containers文件夾中會(huì)把同名components與redux和vm連接,同時(shí)進(jìn)行國(guó)際化,組件節(jié)流,版本控制,虛擬IO監(jiān)聽(tīng)等操作,邏輯非常清晰;
  • 所有ui狀態(tài)在reducer/gui.js中進(jìn)行組裝然后統(tǒng)一導(dǎo)出,但是要注意scratch根目錄下的index.js是個(gè)假的入口文件,reducer真正是在lib/app-state-hoc中的AppStateHOC類組裝的,這是一個(gè)中間件路呜;
  • 在入口函數(shù)render-gui中GUI組件使用compose函數(shù)進(jìn)行柯里化(將f(a)(b)(c)(d)變成f(a,b,c)(d)叫做柯里化)封裝了AppStateHOC, HashParserHOC,TitledHOC三個(gè)中間件迷捧;
  • AppStateHOC通過(guò)判斷是否需要加載paint和gui來(lái)加載不同的store,因此<Provider>也在這個(gè)組件當(dāng)中,guiMiddleware是一個(gè)封裝了throttle的柯里化函數(shù),按照中間件模式調(diào)用,用于為組件節(jié)流(如果一秒內(nèi)點(diǎn)了很多次,只會(huì)執(zhí)行兩次),封裝之后返回了經(jīng)過(guò)國(guó)際化(多語(yǔ)言模塊)和節(jié)流處理的高級(jí)組件;
  • 當(dāng)vm啟動(dòng)時(shí),在runtime入口定義了defaultBlockPackages類,這里面聲明了每個(gè)block塊的功能函數(shù)(比如moveTo)胀葱;
  • 在vm/engine/runtime 715行,有一個(gè)_registerBlockPackages函數(shù),會(huì)加載所有block塊動(dòng)作漠秋;
  • 然后,通過(guò)聲明基類函數(shù)getPrimitives取得各個(gè)模塊中的block預(yù)定義動(dòng)作,之后通過(guò)訂閱分發(fā)(路由模式)的方式生成packagePrimitives類,這樣block塊的特定功能就都可以在vm中使用了;
  • 當(dāng)有點(diǎn)擊事件發(fā)生時(shí),vm-listener首先捕獲事件,然后把消息推送至虛擬機(jī),虛擬機(jī)會(huì)定位到對(duì)應(yīng)的sprite或者帶有hats的sprite,執(zhí)行注冊(cè)的函數(shù);

小結(jié)

整個(gè)scratch 項(xiàng)目的源碼非常龐大硼婿,有很多我還沒(méi)有時(shí)間和精力進(jìn)行總結(jié),期待項(xiàng)目能夠順利推進(jìn)搂抒,然后投入更多的研發(fā),然后才能進(jìn)一步深入尿扯。

我曾打算一個(gè)人使用vue 3 重寫整個(gè)gui求晶,但是沒(méi)有經(jīng)費(fèi)支持,業(yè)余時(shí)間衷笋,個(gè)人的話真的有點(diǎn)力不從心誉帅。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市右莱,隨后出現(xiàn)的幾起案子蚜锨,更是在濱河造成了極大的恐慌,老刑警劉巖慢蜓,帶你破解...
    沈念sama閱讀 218,941評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件亚再,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡晨抡,警方通過(guò)查閱死者的電腦和手機(jī)氛悬,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門则剃,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人如捅,你說(shuō)我怎么就攤上這事棍现。” “怎么了镜遣?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,345評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵己肮,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我悲关,道長(zhǎng)谎僻,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,851評(píng)論 1 295
  • 正文 為了忘掉前任寓辱,我火速辦了婚禮艘绍,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘秫筏。我一直安慰自己诱鞠,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,868評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布这敬。 她就那樣靜靜地躺著航夺,像睡著了一般。 火紅的嫁衣襯著肌膚如雪鹅颊。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,688評(píng)論 1 305
  • 那天墓造,我揣著相機(jī)與錄音堪伍,去河邊找鬼。 笑死觅闽,一個(gè)胖子當(dāng)著我的面吹牛帝雇,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播蛉拙,決...
    沈念sama閱讀 40,414評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼尸闸,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了孕锄?” 一聲冷哼從身側(cè)響起吮廉,我...
    開(kāi)封第一講書(shū)人閱讀 39,319評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎畸肆,沒(méi)想到半個(gè)月后宦芦,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,775評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡轴脐,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評(píng)論 3 336
  • 正文 我和宋清朗相戀三年调卑,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了抡砂。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,096評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡恬涧,死狀恐怖注益,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情溯捆,我是刑警寧澤丑搔,帶...
    沈念sama閱讀 35,789評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站现使,受9級(jí)特大地震影響低匙,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜碳锈,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,437評(píng)論 3 331
  • 文/蒙蒙 一顽冶、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧售碳,春花似錦强重、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,993評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至艺智,卻和暖如春倘要,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背十拣。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,107評(píng)論 1 271
  • 我被黑心中介騙來(lái)泰國(guó)打工封拧, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人夭问。 一個(gè)月前我還...
    沈念sama閱讀 48,308評(píng)論 3 372
  • 正文 我出身青樓泽西,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親缰趋。 傳聞我的和親對(duì)象是個(gè)殘疾皇子捧杉,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,037評(píng)論 2 355