提供:Japanese Scratch-Wiki
この記事では、Scratchで重力をシミュレーションする方法や、重力があるように見せかける方法を説明する。
物体の周囲に働く重力を表現する(三角関数)
最初に、物体のまわり360度全方向にはたらく重力の表現方法を説明する。地球のまわりに月がまわっている様子を再現すると考えればよい。 ここでは、三角関数の基本公式の1つである sin2x + cos2y = 1を利用して、キャラクターを惑星の中心から一定の距離を保って回転する例を紹介する。 以下のスクリプトは、操作するキャラクターのほうに追加すること:
@greenFlag が押されたとき::events hat [距離 v] を [130] にする [回転角度 v] を [0] にする ずっと ((回転角度) + (90)) 度に向ける x座標を ((((回転角度::variables)の[sin v]::operators) * (距離::variables)) + ((planet v)の[x座標 v])) 、y座標を ((((回転角度::variables)の[cos v]::operators) * (距離::variables)) + ((planet v)の[y座標 v])) にする もし <((回転角度)の[絶対値 v]::operators) > [359]> なら [回転角度 v] を [0] にする end もし <<[#0cc] 色に触れた> ではない> なら [距離 v] を (-1.5) ずつ変える end end
プレイヤーが惑星の上を移動できるようにするには、次のスクリプトを追加する:
@greenFlag が押されたとき::events hat ずっと もし <[スペース v] キーが押された> なら (10) 回繰り返す [距離 v] を (5) ずつ変える end <[planet v] に触れた> まで待つ end もし <[右向き矢印 v] キーが押された> なら コスチュームを [costume1 v] にする (10) 回繰り返す [回転角度 v] を (2) ずつ変える end end もし <[左向き矢印 v] キーが押された> なら コスチュームを [costume3 v] にする (10) 回繰り返す [回転角度 v] を (-2) ずつ変える end end end
キャラクターの動きにあわせて、惑星のほうも回転したいときは、次のスクリプトを追加する。
@greenFlag が押されたとき::events hat ずっと [キャラクター v] へ向ける end
効率的になめらかな動きが実現できるので、Scratch上級者には、このような三角関数を使った方法がおすすめである。工夫次第では、丸くない物体のまわりを自由に移動することも可能である。
この例のような、三角関数を利用して重力を表現しているプロジェクトの例としては、こちらを参照してほしい。
物体の周囲に働く重力を表現する(回転)
先ほどと似たような動作は、スプライトのコスチュームの中心を重力の発生ポイントに変更する方法でも実現できる。この方法は、一見シンプルに見えるが、やってみると意外と複雑になる。
@greenFlag が押されたとき::events hat 表示する x座標を (0) 、y座標を (0) にする (0 v) 度に向ける ずっと もし <<<[スペース v] キーが押された> または <<[右向き矢印 v] キーが押された> または <[左向き矢印 v] キーが押された>>> ではない> なら もし <[Sprite1 v] に触れた> なら コスチュームを [コスチューム1 v] にする end end end @greenFlag が押されたとき::events hat ずっと <[上向き矢印 v] キーが押された> まで待つ [ジャンプ 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 が押されたとき::events hat ずっと もし <<[右向き矢印 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 が押されたとき::events hat ずっと もし <<[左向き矢印 v] キーが押された> かつ <<[上向き矢印 v] キーが押された> ではない>> なら @turnLeft (-5) 度回す コスチュームを [コスチューム5 v] にする (0.05) 秒待つ @turnLeft (-5) 度回す コスチュームを [コスチューム6 v] にする (0.05) 秒待つ end もし <<[左向き矢印 v] キーが押された> かつ <[上向き矢印 v] キーが押された>> なら @turnLeft (-5) 度回す コスチュームを [コスチューム4 v] にする (0.05) 秒待つ @turnLeft (-5) 度回す コスチュームを [コスチューム4 v] にする (0.05) 秒待つ end end
回転をつかって重力を表現するプロジェクトの例としては、こちら を参照してほしい。
物理法則を使った重力の表現
重力のシミュレーションの上級テクニックとして、次のニュートンの万有引力の法則を使って、1つのスプライトが複数の物体の重力の影響を受ける場合の動きをシミュレーションする。
変数とリスト
上の式とニュートンの運動の第二法則 (F (力) = m (質量) × a (加速度)) から、物体の速度の変化 (加速度) は次の式で求めることができる: a = (Gm2)/(r2)
この式は、一方の物体による重力 (質量 = m2) によってもう一方の物体の速度が変化する様子を表している:
この等式を利用するには、次の3つの変数が必要になる。
- G (ニュートンの万有引力定数)
- 質量(m2) (もう一方のオブジェクトの質量)
- 距離(r) (オブジェクト間の距離)
Gは万有引力定数と呼ばれるもので、これをそのまま使うには、質量や距離を扱いづらい巨大な値にしなければいけないことが多い。式を簡単にして、扱いやすい数字を使うためには、ここではGについては省略して、質量についても小さな値を使うことにする。もしも、プロジェクトで扱う物体の質量が月と同じくらい重くて、物体間の距離が低軌道 (人工衛星などの軌道のうち、低めのもの) と同じくらい離れているならば、Gとして、6.67*10-11という値を使用する。
m2の質量と距離に応じた、m1(スプライト)の動く速度は次の変数に格納する:
- X速度
- Y速度
加速度をX成分とY成分に分解するときは、三角比を使用する。(重力をX方向とY方向に分解したときにできる直角三角形が、2つの物体がつくる直角三角形と相似になることを利用している)。
- 三角比
最後に、すべての物体の質量とX座標、Y座標を計算するためのインクリメント変数を用意する:
- i
スプライトに重力を与えるすべての物体の質量は、リストで保存する:
- 質量リスト
各物体のX座標とY座標についても、同様にリストで保存する:
- X座標リスト
- Y座標リスト
スクリプト例
まずは、プロジェクト内の各物体を回転するためのカスタムブロックを作成する。
定義 オブジェクトをチェック//「画面を再描画せずに実行する」をオンにすること [i v] を (1) にする // リストの先頭に ([質量リスト v] の長さ :: list) 回繰り返す . . . // ここに計算を追加 [i v] を (1) ずつ変える // 次のオブジェクトに進む end
カスタムブロックでは、「画面を再描画せずに実行する」をオンにするのを忘れないでほしい。 次に、現在のスプライトとそれぞれの物体との距離の計算を追加する。
定義 オブジェクトをチェック [i v] を (1) にする // リストの先頭に ([質量リスト v] の長さ :: list) 回繰り返す [距離 v] を ([平方根 v] \( (((((i) 番目( [X座標リスト v] ) :: list) - (X座標)) * (((i) 番目( [X座標リスト v] ) :: list) - (X座標))) + ((((i) 番目( [Y座標リスト v] ) :: list) - (Y座標)) * (((i) 番目( [Y座標リスト v] ) :: list) - (Y座標)))) \)) にする [i v] を (1) ずつ変える end
次に、X成分、Y成分に分解する前の、加速度全体の値を計算する:
定義 オブジェクトをチェック [i v] を (1) にする // リストの先頭に ([質量リスト v] の長さ :: list) 回繰り返す // 上で説明した計算式 [距離 v] を ([平方根 v] \( (((((i) 番目( [X座標リスト v] ) :: list) - (X座標)) * (((i) 番目( [X座標リスト v] ) :: list) - (X座標))) + ((((i) 番目( [Y座標リスト v] ) :: list) - (Y座標)) * (((i) 番目( [Y座標リスト v] ) :: list) - (Y座標)))) \)) にする [加速度 v] を (((i) 番目( [質量リスト v] ) :: list) / ((距離::variables) * (距離::variables))) にする [i v] を (1) ずつ変える end
次に、スプライトにかかる重力をX成分とY成分に分解する。これには、オブジェクトの水平方向と垂直方向の距離に、加速度と距離の比率を適用すればよい。 具体的には次のスクリプトになる:
定義 オブジェクトをチェック [i v] を (1) にする // リストの先頭に ([質量リスト v] の長さ :: list) 回繰り返す [距離 v] を ([平方根 v] \( (((((i) 番目( [X座標リスト v] ) :: list) - (X座標)) * (((i) 番目( [X座標リスト v] ) :: list) - (X座標))) + ((((i) 番目( [Y座標リスト v] ) :: list) - (Y座標)) * (((i) 番目( [Y座標リスト v] ) :: list) - (Y座標)))) \)) にする [加速度 v] を (((i) 番目( [質量リスト v] ) :: list) / ((距離::variables) * (距離::variables))) にする // 上で説明した計算式 [比率 v] を ((加速度) / (距離::variables)) にする [X速度 v] を ((比率) * (((i) 番目( [X座標リスト v] ) :: list) - (X座標))) ずつ変える // 引力ベクトルのX方向の成分 [Y速度 v] を ((比率) * (((i) 番目( [Y座標リスト v] ) :: list) - (Y座標))) ずつ変える // 引力ベクトルのy方向の成分 [i v] を (1) ずつ変える end
これで骨格部分は終了だ。次に、計算したX速度とY速度を利用するスクリプトを追加する。
@greenFlag が押されたとき::events hat [X速度 v] を (0) にする [Y速度 v] を (0) にする ずっと オブジェクトをチェック :: custom x座標を (X速度) ずつ変える // 速度を反映 y座標を (Y速度) ずつ変える end 定義 オブジェクトをチェック . . . // 上記参照
最終的なスクリプト
ここまでの手順にしたがうと、プロジェクトの最終型は次のようになる:
定義 オブジェクトをチェック [i v] を (1) にする // リストの先頭に ([質量リスト v] の長さ :: list) 回繰り返す [距離 v] を ([平方根 v] \( (((((i) 番目( [X座標リスト v] ) :: list) - (X座標)) * (((i) 番目( [X座標リスト v] ) :: list) - (X座標))) + ((((i) 番目( [Y座標リスト v] ) :: list) - (Y座標)) * (((i) 番目( [Y座標リスト v] ) :: list) - (Y座標)))) \)) にする [加速度 v] を (((i) 番目( [質量リスト v] ) :: list) / ((距離::variables) * (距離::variables))) にする // 上で説明した計算式 [比率 v] を ((加速度) / (距離::variables)) にする [X速度 v] を ((比率) * (((i) 番目( [X座標リスト v] ) :: list) - (X座標))) ずつ変える // 引力ベクトルのX方向の成分 [Y速度 v] を ((比率) * (((i) 番目( [Y座標リスト v] ) :: list) - (Y座標))) ずつ変える // 引力ベクトルのy方向の成分 [i v] を (1) ずつ変える end @greenFlag が押されたとき::events hat [X速度 v] を (0) にする [Y速度 v] を (0) にする ずっと オブジェクトをチェック :: custom x座標を (X速度) ずつ変える // 速度を座標に反映 y座標を (Y速度) ずつ変える end
スクロール型ゲーム (Scroller) で重力のシミュレーションを行う
スクロール型ゲームなどのプロジェクトでは、通常、下方向の引力 (重力) のみが使用される。次に、使用可能な方法をいくつか紹介する。
速度を使用する方法
速度を使用して重力を表現する方法は、様々な場面で使用できる効果的な方法である。次にスクリプトの例を示す。— ただし、このスクリプトではスプライトが地面の上にピタッと止まらず、地面に少しめり込む形になるので注意してほしい。このスクリプトは、重力の影響を受けるすべてのスプライトに追加する。
@greenFlag が押されたとき::events hat x座標を (0) 、y座標を (0) にする ずっと y座標を (Y速度) ずつ変える [Y速度 v] を ((Y速度) * (0.98)) にする //空気抵抗を表している end
@greenFlag が押されたとき::events hat ずっと もし <<[地面 v] に触れた> ではない> なら [Y速度 v] を (-0.1) ずつ変える end end
@greenFlag が押されたとき::events hat ずっと もし <[地面 v] に触れた> なら [Y速度 v] を [0] にする end <<[地面 v] に触れた> ではない> まで待つ end
このスクリプトの使用例は、こちら で確認できる。
位置を直接変化させる方法
次に、速度を使用する方法よりも単純だが、それなりの効果が得られる方法を紹介する。速度を使用する方法に比べ、ジャンプのリアルさは負けるが、どのような場面でも使いやすいというメリットがある。なにより、初心者にとっても理解しやすく、より高度なスクリプトへの足がかりとなるだろう。
@greenFlag が押されたとき::events hat ずっと もし <<[地面 v] に触れた> ではない> なら y座標を (-1) ずつ変える end end @greenFlag が押されたとき::events hat ずっと もし <[上向き矢印 v] キーが押された> なら (10) 回繰り返す y座標を (10) ずつ変える end end <[地面 v] に触れた> まで待つ end
参照プロジェクト一覧
- Direct Movement Example 作者: dazman_test
- Platformer v0.2 作者: Backlong
- First Project: Blob Advanced 作者: Blobzer22
- Cross Sections 作者: poose