ポンクソフト

忍者アクション - Flash(ActionScript)で様々なゲームを作ろう

前ページ Flash(ActionScript)で様々なゲームを作ろう TOP 次ページ

目次

  1. Flash(ActionScript)で様々なゲームを作ろう
  2. イライラ棒もどき
  3. 忍者アクション
  4. ブロック崩し
  5. リアルタイム・オセロ
  6. パットゴルフ

実行画面

マウスで忍者を動かして、手裏剣を刀で跳ね返すと得点が入り、手裏剣が忍者に当たるとゲームオーバーです。だんだん手裏剣の数が多くなって難しくなります。ちなみに私の最高得点は 3870 点です。
主人公が全く忍者に見えないのは気にしないでください。アメリカ忍者です。

.fla ファイルダウンロード

今回のポイント

画面作成

まずステージ・ステージに乗せるシンボルなどを作ってゆきます。

ステージのプロパティ

最初にステージのプロパティを適当に設定します。この解説で使っているムービーでは、サイズを「320×320」、背景色を「#999999」、フレームレートを「30fps」としています。

主人公キャラクタの作成

次に主人公キャラクタのムービークリップを作成します。主人公の中央に中心点が来るようにし、回転処理を簡略化するために右向きで作成してください。また、後述しますが当たり判定を点でする関係上、あまり大きいキャラクタにはしない方が良いでしょう。
ninja_jiki.gif
完成したらシンボルに変換して適当な名前でムービークリップにし、ステージ上のインスタンスに「jiki_mc」と名前を付けます。

次に主人公が振る刀のムービークリップを作成します。主人公に追従するように子インスタンスとして作成したいので、主人公のムービークリップを作成している画面のまま、新規レイヤーなどを作って作成してください。画面左上に現在編集中のムービークリップの階層が表示されるので確認してください。
↓主人公キャラクタのシンボルを「Jiki」とした場合
ninja_kaisou_jiki.gif
主人公の上部に上向きに作成し、中央点を主人公の中央点と重なるように作成してください。以下の図のような位置関係です。
ninja_jiki_sword.gif ninja_jiki_sword2.gif
完成したらシンボルに変換して適当な名前でムービークリップにし、インスタンスに「sword_mc」と名前を付けます。

得点テキストの作成

次に得点が入るテキストを作成します。シーンのムービークリップに戻り、左上あたりにテキストツールで「0」と書きます。
ninja_score.gif
プロパティで「ダイナミックテキスト」にし、「選択可能」のチェック(下図の赤色で囲った部分)を外し、「変数」の項目に「score」と記述します。
ninja_score_property.gif

弾の作成

次に弾(手裏剣)のムービークリップを作成します。弾は動的に作成するため、メニューの「挿入」→「新規シンボル」から「ムービークリップ」を選び作成してください。ステージ上で描いてシンボルに変換してインスタンスを削除する、という方法でも構いません。
ninja_tama.gif
完成したら、ライブラリウインドウの弾シンボルを右クリックし「リンケージ」を選び、「リンケージプロパティ」のウインドウで「ActionScriptに書き出し」にチェックを入れ、「識別子」の欄に「Tama」と書きます。
ninja_tama_linkage.gif
ActionScript からは、シンボルにシンボル名でアクセスすることはできず、このリンケージの識別子を使う必要があります。

ゲームオーバー画面の作成

次に2フレーム目にゲームオーバー画面を描きます。2フレーム目にキーフレームを挿入し、主人公キャラクタと刀を削除し(得点テキストは削除しない)、下図のように適当にゲームオーバー画面を描き、リプレイ用のボタンシンボルを作ります。
ninja_gameover.gif

手裏剣を跳ね返す効果音を追加

さらにゲームらしくするために、手裏剣を跳ね返したときの効果音を追加します。フリー素材や自作するなどして効果音を用意してください。wav ファイルでも mp3 ファイルでも構いません。用意ができたら、メニューの「ファイル」→「読み込み」→「ライブラリに読み込み」を選び、ファイルを選びます。ライブラリウインドウにサウンドが表示されたら右クリックから「リンケージ」を選び、「ActionScriptに書き出し」にチェックを入れ、「識別子」の欄に「se_sword」と書きます。

ActionScript の記述

続いて、フレームやムービークリップに ActionScript を記述して行きます。

1フレーム目のアクション

1フレーム目をクリックして、以下のアクションを記述します。
stop();
ゲームオーバー画面に移行しないようにストップするためです。

主人公インスタンスのアクション

主人公インスタンスをクリックして以下のアクションを記述します。
onClipEvent(load) {
  tno = 0;        // 弾の番号
  tint = 30;        // 弾の出現間隔
  tcnt = 0;        // 弾の出現間隔カウンタ
  _root.score = 0;
  sword_mc._visible = false;
  se = new Sound();
  se.attachSound("se_sword");
}

onClipEvent(enterFrame) {
  vx = (_root._xmouse - _x) / 4;
  vy = (_root._ymouse - _y) / 4;
  _x += vx;
  _y += vy;
  if (Math.abs(vx) > 1 || Math.abs(vy) > 1) {
    _rotation = Math.atan2(vy, vx) * 180 / Math.PI;
  }
  if (sword_mc._visible) {
    sword_mc._rotation += 20;
    if (sword_mc._rotation == 180) {
      sword_mc._rotation = 0
      sword_mc._visible = false;
    }
  }
  // 弾の処理
  if (++tcnt > tint) {
    tmc = _root.attachMovie("Tama", "tama" + tno, tno);
    tmc.speed = 6;
    tmc.hit_flag = false;
    tamaPos(tmc);
    tmc.onEnterFrame = tamaEvent;
    if (++tno > 1000) tno = 0;
    tcnt = 0;
  }
  tint -= 0.01;

  // 弾の初期座標・角度設定
  function tamaPos(tmc) {
    switch (Math.floor(Math.random() * 4)) {
    case 0:  // 右から登場
      tmc._x = Stage.width;
      tmc._y = Math.random() * Stage.height;
      tmc.deg = Math.random() * 90 + 135;
      break;
    case 1:  // 下から登場
      tmc._x = Math.random() * Stage.width;
      tmc._y = Stage.height;
      tmc.deg = Math.random() * 90 + 225;
      break;
    case 2:  // 左から登場
      tmc._x = 0;
      tmc._y = Math.random() * Stage.height;
      tmc.deg = Math.random() * 90 + 315;
      break;
    case 3:  // 上から登場
      tmc._x = Math.random() * Stage.width;
      tmc._y = 0;
      tmc.deg = Math.random() * 90 + 45;
      break;
    }
  }

  // 弾のイベントハンドラメソッド
  function tamaEvent() {
    // 移動
    this._rotation += 30;
    this._x += this.speed * Math.cos(Math.PI/180 * this.deg);
    this._y += this.speed * Math.sin(Math.PI/180 * this.deg);
    if (!this.hit_flag) {
      // 刀との当たり判定
      if (sword_mc._visible && this.hitTest(sword_mc)) {
        this.deg = _rotation;
        this.speed = 20;
        this.hit_flag = true;
        _root.score += 10;
        se.start();
      // 自機との当たり判定
      } else if (this.hitTest(_x, _y, false)) {
        _root.gotoAndStop(2);
      }
    }
    // 画面外に消えるか、ゲームオーバーに移行していたら弾を削除
    if (this._x < 0 || this._x > Stage.width ||
      this._y < 0 || this._y > Stage.height ||
      _root._currentframe == 2) {
      this.removeMovieClip();
    }
  }
}

onClipEvent(mouseDown) {
  sword_mc._visible = true;
}
ここにゲーム中の処理が全て記述してあります。解説は後述します。

ゲームクリアボタンのアクション

ゲームオーバー画面のリプレイボタンをクリックして以下のアクションを記述します。
on(release) {
  gotoAndPlay(1);
}
クリックされたらゲーム画面に戻ります。

実行

以上が完成したら保存してゲームを実行してみてください。

ゲーム処理の解説

ゲーム中の ActionScript の解説をします。

初期設定

onClipEvent(load) {
初期設定部分です。以下に内容の解説をします。
  tno = 0;        // 弾の番号
  tint = 30;        // 弾の出現間隔
  tcnt = 0;        // 弾の出現間隔カウンタ
弾は複数発射されるので、tno で弾に番号を付けます。tint はひとつ弾が発射されてから、次に弾が発射されるまでの時間間隔(フレーム数)です。tcnt はその出現間隔をカウントするためのカウンタです。
_root.score = 0;
得点を0点にクリアします。得点が書いてあるダイナミックテキストはステージ上に直接置かれているので、ステージのムービークリップ (_root) を指定します。
sword_mc._visible = false;
最初は刀を非表示にします。
se = new Sound();
サウンドを鳴らす場合は、まずサウンドオブジェクトを生成する必要があります。
se.attachSound("se_sword");
サウンドオブジェクトに効果音を割り当てています。先ほど効果音の読み込みで指定した識別子を使います。

毎フレームの処理

onClipEvent(enterFrame) {
毎フレームの処理です。以下に内容の解説をします。
  vx = (_root._xmouse - _x) / 4;
  vy = (_root._ymouse - _y) / 4;
vx, vy は主人公の x, y 方向の速度です。マウスの位置と主人公の位置の差によって算出しているので、マウスを早く動かせば速度も速く、マウスをゆっくり動かせば速度も遅くなります。
  _x += vx;
  _y += vy;
主人公の座標に速度を追加します。
  if (Math.abs(vx) > 1 || Math.abs(vy) > 1) {
    _rotation = Math.atan2(vy, vx) * 180 / Math.PI;
  }
この部分は主人公の向きをマウスに向かうように回転している部分です。まず速度が非常に遅い場合は、回転すると見苦しくなってしまうので回転しないようにしています。具体的には x, y いずれかの速度の絶対値が 1 以下なら回転しないようにします。Math.abs は数値の絶対値を返すメソッドです。
そして実際の回転処理ですが、まず座標 (x, y) があったとき、原点からこの座標に向かう角度を t とすると、以下の式が成り立ちます。
tan(t) = x / y
今回はこの角度 t が知りたいのでタンジェントの逆関数アークタンジェントを使います。
atan(x / y) = t
さらにここで算出した角度はラジアンなので、度数に直すために 180 / π をかけています。
  if (sword_mc._visible) {
    sword_mc._rotation += 20;
    if (sword_mc._rotation == 180) {
      sword_mc._rotation = 0
      sword_mc._visible = false;
    }
  }
刀のインスタンスが _visible つまり表示されているときは、刀の回転処理を行います。まず 20 度回転し、180 度つまり半回転したら、回転角度をリセットし、刀を非表示にします。
if (++tcnt > tint) {
この if 文の中は弾の生成処理を行っている部分です。弾の出現間隔カウンタ tcnt をインクリメントし、それが弾の出現間隔 tint を超えたら弾のインスタンス生成処理を行います。
tmc = _root.attachMovie("Tama", "tama" + tno, tno);
attachMovie はシンボルからインスタンスを生成するメソッドです。ここでは _root(ステージ)ムービークリップの子ムービークリップインスタンスとして弾を追加しています。第1引数の "Tama" はシンボルの識別子、第2引数はインスタンス名、第3引数はムービークリップの深度です。それぞれの弾インスタンスについて一意の名前(違う名前)を付けなければならないのでここでは弾の番号 tno を名前に追加しています。深度とはそれぞれのインスタンスを重ね合わせる順番です。戻り値 tmc には、生成されたインスタンスを指し示す値(参照と言います)が入ります。
tmc.speed = 6;
弾インスタンスのスピードを設定しています。
tmc.hit_flag = false;
hit_flag は弾が刀によって跳ね返されたら true になる変数です。
tamaPos(tmc);
弾の初期座標・角度を決める関数を呼んでいます。処理が長いので別関数にしています。
tmc.onEnterFrame = tamaEvent;
弾の毎フレーム処理を tamaEvent という関数に設定しています。onClipEvent(enterFrame) と同じものですが、こちらはインスタンスをクリックせずに別の場所に書くことができる、という利点があります。これをイベントハンドラメソッドと呼びます。
if (++tno > 1000) tno = 0;
弾の番号が大きくなったら 0 にリセットしています。
tcnt = 0;
最後に弾のカウントを 0 にリセットします。
tint -= 0.01;
だんだん弾の出現間隔を短くしています。
function tamaPos(tmc) {
弾の初期座標・角度を計算する関数です。
switch (Math.floor(Math.random() * 4)) {
上下左右の全方向から出したいので、まず乱数によって 0 ~ 3 の値を出し、0:画面右 1:画面下 2:画面左 3:画面上 から登場するようにします。
    case 0:
      tmc._x = Stage.width;
      tmc._y = Math.random() * Stage.height;
      tmc.deg = Math.random() * 90 + 135;
      break;
右から登場する場合は、まず弾の x 座標を画面右端にし、y 座標を画面上下のランダムな位置にし、弾の移動する角度を 135 度 ~ 225 度の範囲でランダムにします。
下・左・上の各処理も同じことを行っています。
function tamaEvent() {
弾の毎フレームの処理を行うイベントハンドラメソッドです。
this._rotation += 30;
弾は手裏剣なので高速に回転させます。this とはこのメソッドが属しているオブジェクト、つまり弾インスタンスのことです。この this を省略すると現在のムービークリップ、つまり主人公に対する処理になってしまうので省略することはできません。
    this._x += this.speed * Math.cos(Math.PI/180 * this.deg);
    this._y += this.speed * Math.sin(Math.PI/180 * this.deg);
弾の移動処理です。角度のコサインによって x 座標、サインによって y 座標を算出しています。
if (!this.hit_flag) {
刀によって跳ね返っていない場合、以下の当たり判定処理を行います。
if (sword_mc._visible && this.hitTest(sword_mc)) {
まず弾と刀との当たり判定を行います。刀が表示されていて、なおかつ hitTest メソッドによって弾と刀の領域が重なっていたら当たっているとみなし、以下の処理を行います。
this.deg = _rotation;
弾の角度を主人公の角度と同じにします。つまり主人公の向いている方へ飛んで行くことで跳ね返っているように見せているのです。
        this.speed = 20;
        this.hit_flag = true;
        _root.score += 10;
跳ね返っていくときはスピードを上げて、跳ね返りフラグをセットし、得点を追加します。
se.start();
start はサウンドオブジェクトのサウンドを演奏するメソッドです。
      } else if (this.hitTest(_x, _y, false)) {
        _root.gotoAndStop(2);
      }
次に弾と主人公との当たり判定を行いますが、当たり判定の領域を狭くするために主人公の中心座標にのみ、当たり判定を行っています。弾と主人公が当たったらゲームオーバー画面にジャンプします。
    if (this._x < 0 || this._x > Stage.width ||
      this._y < 0 || this._y > Stage.height ||
      _root._currentframe == 2) {
      this.removeMovieClip();
    }
弾が画面外に消えるか、現在ゲームオーバー画面(2フレーム目)ならば弾を削除します。_currentframe はムービークリップの現在再生しているフレームが入っているプロパティです。mc.removeMovieClip によってムービークリップ mc を削除します。今の場合は this つまり弾インスタンスを削除しています。
onClipEvent(mouseDown) {
  sword_mc._visible = true;
}
マウスが押されたときは刀のインスタンスを表示して刀を振る処理を実行できるようにしています。
前ページ Flash(ActionScript)で様々なゲームを作ろう TOP 次ページ
このエントリーをはてなブックマークに追加 そっか0