シューティングゲームを作る 〜その2〜
サンプルシューティングゲームのメイン処理である「メインルーチンのスクリプト」について解説します。
if (Math.random() < enRatio){ //変数enRatioが、乱数より大きかったら
duplicateMovieClip("_root.enChar", "enChar" + enNum, enNum + 1000);
//敵を複製する
enNum ++; //enNumに1を足す
if (enNum > 50){enNum = 1;} //enNumが50以上になってしまった場合は1に戻す
}
if (enRatio < 0.5){enRatio += 0.00001;} //enRatioが0.5よりも小さい場合は0.00001を足す
textScore = "SCORE :" + score; //スコア表示
textDamage = "DAMAGE:" + damage + "%"; //ダメージ表示
//----<ここから背景を表示するスクリプト>----
if (Math.random() < 0.05){ //取得した乱数が0.05よりも小さかったら
bkNum ++;
if (bkNum > 50){bkNum = 0;}
bk = "Back" + bkNum;
sc = int(Math.random() * 3) + 1;
_root.attachMovie("MC_Back" + sc, bk, bkNum);
eval(bk)._x = Math.random() * 280 + 20;
eval(bk)._y = 160;
r = Math.random() * 70 + 30;
eval(bk)._xscale = r;
eval(bk)._yscale = r;
eval(bk)._alpha = (r - 30) / 2;
if (enRatio > 0.07 && enRatio <= 0.09){eval(bk)._xscale = Math.random() * 150 + 30;}
if (enRatio > 0.09){eval(bk)._rotation = Math.random() * 360;}
}
//----<背景を表示するスクリプトここまで>----
if (damage >= 100){gotoAndPlay("ゲームオーバー");} //ダメージが100以上になったらラベルに飛ぶ
ゲーム中で表示されている背景の処理は、上記の「背景を表示する部分」で行われています。背景を表示したくない場合は、この部分の処理を削除してください。
最後の行の処理によってダメージが100以上になるとラベル「ゲームオーバー」に移動し、「GAMEOVER」の文字とリプレイボタンが表示されます。
リプレイボタンを押すとイベントのはじめに戻ってタイトル画面に戻ります。
■ シューティングゲームの改造
このサンプルシューティングゲームを改造して、ダメージ制ではなく当たり判定制のゲームにしてみます。
まず、「敵スプライト」の以下の部分を削除します。
if (_y > 320){
_root.damage += 20;
_root.dmChar.gotoAndPlay("movieStart");
this.removeMovieClip();
}
上記の部分は、敵が画面の最下に来たときにダメージが +20 される処理です。
次に、以下の処理を上記の処理があった部分に記述します。
if (this.hitTest(_root.myChar)) {
_root.damage = 100;
_root.dmChar.gotoAndPlay("movieStart");
this.removeMovieClip();
}
if (_y > 320){
this.removeMovieClip();
}
これで、敵と自機が接触したところでダメージが +100 され、ゲームオーバーになります。
ちなみに、壁などの画像を作成してスプライトに入れて上記の処理を書き込むと、障害物を作成することができます。
当然、その壁に当たってもゲームオーバーになります。
当たり判定シューティングゲームサンプルソースのダウンロード
*これはCoaさんのサイトで配布されているParaFla! Shooting Gameの pfl を一部編集したものです。
自機を左右だけでなく上下にも移動したい場合は、
if(_y < 300){_y += Key.isDown(Key.DOWN) * 6;}
if(_y > 20){_y -= Key.isDown(Key.UP) * 6;}
という処理を「自機スプライト」の『onClipEvent(enterFrame){}』内に記述します。
すると、画面内で自機が上下左右に移動できるようになります。
また、縦スクロールシューティングゲームではなく横スクロールシューティングゲームにしたい場合は、以下を参照してください。
横シューティングゲームサンプルソースのダウンロード
さらに、ボスとエンディングを追加したものを作成しました。
敵を20体以上倒すと青い物体が現れるので、それを破壊するとエンディングに移行します。
シューティングゲームエンディングサンプルソースのダウンロード
サンプルシューティングゲームの解説はここまでです。
後は画像を変えたり ActionScript を改造したりして、自由にゲームを作ってみてください。
■ 補足
このサンプルの中ではいろいろなメソッドが使用されていますが、いくつかの点について補足してみます。
まず、「自機のスプライト」のスクリプトでは自機を移動させるための処理に、
if(_x < 300){_x += Key.isDown(Key.RIGHT) * 6;}
という部分があります。
「Key.isDown()」は指定したキーが押されていれば 1 、押されていなければ 0 を返すので、
押されていた場合 1 * 6 = 6 ピクセル横に移動し、押されていない場合は 0 * 6 = 0 で移動しないことになります。
このようにメソッドの返り値で計算をして移動距離を決めるほかに、以下のようにしても同じ処理が行えます。
if(_x < 300 && Key.isDown(Key.RIGHT)){_x += 6;}
こちらは、キーが押されているか押されていないかを調べて、押されていた場合 6 ピクセル横に移動するという処理です。
どちらにしても最終的な結果は同じですが、処理を実現するための方法はいくつもあるということを知っておきましょう。
次に、上記メインルーチンのスクリプト17行目では「int()」関数が使われています。これは数値を四捨五入する関数なのですが、この関数は旧バージョン(SWF4)で使われているもので現在では使用が勧められていません。(Adobe によるといつ使用できなくなってもおかしくない状態だそうです。)
この代わりに、同じく数値を四捨五入する「Math.round()」メソッドを使用するようにしましょう。
他には、文字列をターゲットに変換する「eval()」関数があります。
この関数は非常に便利で、このサンプルシューティングゲーム内でも多く使われていますが、eval 関数はものすごく大量に使用すると処理が遅くなる?らしいです。
同じ処理をする方法は他に以下のようなものもあります。
eval("hen" + "suu") = 10; // eval 関数を用いる方法
this["hen" + "suu"] = 10; // カッコで記述する方法
■ その他
このサンプルシューティングゲームにはバグがあります。
まず、「敵のスプライト」で、自機の弾と当たっているかどうか調べている部分を見てみます。
〜
for (i=1; i<10; i++){ //iを1〜10まで変化させて繰り返す
if (this.hitTest(eval("_root.shChar" + i))){ //自機の出す弾に当たったら
eval("_root.shChar" + i).removeMovieClip(); //弾を消去する。
_root.bmNum ++;
if (_root.bmNum > 50){_root.bmNum = 1;}
//ここから爆風を表示する処理--------------------------
bc = "bmChar" + _root.bmNum;
_root.attachMovie("MC_Bomb", bc, 1050 + _root.bmNum);
eval("_root." + bc)._x = _x;
eval("_root." + bc)._y = _y;
//ここまで--------------------------------------------
_root.score += 10; //スコアを +10 する
this.removeMovieClip(); //自分を消去する
}
}
〜
for 文より、以下のスプライト(弾のスプライト)と当たり判定を調べています。
_root.shChar1
_root.shChar2
_root.shChar3
_root.shChar4
_root.shChar5
_root.shChar6
_root.shChar7
_root.shChar8
_root.shChar9
次に、「自機のスプライト」で、自機の弾を発射させる部分を見てみます。
〜
if (Key.isDown(90)){ //キーコード90(Z)のキーを押したら
if(shKeydown == 0){ //shKeydownが0だったら
shNum ++; //shNumに1を足す
if (shNum > 10) shNum = 1; //shNumが10までいったら1に戻す
eval("_root.shChar" + shNum).removeMovieclip();
//↓で作ろうとしているスプライトが既に存在していたら消去する
duplicateMovieClip("_root.shChar", "shChar" + shNum, shNum + 980);
//duplicateMovieClipはスプライトを複製するActionScript。
//ここでスプライトをコピーしている。
}
shKeydown = 1; //shKeydownを1にする
}else{shKeydown = 0;} //それ以外なら(shKeydownが1だったら)0にする
〜
shNum の値を変化させることで、弾として以下のスプライトを作成しています。
_root.shChar1
_root.shChar2
_root.shChar3
_root.shChar4
_root.shChar5
_root.shChar6
_root.shChar7
_root.shChar8
_root.shChar9
_root.shChar10
この2種類を比較すると、「shChar1 〜 shChar10」を作成しているのに、当たり判定の比較は「shChar1 〜 shChar9」までしか行っていません。
このままだと shChar10 が発射されたとき、この弾には敵との当たり判定がないことになります。
これを修正するためには、上記「敵のスプライト」の部分の1行目にある for 文の条件を以下のようにします。
for (i=1; i<10; i++){
↓
for (i=1; i<=10; i++){
これで、正しく当たり判定の比較が行われます。