[Unity] 2Dシューティングゲームを作る 6 [チュートリアル]

株式会社プライムストラクチャーのエンジニアのSayaです。

今回は前回に引き続き、 Unity の公式から 2D のシューティングゲームを作るチュートリアルを参考にしながら簡潔にまとめてみたいと思います。

ゲーム開始時の無敵時間の実装

ゲーム開始時にプレイヤーを点滅させ、無敵となる状態を実装します。
Enemy のダメージアニメーションの実装と同じ方法で実装します。

レイヤーの追加

Assets / Animations / Player から Player アニメーターコントローラーをダブルクリックして Animator ウィンドウを開きます。

Invincible Layer を追加し、Weight を 1 にします。

アニメーションの作成

Player プレハブをシーン上へドラッグ&ドロップします。
Assets / Animations / Player フォルダを選択し右クリックをして、Create -> Animation を選択します。
名前は Invincible とします。

Invincible アニメーションのインスペクタ上で Loop Time にチェックを入れてください。

Invincible Layer に Invincible アニメーションをドラッグ&ドロップし、Invincible ステートを作成します。

Create State -> Empty で Dummy ステートを作成し、Invincible ステートから Dummy ステートへの Transition を作成します。
Transitionの Exit Time3 にします。
これは 3 回 Invincible アニメーションをループさせるという意味です。

次にアニメーションを作成していきます。
Player ゲームオブジェクトを選択した状態で Animation ウィンドウを開き、Normal から Invincible アニメーションに切り替えます。

Add Property ボタンで Sprite Renderer の EnabledBox Collider 2D の Enabled の 2 つを追加します。

0 フレーム目で両方の Enabled のチェックを外し、60 フレーム目 (1:00) でオンになっているようにします。
そして 60 フレーム目の Box Collider 2D のキーを削除します。
そして 60 フレームまで Key が交互にオフ、オン、オフ、オンとなるように配置します。

最後にシーンから Player オブジェクトを削除してゲームを再生してみると、X キーでスタートしたら点滅アニメーションと共に 3 秒間の無敵効果が付与されます。

Wave を増やす

Wave を増やしてゲーム性を作っていきます。
自分で作成してもよいのですが、こちらからダウンロードして配置することもできます。

Prefabs フォルダに Wave を追加出来たらシーンの Emitter を選択して、Emitter のインスペクタ上の Waves に追加した Wave を1つずつドラッグ&ドロップします。
これでゲームを再生すると追加された Waves が順番に流れてきます。

スコアの実装

ゲーム中のスコアとハイスコアが表示されるようにします。

スコアの表示

まず空のゲームオブジェクトを作成し、名前を Score GUI とします。
Position は (0,0,0) にします。

もう一つ空のゲームオブジェクトを作成し、Score と名付けます。
Score GUI の子要素にしたらインスペクターの Add Component ボタンを押して GUI Text を追加します。
もう一つ空のゲームオブジェクトを作成し、HighScore と名付け、Score GUI の子要素にして GUI Text を追加します。
そして各設定を以下のようにします。
* Score
Position : (1, 1, 0)
Text: 0
Anchor : Upper right
Font : SAM_5C_27TRG_
Font Size : 24

  • HighScore
    Position : (1, 0, 0)
    Text: 0
    Anchor : Lower right
    Font : SAM_5C_27TRG_
    Font Size : 24

正しく設定されていれば右上と右下にスコアが 0 と表示されます。

スコアスクリプトの作成

Scripts フォルダに Score.cs を作成します。

ゲームでデータを保存する時に使う PlayerPrefs クラスを使用してスクリプトを作成していきます。

[Score.cs]
using UnityEngine;

public class Score : MonoBehaviour
{
  // スコアを表示するGUIText
  public GUIText scoreGUIText;

  // ハイスコアを表示するGUIText
  public GUIText highScoreGUIText;

  // スコア
  private int score;

  // ハイスコア
  private int highScore;

  // PlayerPrefsで保存するためのキー
  private string highScoreKey = "highScore";

  void Start ()
  {
    Initialize ();
  }

  void Update ()
  {
    // スコアがハイスコアより大きければ
    if (highScore < score) {
      highScore = score;
    }

    // スコア・ハイスコアを表示する
    scoreGUIText.text = score.ToString ();
    highScoreGUIText.text = "HighScore : " + highScore.ToString ();
  }

  // ゲーム開始前の状態に戻す
  private void Initialize ()
  {
    // スコアを0に戻す
    score = 0;

    // ハイスコアを取得する。保存されてなければ0を取得する。
    highScore = PlayerPrefs.GetInt (highScoreKey, 0);
  }

  // ポイントの追加
  public void AddPoint (int point)
  {
    score = score + point;
  }

  // ハイスコアの保存
  public void Save ()
  {
    // ハイスコアを保存する
    PlayerPrefs.SetInt (highScoreKey, highScore);
    PlayerPrefs.Save ();

    // ゲーム開始前の状態に戻す
    Initialize ();
  }
}

作成した Score.cs を Score GUI ゲームオブジェクトにドラッグ&ドロップします。

インスペクターの “Score GUIText” と “High Score GUIText” に Score ゲームオブジェクトと HighScore ゲームオブジェクトをそれぞれドラッグ&ドロップします。

Enemy にポイントを持たせる

Enemy の爆発時にスコアにポイントを追加する処理を追加します。

[Enemy.cs]
using UnityEngine;
using System.Collections;

public class Enemy : MonoBehaviour
{
  // ヒットポイント
  public int hp = 1;

  // スコアのポイント
  public int point = 100;

  // Spaceshipコンポーネント
  Spaceship spaceship;

  IEnumerator Start ()
  {

    // Spaceshipコンポーネントを取得
    spaceship = GetComponent<Spaceship> ();

    // ローカル座標のY軸のマイナス方向に移動する
    Move (transform.up * -1);

    // canShotがfalseの場合、ここでコルーチンを終了させる
    if (spaceship.canShot == false) {
      yield break;
    }

    while (true) {

      // 子要素を全て取得する
      for (int i = 0; i < transform.childCount; i++) {

        Transform shotPosition = transform.GetChild (i);

        // ShotPositionの位置/角度で弾を撃つ
        spaceship.Shot (shotPosition);
      }

      // shotDelay秒待つ
      yield return new WaitForSeconds (spaceship.shotDelay);
    }
  }

  // 機体の移動
  public void Move (Vector2 direction)
  {
    GetComponent<Rigidbody2D>().velocity = direction * spaceship.speed;
  }

  void OnTriggerEnter2D (Collider2D c)
  {
    // レイヤー名を取得
    string layerName = LayerMask.LayerToName (c.gameObject.layer);

    // レイヤー名がBullet (Player)以外の時は何も行わない
    if (layerName != "Bullet (Player)") return;

    // PlayerBulletのTransformを取得
    Transform playerBulletTransform = c.transform.parent;

    // Bulletコンポーネントを取得
    Bullet bullet = playerBulletTransform.GetComponent<Bullet>();

    // ヒットポイントを減らす
    hp = hp - bullet.power;

    // 弾の削除
    Destroy(c.gameObject);

    // ヒットポイントが0以下であれば
    if(hp <= 0 )
    {
      // スコアコンポーネントを取得してポイントを追加
      FindObjectOfType<Score>().AddPoint(point);

      // 爆発
      spaceship.Explosion ();

      // エネミーの削除
      Destroy (gameObject);

    }else{

      spaceship.GetAnimator().SetTrigger("Damage");

    }
  }
}

Wave プレハブにある Enemy の Point 変数を変更することでポイントを調整出来ます。

ハイスコアの保存

Manager.cs のゲームオーバー時の処理部分に追加します。

[Manager.cs]
using UnityEngine;

public class Manager : MonoBehaviour
{
  // Playerプレハブ
  public GameObject player;

  // タイトル
  private GameObject title;

  void Start ()
  {
    // Titleゲームオブジェクトを検索し取得する
    title = GameObject.Find ("Title");
  }

  void Update ()
  {
    // ゲーム中ではなく、Xキーが押されたらtrueを返す。
    if (IsPlaying () == false && Input.GetKeyDown (KeyCode.X)) {
      GameStart ();
    }
  }

  void GameStart ()
  {
    // ゲームスタート時に、タイトルを非表示にしてプレイヤーを作成する
    title.SetActive (false);
    Instantiate (player, player.transform.position, player.transform.rotation);
  }

  public void GameOver ()
  {
    // ハイスコアの保存
    FindObjectOfType<Score>().Save();

    // ゲームオーバー時に、タイトルを表示する
    title.SetActive (true);
  }

  public bool IsPlaying ()
  {
    // ゲーム中かどうかはタイトルの表示/非表示で判断する
    return title.activeSelf == false;
  }
}

まとめ

今回は 2D シューティングゲームの作成の流れを Unity 公式チュートリアルを用いながらまとめていきました。

このチュートリアルを行うことでプレハブの作り方やテクスチャの編集方法、ゲームの処理に用いるメソッドやアニメーションなど 2D ゲーム制作に必要な技術を一通り試していく事が出来ました。

各操作をより詳しく確認したい方は Unity の公式プリファレンスを参照して頂くと理解しやすくなると思います。

参考文献

2Dシューティング – Unity
エネミーのHP、弾の攻撃力、アニメーションの追加 – Unity
Waveを5個にする、スコアの実装 – Unity