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

条件付きで図形を動かす

 前回,机の上をころがる(等速運動する)ボールのシミュレーションをするスケッチを作りました.今回は,その動きにさらに跳ね返りを組み入れてみます.

画面下で跳ね返らせてみる

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

06-1.jpg

  前回のスケッチをちょっとだけ変更

 まず,前回のプログラムを少しだけ変更します.変更したのは,t 秒後の位置を求める計算式のところです.前回はここで,速さの X 成分,Y 成分を計算していましたが,これは毎回同じですので,最初に変数 vx,vy に入れてしまうようにしました.なお,演習で行った重力を含む運動のスケッチでは,速さも t によって変化しますので,このようなことはできないことに注意して下さい. また,転がす方向を 3/8 Π にしました.

int r = 10;
float x0 = r, y0 = r;
float v = 30;
float theta = (PI/8)*3;

float t = 0;
float x = x0, y = y0; 
float vx = v * cos(theta), vy = v * sin(theta);  // 追加

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

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

 x = x0 + vx*t;  // 変更
 y = y0 + vy*t;  // 変更

 stroke( 0, 0, 100, 100 );
 fill( 0, 200, 255, 100 );
 ellipse( x, y, 10, 10 );
 t = t + 0.1;
}

  画面下にぶつかったときの判定

 まずは画面下(下壁)にぶつかったら跳ね返らせてみます.まず毎回ボールを描いたときに下壁にぶつかったかどうかを判定し,下壁ぶつかっていたら跳ね返る処理をするようにします.下壁にぶつかったときとは 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 文を使えばよいでしょう.なお >= は左辺が右辺以上であったら真を返す条件演算子です.

  跳ね返らせてみる

 下壁で跳ね返った後は,速度の Y 成分の符号が反転するということは容易にわかるでしょう.もちろん,X 成分は変化しません.もちろん,摩擦などを考えれば X 成分も変わりますし,Y 成分も絶対値が変わるでしょうが,今回はそこまで考えないことにします.

 跳ね返った後の速度がわかったら,後は,跳ね返った場所からその速度で,転がし直させればよいのです.そのために,(x0,y0) に現在の座標を代入し,t を 0 にリセットします.ただし,y0 には下壁にぶつかったと判定された時の座標 y ではなく,厳密に画面下についたときの値 height-r を代入しています.これは,t のきざみによっては,下壁にぶつかったと判定されるのが,ボールが下壁にめり込んだときの場合もあり,このときの Y 座標を y0 に入れてしまうと,次の座標計算時も,ボールが下壁にぶつかっていると判定されてしまう可能性があるからです.

 上記のことから,下壁にぶつかったときには,次のように各変数の値を書き換えればよいはずです.

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

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

int r = 10;
float x0 = r, y0 = r;
float v = 30;
float theta = (PI/8)*3;

float t = 0;
float x = x0, y = y0; 
float vx = v * cos(theta), vy = v * sin(theta);

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

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

 x = x0 + vx*t;
 y = y0 + vy*t;

 stroke( 0, 0, 100, 100 );
 fill( 0, 200, 255, 100 );
 ellipse( x, y, 10, 10 );
 t = t + 0.1;
 
 if( y > height-r )
 {
   vy = -vy;
   x0 = x;
   y0 = height-r;
   t = 0;
 }
}

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

四方の壁を作る

 画面下にぶつかったときだけでなく,上と両横でもバウンドするようにしてみましょう.どの壁に当たったときでも,やることは同じです.速度と初期位置と経過時間を書き換えるだけです.完成したときの画面はつぎのようになります(少し,塗りつぶしの透明度をあげて,軌跡を長く表示させています).

06-2.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 ファイルのファイル名です.追加した後に実行すると,スケッチの保存先に指定したファイル名のファイルが作られているはずです.

課題

 前回の課題で作った重力がある空間でボールを投げた時の動きを表示するスケッチで,地面に当たるとバウンドするようにしてみましょう.前回の課題の正解例を次に示します.できあがったスケッチには半角英数字で 学籍番号_K6 と名前をつけ,pde ファイルを Web クラスから提出してください.

int r = 10;
float x0 = r, y0 = r;
float v = 30;
float theta = PI/8;
float g = 9.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(30);
}

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

 x = x0 + v*cos(theta)*t;
 y = y0 + v*sin(theta)*t + g*t*t/2;  // 変更

 stroke( 0, 0, 100, 100 );
 fill( 0, 200, 255, 100 );
 ellipse( x, y, 10, 10 );
 t = t + 0.1;
}

  ヒント

 バウンドした後は,速度を変化させて投げ直すという処理に置き換えらるのは,今回作ったスケッチと同じです.その速度の変化も X 成分は変化せずに, Y 成分が反転するだけと,ボールを転がしたときのバウンドと同じです.ただ,違うのは,バウンドした時の速度の Y 成分は,重力加速度の影響で,最初の速度とは変わる点です.

 まずバウンドすると判定されたときの速度は次のように求められます.

5-23.jpg

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

  float vx = v*cos(theta);
  float vy = v*sin(theta)+g*t;
  vy = -vy * 0.8;

と書けます.これがバウンド後の X 軸方向,Y 軸方向それぞれの速度ということになります.

  発展課題

 横の壁にぶつかったときに跳ね返る処理を入れてみましょう.