コンピュータプログラミングI(4)
条件判定

June 29, 2017

Nakajima, Yajima
Iwai, Tatsuta
Kakizaki, Ikeda

このスライドの使い方

テキスト等がはみ出した場合は、フォントサイズを小さくして調整する。 「S」 キーで小さく、「B」 キーで大きくなる。また、 下記のキーボード操作が使用できる。(一部キー操作は IE のみ対応)

「←」 or 「Page Up」 前のスライドに戻る
「→」 or 「Page Down」 or「スペース」 次のスライドに進む
「Home」 and 「End」 先頭(Home)または最後(End)のスライドへ移動
「C」 or 「contents?」 をクリック スライド一覧の表示
「F11」 or 「Ctrl+Shift+F (Win)」, 「Cmd+Shift+F (Mac)」 フルスクリーン表示と通常表示の切り替え
「F」 フッタの表示と非表示の切り替え
「A」 全スライド表示に切替 (印刷時に使う)
「S」「-」/「B」「+」 フォントサイズの大(B) 小(S)

本日のゴール

復習: ifブロックの文法

「もし ○○ であればXXXXする」という処理を記述するために、if文を使う

if (test) {
  条件を満たしたときの処理の中身
}

「test」の部分には、 関係演算子 を使った式を記述する.testがtrue(成り立っている)であれば{}内を実行する. testがfalse(成り立っていない)であれば{}内は実行されない

また「もし ○○ であればXXXXする そうでなければYYYYする」という記述もできる

if (test) {
  条件を満たしたときの処理の中身
}
else {
  条件を満たさなかったときの処理の中身
}

※ for文と同様に、 「中身」が1つの文のときは中カッコ ({, }) を省略できる

test(条件式)の書き方

if (x > 0){
  ellipse(x, y, 10, 10);
}
if (x > 0){ 
  fill(255, 0, 0);
}else{
  fill(255, 255, 255);
}

条件の式を計算して、その結果を求める

この例では、プログラムの実行中にこのifブロックの時点での変数xを調べる

if文は、testの計算結果がtrueかfalseかによって 行う処理を変えることができる

例題: ウィンドウの左半分と右半分でボールの色を変える

int x;
void setup() {
  size(480, 120);
  noStroke();
  fill(0, 0, 0);
  x = 20;
}

void draw() {
  x += 1;
  if (x <= 240){
    fill(220, 120, 120);
  }else{
    fill(120, 120, 220);
  }
  
  background(255, 255, 255);
  ellipse(x, 60, 40, 40);
}

例題: ウィンドウの端に行くと跳ね返るボール

int x;
int speed;
void setup() {
  size(480, 120);
  noStroke();
  fill(0, 0, 0);
  x = 20;
  speed = 1;
}

void draw() {
  if (x <= 20){
    speed = 1;     // <-- ウィンドウの左端に着いたら、方向を右にする
  }
  if (x >= 460){
    speed = -1;    // <-- ウィンドウの右端に着いたら、方向を左にする
  }
  x += speed;
  background(255, 255, 255);
  ellipse(x, 60, 40, 40);
}

変数speedに注目

例題: 重力と反射

先週の重力によって落下するボールのアニメーションを改造し、 地面に着いたら跳ね返るようなアニメーションにする

float y;             //  <-- ボールのy座標
float speed;         //  <-- ボールの速度
float gravity;       //  <-- 重力加速度

void setup() {
  size(200, 480);
  noStroke();
  fill(0, 0, 0);
  y = 0;
  speed = 0;
  gravity = 9.8 / 60;
}

void draw() {
  if (y >= 460) {    // <-- ボールが地面に着いたら、反射係数 0.8 で跳ね返る
    speed = speed * -0.8;
    y = 460;
  }
  speed += gravity;
  y += speed;
  background(255, 255, 255);
  ellipse(100, y, 40, 40);
}

練習(4-1)

斜め上に打ち上げるボールのアニメーションを行う下のプログラムを改造し、 地面と左右の壁にボールがあたると跳ね返るようにしてみよう
[ サンプル ]

float x;
float y; 
float xSpeed;
float ySpeed;       
float gravity;   

void setup() {
  size(480, 480);
  noStroke();
  fill(0, 0, 0);
  x = 0;
  y = 480;
  xSpeed = 3;
  ySpeed = -12;
  gravity = 9.8 / 60; 
}

void draw() {
  x += xSpeed;
  ySpeed += gravity;  
  y += ySpeed;         

  background(255, 255, 255);
  ellipse(x, y, 40, 40);
}

二重のifブロック

ifブロックを二重、三重に書くこともできる

if (x > 0){                                 //<-- x > 0 がtrueならば
  if (y > 0){
    //xが0より大きくて、yが0より大きいときの処理
  }else{
    //xが0より大きくて、yが0以下のときの処理
  }
}else{                                       //<-- x > 0 がfalseならば
  if (y > 0){
    //xが0以下で、yが0より大きいときの処理
  }else{
    //xが0以下で、yが0以下のときの処理
  }
}

条件判定の「かつ」/「または」

複数の条件を組み合わせて、より複雑な条件式を書くことができる
2つの条件式を組み合わせるために、 「かつ」や「または」などの意味を持つ演算子がある

&& 「〜かつ〜」
|| 「〜または〜」
! 「〜ではない」

変数xとyがある範囲にあるかどうかを判定する条件式の例

if (x > 0 && y > 0)      <-- xが0より大きく、かつyが0より大きい

if (x > 0 || y > 0)      <-- xが0より大きい、またはyが0より大きい

if (0 <= x && x <= 100)  <-- xが0以上、かつxが100以下

if (20 <= x && x <= 80 || 30 <= y && y <= 100)
  ....                   <-- xが20以上80以下、またはyが30以上100以下

if ((20 <= x || x <= 80) && (30 <= y || y <= 100))
  ....                   <-- xが20以上または80以下、かつyが30以上または100以下

||より&&が優先される(先に計算される)
異なる順序で計算する場合はカッコを使う
! (〜ではない) は、&&よりもさらに優先される

「かつ」や「または」などの意味を持つ演算子

以下の演算子を論理演算子と呼ぶ.関係演算子の計算結果, boolean(trueかfalseのみを保存するデータ型)型に対して計算を行う演算子である.

&& 「〜かつ〜」
|| 「〜または〜」
! 「〜ではない」

具体的には以下のような計算結果となる.

演算子の優先順位(教科書 p.202)

表: 演算子の優先順位

  記号
カッコ()a * (b + c)
単項++ -- !a++ --b !c
乗除* / %a * b
加減+ -a + b
関係> < <= >=if (a > b)
等号== !=if (a == b)
論理積&&if (x == y && a > b)
論理和||if (x == y || a > b)
代入= += -= *= /= %=a = 44

上の演算子ほど優先順位が高く(先に計算される)、 下の演算子ほど優先順位が低い(後に計算される)

特に +,- より *,/ が優先され、 || より && が優先されることは頭に入れておこう

演算子の使い方に関する よくある間違い

例題: 図形の内か外かの判定(教科書 pp.69-72)

練習(4-2): マウスが図形の内側か外側か判定(1)

  1. 下のプログラムをベースに、マウスカーソルが図形の内側に入ったとき、図形の色が変化するアニメーションを行おう
    [ サンプル ]
  2. 次に、これを少し改造して、 図形の上でマウスのボタンを押したときだけ色が変わるようにしてみよう
    ヒント: 変数 mousePressed は、それ自体がboolean型(true(成り立つ)またはfalse(成り立たない) の値をとる)である
void setup() {
  size(480, 480);
  noStroke();
  fill(128, 128, 128);
}

void draw() {
  background(255, 255, 255);
  rect(20, 20, 200, 100);
  ellipse(320, 320, 100, 100);
}

練習(4-3): 移動している図形の内側か外側か判定

今度は移動する図形に対して、マウスカーソルが図形の内側か外側か判定して、図形の色を変えてみよう
[ サンプル ]

float x;
float y;
float rad;

void setup() {
  size(480, 480);
  noStroke();
  fill(128, 128, 128);
  rad = 0;
}

void draw() {
  background(255, 255, 255);
  x = 200 * cos(rad) + 210;
  y = -200 * sin(rad) + 210;

  rect(x, y, 60, 60);

  rad += 0.01;
}

複数の条件に分岐するifブロック(教科書 pp.66-67)

「AならばXを行い、そうでないときBならばYを行い、そうでないときCならばZを行い...」のように複数の条件によって処理を分けたい
--> if - else if - else という書き方を使う

if ( 条件1 ) {
  処理1
}else if ( 条件2 ){
  処理2
}else if ( 条件3 ){
  処理3
}else{
  上のすべての条件に当てはまらなかったときの処理
}
  

このifブロックでは、条件1から順に条件を調べていき、 条件を満たしたらその中身の処理だけを行う
すべての条件を満たさなかったとき、最後のelseの中身の処理を行う

練習(4-4)

2つの正方形が重なりあった領域を考える
(1)2つの正方形が重なっている領域
(2)左上の正方形の(重なりあっていない)領域
(2)右下の正方形の(重なりあっていない)領域
のそれぞれの上にマウスカーソルが来たとき、 図形すべての色を上の場合に対応させて3色に変化させなさい
[ サンプル ]

void setup() {
  size(480, 480);
  noStroke();
  fill(128, 128, 128, 128);
}

void draw() {
  background(255, 255, 255);

  /* fill in here */
  rect(20, 20, 200, 200);
  rect(120, 120, 200, 200);
}

forループとifブロックの組み合わせ

前の回で繰り返し処理を行うforループを学んだ
forループの中で変化する変数を使って、ifブロックを書くこともできる

10個 正方形を並べ、左半分と右半分で色を変える

size(480, 120);
background(255, 255, 255);
fill(0, 0, 0);
noStroke();

for (int i = 1; i <= 10; i++) {
  if (i <= 5){
    fill(220, 100, 120);
  }else{
    fill(120, 100, 220);
  }
  rect(i*40, 40, 30, 30);
}

演習問題

問題1

  1. 異なった速度で延び縮みするバーをアニメーションで描き、 さらに、最も高い位置にあるバーを境に背景を塗り分けるようにしなさい
    スケッチ名: highestBar
    スケッチフォルダ内の.pdeファイルのみを提出
    [ サンプル ]

    ヒント: 3つのバーのy座標をそれぞれy1, y2, y3としたとき、 y1, y2, y3の中から最も高い(座標では小さい値)値を探せば良い
    3つの変数から最小のものを探すifブロックを考えること

  2. 「例題: ウィンドウの端に行くと跳ね返るボール」を改造し、 x軸方向に加えて、y軸方向にも動きを加え、ウィンドウの四隅で跳ね返るボールの アニメーションを描くプログラムを作成しなさい
    スケッチ名: xyBouncingBall
    スケッチフォルダ内の.pdeファイルのみを提出
    [ サンプル ]

演習問題

問題2

前回の演習問題「問題2」の解答例は次のスライドのとおり
前回のプログラムをベースに、単純往復する正方形を敵とみなし、 弾丸の当たり判定を行うように改造しなさい
当たったときに画面の変化を行うこと
この他、ゲーム風の臨場感を与えるデザインや表現については各自で自由に加えても良い
スケッチ名: simpleShooting
スケッチフォルダ内の.pdeファイルのみを提出

int bulletX;
int bulletY;
float enemyX;
float enemyY;
float enemyRad;

void setup() {
  size(480, 480);
  noStroke();
  bulletX = 1000;
  bulletY = 0;
  enemyX = 400;
  enemyRad = 0;
}

void draw() {
  background(0, 0, 0);

  fill(255, 255, 255);
  ellipse(mouseX, mouseY, 20, 20);
  fill(255, 0, 0);
  triangle(bulletX-8, bulletY-4, bulletX-8, bulletY+4, bulletX+8, bulletY);
  enemyY = 200 * sin(enemyRad) + 210;
  fill(255, 255, 255, 180);
  rect(enemyX, enemyY, 60, 60);

  if (mousePressed) {
    bulletX = mouseX;
    bulletY = mouseY;
  }
  bulletX += 2;
  enemyRad+=0.01;
}