ついに完成、シューティングの基本!
いつものリビング、いつもの俺たち、だけれども今日の由紀はどこか違った感じ。
何というか、ワクワクしているようなのだ。
「さてお兄ちゃん! 今回でひとまず最低限のゲームは完成します」
「いきなり進むなぁ……弾幕とか派手なエフェクトが出るのか?」
「いえ、最低限、です。自機と敵が動いて弾を発射して当たれば敵が消えます。どうです? ゲームっぽいでしょう」
「いきなり随分進むんだな、もうちょっと基礎からやるのかと思ったが」
「大丈夫です、基礎の組み合わせでこのくらいなら作れます」
ゲームか……作ったのは初めてだなあ、プレイはよくやってるけど。
「では、まずは操作性を上げましょう!」
「操作性?」
俺が聞くと、はいとスマホを俺に渡してくる由紀……起動してみろってことか?
俺が起動させると四角と円が表示されて円を押すと四角が動いて……あれ? 止まったな……
「押したときと動かしたときに時期のxが上下しますから同じところを押しっぱなしだと動かないんです」
「じゃあどうすれば?」
「速度の変数を作りましょう、ひとまずそれで用をなします。速度はfloatのmovexにしましょう」
確かクラス宣言の下に書くんだったよな……ほいっと。
「書けたぞ」
「じゃあコンストラクタで0に初期化しましょう」
「え……速度が0だと動かないんじゃ……」
「そこでタッチイベントのメソッドをいじります、今回は最低限なのでy軸の移動はしません、某ゲームセンターを席巻した侵略者ゲームの超しょぼいやつだと思ってください」
ええと……
「myshipxを自機のX座標としてどれだけ移動するかを直接Xをいじるコードから変更しましょう。そこでmovexに動かしたい方向へ数字を代入してください」
ううんと……こうか?
------
if (tx >= padx + 20 && tx <= padx + 100 && ty >= pady - 30 && ty <= pady + 30) {
movex = 10;
}
else if (tx <= padx - 20 && tx <= padx + 100 && ty >= pady -30 && ty <= pady + 30) {
movex = -10;
}
-----
「いいですね、指を離したときには移動量が0になるようにしておきましょう」
-----
case MotionEvent.ACTION_UP:
movex = 0;
break;
-----
「これだけでちゃんと止まってくれます、次はrun()をいじるわけですが……ちょっと予想してみてください」
movexは移動量だからmyshipxを変更するには……こうかな?
-----
myshipx += movex;
-----
「当たりです! お兄ちゃんもなかなかわかってきましたね!」
ふぅ、どうやら正解らしい。
「で、ちょっと物足りないですよね? 足りないでしょう……敵と弾が」
「そういえばシューティングなら弾を撃てるし敵も必要だな」
「そこでお兄ちゃんには新しいクラスを作ってもらいます」
「クラス? このGameMainみたいなものか?」
「そうです、今回はシンプルに弾のx座標とy座標を持つクラスを作成しましょう。名前はBulletにしましょう」
ええっとプロジェクトのフォルダを右クリックして……
「このNewの中にあるJava Classってやつでいいのか?」
「そうですね、作ってください」
名前はBulletだったな。
「できたぞ。これにもsuper(context)がいるのか?」
「いえ、これはただ単に値をまとめるだけのクラスなので不要です。まずはfloat x,yを宣言してください」
俺は言われた通りにクラス宣言の下に書き込む。
「あれ? これに直接値を入れればいいのか?」
「いえ、コンストラクタで初期化しましょう、コンストラクタはBulletクラスなのでpublic Bullet(float x,float y){} になります」
--------
public Bullet(float x,float y){
this.x = x;
this.y = y;
}
--------
「こうですね」
「コンストラクタに引数があるな……それにthisって何だ?」
「thisはこのクラスのという意味です、引数のxと区別するためにつけています」
「このxとyは?」
「それをnewでインスタンスを作ったときに指定します。具体的にはこうです」
bullet = new Bullet(-1,-1);
「その-1は何なんだ?」
「初期状態で画面外に出しておきます、発射されたら自機の位置に置きます」
うん? よくわからんが?
「ではタッチイベントのif文の末尾にelse{}を追加してください。ifの中が真でなければ実行されます。そして中身はこうです」
-------
}else{
if(bullet.y < 0) {
shot();
}
}
-------
「なんでbullet.yが0以下の判定が入ってるんだ?」
「これを入れておかないと弾が画面内にあるのに新しい弾が出て座標がそっちに上書きされるのでそれを防ぐためですね」
「じゃあshot()メソッドを作りましょう。とはいえこれはすごく簡単です。
-------
private void shot() {
bullet.y = height-300;
bullet.x = myshipx;
}
------
たったこれだけです。y座標が直打ちなのはちょっとカッコ悪いですけど今回は困らないのでこれで行きましょう」
「自機の位置に弾を持ってくるわけか、じゃあrun()の中でyを上に上げてけばいいのか?」
「はい、これは簡単なのですが……ちょっと難しいことがあります……」
「難しい? 複雑なコードを書かなきゃならないのか?」
「いえコード自体は以下でとても簡単です」
y -= 30;
「なんだ、これだけか。どこが難しいんだ?」
「yを減らす量です、大きくすれば弾がすっ飛んで行きますし、小さくすればのろのろ飛んで行きます」
「それがどうかしたのか?」
「ゲームバランスってやつですよ……どのくらいの量にするのがいいかはプレイヤー層にもよりますしマシンスペックでも変わりますからね、これは正解がないんです、ここに書いたのはあくまで一例です」
ゲームバランス……難しすぎても楽すぎてもダメだしなあ……
「まあそれに関しては今は考えなくてもいいでしょう。次は敵クラスを作りましょうEnemyクラスをBulletクラスと同じように作ってください」
それはできるけど……
「これでいいのか?」
俺はEnemyクラスを作った。
「もしかしてコンストラクタとかもBulletと一緒でいいのか?」
「そうですね名前が変わっただけでほとんど一緒で構いませんが、x,yの他にboolean isAlive;も入れておきましょう。これはコンストラクタでtrueを代入しておいてください」
「なんに使う変数なんだ?」
「敵が生きているかどうかの判断ですね、倒したらisAliveにfalseを入れて画面から消します」
「あ! わかった! onDrawにif文を入れるんだな!」
由紀がぽかんとした顔でこちらを見てきた、その後で微笑みながら言った。
「正解です! じゃあ書いてみてくれますか?」
「こうだろ」
--------
if(enemy.isAlive == true) {
canvas.drawRect(enemy.x, enemy.y, enemy.x + 100, enemy.y + 100, p);
}
--------
「正解です! じゃあどんなときisAliveが書き換わるかは書けますか?」
「え……うーん、わからん」
「こう書けばいいんです、これを俗に『当たり判定』と言います」
--------
if(bullet.x >= enemy.x && bullet.x <= enemy.x+100 && bullet.y <= enemy.y && bullet.y >= enemy.y - 100){
enemy.isAlive = false;
}
--------
「なんか記号がいっぱいでよくわかんないんだが……」
「『&』は『かつ』って意味です、敵の左端のx座標が弾のx座標より大きい、要は敵の左端が弾の左端より右にあるってことです、そんな感じで読んでみてください」
頭がこんがらがってきた。
「なあもっと簡単に『bullet.x == enemy.x && bullet.y == enemy.y』とかにできないのか?」
「それはとてもいい質問ですね! 実はできます! ただ敵も弾も1ドットしか判定がないので自機と敵弾ならとも書く自分の弾が1ドットの判定だとストレスが溜まりますよね、だからその方法は自機の当たり判定にしか使えないんです」
なるほど、確かに自分の弾が全然あたらないとストレスだもんな。
「さあお兄ちゃん! ついにプロトタイプの完成ですよ! 存分にプレイしてください!」
由紀はそういうとスマホを差し出してきた、俺はMacBookにつないで実行ボタンを押す。
「おお! 動いてる! 弾も飛んでる! 当たったら敵の四角が消えた!」
「とっても単純ですけど突き詰めていけばシューティングゲームはこれの改変です、もちろん必要なテクニックとかもありますけどね。じゃあ講義はこの辺でおしまいにしましょう」
「すごいな、自分で作ったんだ……信じられないよ」
「ふふ……楽しいでしょう、自分で何かを作るのは、ね」
「ああ、ありがとう、スッゲー楽しかった!」
「ええそれじゃあこの辺で私の特別講座もお開きにしましょうか」
こうして俺たちはいつもの日常に戻って行った。
ただ俺はその時の興奮が忘れられず進路選択で理系を選んだ、後悔はしていない、俺もいつかは一から作ることの楽しさを誰かに教えられたら……と思っている。