FALさんの「Processingでゲーム制作」で学ぼう! 3
Processing Community Day 東京 でのワークショップ講師の FAL さんによって公開された「Processingでゲーム制作」の資料で勉強させてもらってます。
前回は弾にあたった敵機や、敵機に当たった自機の爆発効果を追加しました。
でも、爆発が一瞬だけでなんか物足りない…
前回の記事はこちら。
FALさんの「Processingでゲーム制作」で学ぼう! 2
普通爆発ってどうだっけ?
前回実現させた爆発効果は、一瞬パッと出るだけのものでした。
物足りないですよね。
これは1フレームだけの描画で終わってるからです。
これを複数フレームにわたって描画するようにすれば、それらしい爆発になるのではないでしょうか?
爆発を独立したエレメントとして実装すれば?
敵機や自機はエレメントとして実装されていて、出現から消滅まで複数フレームに渡って存在し続けます。
爆発もこれと同様にエレメントとして実装すれば、複数フレームにわたっての爆発が実現できるのでは?
こんな感じで敵機や自機が消滅するときに newExplosion というエレメントを生成する!
if (element.isDead) {
Element newExplosion = new Element(
new SquareDisplayer(),
new DefaultUpdater(),
new DummyDestroyer()
);
newExplosion.position.set(element.position.x, element.position.y);
explosionElements.add(newExplosion);
iterator.remove();
}
…あれ? でもこれ newExplosion エレメントが消滅するときにもまた newExplosion が生成されてしまうのでは?
あ、ダメだコレ。
そもそも論
う〜ん、上手く行きませんね。ちょっと考え直してみましょう。
そもそも爆発しているのは敵機や自機であり、衝突して爆発してから消滅ですよね。
前回のコードだと衝突したら即死(element.isDead)であり、死んでたら爆発させるということになっています。
この考えはちょっと変かもしれませんね。
敵機が場外に退場する際も爆発しちゃってますし。
まず、爆発はそれぞれのエレメントが爆発するんだから、エレメントのメソッドとして爆発があるべきではないでしょうか?
衝突は破壊をもたらし、破壊は爆発を呼び、爆発しきったら死、という感じ。
・死とは別に破壊とライフというステータスを持つ
・衝突は破壊をもたらし、破壊後は1フレームごとにライフが減る
・ライフがゼロになると死
・場外は即死
という考えなら納得感あるし、コードにも起こせそうです。
あらためてコーディング
この考えをコードに起こしてみましょう。
前回のコードは捨てて、前々回のコードを元にします。
まずはこれ。
・死とは別に破壊とライフというステータスを持つ
Element.pde 中の class Element に isBroken と life というフィールドを追加します。
class Element {
PVector position, velocity;
boolean isDead = false;
boolean isBroken = false;
int life = 30;
・衝突は破壊をもたらし、破壊後は1フレームごとにライフが減る
これはまず衝突時に破壊というステータスを立てます。
ElementList.pde の class ElementList 中の collide メソッドでの衝突判定。
if (distance < 50) {
element.isDead = true;
other.isDead = true;
}
ここを isDead ではなく isBroken を立てるようにします。
if (distance < 50) {
element.isBroken = true;
other.isBroken = true;
}
そして、破壊後にライフを減らすのは、 ElementComponent.pde の class DefaultUpdater と class PlayerUpdater それぞれの run メソッド中に実装します。
これをメソッド中の最後に追加。
// Shorten life if broken
if (element.isBroken) {
--element.life;
ellipse(position.x, position.y, 100.0, 100.0);
}
life を1減らして、爆発効果として ellipse を描画しています。
class DefaultUpdater と class PlayerUpdater で描画を変えれば、敵機の爆発と自機の爆発の効果を変えることが出来ますね。
・ライフがゼロになると死
ElementList.pde の class ElementList 中の update メソッドに消滅のコードがあります。
if (element.isDead) iterator.remove();
この直前にコードを追加しましょう。
// Die if life <= 0
if (element.life <=0) element.isDead = true;
・場外は即死
これは ElementComponent.pde 、 class DefaultUpdater の run メソッド中に元々入っているコードそのままで OK ですね。
// Die if out of screen
if (position.x < 0 || position.x > width ||
position.y < 0 || position.y > height) {
element.isDead = true;
}
できた!爆発効果を長くできましたよ。
もうひと工夫
でも、弾にもライフがあるから、敵機を複数なぎ倒していっちゃいますね。
これは弾のライフの初期値を小さくすれば解決できそうです。
ついでに爆発効果ももう少し派手にしてみましょう。
Element を生成する際にライフの初期値を指定できるようにします。
それには Element.pde の class Element のコンストラクタを変更して、
Element(ElementComponent displayer, ElementComponent updater, int life) {
position = new PVector();
velocity = new PVector();
// Set components
this.displayer = displayer;
this.updater = updater;
this.life = life;
}
Element の生成時に3番目のパラメータでライフ値を指定するようにします。
弾の生成の場合はライフを 1 にしてすぐ消滅するように。
Element newBullet = new Element(
new BulletDisplayer(),
new DefaultUpdater(),
1
);
爆発効果の方は、例えば乱数を使ってこんな感じに。
float rndX = random(-50.0, 50.0);
float rndY = random(-50.0, 50.0);
float eW = sqrt(rndX * rndX + rndY * rndY);
ellipse(position.x + rndX, position.y + rndY, eW, eW);
そうするとこう!
うん!まずまず!
自機が一回の衝突で破壊されちゃう
今回は弾のライフを 1 にすることによって衝突後にすぐ弾が消滅するようにしましたが、ライフが長くて弾が敵機を突き抜けていくのも気持ちいいですね。
自機がパワーアップした時にこうなったらゲームっぽくなりそうです。
あと、自機が一回の衝突で破壊されてしまうのもちょっと寂しい感じ。
衝突毎にライフが減っていって、何回か衝突後に破壊されるといいかも。
コード的にはライフを減らすのにインスタンスのフィールドを外部から直接変更している点が気になります。
解決にはどうすれば…?
この記事が面白かったらサポートしていただけませんか? ぜんざい好きな私に、ぜんざいをお腹いっぱい食べさせてほしい。あなたのことを想いながら食べるから、ぜんざいサポートお願いね 💕