[Go to “teaching” in Morimoto Lab]
ボールをバウンドさせよう
ーアニメーションと跳ね返りの基礎ー
はじめに:プログラミングは特に学習の最初の時点でのハードルが高く、慣れるまでは大変に感じるかもしれませんが、とても便利かつ数学や英語の必要性を実感できます。Processingは初心者でも扱いやすいプログラミングソフトです。ウェブで無料でダウンロードできて、WindowsでもMacでも動きます。元々はヴィジュアルアートを目的として開発されました。他の本格的な言語(C言語など)とも似ていますし、マウスやカメラによる外部入力や、様々なライブラリと呼ばれる機能を比較的簡単に使うことができます。
公式サイトからダウンロードしたフォルダを解凍し、実行ファイル(winの場合processing.exe)をダブルクリックするとProcessingが起動できます。
上部のテキストエディタにプログラムを記載し、左上の三角ボタンを押すと実行できます。
(Ctrl+rは実行のショートカットキー)
注意:タブは使わない
タブは新しいプログラムを別途作るのではなく、最初のプログラムの続きとして作られます。新しいプログラムを作成する場合は、メニューのファイルから保存した上で、メニューの新規作成から、新しいプログラムを作りましょう。
以下のプログラムを実行すると図のような300x300ピクセルのウィンドウが表れます。
size(300,300);
//size(横幅、縦幅);
size()
は指定した大きさのウィンドウを作る命令(関数)です。一つのプログラムに一つだけ書きましょう。
;
はセミコロン。プログラムの命令ごと(大体は行の最後)に必ず付ける決まり。
//
はコメントアウト。この行のこれよりあとはプログラムから無視されます。
隣の図は座標を表す。普通の座標と違って、y方向(上下)が逆なので注意。
→
1.1のプログラムの最後に以下を追加してください。画面の色が白で塗りつぶされます。色は0~255で強さを表します。
background(255);
次に、background(255,0,0);に変えてみましょう。
パラメータが3つあるときは、それぞれR,G,B(red, green, blue)を表し、3色を混ぜて様々な色を表現します。
絵具のような減法混色ではなく、加法混色は沢山混ぜるほど明るい色=白に近づきます。
加法混色の図
size(300,300);
background(255);
ellipse(3,3,4,6);
//ellipse(x位置,y位置,円の横幅、円の縦幅)
楕円という意味のellipse()という命令は4つパラメータで座標と大きさを指定します。
座標は円の中心のものです。
左図のように円を描くとき、上記のようにプログラムします。
void setup(){
size(300,300);
println(”SET ”);
}
void draw()
{
println(“DRAW ”);
}
print
はコンソールと呼ばれる画面下の方の黒い画面に文字を出力
する。
setup
はプログラムを実行すると、一回だけその内容が処理される。
draw
の内容はsetupの処理後、何度も繰り返し呼び出されて処理される。
なので、このプログラムを実行すると、コンソールに「SET DRAW DRAW …」と表示される。
int c=0;
//setupは略。さっきと同じ
void draw(){
c = c+1;
println(c);
//ellipse(c, 50, 100, 100);
}
int
は整数(…,-1,0,1,2,…)を表す。
整数のデータcを作成し、drawで+1し続けると、「SET 1234…」と表示される。
cをellipse()の位置のパラメータにしたら、ボールが移動する。
ボールの描画が重なるので、backgroundをdraw内の最初にすると、前の描画が消える。
加速させる必要はなく、速度を今と別の定数に変更するだけでよい。
int bx=200;//ballのx位置
int by=100;//ballのy位置
int vx = 10;//ballのx方向の速度velocity
int vy = 10;//ballのy方向の速度velocity
int bs =100;
//setupは略
void draw(){
background(255);
ellipse(bx, by, bs, bs);
bx = bx + 1;//+vxに変更してみる
if(bx > width){vx = -1 * vx;}
}
ボールの位置を表す変数bx, byを用意。
x方向のボールの速度を表すvx, vyも用意。
ボールの大きさbsも用意。
右の壁に当たったら跳ね返る場合、速度を逆にしたらよい。
ifを使って、「もしボールの位置が画面の一番右より大きくなったら」「x方向の速度を逆にする」という処理をする。
widthにはあらかじめ画面の横幅が入っている。画面の縦幅はheight。
ここまでは、y方向の移動のことは行わず、x方向のみを実装してみてください。
y方向の処理を加えてください。
x方向に行った処理と同様です。
ユーザの動かすマウスに当たったら跳ね返るようにしましょう。
void draw(){
//2.3までの内容は省略
//マウスとインタラクション
int dist = (bx-mouseX)*(bx-mouseX) +
(by-mouseY)*(by-mouseY);
if(dist < bs/2*bs/2){
vx = vx * -1;
vy = vy * -1;
//bs = bs - 1;
}
}
マウスの位置はmouseX, mouseYに用意されています(Processing側で用意してくれています)。
マウスとボールの距離がボールの半径より小さい時、マウスはボールに触っているか、ボールの内側に入っています。
このとき、ボールを反対に跳ね返らせます。
他にも、ボールとマウスが触れたとき、ボールのサイズを小さくしてみるなどのインタラクションを実装してみてもよいですね。
これまで学んだこと+自分のアイデアでゲームや面白い表現を考えてみましょう。
ボールを自分で選んだ絵に置き換えて、ゲームらしくしてみましょう。
//冒頭のボールの変数の定義などは省略
PImage img;//①
void setup()
{
img = loadImage("sura.png");//②
size(500, 500);
}
void draw()
{
background(255);
ellipse(bx, by, bs, bs);
image(img, bx-bs/2, by-bs/2, bs, bs);//③
//以下は省略
}
ボールの代わりに画像を表示する場合は、左の①~③を追加します。
ただし、””の部分は自分の使いたい画像の名前にします。
更に、プログラムのあるフォルダに使いたい画像ファイルを置くと、使えます。
画像はウェブで検索し、
画像を右クリック、
名前を付けて画像を保存、
デスクトップなどに保存、
等の後、プログラムのあるフォルダに移動します。
プログラムのある位置は、まずプログラムを保存した上で、
メニュー>スケッチ>スケッチフォルダーを開く
とすると自動で開くことができて便利です。
採点する人に、ゲーム性を説明してください。
※Pongというゲームの一人バージョンは今日の内容で作れそう
※モンストもある程度作れそう?
※インベーダーゲームもある程度作れそう?
四角形を描画する方法 :rect(x位置,y位置,横幅,縦幅)
ellipseと違い、デフォルトの座標の位置は左上なので、同じ位置に同じ大きさのellipseとrectを描画すると以下のようになります
メニューの ファイル>保存
でプログラムをデフォルトの場所に保存できます。
※保存された場所は2の方法で確認できます。参照URLにデフォルトの場所の変え方があります。
ファイル名は自動で「Sketch_140915a」などになります。数字はその日の日付で、a,b,c,…はその日何番目に作られたファイルかで決まります。
また、ファイルはメインのpdeファイルと同じ名前のフォルダ内に、一緒に作成されます。Processingのプログラムファイルは同じ名前のフォルダ内に配置されていないと実行できません。
参照 https://r-dimension.xsrv.jp/classes_j/start/
メニューの スケッチ>フォルダーを開く
を選ぶと該当フォルダが開きます。
画像を置くときなどに活用しましょう。
Macの場合 https://support.apple.com/ja-jp/guide/mac-help/mchlp2304/mac
Windowsの場合 https://www.pc-koubou.jp/magazine/36291
上記のURLが無効になっている場合「Mac 拡張子 表示」などで検索すると出てきます。
これも画像を読みこむ際に必要です。
理系なら、拡張子は表示しておきましょう!
WinならCtrl+T、
Macだとコマンドキー+T
でコードをきれいに整形できます。
きれいなコードはバグよけに必須です!
他にも以下もよく使いますが、コード整形はコードを書きながら逐次行うこと必須!
プログラムの実行:Win Ctrl+R
※よく使う。▶ボタン押さなくていい
コメントアウト: Win Ctrl+/
※よく使う。//を自動でいれたり、削除。複数行選択していれば複数行に対して行える
exeは実行ファイルという、アプリを実行するファイルの拡張子です。
processing.exeはProcessingというアプリを実行するファイルなのですね。
sketch_22414a.pdeなどというファイルは書いたコードのテキストファイルです。
初回でやるのはボリュームが多いかなと思うので省いている内容です(後の回でもやりません^^;)。ボールの反射は壁に当たった時は単純でよいのですが、マウスに当たった時は違和感があるでしょう。本当はマウスが小さなボールだとみなして接面で反射させるのが正しいです。下記のサイトを見ると、ボールの正しい反射方向の計算の仕方がわかります。また、その実装例を以下にのせていますが、これから教えることがたくさん含まれています・・・。
参考:反射ベクトルを求めるhttps://qiita.com/edo_m18/items/b145f2f5d2d05f0f29c9
//反射面のベクトル:マウスとの反射の場合、ボールとマウスの接面
float vecx = mouseX - bx;//ボールからマウスへのベクトル
float vecy = mouseY - by;//ボールからマウスへのベクトル
float dist = sqrt(vecx*vecx +vecy*vecy);
if (dist>=radi)return;//ボールが衝突してたら以下の計算をする。
float mx = mouseX;
float my = mouseY;
//反射面のベクトル:マウスとの反射の場合、ボールとマウスの接面
PVector F = new PVector(vx, vy);//ボールの進行ベクトル
PVector N = new PVector(bx-mx, by-my);//面の垂直ベクトル
N = N.normalize();
float a = -F.dot(N);//Nに投影したFの大きさ
PVector R = F.add(N.mult(2.0*a));
//以下のtは参考サイトにはありません。ボールのめり込みを解消しつつ、不自然な挙動を減らす目的のものです。
float t = radi-dist;
t *= sq((1.0-t)/radi);
vx = R.x+N.x*t;
vy = R.y+N.y*t;
ellipse(mx, my, 10, 10);
line(mx, my, mx+N.x*10, my+N.y*10);
衝突するボール同士の場合も同じ原理ですが、同じ重さ・跳ね返り係数1の場合、単純に二つのボールの速度を交換すればよいです。(でも原理を知っておくのは大事ですよね!)