From Test-Scratch-Wiki
Simulating Gravity, or at least the effect of gravity in Scratch can be difficult, but due to trigonometric 积木 in Scratch, it is possible.
Tip: | You should always adjust the scripts shown in this tutorial as necessary to fit your 专案. |
Creating Gravity Using Trigonometry
This section is designed to teach you how to simulate gravity's pull on an object around a center-point. This is similar to how the gravity of a star affects the motion of a planet.
The script below is based on a simple trigonometric identity which states that sin2x + cos2y = 1.
Below are the scripts you will need to put into the object that you want to rotate:
當 @greenflag 被點擊 變數 [Distance v] 設為 [100] 變數 [Rotation v] 設為 [0] 重複無限次 重複 (360) 次 定位到 x: ((([sin v] of (Rotation)) * (Distance)) + ([x 座標 v] \( [角色2 v] \))) y: ((([cos v] of (Rotation)) * (distance)) + ([y 座標 v] \( [角色2 v] \))) 面朝 (([direction v] of [Sprite2 v]) + (90)) 度 如果 <[359] < (Rotation)> 那麼 變數 [Rotation v] 設為 [0] end 如果 <[-359] > (Rotation)> 那麼 變數 [Rotation v] 設為 [0] end 如果 <<碰到 [Sprite2 v] ?> 不成立> 那麼 變數 [Distance v] 改變 (-1.5) end end end
If you want the person playing the game to control the rotation you can use this script:
當 @greenflag 被點擊 重複無限次 如果 <[向右 v] 鍵被按下?> 那麼 變數 [Rotation v] 改變 (2) 造型換成 [造型3 v] end end 當 @greenflag 被點擊 重複無限次 如果 <[向上 v] 鍵被按下?> 那麼 重複 (10) 次 變數 [Distance v] 改變 (5) end 等待直到 <碰到 [Sprite2 v] ?> end end 當 @greenflag 被點擊 重複無限次 如果 <[向左 v] 鍵被按下?> 那麼 變數 [Rotation v] 改變 (-2) 造型換成 [造型4 v] end end
For the "Planet" or other object that is being rotated about you will want to use this script:
當 @greenflag 被點擊 重複無限次 面朝 [planet v] 向 end
Make sure you set the "Planet" or other object's rotation to "do not rotate".
Using trigonometry is a smooth and effective way for more experienced Scratcher to simulate gravity. With some more advanced scripts you can even rotate about non-circular objects.
An example of trigonometric gravity can be seen here.
Creating Gravity Using Rotation
Another method of simulating gravity is to change the center of a sprite so when you rotate it, it appears to be pulled by gravity. This method is much more simple, but far more difficult to achieve.
- Change the sprite's center to the center of the planet. File:绘图编辑器 With Sprite Center in Center.png
- Repeat Step 1 for every single sprite of that character.
- Write scripts for each sprite for every different situation:
當 @greenflag 被點擊 顯示 定位到 x: (0) y: (0) 面朝 (0 v) 度 重複無限次 如果 <<<[空白 v] 鍵被按下?> 或 <<[向右 v] 鍵被按下?> 或 <[向左 v] 鍵被按下?>>> 不成立> 那麼 如果 <碰到 [角色1 v] ?> 那麼 造型換成 [造型1 v] end end end 當 @greenflag 被點擊 重複無限次 等待直到 <[向上 v] 鍵被按下?> 播放音效 [jump v] 重複 (20) 次 造型換成 [造型4 v] 移動 (1.5) 點 end 重複 (10) 次 造型換成 [造型4 v] 移動 (1) 點 end 重複 (10) 次 造型換成 [造型4 v] 移動 (-1) 點 end 重複 (10) 次 造型換成 [造型4 v] 移動 (-1.5) 點 end 造型換成 [造型1 v] 定位到 x: (0) y: (0) end 當 @greenflag 被點擊 重複無限次 如果 <<[向右 v] 鍵被按下?> 且 <<[向上 v] 鍵被按下?> 不成立>> 那麼 右轉 @turnright (5) 度 造型換成 [造型2 v] 等待 (0.05) 秒 右轉 @turnright (5) 度 造型換成 [造型3 v] 等待 (0.05) 秒 end 如果 <<[向右 v] 鍵被按下?> 且 <[向上 v] 鍵被按下?>> 那麼 右轉 @turnright (5) 度 造型換成 [造型4 v] 等待 (0.05) 秒 右轉 @turnright (5) 度 造型換成 [造型4 v] 等待 (0.05) 秒 end end 當 @greenflag 被點擊 重複無限次 如果 <<[向左 v] 鍵被按下?> 且 <<[向上 v] 鍵被按下?> 不成立>> 那麼 右轉 @turnright (-5) 度 造型換成 [造型5 v] 等待 (0.05) 秒 右轉 @turnright (-5) 度 造型換成 [造型6 v] 等待 (0.05) 秒 end 如果 <<[向左 v] 鍵被按下?> 且 <[向上 v] 鍵被按下?>> 那麼 右轉 @turnright (-5) 度 造型換成 [造型4 v] 等待 (0.05) 秒 右轉 @turnright (-5) 度 造型換成 [造型4 v] 等待 (0.05) 秒 end end
One example of rotational gravity can be seen here.
Creating Gravity Using Physics
One advanced technique for simulating gravity involves Newton's law of universal Gravity:
Variables and Lists
From this equation and Newton's 2nd Law of Motion (which states that F = ma) we can solve for the change in velocity of an object as: a = (Gm2)/(r2)
This describes the acceleration of one object due to the gravity of another (with mass = m2)
In the equation above, three 变量s can be seen to be needed:
- G (Newton's universal law of gravity)
- m2(mass of the other object)
- r (the distance the objects are from each other)
G is a universal constant and can often lead to masses and distances that seem very awkward or unintuitive. To simplify the equation and allow you to use easier/friendlier numbers, we can actually ignore G. When you choose your relative masses you will be factoring it in. If the project involves very large (e.g. Moon-sized) masses and large (e.g. low-orbital level) distances, use 6.67*10-11 for G.
Along the mass of object two and its distance, the speed of the moving object (object one) will need to be stored:
- X Velocity
- Y Velocity
Also, to turn the acceleration into its x and y components, a ratio will be used (this is based on the idea that the x and y forces form a right triangle similar to that formed by the objects themselves)
- Ratio
Finally, a variable will be used to iterate through every mass and every object's x and y 座標:
- I
Those masses will be stored in a list:
- Masses
As well as the x and y 座標s:
- x座標s
- y 座標s
编写程式
To begin, a custom block is needed that will iterate through every object in the project:
定義 Check Objects//make sure this runs without screen refresh! 變數 [I v] 設為 (1) // the beginning of the list 重複 (清單 [Masses v] 的項目數 :: list) 次 . . . // this is where the calculations will go 變數 [I v] 改變 (1) // moving onto the next object end // each object takes up two items in the list
To note, the custom block needs to run without a screen refresh. After the custom block is created, the distance between the sprite and an object needs to be computed:
定義 Check Objects 變數 [I v] 設為 (1) // the beginning of the list 重複 (清單 [Masses v] 的項目數 :: list) 次 變數 [Dist. v] 設為 ([sqrt v] 數值 ((((清單第 (I) 項項目\( [x positions v] \) :: list) - (x座標)) * ((清單第 (I) 項項目\( [x positions v] \) :: list) - (x座標))) + (((清單第 (i) 項項目\( [y positions v] \) :: list) - (y 座標)) * ((清單第 (i) 項項目\( [y positions v] \) :: list) - (y 座標))))) 變數 [I v] 改變 (1) end
Next, the overall acceleration is needed:
定義 Check Objects 變數 [I v] 設為 (1) // the beginning of the list 重複 (清單 [Masses v] 的項目數 :: list) 次 變數 [Dist. v] 設為 ([sqrt v] 數值 (((清單第 (I) 項項目\( [x positions v] \) :: list) - (x座標)) * ((清單第 (I) 項項目\( [x positions v] \) :: list) - (x座標))) + (((清單第 (i) 項項目\( [y positions v] \) :: list) - (y 座標)) * ((清單第 (i) 項項目\( [y positions v] \) :: list) - (y 座標))))) 變數 [Acceleration v] 設為 ((item (i) of [Masses v] :: list) / ((Dist.) * (Dist.))) // equation we found above 變數 [I v] 改變 (1) end
Next, the force is needed to turn into its x and y components. To achieve this, the force will be compared to the distance, and that ratio, when compared to the horizontal/vertical distance between the sprite and an object, will achieve just that:
定義 Check Objects 變數 [I v] 設為 (1) // the beginning of the list 重複 (清單 [Masses v] 的項目數 :: list) 次 變數 [Dist. v] 設為 ([sqrt v] 數值 ((((清單第 (I) 項項目\( [x positions v] \) :: list) - (x座標)) * ((清單第 (I) 項項目\( [x positions v] \) :: list) - (x座標))) + (((清單第 (i) 項項目\( [y positions v] \) :: list) - (y 座標)) * ((清單第 (i) 項項目\( [y positions v] \) :: list) - (y 座標))))) 變數 [Acceleration v] 設為 ((item (i) of [Masses v] :: list) / ((Dist.) * (Dist.))) // equation we found above 變數 [Ratio v] 設為 ((Acceleration) / (Dist.)) 變數 [X Velocity v] 改變 ((Ratio) * ((清單第 (I) 項項目\( [x positions v] \) :: list) - (x座標))) // x component of the force vector 變數 [Y Velocity v] 改變 ((Ratio) * ((清單第 (i) 項項目\( [y positions v] \) :: list) - (y 座標))) // y component of force vector 變數 [I v] 改變 (1) end
The script is now done, though the variables X Velocity and Y Velocity need to have some use:
當 @greenflag 被點擊 變數 [X Velocity v] 設為 (0) 變數 [Y Velocity v] 設為 (0) 重複無限次 Check Objects :: custom x 改變 (X Velocity) // applying the velocities y 改變 (Y Velocity) end 定義 Check Objects . . . // refer above for the coding
Final Product
Once the steps above have been followed, this should be the final coding:
define Check Objects 變數 [I v] 設為 (1) // the beginning of the list 重複 (清單 [Masses v] 的項目數 :: list) 次 變數 [Dist. v] 設為 ([sqrt v] 數值 ((((清單第 (I) 項項目\( [x positions v] \) :: list) - (x座標)) * ((清單第 (I) 項項目\( [x positions v] \) :: list) - (x座標))) + (((清單第 (i) 項項目\( [y positions v] \) :: list) - (y 座標)) * ((清單第 (i) 項項目\( [y positions v] \) :: list) - (y 座標))))) 變數 [Acceleration v] 設為 ((item (i) of [Masses v] :: list) / ((Dist.) * (Dist.))) // equation we found above 變數 [Ratio v] 設為 ((Acceleration) / (Dist.)) 變數 [X Velocity v] 改變 ((Ratio) * ((清單第 (I) 項項目\( [x positions v] \) :: list) - (x座標))) // x component of the force vector 變數 [Y Velocity v] 改變 ((Ratio) * ((清單第 (i) 項項目\( [y positions v] \) :: list) - (y 座標))) // y component of force vector 變數 [I v] 改變 (1) end 當 @greenflag 被點擊 變數 [X Velocity v] 設為 (0) 變數 [Y Velocity v] 設為 (0) 重複無限次 Check Objects x 改變 (X Velocity) // applying the velocities y 改變 (Y Velocity) end
滚动卷轴裡的重力模拟
Gravity can be replicated on Scratch to be used in Scrollers and other project where an object is forced downward. Listed below are several methods that you can use.
Velocity Method
The Velocity Method is a great method for creating gravity and is highly effective and adaptable for multiple situations. Here is an example script —please note, this script will have the sprite inside the ground, rather than on top of it. This script will be placed into the Sprite that is being affected by gravity:
當 @greenflag 被點擊 定位到 x: (0) y: (0) 重複無限次 y 改變 (Y Velocity) 變數 [Y Velocity v] 設為 ((Y Velocity) * (0.98)) end
當 @greenflag 被點擊 重複無限次 如果 <<碰到 [Ground v] ?> 不成立> 那麼 變數 [Y Velocity v] 改變 (-0.1) end end
當 @greenflag 被點擊 重複無限次 如果 <碰到 [Ground v] ?> 那麼 變數 [Y Velocity v] 設為 [0] end 等待直到 <<碰到 [Ground v] ?> 不成立> end
Click here to see an example.
Direct Movement Method
Direct movement is more simple than the Velocity Method, but far less efficient at what it does. Not only does the jump look unrealistic, but it is far less practical in almost all situations. Nonetheless, the script works and is a good starting point for beginners:
當 @greenflag 被點擊 重複無限次 如果 <<碰到 [Ground v] ?> 不成立> 那麼 y 改變 (-1) end end 當 @greenflag 被點擊 重複無限次 如果 <[向上 v] 鍵被按下?> 那麼 重複 (10) 次 y 改變 (10) end end 等待直到 <碰到 [Ground v] ?> end
示例
- Direct Movement Example by dazman_test
- Platformer v0.2 by Backlong
- First Project: Blob Advanced by Blobzer22
- Cross Sections by poose