分身同步移動

Scratch 分身再研究

分身同步移動 1-時間控制法

當年有個大型機台電玩叫做 Space Invaders,敵人排成會好幾排,一起向左或向右移動,不時還會俯衝下來攻擊。Scratch 要復刻這個遊戲不難,但要如何讓敵人同時往左或往右移動呢?傑夫老師帶你來研究各種做法。

https://scratch.mit.edu/projects/384762400/

Rokcoder 的遊戲 Space Invaders:https://scratch.mit.edu/projects/384762400/

先看看要做到最基本的效果,三個蝴蝶分身同時往左或往右移動。

三個蝴蝶分身同時往左或往右移動

三個蝴蝶分身同時往左或往右移動

建立分身的程式不用說明,而這個方式是想利用定時變換全域變數(方向)來讓所有分身變換方向。變數方向的值為 1 就往右、變數方向的值為 -1 就往左移動,每 2 秒變換一次。

定時變換公有變數(方向)來讓所有分身變換方向

分身的程式,就這麼簡單。每 0.2 秒移動 5 點,但往左還是往右,由變數(方向)決定。

每 0.2 秒移動 5 點,但往左還是往右,由變數(方向)決定。

每 0.2 秒移動 5 點,但往左還是往右,由變數(方向)來決定。

這麼做,可以讓蝴蝶分身都同步往左或往右移動,但是~會發現有時候點擊蝴蝶時,分身不會刪除。

發現有時候點擊蝴蝶分身不會刪除

發現有時候點擊蝴蝶分身不會刪除

這是因為分身的『重複直到』迴圈中有個『等待 0.2 秒』,如果蝴蝶被點擊的瞬間發生在這 0.2 秒之內,就不會被偵測到。

雖然可以用『當角色被點擊』時『分身刪除』來解決這個問題,但如果今天是被子彈射擊到要分身刪除,就不能這麼做了,必須把『等待 0.2 秒』換掉。

傑夫老師的做法是,用一個私有變數(.tick),分身產生時從 0 開始,迴圈每跑一圈加 1 ,也就是記錄迴圈跑了幾圈的意思。因為迴圈中有個『圖像效果顏色改變 0』,這會讓迴圈一圈跑 0.03 秒。之後加上『如果 《.tick 除以 7 的餘數等於 0》』時再移動,就可以了。為什麼是除以 7?因為 0.03 x 7 = 0.21,也就是 0.21 秒才會移動,與等待 0.2 秒的效果相同。

傑夫老師決定還是使用 "私有變數" 一詞比較合適要分清全域變數、私有變數為何,請參考 分身編號 1 -Scratch分身與執行緒。並且老師會在私有變數的名稱前面加一個 " . ",這樣就可由名稱上直接來分辨這是個私有變數。

如果不知道為什麼一圈 0.03 秒的,請見 等待 0 秒? - Scratch 執行緒深入研究

修改過的分身程式

修改過的分身程式

這方法是由時間來決定是否要換方向,是否有其他做法,待傑夫老師下回分解。

分身同步移動 2各自計步法

前面的方式中,方向是由時間來決定的,但大多數的情況是由移動的步數來決定才對,也就是所有分身一起往左或往右移動一樣的距離後再變換方向,所以上面的方法要繼續做修改。

既然要由移動的距離決定,那就來分別計算每個分身都走了幾步,走到了一樣步數的時候就變換方向。然而,要用這個方法,方向也要變為私有變數,也就是讓每個分身有各自的方向、各自去決定何時該回頭。所以傑夫老師建立了兩個變數(.計步)與(.方向),分身的程式就修改如下。

為了看出差別,先移除修改不能被點擊加入(.tick)的部分程式,改回使用『等待 0.2 秒』。

也請注意,原本本尊程式最下方每 2 秒改變方向的程式要刪除掉。

分身的程式就修改如此

分身的程式就修改如此

每個分身,都有自己的方向而且一開始都是往右,也都各別有一個記錄步數的變數(.計步),一開始都是 0。迴圈每執行一次(.計步)就加 1,每加到 10 就會改變(.方向)也會把(.計步)歸零。這樣,就可以讓所有分身每走10步就變換方向了。

等一等,聰明的你有沒有看出來?改成每個分身走 10 步就換方向,可是方向與計步都是每個分身自行處理的,這沒有達到題目"同步"的目的呀!除非,每個分身要同時邁出第一步。

我們來改成 10 個分身看看,分身程式不變,本尊程式稍稍修改如下:

建立 10 個分身

建立 10 個分身

只是變成 10 個分身,就變的不同步了,怎麼會這樣~?

一開始就沒有同時往右,也就沒有同時變換方向

一開始就沒有同時往右,也就沒有同時變換方向

由於每個分身產生的時候有時間差,所以一開始就沒有同時往右,也就沒有同時變換方向了。

修改方式 1:『分身產生』後不急著就開始移動,等待一個變數(開始)被本尊改變後,再開始進入迴圈。

這就只是強制讓所有分身一起動起來,很好理解。

修改方式 2:建立分身的『重複 10 次』改用一個「函式」來執行,而這個函式必須勾選「執行完畢再更新畫面」。

這樣,10 個分身先建立好顯示在舞台上之後,所有的分身才會一起動起來。

必須勾選「執行完畢再更新畫面」

必須勾選「執行完畢再更新畫面」

建立分身改用含式方式

建立分身改用含式方式

修改後就會同步往左、往右移動了,因為所有的分身是同時出現的。

所有分身同時出現就會同步往左、往右移動

真的要做到"同步"不是應該用到廣播嗎?那可以用廣播嗎?且聽傑夫老師下回分解。

分身同步移動 3廣播訊息法

在用廣播之前,先用分身來看看,以下的做法是否可以?

範例回到3隻蝴蝶,現在要做到的效果是只要有一隻蝴蝶分身碰到邊緣,就改變『方向』,讓所有的蝴蝶就一起回頭。

只要有一個分身碰到邊緣,就改變『方向』

只要有一隻蝴蝶分身碰到邊緣,就改變『方向』

以下就是執行結果。傑夫老師沒有加『等待0.2秒』就是為了要讓各位看到長時間的變化,最左邊那隻蝴蝶分身與中間的距離越來越遠了!

最左邊那隻蝴蝶分身與中間的距離越來越遠了!

最左邊那隻蝴蝶分身與中間的距離越來越遠了!

  • 為什麼會這樣!?
    那是因為
    分身執行是有先後順序的,最左邊的蝴蝶分身最先執行,當它往左碰到邊緣時立刻把『方向』變更了,造成另外兩隻蝴蝶分身,就先回頭了。這狀況一直持續下去,最後變成了最左邊的蝴蝶分身與中間那隻的距離越來越遠了。

  • 那為什麼最右邊的不會這樣!?
    因為
    最右邊的蝴蝶分身最後執行,三隻蝴蝶都往右走了一步後,最右邊的蝴蝶分身"才"碰到邊緣改變『方向』,而三隻蝴蝶都在下一個迴圈中往左移動。

前面說了,既然叫同步,用廣播叫每個分身同時移動,應該就會同步了吧?傑夫老師把程式改成這樣,統一由本尊發廣播訊息,命令所有分身同時移動。

統一由本尊發廣播訊息,命令所有分身同時移動

統一由本尊發廣播訊息,命令所有分身同時移動

『當分身產生』之後,什麼都不做,就等著被點擊。但每個分身都會收到廣播訊息『移動』,收到後便移動並且判斷是否碰到邊緣,如果有任何一個分身碰到邊緣,就改變『方向』。

執行結果如下,這次換成右邊的蝴蝶分身脫隊了!

這次換成右邊的蝴蝶分身脫隊了

這次換成右邊的蝴蝶分身脫隊了

原來~分身處理廣播訊息也有先後順序。從上面的分析不難推斷,最右邊的蝴蝶分身最先處理廣播訊息

這裡還要注意一點,就是本尊的位置。

本尊要定位到中間

因為本尊雖然隱藏了也會收到廣播,並且執行到『碰到邊緣』,如果不把它定位到中間,會影響執行結果。但是這不是正解,如果要尋求正解,請看分身管理這篇

那這要怎麼解決呢?要解決這個方式就必須使用到一個新的變數『碰到了』,並且程式修改成這樣

當有任何一個分身碰到邊緣時,就把『碰到了』設為 1,但不立即改變『方向』

當有任何一個分身碰到邊緣時,就把『碰到了』設為 1,但不立即改變『方向』

利用『碰到了』這個旗標變數,當有任何一個分身碰到邊緣時,就把『碰到了』設為 1,但不立即改變『方向』,而是在本尊的程式中來改變。

這樣,可以理解成,當所有蝴蝶分身都移動之後,這時才由本尊檢查看是否有分身碰到了邊緣,如果有才將方向改變,在下一次發出廣播時所有分身再會往新的方向移動。

這裡面,還是有很多 Scratch 執行緒相關的事,但傑夫老師就不詳述了,避免大家睡著了 😴。但如果您是 Scratch 老師,在遇到這樣的問題時,必須找到解法並且能解釋給學生聽。

這個分身同步的單元就說明到這邊,Bye now~