資訊內容
淺談Scratch的舞臺刷新機制 Part 2——在常規積木中的應用
“?簡單來說,我們之所以能從各種屏幕上看到畫面的動態變化,都是由于屏幕在進行不斷地刷新——不斷地快速切換靜態的畫面,由于視覺暫留效應,給人產生畫面動態變化的“錯覺”。在Scratch中,可以通過舞臺觀察到角色的運動等動態效果,那么,Scratch的舞臺是否也可以看做是一個小屏幕呢?本文將對于Scratch舞臺的刷新機制進行討論。”
在淺談Scratch的舞臺刷新機制 Part 1——自制積木的不刷新屏幕功能一文中,介紹了“運行時不刷新屏幕”功能的原理及其應用。此外,關于舞臺的刷新機制,在一般積木中也有涉及,本文將會討論舞臺的刷新機制在一般積木中的應用及其實現原理。
01
案例演示
舞臺通過不斷刷新,才能讓用戶看到角色的變化,不論是運動也好,造型也罷,可以說舞臺刷新是Scratch重要的底層功能。那么除了“在運行時不刷新屏幕”還有哪些地方可以利用舞臺的刷新機制呢?或者說,關于舞臺的刷新機制還有哪些tips呢?別急,我們對于舞臺的刷新機制還不夠了解,先來思考一個問題。
為什么【重復執行】配合【移動()步】積木可以實現角色在舞臺上移動的效果呢?為什么我們可以看到角色移動的過程呢?為什么角色不是“嗖”一下就從舞臺左側閃到舞臺右側呢?也許初學者會被這樣告知,是因為程序的執行有一個延遲時間,每次移動都會延遲一小會兒,這樣就能看到移動的過程了。那么這種說法是否正確呢?再來看兩段代碼吧
右轉90度,循環4次
右轉90度,順序執行
兩段代碼在邏輯上可以說是一樣的,他們的運行結果也是一樣的,那展示它們到底意義何在?
循環結構效果
順序結構效果
盡管兩段代碼在邏輯上幾乎一致,結果也一模一樣,但是他們的運行過程有著天壤之別。在循環結構中,可以看到角色旋轉的過程,而在順序結構中,程序像是沒有執行。
02
解釋
結合上一篇中關于“運行時不刷新屏幕”功能的講解,對于這個現象應該并不陌生,也很好解釋,其實程序是執行了的,只是在執行時沒有刷新屏幕罷了,依次右轉四次,剛好是一周,又回到了原來的位置,盡管執行完畢后舞臺進行了一次刷新,但是“為時已晚”,看起來程序像是未曾運行過一般。
基于這兩種不同的現象,我的推論是,順序結構的代碼,在執行過程中,都不會刷新舞臺,只有在執行完最后一塊積木后,才會進行刷新;而循環結構的代碼,每一輪循環都會刷新一次舞臺,如循環結構中角色的旋轉效果,每執行完一次右轉的代碼,當輪循環結束,舞臺刷新一次,如此我們就會看到角色旋轉的過程了。循環結構不能單獨存在,循環結構中必然包含順序結構,所以本質還是順序結構執行完后對舞臺進行刷新。
03
延伸
在順序結構中,程序必然是只有執行完最后一塊積木才會刷新舞臺嗎?這種說法,可以說對,也可以說不對。
【等待()秒】積木對于順序結構中舞臺刷新的影響
即使是在順序結構中,代碼也不總是只有執行完最后一塊積木才刷新舞臺的,【等待()秒】積木可以打破這種順序結構中不刷新屏幕的默契,強行使其刷新,類似地,其他還有【等待()】(條件成立)積木、【說()()秒】積木、【思考()()秒】積木,凡是會使程序進入“阻塞”狀態的積木,都會使屏幕刷新。寫到這里我忽然恍然大悟,對于舞臺刷新的認識,更加證實了我之前對于【等待()】(條件成立)積木的認識,也就是在2.0中我們熟悉的【在()之前一直等待】積木。篇幅有限,亦不是主題,直接上結論:【等待()】(條件成立)積木的本質就是【重復執行直到()】積木的變形。
【等待】的本質是循環執行一段空的代碼,直到條件成立,跳出循環
如圖所示兩段代碼首先在效果上是完全等價的,其次表現也是完全一樣的。在Scratch中,只有正在執行的代碼才出現高亮黃色邊緣,三種循環如此,各種等待積木亦是如此。因此【等待】積木的本質是循環執行一段空的代碼,直到條件成立,跳出循環。現在又多了一條理由:循環結構的代碼才會在程序執行過程中不斷刷新屏幕,【等待】積木會在順序結構中強制刷新屏幕,因此【等待】的本質就是循環。還可以推斷出如下結論:
【等待()秒】的本質也是等待條件成立,只不過在這里條件是時間
【等待()秒】也可以看做是一種循環
回到我們的主題——舞臺刷新,為何那些使程序進入阻塞狀態的積木,如等待()秒,也可以使舞臺刷新,現在看來似乎是理所應當的了,因為他們的本質都是循環。
至于【重復執行】配合【移動()步】積木可以讓用戶看到角色在舞臺上移動的過程,其原因確實是由于循環結構導致的,每移動一次,完成一輪循環,舞臺就刷新一次,周而復始,用戶就可以觀察到角色移動的過程了。
04
辟謠
至于延遲時間的說法,其實是由于在循環時,舞臺會被刷新,刷新舞臺才能看出移動的過程。而在刷新舞臺的過程中,有一個附贈品——時間的消耗,刷新舞臺需要消耗一定的計算資源,計算機在執行更底層的舞臺重繪時需要花費一定的時間。這僅僅是舞臺刷新的一個附贈品,而舞臺刷新的真正任務是使用戶觀測到角色的運動過程,因此那些關于積木內部延遲時間的討論并無意義,其實測算出來的是舞臺刷新所需的時間。就如A直接產生B現象,A又順帶產生了C現象,人們觀測到了C現象,就直接下定論說是C導致B。這是一種人們在探索未知領域中常犯的錯誤,也許本文所討論的、得出的結論亦是一種類似這樣的錯誤也說不定呢?
05
應用1
總結了這么多看似沒有實際用處的推論,總該寫一些具有使用價值的東西了吧?
污漬擦除
抹布角色帶有一個和背景顏色相同的純色塊造型
根據上文得出的結論,順序結構不刷新舞臺,因此切換成純色塊造型時,舞臺是沒有刷新的,用戶也是看不到效果的。在執行完移到鼠標時針和圖章的代碼后,舞臺依舊沒有刷新,最后切換回抹布造型,這時候順序結構執行完畢,刷新舞臺,用戶只能看到最終的造型——抹布,而看不到之前的造型切換過程。而在執行圖章代碼時,在舞臺中留下的“印記”是“當前”造型,也就是純色塊,因此抹布能將純色涂抹在舞臺中,實現遮蓋住污漬的效果,而自身造型看起來不發生改變。
06
應用2
接下來介紹另一個關于舞臺刷新的應用技巧——碰撞塊
在制作案例時,尤其是一些游戲類的案例,常常會用到碰撞偵測,在角色碰到其他對象時,通過后續代碼控制其相應的行為。而角色往往又不是一些常規的幾何圖形,邊緣不光整,所以在碰撞偵測時會產生穿墻BUG,面對這種情況,我們可以使用一種我稱之為碰撞塊的技巧。以坦克對戰為例:
在控制坦克移動時,一旦碰到墻壁,則后退一定距離,但是由于坦克是個不規則圖形,往往在實際操作中會倒退進墻壁內部從而產生穿墻BUG
解決方法是給坦克創建一個邊緣規則的“碰撞塊”造型
在執行碰撞偵測等代碼之前,先切換成碰撞塊造型,在最后將造型切換回坦克造型即可。此時在用戶眼前呈現的始終是坦克的造型,而在執行中間的代碼時卻是以碰撞塊造型去進行碰撞偵測的,不會產生穿墻BUG
在了解了舞臺刷新機制及其應用技巧后,別忘記額外的小收獲:Scratch中所有的“等待”,也許其實都是由循環模擬出來的。
聲明:本文章由網友投稿作為教育分享用途,如有侵權原作者可通過郵件及時和我們聯系刪除
