資訊內(nèi)容
控制Scratch異步代碼的執(zhí)行順序
你是否在編寫項(xiàng)目時(shí)遇到過一些棘手的BUG,比如邏輯明明是通順的,但是執(zhí)行結(jié)果卻不符預(yù)期。又如兩段代碼完完全全一模一樣,但是結(jié)果卻大相徑庭。這極有可能是代碼的執(zhí)行順序沒有得到控制所導(dǎo)致的,這是一些初學(xué)者常常會(huì)遇到的問題。本文將分析這種代碼執(zhí)行順序失控的原因及其應(yīng)對(duì)方法。
01
依照慣例,先來看幾個(gè)案例。
《恐龍吃蘋果》
舞臺(tái)布局
恐龍代碼
使用鍵盤方向鍵控制恐龍移動(dòng),點(diǎn)擊綠旗使恐龍回到起始位置,準(zhǔn)備進(jìn)行下一次游戲。
蘋果代碼
判斷蘋果是否碰到恐龍,一旦碰到則隱藏,當(dāng)綠旗被點(diǎn)擊時(shí)將蘋果切換至顯示狀態(tài),準(zhǔn)備進(jìn)行下一次游戲。
案例很普通,代碼也普通得不能再普通了,都進(jìn)行了初始化操作,甚至可以說代碼是比較規(guī)范的。那么來看一下實(shí)際運(yùn)行效果。
案例效果
注意到問題所在了嗎?在圖中,一共點(diǎn)擊了三次綠旗,第一次,啟動(dòng)程序,控制恐龍移動(dòng),蘋果被恐龍吃掉-隱藏;第二次點(diǎn)擊綠旗,重啟程序,恐龍確實(shí)回到初始位置了,但是,明明設(shè)置了顯示狀態(tài)的初始化,蘋果卻并沒有出現(xiàn)。第三次點(diǎn)擊綠旗才出現(xiàn)。
問題是,為什么第二次點(diǎn)擊綠旗時(shí),蘋果沒有按照預(yù)想的那樣,切換成顯示狀態(tài)呢?
在Scratch中遇到BUG時(shí),有很多種調(diào)試方法,這次介紹一種變量法,通過變量來判斷某處代碼是否執(zhí)行、執(zhí)行次數(shù)。
新建變量“score”,在蘋果代碼中增加【將(score)增加(1)】
為了調(diào)試BUG,因此在這里不對(duì)變量做初始化。
調(diào)試效果
變量score初始值為0,在第一次點(diǎn)擊綠旗,被恐龍吃掉后,score的值變?yōu)?,此時(shí)再次點(diǎn)擊綠旗重啟程序,恐龍回到初始位置,蘋果沒有顯示,而score的值此時(shí)變?yōu)?,說明畫圈處的代碼被執(zhí)行了兩次。
所以,蘋果并不是沒有顯示,而是顯示后再一次碰到恐龍,再次隱藏。唯一合理的解釋是,在第二次點(diǎn)擊綠旗時(shí),蘋果的代碼被先執(zhí)行了,而此時(shí)恐龍并沒有回到初始位置,因此蘋果再次碰到恐龍,再次隱藏。這時(shí)候再執(zhí)行恐龍的代碼,恐龍回到初始位置,為時(shí)已晚,蘋果已經(jīng)被恐龍“誤食”了。
在Scratch中,看似同時(shí)執(zhí)行的代碼,實(shí)則是有先后順序的。兩段代碼沒有按照預(yù)想的先后順序執(zhí)行,導(dǎo)致程序初始化時(shí)出現(xiàn)BUG。
很多初學(xué)者經(jīng)常會(huì)遇到這樣的問題,有的程序點(diǎn)擊一次是無法正常運(yùn)行的,第二次點(diǎn)擊才會(huì)正常。大多數(shù)情況其實(shí)和上文中展示的這個(gè)案例屬于同一種情況。如果再次遇到類似這樣的情況,就要好好考慮一下是不是由于沒有控制好代碼的先后執(zhí)行順序而導(dǎo)致初始化BUG。
02
這個(gè)問題應(yīng)該如何解決呢?既然是代碼執(zhí)行順序不受控制,那么最簡單的方法就是通過【等待()秒】積木來調(diào)整順序。我們希望的是恐龍先“離開事發(fā)地點(diǎn)”,回到初始位置,再執(zhí)行蘋果是否碰到恐龍的代碼,只需要在點(diǎn)擊綠旗后,等待一段短暫的時(shí)間再執(zhí)行這段代碼即可。
至于等待的時(shí)間,設(shè)置成0.1還是0.01其實(shí)都可以,但是在這里我建議將數(shù)值設(shè)為0,即【等待(0)秒】。兩段當(dāng)綠旗被點(diǎn)擊積木下的代碼的先后執(zhí)行順序間隔非常短,等待0秒積木足以改變其順序。因?yàn)椤镜却?)秒】積木會(huì)刷新屏幕,而刷新屏幕相對(duì)來說耗時(shí)較長(參見淺談Scratch的舞臺(tái)刷新機(jī)制 Part 2——在常規(guī)積木中的應(yīng)用)。
加入【等待(0)秒】后,蘋果初始化正常
這在我看來有兩點(diǎn)意義,一是副作用最小,我們的目的是控制程序運(yùn)行的先后順序,但是如果等待的時(shí)間過久,會(huì)造成明顯的卡頓,因此在能保證代碼運(yùn)行順序的前提下,時(shí)間越短越好。二是起到一種標(biāo)志作用,這種特殊的用法我們不妨約定俗成地將其視作為解決這類BUG的標(biāo)志,一旦看到這樣的用法,就知道是用來控制代碼執(zhí)行順序的。
關(guān)于【等待(0)秒】還可以參照科技傳播坊的疑難雜癥視頻 vol.41 《等待0秒的意義》。
03
BUG是解決了,但是在《恐龍吃蘋果》這個(gè)案例中,為什么是先執(zhí)行蘋果的代碼再執(zhí)行恐龍的代碼?而不是反過來呢?是什么決定了代碼的執(zhí)行順序?
為了更直觀地表現(xiàn)代碼的執(zhí)行順序,我們換一個(gè)更簡單的案例,通過變量來展現(xiàn)執(zhí)行順序。
圖層順序?qū)τ诋惒酱a執(zhí)行順序的影響
初始狀態(tài)下,橘貓的代碼是將變量設(shè)為0,圖層在后,藍(lán)貓的代碼是將變量設(shè)置為1,圖層在前。運(yùn)行結(jié)果為0,表明藍(lán)貓的代碼先執(zhí)行了,橘貓后執(zhí)行,將變量覆蓋為0。
通過鼠標(biāo)拖拽改變圖層順序,將橘貓圖層置于藍(lán)貓前面。運(yùn)行結(jié)果為1,表明橘貓的代碼先執(zhí)行了,藍(lán)貓后執(zhí)行,將變量覆蓋為1。
通過實(shí)驗(yàn)我們可以得出以下結(jié)論:
不同角色的異步代碼執(zhí)行順序如下:角色圖層在前的先執(zhí)行,圖層在后的后執(zhí)行。
為排除鼠標(biāo)拖拽可能產(chǎn)生的其他因素,通過代碼調(diào)整圖層順序,結(jié)論依舊成立。
04
盡管調(diào)整圖層順序是一種可控的、確定的能控制異步代碼執(zhí)行順序的方法,但是編寫程序的我們不可能通過手動(dòng)拖拽角色來控制代碼執(zhí)行順序。萬一體驗(yàn)者在非全屏模式下不小心拖拽了某個(gè)角色,改變了執(zhí)行順序而導(dǎo)致BUG。代碼明明完全一樣,但就是無法正常運(yùn)行,那將會(huì)是一件多么尷尬的事。(下次再遇到這樣的情況可以考慮一下是否是因?yàn)閳D層順序影響了代碼執(zhí)行順序,而又沒有很好地控制執(zhí)行順序)
為控制代碼執(zhí)行順序,上文中也提到了,可以使用【等待(0)秒】積木來解決,這種方法簡單直接,且對(duì)原代碼的改動(dòng)最小,建議新手使用。
但是這是一種“把代碼寫死”的做法,在此給追求優(yōu)質(zhì)代碼的scratchers提供一種更完美的思路——消息,利用消息來控制代碼的執(zhí)行順序。
橘貓代碼
藍(lán)貓代碼
通過【廣播()并等待】實(shí)現(xiàn)同步
隨手畫的流程圖
控制代碼的執(zhí)行順序,你學(xué)會(huì)了嗎?
聲明:本文章由網(wǎng)友投稿作為教育分享用途,如有侵權(quán)原作者可通過郵件及時(shí)和我們聯(lián)系刪除
