Skip to content

第4回 Processing.js で初めてのゲームプログラミング

第3回までで、自機と弾の表示、そして弾のクラス化まで終わりました。前回をふりかえってみると、弾幕を出すために内部の構造変更を進めた回であり、とても大事な会ではあったのですが、読者の皆さんからみると、とりたてて派手なことはなく、つまらないカンジだったのかもしれません。しかし、それはこれから高くジャンプするために、しゃがんだ様なものなのです。ジャンプするのは、今回ですよ!さて、いよいよ、前回のそのクラスを「配列」という仕組みを使って弾幕にしてしまいましょう。

配列というのは、たくさんの変数をしまっておき、必要に応じて取り出すことができる、プログラムには欠かせない、頼りに相棒です。クラスと一緒で、理解するためにはチョット大変かもしれませんが、がんばって理解しましょう。配列にも、いくつか種類があるのですが、今回は ArrayList という、いつでも増やしたり減らしたりできる配列を作れるクラスを使って、弾を弾幕にしていきます。前回のソースをちょっと改造してみましょう。こんな感じです。なお、だんだんと、ソースコードが長くなってきたので、今回から、変更の中で主な部分だけこのページで紹介し、全体のソースはリンク先での紹介にしていこうと思います。

ArrayList danmaku;
// setup
void setup() {
  size(320, 320);
  frameRate(30);
  noCursor();  // clear mouse cursor
  danmaku = new ArrayList();
  for (int i = 0; i < 50; i++)
    danmaku.add(new Tama(random(width), random(height), 10));
}
// ... 中略 ...
//
void draw() {
   background(0); // clear
   ship(mouseX, mouseY);
   for (int i = danmaku.size() -1; i  >= 0; i--) {
     Tama t = (Tama)danmaku.get(i);
     t.update();
   }
}

sample04_1
サンプルプログラム04-1

どうでしょう?たくさんの弾が、バラバラと落ちてきましたね。これは、最初の setup 関数で一気に、50個のインスタンスを生成して(クラスとインスタンスの関係図は前回の図を参照)、出来たインスタンスは danmaku という ArrayList に add しています。50個作るとき、座標指定はメンドクサイので、xy 座標は、ランダムで設定してしまいました。

新しく出てきた ArrayList について図を用意しました。詳細はともかく、こういうふうな動作をするのだとイメージしておいてください。

また、draw() 関数内では、danmaku に入っている Tama クラスのインスタンスを使い、それぞれのupdate 関数を呼び、動かしているわけです。その際に、ArrayList は、size という関数を呼び出すことで、今、何個のインスタンスが入っているか数えて、その数だけループするようにしているというわけです。こうしておくことで、今後、弾幕がなんこに増えても、この draw 関数はちゃんとその分の update を呼び出してくれるというわけなのです。便利ですね!

しかし、この動作では、まったく弾幕ゲームに見えません。弾幕ゲームというからには、もっと弾がバラバラに、キレイに飛び散って欲しいものです。なぜ、そういう風になっていないのかというと、いまは全ての弾が、おじように update 関数が呼ばれるたびに、Y座標が +10 されるだけだからです。では、解決策として、それぞれのインスタンスが別々の動きをするように改造すればいいのです。それぞれのインスタンスが別々の動きをするためには、座標同様に、毎フレームにXとYの移動量を覚えている必要がありますね。その変数を dx, dy として、その変数をクラスに追加し、適当な値を設定するようにしてみます。

void setup() {
  size(320, 320);
  frameRate(30);
  noCursor();  // clear mouse cursor
 
  danmaku = new ArrayList();
 
  for (int i = 0; i < 360; i+= 10) {
    float rad = radians(i);
    danmaku.add(new Tama(width/2, height/2, 10, cos(rad), sin(rad)));
  }
}

sample04_2
サンプルプログラム04-2

オー、どうでしょう?一気に弾幕っぽくなってきたと思いません?

先ほど書いたようにdx,dy をクラス変数に追加したのですが、今回は、Tamaクラスのインスタンスを作る際に、丸く動くように36個のインスタンスを生成してみたのです。正確には生成場所は全部同じ場所(画面中央)なのですが、それぞれの弾が中心から放射線状に動くように dx と dy を設定しているのですね。この計算のために、sincos という三角関数を使いました。setup 関数内の該当箇所を見てもらえるとわかりますが、360度ぐるっと10度に1発つづ、インスタンスを生成しています。そして、update 関数内では移動後に、画面外にでたらまた、真ん中に戻すように変更してみました。dx, dy の移動量は変えてません。これだけでも、ずいぶんとそれぽく見えるものですね。sin、cos という三角関数は清水さんも記事で書かれています。この2つの関数はゲーム内で、なにかを動かそうとするときに、欠かせない大切な相棒です。sin、cos について、図を用意しました。こちらもみて、参照にしてください。

sinとcos

このように、動かしたい方向がわかった後、実際にプログラムに落とすには、x成分とy成分に分解し、指示してあげる必要があるのです。その際の計算にsinとcos は欠かせないというわけなんですね。補足ですが、sin と cos の引数の単位はラジアンなので、0 〜 360度を、ラジアン(0 〜 2π)に変換するため、radians 関数を呼んで、変換してます。

では、いい感じに弾幕っぽくなってきたところで、これまで適当に出してきた弾幕をちゃんとボスから発射されるように、ボスを作成してみましょう。例によって、ボスも Boss クラスを作っていきましょう。

class Boss {
  float bx, by;        // ボスの座標
  ArrayList danmaku;  // ボスが弾を吐くので、ここに移動
 
  Boss(float x, float y) {
    bx = x;
    by = y;  
    danmaku = new ArrayList();
  }
 
  void fire_360(float x, float y) {  
    for (int i = 0; i = 0; i--) {
      Tama t = (Tama)danmaku.get(i);  // ArrayList から Tamaをとりだし
      if (t.update() == false)   // update メソッドをよび
        danmaku.remove(i);   // 画面外だったら、削除
    }
  }
  // ... 略
}

sample04_3

サンプルプログラム04-3

前回のソースとちょっと変わってしまいました。新設した Boss クラスをみてもらえればわかりますが、弾を発射するのはBossなので、danmaku 変数はBossクラス内に移動しています。こんなふうに、クラス内の管理で済むものは、クラス内に入れてしまうほうが良いです。こうしておくと、将来、ボスを2匹だすことになっても、全く変更なしで済むわけですね。

そして、これまでは弾は画面外に出てしまっても座標を再設定して使いまわしていましたが、画面に何個出るのか不明なため、このソースからは方針を変更し、画面外に出てしまった弾は ArrayList クラスの remove を呼んで削除してしまっています。そして、弾はBossクラス内で、じゃんじゃん生成していけるのですね。

そしてもう一つ。Boss をゆらゆら動かすために、ここでも sin 関数を使っているのですが、じつはこで、sin 関数の引数として、システム変数 frameCount を渡しています。このframeCount はプログラムがスタートして、1フレーム毎に1づつ自動で加算される変数です。この自動で加算されるという変数はゲームの中で、いろんな局面で便利に使うことが出来ます。たとえば、別の場所でもつかっていて

if (frameCount % 30 == 0) {
  ...
}

というような処理を行なっている箇所があります。% 演算子は、A % B のように使った場合、AをBで割ったときの余りを計算するための演算子なんですね。(たとえば、 4 % 3 = 1 です)上記のように書くと、30フレームに一度、発生させたい処理を、特別な変数を作ることなく、簡単に実装することができる訳です。

ふぅ。ちょっと適当ですけれど、なんとかボスの実装も出来ました。

しかし、残念ながらまだゲームになっていません。シューティングゲームに必要な要素「当たり判定」がまだ入っていないからです。次回、第5回では当たり判定の実装を進めていきたいと思いますよ!ではでは。

このエントリーをはてなブックマークに追加
はてなブックマーク - 第4回 Processing.js で初めてのゲームプログラミング
Post to Google Buzz
Share on GREE

Related posts:

  1. 第3回 Processing.js で初めてのゲームプログラミング
  2. 第2回 Processing.js で初めてのゲームプログラミング
  3. 第1回 Processing.js で初めてのゲームプログラミング

Facebook comments:

Post a Comment

Your email is never published nor shared. Required fields are marked *
*
*