Scratch克隆技術、多線程編程及通訊技術初探

一、引言

Scratch,作爲世界流行的青少年編程語言,其對青少年智力的開發及計算思維的培養根本毋庸置疑。既然定位在青少年,那就不能複雜,但是,又要遵循“低門檻,高上限”兩個基本特徵。讓青少年儘快入門的同時,又可以讓部分能夠深入鑽研的同學深刻體會到編程的創造性、複雜性及內在樂趣。而後者,在全國青少年編程競賽與等級考試中肯定要體現出來——自然也是體現參加者作品創意與難度的所在。

Scratch開發者恰當地把握了上述要求與特徵:最基礎最重要的計算機編程語言特徵必須具備,同時又儘可能巧妙地“屏蔽”程序設計算法及內在原理的複雜性,在界面設計上追求“極簡且穩定第一”的風格——就像小朋友手中的真實積木,任意摔打而毫無問題。

我們知道,Scratch程序運行原理上是基於事件驅動的,這一點學起來並不複雜。但另一方面,多線程編程及其同步技術這種“高上限”又無法迴避——這是開發複雜應用程序最實用但又最複雜的技術之一。

還是那句話,Scratch絕不是玩具式語言!下面通過實例來說明問題。

二、問題需求

在本文中,我們想使用Scratch開發一個如圖所示的小程序。

Scratch克隆技術、多線程編程及通訊技術初探

在三消遊戲、卡牌遊戲中經常出現本程序中的需求,即按指定矩陣排列規律在屏幕特定區域佈局精靈。爲了簡化問題,我使用了大寫的26個英文字母來做試驗,如圖所示。
爲了朋友們看起來方便,有些基礎性的準備工作我簡單介紹一下。

爲程序準備大小相同的26個英文字母角色

手段多樣。我使用的辦法是結合Scratch的導出功能與Photoshop聯手搞定。


有興趣的朋友高度推薦自學一下Photoshop,這個軟件類似於日常辦公中的Office軟件,在日常圖形圖像處理中功能極其強大!一經學會,終生受益!


總體步驟如下:

【第一步】Scratch中內置的角色庫的”字母“類型中已經提供26個字母的造型,如圖所示:
Scratch克隆技術、多線程編程及通訊技術初探

【第二步】添加一個空白角色,切換到造型編輯器(或者稱圖形編輯器)狀態下,從內置角色庫中把上述字母造型逐個按序加入到本角色中,參考下圖:

Scratch克隆技術、多線程編程及通訊技術初探

【第三步】仔細觀察,這些字母的造型大小並不一致(我上圖中給出的是經過我加工的,所以大小一樣),而且大小差距不少。如果根據我們上面程序要求,非常有必要把它們調整得一樣大小。怎麼辦?

考慮到系統內置造型編輯器的有限功能,想到:把它們導出,然後用Photoshop統一處理。請參考接下來的步驟。

【第四步】先在造型編輯器中把上述造型逐個轉換成位圖類型。注:默認添加的字母造型是矢量的,只能導出爲.SVG格式。在轉換成位圖類型後即可把它們導出成.PNG格式,然後使用Photoshop處理。有興趣的朋友,可以分析一下直接使用矢量編輯軟件如CoreDraw或者Illustrator等直接處理.SVG文件。因爲我的Photoshop是CS6,默認不能直接處理.SVG,所以我先轉換成位圖類型。
【第五步】在得到位於同一文件夾下的26個.PNG文件後,可以很輕鬆地使用Photoshop把它們批量修改成同一尺寸(有興趣的朋友可以參考我本文稍後整理的短博文,在此省略介紹)。考慮到Scratch的創作屏幕爲480X360像素,所以,我把每一個字母的大小修改成30X34像素大小。

爲了度量方便性,這裏還有一個小技巧是:我把背景圖替換成了Scratch系統內置的背景圖,名字爲Xy-grid-30px。

克隆技術的需求

針對上面如圖所示的字母排列,不少中學信息學教材中介紹逐個角色方式創建,並逐個排列到屏幕上。這種方法是最原始、最簡單、最直接的,但往往也是最有問題的方法。不妨設想:在擁有幾十甚至上百個關卡的卡牌或者消除類遊戲中,如果使用這種排列方法,麻煩大了!
顯然,最好的辦法是利用Scratch中的克隆技術:創建一個角色,並讓這個角色擁有上面26個英文字母的26種造型。那麼問題來了:

【問題1】如何利用克隆技術?
【問題2】如何有效管理這些造型並適時地動態調整?


克隆對應的英文單詞是“Clone”,意思是完全複製。在Scratch編程中,克隆不僅複製母體的所有靜態屬性,還複製包括執行代碼在內的一切。在遊戲軟件開發中,常常要求相同的角色的大量不同的副本,而且要求這些副本表現出與母體完全相同的行爲;例如,大量的殭屍與小魚、無數的雨點與雪花……
因此,巧妙地使用克隆技術,能夠生成大量相似或相同表現的角色,並極大地簡化程序、特別是遊戲軟件的開發過程。
【注】在本文中,我們把作爲克隆種子的角色統一稱爲“母體”,把每一個克隆生成的角色簡稱爲“克隆體”,理解與搞清“母體”與“克隆體”之間的關係是克隆技術編程的關鍵。


克隆技術使用的情形

例一:生成天空中的雨點

下面的兩段代碼針對故事中的“雨點”角色編程:
第一段
Scratch克隆技術、多線程編程及通訊技術初探

第二段
Scratch克隆技術、多線程編程及通訊技術初探

【技術總結】此處代碼的特點是:母體角色(只有一個)只負責生成克隆體角色,各種屬性的設置統一由克隆體自身處理。這屬於克隆技術編程的最簡單的情形。這種情形下,第二段代碼可以盡情使用程序中定義的全局變量,但要注意各克隆體之間使用上不應出現衝突。
【問題】這兩段代碼屬於兩個線程,這兩個線程的執行看起來沒有什麼共享數據或者同步要求,所以,這種情形下的克隆編程是比較簡單的。


多線程、多進程編程是幾乎每一箇中級程序員必須面對和要克服的難題,Scratch後臺系統的特徵與實際程序開發的需求要求它不得不引入多線程技術,儘管Scratch竭力巧妙地掩蓋這種技術,但這些技術本身具有的複雜性在使用Scratch編寫比較複雜的程序時必然(而且已經)彰顯出來且需要克服。值得慶幸的是,Scratch開發者早已預料到這一點,並已經給出了圓滿的解決方案。

例二:生成三隻有規律排列的小貓
先看下圖:
Scratch克隆技術、多線程編程及通訊技術初探

【問題一】哪一個是母體?答案見下圖:
Scratch克隆技術、多線程編程及通訊技術初探

即最右邊一個是母體!
截止到目的,我們對克隆技術使用要求是生成滿天的雨滴或者是三隻貓,並沒有要求區別母體與克隆體!但是,有些,甚至是更多,應用情況下要求區別對待母體與克隆體(甚至是各克隆體之間也要區別)。
【問題二】要想使左邊第一隻貓成爲母體,怎麼辦?

先看下面的圖示:
Scratch克隆技術、多線程編程及通訊技術初探

結合上圖,得出目前結論是:克隆體總是由母體生成的!

因此,要解決上面【問題二】要求在克隆體內修改座標,而不能在母體代碼中修改座標(母體代碼中修改總是修改母體角色的屬性值)。自然,要實現“在克隆體內修改”這種目標,於是積木命令Scratch克隆技術、多線程編程及通訊技術初探登場!

那麼,看接下來的這段代碼及結果圖示:

Scratch克隆技術、多線程編程及通訊技術初探

這段代碼也好理解不是?【問題二】的答案初步有眉目了!但是,新的問題又出現了:

【問題三】第三隻(最右邊)小貓(克隆體)如何生成?

如果相當然修改,可能會有如圖結果:

Scratch克隆技術、多線程編程及通訊技術初探

有關克隆體代碼(積木【當作爲克隆體啓動時】所屬代碼)中繼續克隆自己的問題暫時不討論(涉及到克隆遞歸及最大遞歸深度的問題)。

繼續修改,嘗試如下代碼(與結果圖):
Scratch克隆技術、多線程編程及通訊技術初探

細心的朋友容易觀察出,克隆母體兩次,這兩個克隆體都調用了積木【當作爲克隆體啓動時】所屬代碼,所以結果是:這兩個克隆體小貓的位置是重合的。

再想辦法(結果還是不行!):

Scratch克隆技術、多線程編程及通訊技術初探

不再糾纏下去了,其實,解決上面的【問題二】的辦法是把兩次克隆體代碼區別開來,即區別哪是第一次克隆哪是第二次克隆,問題就好辦了。於是,我們想到下面的解決辦法:
Scratch克隆技術、多線程編程及通訊技術初探

運行結果如下:
Scratch克隆技術、多線程編程及通訊技術初探

注意到,這種方案具有代表性,即如果生成N個位置的X只小貓的話,只要區別這X次克隆問題就迎刃而解了。
上面提供的辦法運用到了在克隆體執行代碼中使用全局變量的功能,其實,大家順着這個路子還會想出更復雜的與克隆有關的問題來。

有興致的朋友可以考慮:解決上面【問題二】是不是還有其他更好的辦法?

三、26個字母排列問題

其實,在前面的舉例中,都涉及到了多線程編程的問題。此時,一旦涉及到數據的共享訪問(或者稱數據同步),則必須設法解決其中同步的問題。現在,讓我們回到本文開始第一張圖所展示的問題上。

篇幅所限,我們僅考慮如圖所示的這一種情形,其他情形類似,有興趣的朋友可以參考本文程序在51CTO上的源碼(突然發現要聯繫博客主管才能上傳,爭取明天解決這個問題)。下面直接給出代碼並輔助一定的解釋。

角色按鈕3X8+2的代碼

Scratch克隆技術、多線程編程及通訊技術初探

含義一目瞭然。

角色字母A的代碼

(1)第一段

Scratch克隆技術、多線程編程及通訊技術初探
這是消息接收到後的初始化工作,注意全局變量“gv克隆體計數器”是用來區別各個克隆體使用的(當然,本例子僅是一個入門,並沒有深入區別對待每一個克隆體的操作)。

(2)第二段

Scratch克隆技術、多線程編程及通訊技術初探

注意:本例子中爲了數據管理的方便,引入了兩個分別記錄屏幕上按規律排列的每一個角色橫縱座標的兩個列表,如圖所示:
Scratch克隆技術、多線程編程及通訊技術初探

其中,“const橫座標列表”用來存儲垂直方向平均切割成16份(30X16=480)每一個角色的中心點的橫座標,“const縱座標列表”用來存儲水平方向平均切割成10份(10X34+20=360)每一個角色的中心點的縱座標。

上面代碼開始時,母體定位,並初始化幾個輔助變量,例如row和column分別用來記錄屏幕上角色所在的行與列(正好也與下面的二重條件循環次數大致相對應——並非嚴格對應)。

接下來,變量“____克隆結束2”的作用是非常重大的。我們引入這個變量的目的是讓程序嚴格地接次序生成屏幕上的克隆體角色(如第1個、第2個、第3個......)。
接下來,兩個循環的循環次數含義不用解釋了,分別對應行數與列數。當生成了第26個角色(Z字母)後,循環結束。這裏循環結束前的“隱藏”積木調用的作用是,用於隱藏母體!!!請各位根據前面克隆體與母體的舉例仔細體會。

row和column在循環體內的修改用於控制屏幕上行數與列數。
接下來,看克隆體執行部分的代碼。

(3)第三段

Scratch克隆技術、多線程編程及通訊技術初探

語句Scratch克隆技術、多線程編程及通訊技術初探的作用是,等待上一個角色操作結束(可能是很長時間,本例中時間是非常短暫的)。

接下來的語句Scratch克隆技術、多線程編程及通訊技術初探作用是,按字母順序生成屏幕上的角色。

接下來,根據兩個數組對應座標值來修改當前角色的座標值。
最後,克隆體計數加1,並設置克隆操作結束的標記。

總體來看,在本實例中,協調主程序與克隆體運行代碼(其實這是典型的兩個線程)的變量“____克隆結束2”的作用功不可沒。

小結

在本文中,我們還只是初步探討了Scratch多線程編程通訊技術與克隆體技術編程的部分內容,並未涉及到全部。但是,相信朋友們已經覺察出Scratch並非市面上談論得那麼“簡單”。也正因如此,Scratch(及其各種“克隆體”)才成爲風靡世界的青少年編程語言。在以後的文章中,我還會給出更多的有關使用Scratch開發創新性應用與遊戲的實例,並進一步探討Scratch編程的奧祕,敬請期待。不足之處,歡迎廣大同仁與青少年朋友批評指正。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章