pg04

テーマ 物理エンジン と プログラム

内容

Algodoo + Thyme

Thyme は第1回の講義で紹介した 2次元物理シミュレータ Algodoo に内蔵されてているAlgodoo専用のスクリプト言語です。

Algodoo のシーンのオブジェクト(図形)をプログラムで制御したり、オブジェクトをプログラムで作成することができます。

今回の授業の説明資料は、動画で用意しました。 youtube にアップロードしてあります。

動画の解像度が不足の場合は、再生解像度の設定を 自動から → 720p に変更 や、全画面表示 を試してみてください。

Thymeについては、私の動画以外に以下の外部サイトの解説も参照してみてください。

参考資料1 http://mandel59.hateblo.jp/entry/2012/03/11/005914

参考資料2 https://www6.atwiki.jp/p-phun/pages/36.html

演習1

第1回の復習とオブジェクトを追跡するカメラの設定について扱う。

・algodoo のオブジェクトをキーボードで操作する。

説明ビデオ1(6分)

操作復習

モーターの回転方向を左右矢印キーで、正転、逆転、上矢印でブレーキに設定する。

・画面を移動するオブジェクトに追随するカメラの設定(画面スクロール)

説明ビデオ2(4分)

フリッパーの作成とカメラの追従設定

※選択したオブジェクトの セレクトメニュー から オブジェクトに合わせて視点を移動させる をチェック

シーンを保存する ファイル名 pg04s1

演習2

・algodoo の Thyme(タイム)

プログラムでオブジェクトを操作する

説明ビデオ3(22分)

オブジェクトのプロパティ(設定値)を変更する。右クリックメニューの スクリプトメニュー から設定できる。

サークルオブジェクトのプロパティ

color 色

※色の設定には RGBAカラーを使用する。値は 0.0~1.0の範囲で、リストの書式 [1.0 , 1.0 , 1.0 , 1.0] を使う。

※値を並べたものをリストという

※リストは様々なプログラム言語でいくつかの値を一組にしてまとめて扱うために登場します。

※Scratchにもリスト機能があります。ゲームやシミュレーションなど複雑な表現で活躍する機能です。

radius 半径

※radiusはサークルオブジェクト専用のプロパティ

次に、四角形(ボックス)を描いてサイズの調整をします。

※ボックスオブジェクトの大きさは radius ではなく、 size で設定する。

size サイズ

※幅 と 高さ をリスト [w , h ] wとhは数値で指定する。

※sizeプロパティは ボックスオブジェクトで利用可能(サークルでは利用不能)

※サークルにはradius ボックスには size の様にオブジェクトに応じてプロパティの項目は異なる。

vel 速度(ベロシティ)

※速度の設定は ベクトル(vx,vy)を使う。 リストの書式で [1.0, 0.0] のように指定する。

オブジェクトに初速を与えて、再生してみよう。

オブジェクトに設定する速度によっては衝突判定に失敗して壁をすり抜ける。

実験映像

モーターの回転スピード(マイナス値は逆回転)を設定する。

ギア(歯車)オブジェクト モーター用のプロパティがある。

・モーターの回転方向をプログラムで制御する

Thyme コンソール の表示 F10 キー

スクリプトの入力欄を開く。

モーターの回線速度の設定を先ほどはオブジェクトのプロパティで直接指定した。

ここでは、変数を準備して変数に記録した値によりモーターの回転速度を調整できるようにする。

変数: メモリに設定値(データ)を格納し、プログラムから利用できるように名前を付けたもの

変数名 変数に付けた名前。複数の異なるメモリを名前を付けて区別する。プログラムで変数名を指定してデータの読み取りや記録をする。

代入 変数に値をセットすること。 「変数に値を 代入 する」というように表現する。

・変数の準備

Thyme コンソールに以下のように順次キーボードから変数名やコマンドを入力していく。

入力したコマンドは、Enterキーを押して実行する。

変数の参照:変数名を入力することで、変数の内容を調べて表示することができる。

scene.my.mtspd

最初に実行した際は undefined 未定定義 と表示される。変数用のメモリは存在しているが値がまだ設定されていない状態のため。

ここで、 mtspd(モータースピード)がプログラムで用いる変数名。変数には予めシステムに設定済みの変数や、プログラマが設定する変数がある。mtspdはこれから利用する予定の変数。

scene.myの部分はalgodooで現在動いているシーンの中のユーザ領域を示すキーワード。

設定値 -1.5 を設定する (初期化)

※ キーボードの上向き矢印を入力すると、入力コマンドの履歴を呼び出して再利用できる。

scene.my.mtspd = -1.5

※ = と - の間には空白が必要です。

※ この例では -1.5 にモータースピードを設定しましたが、シーソーの板のサイズによっては -3.0などより大きな数値にしないと板が動きません。各自で適切な値に調整してください。

手動で操作:

ボックスオブジェクト と サークルオブジェクト と 回転軸 でシーソーを作る

回転軸はモーター化しておく

シーソー作成手順:

・横長のボックスを描く。現実のシーソーよりも短めの長さにする。歯車の回転で地面に接触する長さがあればよい。

・ボックスの位置合わせ スクリプトメニュー pos = [-3.0 , 3.0]

・円を描く。サイズはシーソーの台(ボックス)が地面から浮くような大きさ。

・円の位置合わせ スクリプトメニュー pos = [-3.0 , 3.0]

・円に回転軸をつける 図形アクション → オブジェクトの中心に回転軸を配置する

モーターの回転速度を変数の値で設定するプログラムを回転軸に設定する。

次のコードをモーターのスクリプトメニューから設定する。

morterSpeed = { scene.my.mtspd }

計算式による値の設定する。

次のコードをコンソールに入力して動作を確認する。

scene.my.mtspd = - scene.my.mtspd

※ = と - の間には空白が必要です。

コンソールで実行する度に回転方向が+-で反転することを確認する。

オブジェクトのイベント処理

衝突時に実行するプログラム

onCollide = (e) => { scene.my.mtspd = - scene.my.mtspd }

※ = と - の間には空白が必要です。

※コードについて:

onCollide オブジェクト同士の衝突イベントが発生したときにalgodooシステムから呼び出されるイベントハンドラ(イベント処理プログラム)

onCollide = と代入でイベントハンドラにコードを設定する。関数型言語などでは変数にコードを格納するのはよく使うテクニック(JavaScriptでも同様のパターンを多用する)

(e) => { コード } は引数(コードに渡す変数) e を処理するコードを表現する書式。

a = -a は変数 a の値に - 符号をつけて設定しなおすコード。a がマイナスの値の場合は + の値になる。

シーンを保存する ファイル名 pg04s2

演習3

説明ビデオ4(13分)

次のスクリプトをコンソールで実行:

画面に、XY座標(pos)と半径(radius)を設定してサークルを追加作成するプログラム

scene.addCircle({ pos = [ 0.0 , 2.0 ]; radius = 1.0 })

※コードについて

scene.addCircle(命令内容) は、 scene に対して addCircle 円を追加する 指示をするコード。円の位置と半径は命令に続く ( ) の中に書いて指定する。{ と } の記号も、コードの範囲を示す機能がある。省略はできない。 ; には複数のコードを連続して実行させる機能がある。

画面に、XY座標(pos)とサイズ(size)を設定してボックスを追加作成するプログラム

scene.addBox({ pos = [ 0.0 , 2.0 ]; size = [ 1.0 , 1.0 ] })

(実演は省略)

シミュレーション開始からの経過時間(秒)

sim.time

シミュレーションの開始時点では 0秒 。シミュレーションを開始(再生ボタン)後に、一時停止して、sim.timeの値を観察する(コンソールでsim.timeを評価※)。

※評価とは式やプログラムを実行して値を求めること。

シミュレーションの1フレーム(画面更新)ごとに毎回実行されるプログラム

update = (e) => { radius = 0.1 }

時間に応じて大きくなる半径

update = (e) => { radius = 0.1 + sim.time }

時間に応じて伸縮する半径

update = (e) => { radius = 1 + math.sin(sim.time) }

半分の速度で伸縮

update = (e) => { radius = 1 + math.sin(sim.time/2) }

2倍の速度で伸縮

update = (e) => { radius = 1 + math.sin(sim.time*2) }

・クリックするとサークルを発生させるボタンを作成する。

説明ビデオ5(5分)

クリック時に実行するプログラム

onClick = (e) => { scene.addCircle({ pos := [1, 1] }) }

↑ 位置の変数 pos の値を設定するときに、 := を使う必要がある。

= を使うと、 onClick をプログラムした、クリックしたオブジェクトの pos を変更してしまうため、自分自身が指定した座標にワープしてしまう。

:= を使うと、新しく追加されるボールの pos の方を設定する。

手動でボタンとして利用するサークルを空中に固定し、スクリプトを設定する

何度かクリックした例

サークルを他のオブジェクト(地面など)と重なった位置に発生させた場合、激しく弾むので、発生する場所は要調整。

コンソールで繰り返しコマンドの実験

繰り返し回数(上限50回)を指定してプログラムを実行する。

例) 4回 ボールを追加するプログラム

for(4, (n) =>{ scene.addCircle({ pos = [ 0.0 , 2.0 ]; radius = 1.0 }) })

コンソールで↑を実行後、シミュレーションを開始する。

再生時刻を、ボールが飛び散る直前の状態に戻す。

シーンを保存する ファイル名 pg04s3

応用: 自由課題

課題1のpg04s1 か 課題2のpg04s2 か 課題3の pg04s3 を適当に修正してプログラムを試す。

※授業中で作業した例を、このページに添付しておくので、参考にしてよい。

修正する課題のファイルをalgodooで開いて、以下のようなコマンドの実行や、作業を試せ。

例) ボールを10個横に並べる

ループが実行されるたびに1つ値が増加する変数 n を利用するプログラムの例。 n = 0 1 2 3 4 ...

重なりながら並ぶ

for(10, (n) =>{ scene.addCircle({ pos = [ n , 2.0 ]; radius = 1.0 }) })

距離2でピッタリ並べる

for(10, (n) =>{ scene.addCircle({ pos = [ n*2 , 2.0 ]; radius = 1.0 }) })

ボールを敷き詰める

繰り返し処理の for コマンドで 別の for コマンドを繰り返し実行させる。 2重ループの処理。

for(10, (m) => { for(10, (n) =>{ scene.addCircle({ pos = [ n*2 , m*2 ]; radius = 1.0 }) })})

※{ }の内側の { for(10, (n) のループでボールを横方向に並べている。

※外側の for(10, (m) の変数mは内側のボール生成コマンドの縦方向の位置 pos = [n*2, m*2]に作用する。

※内側のループが外側のループでさらに繰り返し処理される。結果、10x10個のボールが平面に並ぶ。

例)衝突した相手の情報を調べ、色を赤に変更する。

onCollide = (e) => { e.other.color = [1.0, 0.0, 0.0, 1.0] }

時間に応じて半径が増加するプログラムを設定されたボールを10個並べる。

for(10, (n) =>{ scene.addCircle({ pos = [ n*2 , 8.0 ]; radius = 1.0; update = (e) => {radius = sim.time/10} }) })

例)オブジェクトの位置とオブジェクトのサイズをスクリプトで連動させる。

演習3では三角関数 math.sin を利用して周期的な変化を表現した。

三角関数を使わなくても、回転する棒の先端に取り付けたオブジェクトのy座標(x座標でもOK)を利用すれば周期的な変化を利用できる。

xy座標が0と0(pos = [0, 0])を中心にして回転するオブジェクトを作成する(ボックス+歯車+サークルなど)

コンソールで

scene.my.sin

変数を作成する

回転するサークルなどの update を

(e)=>{

scene.my.sin = pos(1)

}

と設定。pos(0)はx座標、pos(1)はy座標を pos のリストの先頭からのインデックス(目次)を指定してデータを読み出す表記法。

scene.my.sin は +回転半径 ~ -回転半径 の間で周期的に変化する。

周期的にサークルの半径を変化させるには、サークルの update に

(e)=>{

radius = 1 + scene.my.sin / 3

}

を設定。 変化する値の範囲を調整するには、 / 3 を /2 や /4 などに修正してみる。また 1+ を 2+ に修正してもOK。

※作業例をこのページに添付しておく。 pg04sSin

三角形にボールを積み上げる例)

for(30, (m) => { for(30-m+1, (n) =>{ scene.addCircle({ pos = [ n*2+m , m*2 ]; radius = 1.0 }) })})

次回は ゲームエンジン Unityの実習

※ Unity2017を使えるようにアカウントを設定しておいてください。

授業中にアカウントの設定の説明はしますが、多人数で一斉に登録作業をした場合、トラブル発生の懸念があります。

設定方法については、次回の資料を参照。

参考資料:

オープンキャンパス模擬講義 Unityで2Dステージ制作 https://sites.google.com/site/kobashijiangyiyong/opunkyanpasu2015

Unityでゲーム作成 https://prezi.com/vi_87shoakh7/13/ (すこし難しい。挑戦してみたい人はどうぞ。キーボードでゲーム板を傾けてボールを転がすゲームの例)

Unity と C#