消しました。Processingでフラッピーバードをつくろう(4):子供のプログラム学習

<!--

# 4.プレイヤーと下の土管の衝突判定をする
Processingでフラッピーバードをつくっていきます。
前回はプレイヤーと土管のプログラムをつくりました。

## そのまえに
### 前回までのプログラムコード
```Java
float x = 100;
float y = 200;
float speed = 0;
float dx = 400;
float dy = 100;
void setup() {
  size(600, 400);
}
void draw() {
  background(0);
  // まとめた土管のプログラムを呼び出す
  dokan();
  // まとめたプレイヤーのプログラムを呼び出す
  player();
}
void mousePressed() {
  speed = -10;
}
void dokan(){
  // 土管のdraw
  dx = dx - 5;
  if (dx + 50 < 0) {
    dx = 600;
    dy = random(200, 300);
  }
  rect(dx, dy, 50, 400 - dy);
}
void player(){
  // プレイヤーのdraw
  speed = speed + 1;
  y = y + speed;
  rect(x, y, 50, 50);
}
```

このプログラムが手元にある前提で話をしていきます。

## 4-1 衝突判定の関数を用意する

### 衝突判定の関数
衝突したかどうかを判定する関数を用意しました。

下のコードを最後の行に追加しましょう。

```Java
int isHit(float px, float py, float pw, float ph, float ex, float ey, float ew, float eh) {
  if (px < ex + ew && px + pw > ex) {
    if (py < ey + eh && py + ph > ey) {
      return 1;
    }
  }
  return 0;
}
```

### 衝突判定の使い方

衝突判定を使うためには、なんと8個の情報が必要です。

1. プレイヤーのx
2. プレイヤーのy
3. プレイヤーの横幅
4. プレイヤーのたて幅
5. 土管のx
6. 土管のy
7. 土管の横幅
8. 土管のたて幅

これらをisHit関数に伝えます。

`isHit(プレイヤーのx, プレイヤーのy, プレイヤーの横幅, プレイヤーのたて幅, 土管のx, 土管のy, 土管の横幅, 土管のたて幅)`

これらを実際のプログラムコードにあわせると、

`isHit(x, y, 50, 50, dx, dy, 50, 400 - dy);`

となります。

isHitは、衝突していれば「1」を、衝突してなければ「0」を作ります。

なので、

```Java
int hit = isHit(x, y, 50, 50, dx, dy, 50, 400 - dy)
if(hit == 1){
  // 衝突していた場合のプログラム
}
```

上のようにif条件分岐と組み合わせて、
isHitが作ってくれた数字「1か0」を、変数「hit」に持たせて、
変数「hit」が「1」かどうかを「==（イコール二つ）」で条件にしています。

このようにして、衝突していた場合のプログラムを書くことができます。

実際にplayer関数の中にプログラムしてみましょう。

drawの中ではありませんよ！

drawの中で呼び出している、player関数の中で、プレイヤーに関するプログラムを書きましょう。

```Java
void player() {
  speed = speed + 1;
  y = y + speed;
  // プレイヤーと土管が衝突しているか、isHit関数で調べる
  int hit = isHit(x, y, 50, 50, dx, dy, 50, 400 - dy);
  // もし、プレイヤーと土管が衝突しているなら
  if(hit == 1){
    // 衝突時のプログラムを書く
  }
  rect(x, y, 50, 50);
}
```


### 衝突判定のアルゴリズム
衝突判定をするプログラムを先に記載しましたが、どういうアルゴリズムかを説明しておきます。

四角形Aと四角形Bの衝突判定をしたい時、以下の4つの条件がすべて満たされた時に衝突していると判定できます。

1. Aの左端が、Bの右端より、左にある。
2. Aの右端が、Bの左端より、右にある。
3. Aの上端が、Bの下端より、上にある。
4. Aの下端が、Bの上端より、下にある。

これら4つの条件がすべて一致したときにだけ「1」を返すプログラムが、先ほど作ったisHit関数です。

```Java
int isHit(float px, float py, float pw, float ph, float ex, float ey, float ew, float eh) {
  if (px < ex + ew && px + pw > ex) {
    if (py < ey + eh && py + ph > ey) {
      return 1;
    }
  }
  return 0;
}
```

論理演算子と呼ばれる「&&」で条件を結ぶことで、複数の条件が一致した時のみの条件分岐が作れます。
（今回は、横の判定と縦の判定をifを二つ使って実現しています。&&が2個、ifが2個で、計4個の条件が同時に一致したとき、をプログラムしています）

衝突判定のアルゴリズム、アルゴリズムをプログラムにするのは難しいので、今回は無理して覚える必要はありません。
いろいろな作品を作っていくうちに自然に覚えていきますので、衝突判定でくじけず、「そういうものなんだな」と割り切って次に行きましょう。



## 4-2 衝突したらプレイヤーが赤くなるようにする

### プレイヤーを赤くする

プレイヤーとなる四角形を赤くするには、**fill**命令を使います。

`fill(色情報1, 色情報2, 色情報3);`

fill命令に色情報を渡すと、四角形に色をつけることができます。

`fill(255, 0, 0);`

赤色にするには、255と0と0、をfill命令に伝えましょう。

```Java
void player() {
  speed = speed + 1;
  y = y + speed;
  // プレイヤーと土管が衝突しているか、isHit関数で調べる
  int hit = isHit(x, y, 50, 50, dx, dy, 50, 400 - dy);
  // もし、プレイヤーと土管が衝突しているなら
  if(hit == 1){
    // 衝突時のプログラムを書く
    fill(255, 0, 0);
  }
  rect(x, y, 50, 50);
}
```

実行すると、衝突時にプレイヤーが赤くなったでしょうか？

### 衝突していないときは白にする

衝突時に赤くなるようになりましたが、一度衝突するとずっと赤色のままです。

しかも、土管まで赤くなってしまったと思います。

なぜでしょうか？

それは、「fill命令を使って白に戻していないから」です。

まずは土管にfill命令を使いましょう。

土管は常に白色なので、
衝突しているかどうか、チェックはいりませんね。

```Java
void dokan() {
  // 土管のdraw
  dx = dx - 5;
  if (dx + 50 < 0) {
    dx = 600;
    dy = random(200, 300);
  }
  fill(255, 255, 255);
  rect(dx, dy, 50, 400 - dy);
}
```

次にプレイヤーです。

```Java
void player() {
  speed = speed + 1;
  y = y + speed;
  // とりえあえず白に戻す
  fill(255, 255, 255);
  int hit = isHit(x, y, 50, 50, dx, dy, 50, 400 - dy);
  if(hit == 1){
    fill(255, 0, 0);
  }
  rect(x, y, 50, 50);
}
```

isHit関数で、衝突判定をする前に、
とりあえずfill命令で白色（255, 255, 255）にしています。

もし衝突していたら、赤色のfill命令に上書きされるため問題ありません。

### ここまでのプログラムコード
```Java
float x = 100;
float y = 200;
float speed = 0;
float dx = 400;
float dy = 100;
void setup() {
  size(600, 400);
}
void draw() {
  background(0);
  // まとめた土管のプログラムを呼び出す
  dokan();
  // まとめたプレイヤーのプログラムを呼び出す
  player();
}
void mousePressed() {
  speed = -10;
}
void dokan() {
  // 土管のdraw
  dx = dx - 5;
  if (dx + 50 < 0) {
    dx = 600;
    dy = random(200, 300);
  }
  fill(255, 255, 255);
  rect(dx, dy, 50, 400 - dy);
}
void player() {
  speed = speed + 1;
  y = y + speed;
  // とりえあえず白に戻す
  fill(255, 255, 255);
  int hit = isHit(x, y, 50, 50, dx, dy, 50, 400 - dy);
  if(hit == 1){
    fill(255, 0, 0);
  }
  rect(x, y, 50, 50);
}
int isHit(float px, float py, float pw, float ph, float ex, float ey, float ew, float eh) {
  if (px < ex + ew && px + pw > ex) {
    if (py < ey + eh && py + ph > ey) {
      return 1;
    }
  }
  return 0;
}
```

-->