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

<!--

# 8. リトライ機能をつくる
ゲームオーバーになった時、もう一度ゲームを始めるためにはプログラムを再起動しないといけませんでした。
これは遊ぶ人にとってはとても面倒なので、再起動せずともリトライできるようにしましょう。

## そのまえに
### 前回までのプログラムコード

```Java
float x = 100;
float y = 200;
float speed = 0;
float dx = 400;
float dy = 200;
int shibou = 0;
int score = 0;
void setup() {
  size(600, 400);
}
void draw() {
  background(0);
  // 死亡フラグがたっていなければ
  if(shibou == 0){
    // 土管のプログラム
    dokan();
    // プレイヤーのプログラム
    player();
  }
  // 死亡フラグがたっていれば
  if(shibou == 1){
    fill(255, 0, 0);
    textAlign(CENTER);
    text("GAME OVER", 300, 200); 
  }
  fill(255);
  textAlign(CENTER);
  textSize(48);
  text(score, width/2, 100);
}
void mousePressed() {
  speed = -10;
}
void dokan() {
  // 土管のdraw
  dx = dx - 5;
  if (dx + 50 < 0) {
    dx = 600;
    dy = random(200, 300);
    score = score + 1;
  }
  fill(255, 255, 255);
  rect(dx, dy, 50, 400 - dy);
  
  // 上の土管
  fill(255);
  rect(dx, 0, 50, dy - 150);
}
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);
    shibou = 1;
  }
  // 上の土管と衝突しているか調べる
  int hit02 = isHit(x, y, 50, 50, dx, 0, 50, dy - 150);
  if(hit02 == 1){
    fill(255, 0, 0); 
    shibou = 1;
  }
  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;
}

```

## 8-1 初期化する関数を用意する
### リトライするには？
リトライするには、ゲームを起動した時と同じ状態に戻せば良いわけですが、「同じ状態に戻す」というのも自分でプログラムする必要があります。

### ゲームを起動した時の状態とは？
プログラムの最初に変数の初期値を定義してきました。

```Java
// 変数の初期値たち
float x = 100;
float y = 200;
float speed = 0;
float dx = 400;
float dy = 200;
int shibou = 0;
int score = 0;
```

リトライ時に、これらの変数を初期値に戻してあげれば良さそうです。
初期値に戻す処理を「**関数**」にしましょう。

```Java
// 初期値に戻す関数 init
void init(){
  
}
```

ここでは「init」という名前の関数を作りました。
関数なので、名前は好きなようにつけてよいのですが、ここではinitという名前にしてあります。
initは初期化するという意味と思っておいてもらえればOKです。

### init関数の中身を作る
では中身を作っていきましょう。
変数たちを初期化してあげればいいので、こうなりそうですね。

```Java
void init(){
  float x = 100;
  float y = 200;
  float speed = 0;
  float dx = 400;
  float dy = 200;
  int shibou = 0;
  int score = 0;
}
```

確かにエラーにはならないのですが、これは誤りです。
「float」やら「int」をつけてしまっていることが問題です。

### グローバル変数とローカル変数
ややこしくなるので説明していませんでしたが、変数には「グローバル変数」と「ローカル変数」というものがあります。

「グローバル変数」はプログラムみんなで共有している変数です。
「ローカル変数」はその関数の中でしか使わない、使い捨ての変数です。

関数の中で「int」や「float」という型をつけてしまうと、それはローカル変数として扱われてしまい、使い捨ての全く新しい変数を作ることを意味してしまいます。

ここでやりたいことは、プログラムみんなで共有している変数を初期化したいので、グローバル変数を初期化する必要があります。

```Java
void init(){
  // グローバル変数にアクセスするようにした
  x = 100;
  y = 200;
  speed = 0;
  dx = 400;
  dy = 200;
  shibou = 0;
  score = 0;
}
```

### 余談
ちょこっと出てきたローカル変数、実はこれ、もう使っていたりします。

```Java
void player() {
  // ..省略
  int hit = isHit(x, y, 50, 50, dx, dy, 50, 400 - dy);
  if(hit == 1){
    fill(255, 0, 0);
    shibou = 1;
  }
  // ..省略
}
```

当たり判定のところで、「hit」というint型の変数を使いました。
この「hit」という変数、グローバル変数でしょうか？ローカル変数でしょうか？

答えは、ローカル変数です。

player関数の中で、「int」という型をつけて変数を作っていますので、これは使い捨ての変数、ローカル変数だとわかります。
当たり判定は、その瞬間だけ判定できればいいので、グローバル変数にしてみんなで共有する必要がありません。なのでローカル変数として使い捨てしています。



## 8-2 スペースキーを押したら初期化する
さて、初期化するinit関数を作りました。

この初期化するinit関数が正常に動作するか確認するために、スペースキーを押したら初期化してリトライできるようにしてみましょう。

```Java
// キーが押された時に呼び出されるkeyPressed関数
void keyPressed(){
  // スペースが押されたら
  if(key == ' '){
    init();
  }
}
```

「**keyPressed関数**」を定義しておくと、キーが押された時の処理を書くことができます。
どのキーが押されてもkeyPressed関数が呼び出されてしまうので、関数の中で「key == ' '」という条件でスペースキーだったときのみinit関数を呼び出すようにします。

実行して、スペースキーを押すとゲームがリトライされるようになったと思います。


## 8-3 ゲームオーバーのときだけ初期化するようにする

スペースキーでのリトライがいつでもできてしまうので、ゲームオーバーになったときのみ、リトライできるように修正しましょう。

ゲームオーバーかどうかは、どうやって判定すればよかったでしょうか？
そう、ゲームオーバーの目印として死亡フラグを作っておきましたよね。

```Java
void keyPressed(){
  // スペースが押されたら
  if(key == ' '){
    // 死亡フラグが立っていたら
    if(shibou == 1){
      init();
    }
  }
}
```

ゲームオーバーになった時、再起動せずともスペースキーを押すことでゲームが再挑戦できるようになりました。

-->