小学校教員のためのプログラミング入門

もっと動かす

 前回,物理法則に従って動くボールのシミュレーションをするスケッチを作りました.今回は,その動きにさらに跳ね返りを組み入れてみます.また,作ったスケッチの配布方法を説明します.さらに,今回は一から自分でスケッチを作る時間を設けます.

地面で跳ね返らせてみる

 前回作ったのスケッチでは,ボールは画面の外に飛び出したあとも,永遠に動き(落ち)続けています.現実の世界では壁や地面にぶつかれば,ボールは跳ね返るはずです.次に跳ね返る処理を加えてみます.

5-9.jpg

  地面についたときの判定

 まずは地面についたらバウンドさせてみます.まず毎回ボールを描く際に地面に着いたかどうかを判定し,地面についていたらバウンドさせる処理をするようにします.地面に着いたときとは y 座標が画面の縦幅 height より大きくなったとき(より正確にはボールの半径を考慮して height-r より大きくなったとき)です.このような判定をしたいときには,条件分岐制御を行うための if 文を利用します.使い方は次の通りです.

if( 条件式 ) 条件が成り立った際に実行する文;

または

if( 条件式 )
{
 条件が成り立った際に実行する文;
        :
}

また,条件が成り立たなかったときの処理も書きたい場合は,

if( 条件式 ) 条件が成り立った際に実行する文;
         else 条件が成り立たなかった際に実行する文;

または

if( 条件式 )
{
 条件が成り立った際に実行する文;
        :
}
else
{
 条件が成り立たなかった際に実行する文;
        :
}

と書きます.さらに,

if( 条件式1 )
{
 条件1が成り立った際に実行する文;
        :
}
else  if( 条件式2 )
{
 条件1が成り立たたず,条件2が成り立った際に実行する文;
        :
}
else
{
 条件1も条件2も成り立たない際に実行する文;
        :
}

という書き方もできます.今回の場合

if( y >= height-r ) ・・・

という if 文を使えばよいでしょう.なお >= は左辺が右辺以上であったら真を返す条件演算子です.

  バウンドさせてみる

 バウンドした後は,初期速度と投げる方向を変化させて投げ直すという処理に置き換えられます.もちろん,初期速度と投げる方向の再設定は物理法則に従わせる必要があります.まずバウンドする直前の速度は次のように求められます.

5-23.jpg

 そして,バウンドした直後の速度は,x 軸方向については変化なく,y 軸方向は正負が反転します.ただ,バウンドした後は通常速度は落ちます.もし,y 軸方向の速度が変化しないとなると,永遠に同じ高さまでバウンドを繰り返すボールになってしまいます.これらをふまえると,バウンド後の x 軸方向,y 軸方向それぞれの速度は

  float vx0 = v0*cos(theta);
  float vy0 = v0*sin(theta)+g*t;
  vy0 = -vy0 * 0.8;

と書けます.バウンド後の x 軸方向,y 軸方向それぞれの速度がわかれば,バウンドした後の速度と角度を求めることができます.

5-24.jpg

逆正接関数(アークタンジェント)は atan メソッドで求めることができます.ただし,atan は x 軸方向の成分が正であるとき -PI/2 〜 PI/2 の値を返す仕様になっているため,x 軸方向の成分が負の場合は,y 軸方向の成分の符号が反転した場合の値が求まってしまうので,求まった値に PI を加える必要があります.

6-11.jpg

これらから初速度と投げる角度を求めるコードは

  v0 = sqrt( vx0*vx0 + vy0*vy0 );
  theta = atan( vy0/vx0 );
  if( vx0 < 0 ) theta = theta + PI;

となります.x 軸方向の速度の符号が負であるかどうかの判定にも if 文を使っています.

 バウンド後は求めた速度と角度での投げなおしをすることと同じになるので,バウンドしたときの x, y 座標を初期位置,時間を 0 に再設定をします.

  x0 = x;
  y0 = height-r;
  t = 0;

完成したスケッチは次の通りです.

int r = 10;
float x0 = r, y0 = r;
float g = 9.8;
float v0 = 30;
float theta = PI/8;

float t = 0;
float x = x0, y = y0; 

void setup()
{
  size(300,300);
  colorMode(RGB,255,255,255,100);
  ellipseMode(RADIUS);
  background(0,0,0);
  frameRate(50);
}

void draw()
{
  stroke( 0, 0, 0, 10 );
  fill( 0, 0, 0, 10 );
  rect( 0, 0, width, height );

  x = x0 + v0*cos(theta)*t;
  y = y0 + v0*sin(theta)*t+g*t*t/2.0;
 
  stroke( 0, 0, 100, 100 );
  fill( 0, 200, 255, 100 );
  ellipse( x, y, 10, 10 );
  t = t + 0.1;
  
  if( y > height-r )
  {
    float vx0 = v0*cos(theta);
    float vy0 = v0*sin(theta)+g*t;
    vy0 = -vy0*0.8;
    v0 = sqrt( vx0*vx0 + vy0*vy0 );
    theta = atan( vy0/vx0 );
    if( vx0 < 0 ) theta = theta + PI;

    x0 = x;
    y0 = height-r;
    t = 0;
   }
}

 なお,このスケッチはかなり荒い作りになっています.たとえば,バウンドするときの y 座標は height-r より大きいことがほとんどです.つまり,地面にめり込んでいる状態から跳ね返っていることになります.これを避けるには,t の増分を小さくして,y の値が height-r と同じ,もしくは,極近い値になるようにする必要があります.

壁も作ってみる

 壁にぶつかったときもバウンドするようにしてみましょう.右壁に当たっとき,左壁に当たったときも,基本的な処理は地面に当たったときと同じです.地面に当たったときには y 軸方向の速度の符号を反転させていましたが,壁に当たったときは x 軸方向の速度の符号を反転させるだけです.角度の求め方も地面に当たったときと同様です.ただ,左壁に当たった後の x 軸方向の速度は必ず正であり,右壁に当たった後の x 軸方向の速度は必ず負ですので,地面に当たったときのように x 軸方向の速度の符号を判定するまでもなく,前者は atan( vy0/vx0) で求まり,後者は atan( vy0/vx0 )+PI で求まることになります.

5-10.jpg

完成したときの画面はつぎのようになります.

5-11.jpg

 さぁ,この処理の追加は自分の力でやってみましょう.

スケッチの配布方法

 スケッチが完成したら,みんなに見せて自慢をしたいでしょう.また,Processing で教材を作成した場合にも,他の人に配る方法が必要だと思います.相手が Processing の開発環境(PDE)を持っていれば,作成したスケッチのコード(pde ファイル)をあげればよいのですが,そういう場合だけではないはずです.ここでは,PDE がない環境でもスケッチを実行できる形式で配布する方法を説明します.

  実行ファイルを生成する

 一つ目は実行ファイルを生成する方法です.実行ファイルとは,Processing の開発環境(PDE)がインストールされていないパソコンでも実行できる形式のファイルのことで,Microsoft Windows で言えば,exe ファイルのことです.すなわち,アプリケーションプログラムのことです.

 実行ファイルを生成するには,PDE のメニューから [File] - [Export Application] を選びます.なお,実行ファイルの生成をする前に,通常の保存作業を先に行っておいてください.実行ファイルの生成を指示すると,下図に示すダイアログが表示されます.Microsoft Windows 用か,Machintosh 用か,Unix 用かが選べますので,適当なものを選びます.Options の Full Screen を選択しておくと,実行したときに画面いっぱいのウィンドウが開いて実行される形式のプログラムが生成されます.

6-2.jpg

 Microsoft Windows 用の実行ファイル生成を指示した場合は,スケッチブックのフォルダ(スケッチの保存指定先)に \スケッチ名\application.windows の中に exe ファイルが生成されます.別の PC でスケッチを実行させたいときには,このフォルダをコピーしてください.

  アプレットを生成する

 二つ目はアプレットを生成する方法です.アプレットは Web ページ上に配置することのできる形式です.アプレットを生成するには PDE のメニューから [File] - [Export] を選びます.するとスケッチブックのフォルダに \スケッチ名\applet の中に複数のファイルが生成されます.

 そのファイルの中に index.html があると思います.これは生成したアプレットを配置した web ページを定義する HTML ファイルのサンプルです.試しに,この index.html を web ブラウザで開いてみてください(通常はダブルクリックをすれば web ブラウザが起動してファイルが読み込まれるはずです).web ブラウザ上にスケッチの実行画面が表示されるはずです.

 生成された一連のファイルを web サイトにアップすれば,自分の作成したスケッチを世界中に公開することが可能です.試しに http://www.u-gakugei.ac.jp/~naoki/processing/sample6/ にアップしてみましたので,この URL の web ページを確認してみてください.

6-5.jpg

紙へ出力する

  PDF を生成する

 Processing で作図をして,それを印刷するなどして利用したい場合があるでしょう.まずは,画面をそのまま PDF 形式のファイルに出力する方法を説明します.

 今作っている動きのあるスケッチは PDF で表現できないのはわかるでしょう.そこで,下に示す前々回に作成したスケッチを例に説明します.

size(360,300);
colorMode(HSB,360,100,100);
background(#FFFFFF);

int x,y;
for( x = 0 ; x < 360 ; x++ )
{
  for( y = 0 ; y < 100 ; y++ )
  {
    stroke( x, y, 100 );
    line( x, y*3, x, y*3+2 );
  }
}

 まず,このコードを新しいスケッチとして入力するか,きちんと保存していた人はそれを読みだしてください.次に,PDE のメニューから [Sketch] - [Import Library] - [pdf] を選んでください.

6-3.jpg

スケッチコードの先頭に

import processing.pdf.*;

が加わったはずです.次に,size メソッドを

size( 360, 300, PDF, "sample.pdf" );

と書き換えます.4番目のパラメータが生成する PDF ファイルのファイル名指定になります.最後に,プログラムの終了ポイント,今回の場合は,コードの一番最後に,

exit(0);

を追加します.以上の変更を行った後,実行をしてみてください.おそらく,実行ウィンドウが表示されることなく,実行が終了すると思います.といっても,かなり長い時間かかるはずです.実行中なのか,実行が終了したのかは,RUN ボタンがオレンジ色かどうかで区別できます.オレンジ色になっている間は実行中,つまり,PDF ファイルの生成中を示します.

 実行が終了したら,スケッチブックの保存先を確認してみてください.\スケッチ名\ フォルダの中に,先ほど指定した名前の PDF ファイルができているはずです.

6-7.jpg

  A4 サイズの PDF を生成する

 生成する PDF のサイズをきちんと指定したい場合もあると思います.そのときには,size メソッドの部分を次のように変更します.

int dpi = 72;
float real_width = 210;
float real_height = 297;
int sheet_w = (int)(real_width * 0.03937 * dpi);
int sheet_h = (int)(real_height * 0.03937 * dpi);
size( sheet_w, sheet_h, PDF, "sample_A4.pdf" );

 ただし,このようにした場合,描画するときの座標もこのサイズにあわせて調整してあげることが必要です.次のコードは,A4 の用紙の中央に描くように調整したものです.

 import processing.pdf.*;
 
 int dpi = 72;
 float real_width = 210;
 float real_height = 297;
 int sheet_w = (int)(real_width * 0.03937 * dpi);
 int sheet_h = (int)(real_height * 0.03937 * dpi);
 size( sheet_w, sheet_h, PDF, "sample_A4.pdf" );
 colorMode(HSB,360,100,100);
 background(#FFFFFF);
 
 int x,y,rx,ry;
 for( x = 0 ; x < 360 ; x++ )
 {
   for( y = 0 ; y < 100 ; y++ )
   {
     rx = (sheet_w-360)/2;
     ry = (sheet_h-300)/2;
     stroke( x, y, 100 );
     line( x+rx, y*3+ry, x+rx, y*3+2+ry );
   }
 }
 
 exit();

6-6.jpg

  画像ファイルを生成する

 PDF ではなく,ワープロソフトなどに取り込むために,JPEG 形式のファイルなど画像ファイルを生成したいこともあると思います.この場合には,save メソッドを利用します.PDF を生成するためのコードを入れる前のスケッチコードを例にとると,終了ポイント,このスケッチの場合はコードの最後に,

save( "sample.jpg" );

を追加してください.パラメータは出力する JPEG ファイルのファイル名です.追加した後に実行すると,スケッチの保存先に指定したファイル名のファイルが作られているはずです.

課題

 http://www.u-gakugei.ac.jp/~naoki/processing/sample6-2/ に示すような動きをするスケッチを作りなさい.

 これは等速運動をするボールの動きをシミュレートしています.つまり,座標(x,y) を一定量(dx,dy) づつ変化させているだけです.また,動きながら色相を変化させています.つまり,HSB における色(c,s,b) を一定量(1,0,0) づつ変化させているだけです.また,左右の壁にぶつかった場合は,dx の符号を反転,上下の壁にぶつかった場合は dy の符号を反転させるだけです.

 このスケッチでは,ボールの半径(r)を 10 に,出発点の座標を (r,r) に,移動量 (dx,dy) は (5,2) に指定してありますが,この値は自由に変えてもらって構いません.ただし,この値を変えやすいようにしておくのがよいでしょう.

 作成したスケッチは実行ファイル形式で出力し,そのうち exe ファイルだけを提出してください.

6-4.jpg