From Test-Scratch-Wiki
分身 are a new feature in Scratch 2.0. They allow you to create complete duplicates of 角色, which can then individually run tasks.
Using clones properly is important — you should make sure your scripts are concise, fast, and readable. This tutorial will explain how to use clones to create a utility for particle effects. This will begin with using clones to create a 'spark' effect, then optimize the code, and finally create an easy-to-use package for a user so that he or she can incorporate it into a 专案 easily. The goal is to create a single block called "Create a spark at x: () y: ()".
Instructions
Creating the Effect
First, you need to create the parent sprite. This sprite will generate all the particles of the spark effect — not that it itself will never be one of the particles. The general plan of the code is:
- To generate a spark effect, go to the required position
- Create 10 clones, each of which is a particle of the spark
- When the particles are created, they fly out and fall, together giving the effect of a spark
First, create your sprite. Name it "Spark" and make its costume a single orange dot.
Note: | The reason why a costume is used instead of the pen to draw is because if the user's script calls "clear", the particle effect will be erased. |
To begin, create two local 变量 and call then velocity x and velocity y. Make sure that they're "for this sprite only".
Note: | Always use local variables where you can so that you do not add too many new variables to the user's palette. If the user has variables of the same name, there will be errors. If you do need a global variable, prefix its name. For example, use "(spark).color" instead of "color". |
Now you will need to write the common velocity-arc script under a "when I start as a clone" block:
當 [空白 v] 鍵被按下 重複 (10) 次 分身 [自己 v] 建立 end 當分身產生 變數 [velocity x v] 設為 ((隨機取數 (-5) 到 (5)) / (3)) 變數 [velocity y v] 設為 (隨機取數 (1) 到 (10)) 重複 (20) 次 x 改變 (velocity x) y 改變 (velocity y) 變數 [velocity y v] 改變 (-1) end 分身刪除
At this point, you can run the script! Just press space to see some sparks.
How come the velocity variables do not get muddled with each other and get reset by each clone? When we clicked "for this sprite only", we made it a lexically scoped variable which is duplicated along with the sprite. That is, each clone had its own velocity x and velocity y variables independent of each other.
One of the issues with this script is that if you press space multiple times, each spark duplicates itself. This is clearly wrong behavior; it happens because when space is pressed, each clone starts creating copies. So we need a new variable which tells us whether we are a clone or not:
當 [空白 v] 鍵被按下 重複 (10) 次 分身 [自己 v] 建立 end 當分身產生 變數 [velocity x v] 設為 ((隨機取數 (-5) 到 (5)) / (3)) 變數 [velocity y v] 設為 (隨機取數 (1) 到 (10)) 重複 (20) 次 x 改變 (velocity x) y 改變 (velocity y) 變數 [velocity y v] 改變 (-1) end 分身刪除
The is clone? variable tells the sprite whether or not to duplicate itself. Make sure this is local, too. You can also fix the issue by instead of using when space key pressed you could use
when gf clicked 重複無限次 如果 <[空白 v] 鍵被按下?> 那麼 重複 (10) 次 分身 [自己 v] 建立 end end end
Optimizations and Improvements
In this section, we will add the following optimizations to the spark engine:
- Sparks will be created gradually, instead of suddenly
- Sparks will fade out and "die" automatically, instead of waiting to touch the edge
First, we hide the parent spark, because it should not be visible. We also make the spark creation routine a custom block. Then we add a small delay when creating a clone, which changes over time to give a more realistic effect:
當 @greenflag 被點擊 變數 [is clone? v] 設為 [no] 隱藏 當分身產生 顯示 變數 [is clone? v] 設為 [yes] 變數 [velocity x v] 設為 ((隨機取數 (-5) 到 (5)) / (3)) 變數 [velocity y v] 設為 (隨機取數 (1) 到 (10)) 重複 (20) 次 x 改變 (velocity x) y 改變 (velocity y) 變數 [velocity y v] 改變 (-1) end 分身刪除 定義 Create effect at (x) (y) 定位到 x: (x 座標) y: (y 座標) 變數 [creation_delay v] 設為 [-0.05] 如果 <(is clone?) = [no]> 那麼 重複 (10) 次 變數 [creation_delay v] 改變 (0.001) 等待 ((creation_delay) * (creation_delay)) 秒 分身 [自己 v] 建立 end end 當 [空白 v] 鍵被按下 Create effect at (1) (1) :: custom
To make sparks fade out, we simply change the ghost effect:
當 @greenflag 被點擊 變數 [is clone? v] 設為 [no] 隱藏 當分身產生 顯示 變數 [is clone? v] 設為 [yes] 變數 [velocity x v] 設為 ((隨機取數 (-5) 到 (5)) / (3)) 變數 [velocity y v] 設為 (隨機取數 (1) 到 (10)) 重複 (20) 次 效果 [幻影 v] 改變 (5) x 改變 (velocity x) y 改變 (velocity y) 變數 [velocity y v] 改變 (-1) end 分身刪除 定義 Create effect at (x) (y) 定位到 x: (x 座標) y: (y 座標) 變數 [creation_delay v] 設為 [-0.03] 如果 <(is clone?) = [no]> 那麼 重複 (10) 次 變數 [creation_delay v] 改變 (0.001) 等待 ((creation_delay) * (creation_delay)) 秒 分身 [自己 v] 建立 分身 [自己 v] 建立 分身 [自己 v] 建立 分身 [自己 v] 建立 end end 當 [空白 v] 鍵被按下 Create effect at (1) (1) :: custom
We also create more sparks for a richer effect, and tweak the creation delay mildly.
Distributing the Code
To distribute the sparks library, we need to create a custom block which can be defined on any sprite. When called by the user, it should send a broadcast to the spark sprite to generate a spark effect.
We do this by creating a global list called "(spark) preferences" which contains a list of information about the spark library. It has, in order:
- x 座標 to spawn
- y 座標 to spawn
- Color to spawn
Adding these touches, we have:
當 [空白 v] 鍵被按下 create effect at (1) (1) :: custom 定義 create effect at (x) (y) 定位到 x: (x 座標) y: (y 座標) 變數 [creation_delay v] 設為 [-0.002] 如果 <(is clone?) = [no]> 那麼 重複 (3) 次 變數 [creation_delay v] 改變 (0.005) 等待 ((creation_delay) * (creation_delay)) 秒 分身 [自己 v] 建立 分身 [自己 v] 建立 分身 [自己 v] 建立 分身 [自己 v] 建立 end end 當分身產生 顯示 變數 [is clone? v] 設為 [yes] 變數 [velocity x v] 設為 ((隨機取數 (-5) 到 (5)) / (3)) 變數 [velocity y v] 設為 (隨機取數 (1) 到 (10)) 重複 (20) 次 效果 [幻影 v] 改變 (5) x 改變 (velocity x) y 改變 (velocity y) 變數 [velocity y v] 改變 (-1) end 分身刪除 當 @greenflag 被點擊 變數 [is clone? v] 設為 [no] 隱藏 當收到訊息 [(spark) spawn v] 效果 [顏色 v] 設為 (清單第 (3 v) 項項目\( [(spark) preferences v] \) :: list) create effect at (清單第 (1 v) 項項目\( [(spark) preferences v] \) :: list) (清單第 (2 v) 項項目\( [(spark) preferences v] \) :: list) :: custom
We also create the global block, and a small demo script:
當 [空白 v] 鍵被按下 Spawn Spark Effect at x: (mouse x) y: (mouse y) color: (隨機取數 (1) 到 (200)) :: custom 定義 Spawn Spark Effect at x: (x) y: (y) color: (color) 替換第 (1 v) 項於 [(spark) preferences v] 成 (x 座標) 替換第 (2 v) 項於 [(spark) preferences v] 成 (y 座標) 替換第 (3 v) 項於 [(spark) preferences v] 成 (color) 廣播訊息 [(spark) spawn v]
An issue here is that when you create a spark while an old one is running, the old spark effect stops. This is because of the broadcast. To avoid this, we use a trigger variable instead of a broadcast. We add a new item to our preferences list. Whenever a new spark is created, we simply set this to "new", and our library resets it back to blank once the effect has been created:
當 @greenflag 被點擊 變數 [is clone? v] 設為 [no] 隱藏 當分身產生 顯示 變數 [is clone? v] 設為 [yes] 變數 [velocity x v] 設為 ((隨機取數 (-5) 到 (5)) / (3)) 變數 [velocity y v] 設為 (隨機取數 (1) 到 (10)) 重複 (20) 次 效果 [幻影 v] 改變 (5) x 改變 (velocity x) y 改變 (velocity y) 變數 [velocity y v] 改變 (-1) end 分身刪除 定義 Create effect at (x) (y) 定位到 x: (x 座標) y: (y 座標) 變數 [creation_delay v] 設為 [-0.002] 如果 <(is clone?) = [no]> 那麼 重複 (3) 次 變數 [creation_delay v] 改變 (0.005) 等待 ((creation_delay) * (creation_delay)) 秒 分身 [自己 v] 建立 分身 [自己 v] 建立 分身 [自己 v] 建立 分身 [自己 v] 建立 end end 當 @greenflag 被點擊 重複無限次 如果 <[new] = (清單第 (4 v) 項項目\( [(spark) preferences v] \) :: list)> 那麼 替換第 (4 v) 項於 [(sparks) preferences v] 成 [] 效果 [顏色 v] 設為 (清單第 (3 v) 項項目\( [(sparks) preferences v] \) :: list) Create effect at (清單第 (1 v) 項項目\( [(spark) preferences v] \) :: list) (清單第 (2 v) 項項目\( [(spark) preferences v] \) :: list) :: custom end end 當 [空白 v] 鍵被按下 Spawn Spark Effect at x: (滑鼠游標的 x) y: (滑鼠游標的 y) color: (隨機取數 (1) 到 (200)) :: custom 定義 Spawn Spark Effect at x: (x) y: (y) color: (color) 替換第 (1 v) 項於 [(spark) preferences v] 成 (x 座標) 替換第 (2 v) 項於 [(spark) preferences v] 成 (y 座標) 替換第 (3 v) 項於 [(spark) preferences v] 成 (color) 替換第 (4 v) 項於 [(spark) preferences v] 成 [new]