見出し画像

ゲームの”障害物”もクラスで作る!- 次々と現れる物体は「配列」にまとめる - JavaScriptでやる1分間プログラミング

さて、ここまでで物体をジャンプさせることができました。おさらいですが、今回のプログラミングの目標はジャンプで障害物を避ける「恐竜ゲーム」を作ることでした。

そして以下が今現在のコードです。まずはユニコーンと称したクラスを作り(今のところ円の形になっています)、スペースバーを押すことで円がジャンプします。Coding Trainのビデオにはない左右の動きも追加しています(どうしてこの動きを入れたかはゲームが完成するとわかります)。

コードは以下の通りです。またコメントなどはきれいにしています。

let unicorn; //ユニコーン変数を作る

function setup() {
 createCanvas(400, 400);
 //ユニコーンを一つ作る
 unicorn = new Unicorn(100, height-25, 50);
}

//キー操作の検知
function keyPressed() {
if (key == ' ')
  unicorn.jump(); //jump関数を呼び出す
}

function draw() {
 background(220);
 fill(200, 0, 200);

 //左右のキーに動きを反応させる
 if (keyIsPressed) {
   if (key == "ArrowRight")
     unicorn.x += 10;
   else if (key == "ArrowLeft")
     unicorn.x -= 10;
 }
 unicorn.move(); //ユニコーンを動かす.
 unicorn.show(); //ユニコーンを表示させる
}

//ユニコーンのクラス
class Unicorn {
//コンストラクタ
 constructor (x, y, r) {
   this.x = x;
   this.y = y;
   this.r = r;
   this.velocity = 0; //最初のジャンプ量はゼロにする
 }

 //jump関数を追加する
 jump() {
  this.velocity = 50; 
 }

 //動く
 move() {
   this.y -= this.velocity; //ジャンプ距離分をYから引く(上昇)
   this.velocity -= 5; //ジャンプ移動距離から重力分の5を引く
 }
 
 //クラスの表示 
 show() {
   this.y = constrain(this.y, 0, height-this.r/2);
   circle (this.x, this.y, this.r);
 }
}

これで円をスペース左右の矢印キーで自由に動かすことができます。

画像1

まずは”障害物”をclassで表現する

次のステップはジャンプして避ける障害物が画面右からどんどんと流れてくるようにするプログラミングです。

まず「障害物」というものを定義します。ジャンプするユニコーンをclassで作ったように、障害物も同じくクラスで作ります

そこでUnicornクラスを作った時と同様に、まず基本クラスを作ります。ビデオでは障害物が列車になっているので、同じようにTrainというクラスの名前にします。次のコードをUnicornクラスのすぐ下に追加してください。

//トレインのクラス
class Train {
 constructor (x, y, r) {
   this.x = x;
   this.y = y;
   this.r = r;
 }
 
 show() {
   rect(this.x, this.y, this.r);
 }
}

列車の絵はまだ表示させず、まずは簡単に四角形(rectを使います)で表示させます。UnicornもTrainも次回にすべて画像に変えます。まずはプログラミングのロジックを完成させないといけないので、初期段階ではこうした円や四角のような簡単な物体を使うのがコツです。図形を絵に変換するのはとても簡単だからです。

実は障害物はこれで完成です。Unicornのようにジャンプしたりしないので、Trainクラスにmoveやjumpのようなメソッドは不要なのです。あとはこれを表示させるわけですが、これが結構クセモノです。。

✔ 障害物はいくつも出てくる
✔ 障害物はランダムに出てくる
✔ 常に右か左に移動する

こうしたことをプログラムでどうやって表現するかが難しいところで、また面白いところです!では一つ一つコーディングしていきましょう。

画像2

障害物をランダムにいくつも発生させる

障害物を表示させたい場合はUnicornでやった時と同様にnew Train()で物体を作り、showメソッドを呼び出すと四角が一つ現れます。

実際UnicornのようにTrainも一つだけ表示させてみましょう。コード全体はこうなります。1⃣、2⃣、3⃣の3か所を追加しただけです。

let unicorn; //ユニコーン変数を作る
let train; //1⃣ トレイン変数を作る

function setup() {
 createCanvas(400, 400);
 //ユニコーンを一つ作る
 unicorn = new Unicorn(100, height-25, 50);
 //2⃣トレインを一つ作る
 train = new Train(300, height-50, 50);
}

//キー操作の検知
function keyPressed() {
if (key == ' ')
  unicorn.jump(); //jump関数を呼び出す
}

function draw() {
 background(220);
 fill(200, 0, 200);
 
 //3⃣トレインを表示
 train.show();

 //左右のキーに動きを反応させる
 if (keyIsPressed) {
   if (key == "ArrowRight")
     unicorn.x += 10;
   else if (key == "ArrowLeft")
     unicorn.x -= 10;
 }
 unicorn.move(); //ユニコーンを動かす.
 unicorn.show(); //ユニコーンを表示させる
}

//ユニコーンのクラス
class Unicorn {
//コンストラクタ
 constructor (x, y, r) {
   this.x = x;
   this.y = y;
   this.r = r;
   this.velocity = 0; //最初のジャンプ量はゼロにする
 }

 //jump関数を追加する
 jump() {
  this.velocity = 50; 
 }

 //動く
 move() {
   this.y -= this.velocity; //ジャンプ距離分をYから引く(上昇)
   this.velocity -= 5; //ジャンプ移動距離から重力分の5を引く
 }
 
 //クラスの表示 
 show() {
   this.y = constrain(this.y, 0, height-this.r/2);
   circle (this.x, this.y, this.r);
 }
}

//トレインのクラス
class Train {
 constructor (x, y, r) {
   this.x = x;
   this.y = y;
   this.r = r;
 }
 
 show() {
   rect(this.x, this.y, this.r);
 }
}

Trainの形は四角なので、円と違って始点が左上の角にあります。なのでタテの位置はheight - 25ではなくheight - 50となっている点に注意してください。これで実行するとこうなります。

画像3

四角が一つポット現れるだけ。当然これではゲームになりません。四角のTrainが左に流れてこないといけないですよね。どうしたらよいか分かりますか?そうです、showする前にトレインのXの位置を左にずらしてやればよいのです。

  
 //トレインを表示
 train.x -= 10; //trainのXを毎回10引くと左に移動していく
 train.show();

これだけで四角が左にすーっと移動していきます!

画像4

まずは一歩前進です。

複数の障害物を「配列」の入れ物に入れる

ところが今はトレインが1つだけできて、左に消えると二度と出てきません。障害物はいっぱいでてきてくれないと面白くありません。そこで、トレインを1つだけ作るのではなく、たくさん作る方法を解説していきます。

まずは変数を配列で定義します。普通の変数の宣言と比較してみてください。

//中身が一つだけの変数
let train;

//中身が複数ある変数=配列
let trains = p[];

このように = [] を加えるとtrainsという入れ物にはいくつもの値を収めることができます。これが「配列」です。配列についての詳しい解説はこのメモを読んでください。

ランダムに障害物を発生させる

ではtrainsという配列の入れ物は用意できましたが、ここに障害物を、例えば10個とか決め打ちして入れてしまっては、1個の時と同じ問題が出てきます。つまり10個表示されたらそれで終わりということです。

そこでsetup関数のところで決め打ちしてトレインを作るのではなく、draw関数のループごとにTrainを作るようにします。ただ、ループごとに作ると滝のように障害物が流れてくるので、ほどよく”間引き”してやらないといけません。それがrandom関数です。

コードは次の2行をdraw関数の中に入れてやるだけです。

  //トレインをランダムに発生させる
 if (random(0, 1) < 0.01)
   trains.push(new Train(width, height-50, 50));

random(0, 1)というのは0と1の間にある数字を適当に作ってやるということです。つまり0.1とか0.26とか0.87とかの小数点の数字が勝手に作られます。そのランダムに出てきた数字が「0.01よりも小さい」という場合にのみTrainが作られつようにします。これは間隔としては100ループに1回の割合で障害物が作られます。ループは1秒に30回も回るのでこのくらいの間隔がちょうどよいです。もちろんもっと間引きしたい場合は0.009くらいにすればよいですし、もっと多くしたい場合は0.02とかにしてみてください。

配列内の障害物をすべて左に流す

そこでループが始まっていくつも障害物ができてくると、配列の中には何個もTrainが入ることになります。この一つひとつを左にずらしてやらないといけません。配列の中身をすべて”スキャン”するには次のようなコードを書きます。

  //トレインを表示
 for (let t of trains) {
   t.x -= 10;
   t.show();
 }

ここのforでtrainsの中身を一つひとつピックアップしてtという一時的に作った変数に入れてくれます。配列のループみたいなものです。そこで各tについてXの位置を10少なくし、そしてshow関数を呼び出してやるわけです。これで配列に何個Trainが入っていて、そのすべてを左にずらしてやることができます。

コード全体はこうなりました。1⃣、2⃣、3⃣が追加した部分です。

let unicorn; //ユニコーン変数を作る
let trains = []; //1⃣ トレインの配列を作る

function setup() {
 createCanvas(400, 400);
 //ユニコーンを一つ作る
 unicorn = new Unicorn(100, height-25, 50);
}

//キー操作の検知
function keyPressed() {
if (key == ' ')
  unicorn.jump(); //jump関数を呼び出す
}

function draw() {
 background(220);
 fill(200, 0, 200);
 
 //2⃣トレインをランダムに発生させる
 if (random(0, 1) < 0.01)
   trains.push(new Train(width, height-50, 50));
 
 //3⃣トレインを表示
 for (let t of trains) {
   t.x -= 10;
   t.show();
 }

 //左右のキーに動きを反応させる
 if (keyIsPressed) {
   if (key == "ArrowRight")
     unicorn.x += 10;
   else if (key == "ArrowLeft")
     unicorn.x -= 10;
 }
 unicorn.move(); //ユニコーンを動かす.
 unicorn.show(); //ユニコーンを表示させる
}

//ユニコーンのクラス
class Unicorn {
//コンストラクタ
 constructor (x, y, r) {
   this.x = x;
   this.y = y;
   this.r = r;
   this.velocity = 0; //最初のジャンプ量はゼロにする
 }

 //jump関数を追加する
 jump() {
  this.velocity = 50; 
 }

 //動く
 move() {
   this.y -= this.velocity; //ジャンプ距離分をYから引く(上昇)
   this.velocity -= 5; //ジャンプ移動距離から重力分の5を引く
 }
 
 //クラスの表示 
 show() {
   this.y = constrain(this.y, 0, height-this.r/2);
   circle (this.x, this.y, this.r);
 }
}

//トレインのクラス
class Train {
 constructor (x, y, r) {
   this.x = x;
   this.y = y;
   this.r = r;
 }
 
 show() {
   rect(this.x, this.y, this.r);
 }
}

適当な間隔でトレインが流れるようになったと思います。

画像5

では実際にジャンプして障害物を避けてみてください。やる前に必ずキャンバスを一回クリックしてからスタートしてください。よい感じでジャンプして逃げられますよね。

画像6

もちろんぶつかってもなにも起きません。そこで次回はクラッシュのロジックに挑戦します。ユニコーンとトレインが接触するとゲームオーバーという典型的なロジックです。物体と物体が接触したかどうかは複雑なロジック必要ですが、実は便利な関数があります。それを使うととても簡単にクラッシュしたかどうかがわかるようになります!

この記事が気に入ったらサポートをしてみませんか?