コンテンツにスキップ

5. 上の土管もつくる

Processingでフラッピーバード風ゲームをつくっていきます。

前回はプレイヤーと下の土管の衝突判定のプログラムをつくりました。 今回は上の土管もつくっていきます。

そのまえに

前回までのプログラムコード

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;
}

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

上の土管を表示する

いまのところ、下の土管だけが表示されていますよね。

上の土管も表示していきましょう。

まずは四角形を表示する

void draw() {
background(0);
// 土管のプログラム
dokan();
// プレイヤーのプログラム
player();
// 上の土管
fill(255);
rect(400, 0, 50, 200);
}

drawの中に、 rect(400, 0, 50, 200); rect命令を書きました。

  • 横400、たて0の位置に表示
  • 横幅50、たて幅200の大きさで表示

という命令ですね。

また、rect命令の前に fill(255); fill命令で土管の色を白色にしています。

どの数字を変数にするか

いまのところ、表示する位置、表示する大きさは固定です。動きません。 横400、たて0の位置。横幅50、たて幅200の固定で、ピクリともしません。

すでに作ってある下の土管と合わせて動くようにしていきましょう。

動かすためにはどうしたらよかったでしょうか?

そう、変数を使いますね。

では、どこの数字を変数にしましょうか?

  • 横の位置400を変数にする?
  • たての位置0を変数にする?
  • 横幅50を変数にする?
  • たて幅200を変数にする?

どれを変数にするか、順番に考えてみましょう。

まず、「横の位置400を変数にする?」です。

横の位置は、下の土管の横の位置と同じですよね。 下の土管の横の位置、xの位置はすでに変数にされていましたよね。 なんでしたっけ?

そう、「dx」です。

上の土管の横の位置は変数「dx」と同じですので、 そのまま変数「dx」を使いまわして、新しく変数をつくる必要はなさそうですね。

「たての位置0を変数にする?」はどうでしょうか?

横の位置と違って、 上の土管のたての位置と、下の土管のたての位置は違いますよね。 下の土管のたての位置、yの位置の変数「dy」は使えなそうですね。

では、新しく変数をつくりましょうか?

いえ、変数をつくる必要はありません。 なぜかというと、上の土管は必ず画面の上からにょきっと生えてきます。 画面の上と、上の土管とはスペースはありません。 ということは、たての位置は「0」で固定でいいんですね。 変数にする必要はありません。

「横幅50を変数にする?」はどうでしょうか?

はい、不要ですね。 下の土管のときも変数にしていません。横幅は50で固定ですので、変数はいりません。

さいご、「たて幅200を変数にする?」はどうでしょうか?

上の土管は、下の土管のたての位置にあわせて、高さが変わりますよね。 変わるということは固定ではないので、変数にしましょうか?

変数にしたいところですが、実はいりません。 理由を説明します。

上の土管の高さの計算方法

上の土管は、下の土管のたての位置に合わせて高さが変わります。

ですが、上の土管と下の土管とのスペースは一定です。 ここではスペース幅を100とします。

ということは、

上の土管の高さ = 下の土管のy - 100

という計算が成り立ちます。

高さも変数にする必要はなさそうですね。

本当にそうか、確認してみましょう。

rect(400, 0, 50, 200);

このrect命令に伝える数字を変えていきます。

まず横の位置は、下の土管のx位置、変数「dx」と同じと説明しました。

rect(dx, 0, 50, 200);

たての位置は0のまま。 横幅も50のままです。

そして、たて幅を先ほどの計算式を使って、

rect(dx, 0, 50, dy - 100);

としてみましょう。

void draw() {
background(0);
// 土管のプログラム
dokan();
// プレイヤーのプログラム
player();
// 上の土管
fill(255);
rect(dx, 0, 50, dy - 100);
}

(drawの中だけを書き出しています。)

実行すると、下の土管とちょうどいいスペースをあけて、 上の土管が下の土管と同じように左に動き出しましたね。

左端にいった後も、問題なく右から出現しています。

変数にしてもよい

今回は、上の土管の表示に関わる数字を、何も変数にしませんでした。

もちろん変数にしてもOKですが、 ここではなるべく変数の数を少なくしておきたかったので、 あえて省略しました。

変数の数が多いと、初心者は混乱してしまうからです。

変数はなるべく使わない方がいい、という意味ではないので、 慣れてきたら変数をどんどん使っていきましょう。

dokan関数に引っ越す

さて、drawの中に書いてしまいましたが、 土管にかかわるプログラムは、前回で dokan() という関数にまとめるようにしました。 今回の上の土管のプログラムもdokan関数にお引越ししましょう。

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);
// 上の土管
fill(255);
rect(dx, 0, 50, dy - 100);
}

drawの中に書いてあった、上の土管のプログラムは消しておきます。

void draw() {
background(0);
// 土管のプログラム
dokan();
// プレイヤーのプログラム
player();
}

上の土管と衝突したらプレイヤーが赤くなるようにする

プレイヤーと下の土管との衝突判定は、前回つくりましたね。

どこに書いたかいうと、プレイヤーにかかわることなので、 player() 関数に書きました。

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);
}

ここに上の土管との衝突判定も書いていきましょう。

まずはコメントで頭を整理します。

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);
}
// ここから書く!
// まずは上の土管と衝突しているか、isHitを使って調べる
// if(衝突していたら)
// fill命令で赤色にする
// ここまで書く!
rect(x, y, 50, 50);
}

下の土管との衝突判定にならって、 上の土管との衝突判定をプログラミングしてみましょう。

まず、

int hit = isHit(x, y, 50, 50, dx, dy, 50, 400 - dy);

この部分を上の土管用に作ってみましょう。

上の土管の情報をisHitに伝えればいいので、

int hit02 = isHit(x, y, 50, 50, dx, 0, 50, dy - 100);

となりますね。

isHitが作ってくれる数字は0か1でした。 上の土管と衝突しているか調べてisHitがつくってくれた数字を、 変数「hit02」として名前をつけておきましょう。

変数「hit」は下の土管との判定。 変数「hit02」は上の土管との判定。 ということになります。

では、実際にプログラミングしてみましょう。

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);
}
// 上の土管と衝突しているか調べる
int hit02 = isHit(x, y, 50, 50, dx, 0, 50, dy - 100);
if(hit02 == 1){
fill(255, 0, 0);
}
rect(x, y, 50, 50);
}

このようになりました。

実行すると、上の土管と衝突した時も、プレイヤーが赤くなるようになりました。

ここまでのプログラムコード

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);
// 上の土管
fill(255);
rect(dx, 0, 50, dy - 100);
}
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);
}
// 上の土管と衝突しているか調べる
int hit02 = isHit(x, y, 50, 50, dx, 0, 50, dy - 100);
if(hit02 == 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;
}