Categories: Unity

Unity:敵機のフォーメーションとスコアの実装~公式チュートリアル 2Dシューティングに挑戦

Unity公式サイトに掲載されているチュートリアルの2Dシューティングに挑戦。今回は敵機のフォーメーションとスコア実装のステップを行いました。チュートリアルを進めながら変更した箇所などをピックアップしています。

前回の記事はこちら
Unity:敵機のHPと弾の攻撃力とアニメーション~公式チュートリアル 2Dシューティングに挑戦

Waveを5個にする、スコアの実装

チュートリアルページ:Waveを5個にする、スコアの実装
このステップの手順は次の通りです。

  1. Waveの作成
  2. スコアの実装

敵機の種類を増やす

このチュートリアルの手順で作成する Wave のために敵機の種類を増やしました。

元のスプライト素材を改造して緑色と紫色の敵機を追加。

Sprite Editor で追加した敵機のスプライトを作成します。

チュートリアルの スプライトとスプライトアニメーションの作成 の手順を参考にアニメーションファイルを作成します。ファイル名はそれぞれ Normal_B、Normal_C に設定。同時に作成されたアニメーターファイルは使用しないので削除。

アニメーターファイル Enemy を複製して新しく作成した敵機に使用します。敵機の2種類作成したので2つ複製します。
[Product]ウィンドウ > Animations > Enemy > Enemy を選択。複製して名前を Enemy_B とEnemy_C に変更。

複製したアニメーターファイルのステートを修正します。
[Product]ウィンドウ > Animations > Enemy > Enemy_Bダブルクリックして [Animator]ウィンドウを開きます。 [Normal]ステートを選択して[Inspector]ウィンドウ > Motion フィールドに新しい敵機のアニメーションファイル Normal_B を割り当てます。

同じ手順でアニメータファイル Normal_C のステートも修正します。

プレハブ Enemy を複製して新しい敵機のプレハブを作成します。
プレハブ Enemy を[Hierarchy]ウィンドウに配置して複製。 名前を Enemy B に変更。[Inspector]ウィンドウ > Sprite Render > Sprite フィールドのスプライトを Spaceship_12(新しく追加した敵機のスプライト)に変更します。

[Inspector]ウィンドウ > Animator> Controller フィールドのアニメーターファイルを Enemy_B に変更します。

最後にオブジェクトを[Project]ウィンドウにドラッグ&ドロップでプレハブに変換して完了です。

同じ手順でプレハブ Enemy_C も作成。敵機のプレハブが3種類に増えました。

Waveの作成

先に追加した敵機のプレハブを組み合わせてこのような Wave を作成しました。

スコアの表示

チュートリアルでは GUIText コンポーネントを使用していますが、ここでは UIオブジェクトを使用します。
[Hierarchy]ウィンドウ > [Create]ボタン > UI > Text を選択。名前を Text Score に変更。

[Inspector]ウィンドウ > Rect Transform の設定はこのようにしました。

Text (Script)コンポーネントの設定はこのようにしました。文字整列の Paragraph > Alignment は右上寄せにしました。

ハイスコアのテキストは Text Score を複製(Ctrl キー+ D キー)して名前をText HighScore に変更します。

[Inspector]ウィンドウ > Rect Transform の設定はこのようにゲーム画面左上に配置しました。

Text (Script)コンポーネントの設定はこのようにしました。

[Scene]ビューで見るとこのようになっています。

スクリプトの作成

スクリプトのコードは GUIText コンポーネントを使用しないので UnityEngine.UI の使用を宣言して変数の型を Text に変更しています。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
// UI処理のクラスを使用する宣言
using UnityEngine.UI;

public class Score : MonoBehaviour
{
    // スコアを格納する Text コンポーネント
    public Text scoreGUIText;
    // ハイスコアを格納する Text コンポーネント 
    public Text highScoreGUIText;
    // スコアを格納する変数
    private int score;
    // ハイスコアを格納する変数
    private int highScore;
    // PlayerPrefs で保存するためのキー highScore を設定
    private string highScoreKey = "highScore";

    //ゲーム開始時の処理
    void Start()
    {
        // ゲームのリセット処理
        Initialize();
    }

    // ゲーム実行中の繰り返し処理
    void Update()
    {
        // スコアがハイスコアより大きければ
        if (highScore 

作成したスクリプト はオブジェクト Manager に割り当てました。

エネミーにポイントを持たせる

スクリプト Enemy の内容にコメントを加えたものがこちら。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Enemy : MonoBehaviour
{
    // スクリプト Spaceship コンポーネントを格納する変数
    Spaceship spaceship;
    // ヒットポイントを格納する変数(初期値 1)
    public int hp = 1;
    // スコアポイントを格納する変数(初期値 100)
    public int point = 100;

    // ゲームのスタート時の処理
    void Start()
    {
        // Spaceship コンポーネントを取得
        spaceship = GetComponent<Spaceship>();
        // ローカル座標のY軸のマイナス方向(画面上から下)に移動する
        spaceship.Move(transform.up * -1);
        // 弾の発射処理(コルーチン Shot )を実行
        StartCoroutine("Shot");
    }

    // トリガーに入った時の処理
    // 衝突した相手の Collider2D コンポーネントを引数 c に格納
    void OnTriggerEnter2D(Collider2D c)
    {
        // レイヤー名を取得して layerName に格納
        string layerName = LayerMask.LayerToName(c.gameObject.layer);
        // レイヤー名がBullet (Player)以外の時は何も行わない
        if (layerName != "Bullet (Player)") return;
        // 弾オブジェクトの Transform コンポーネントの取得
        // 衝突した相手の Collider2D コンポーネントの親(オブジェクト)の
        // Transform コンポーネントを取得して playerBulletTransform に格納
        Transform playerBulletTransform = c.transform.parent;
        // スクリプト Bullet コンポーネントを取得して bullet に格納
        Bullet bullet = playerBulletTransform.GetComponent<Bullet>();
        // ヒットポイントを減らす
        // 変数 hp からスクリプト Bullet の変数 power を引いた結果を hp に渡す
        hp = hp - bullet.power;
        // 弾の削除
        Destroy(c.gameObject);
        // ヒットポイントが0以下であれば
        if (hp <= 0)
        {
            // スコアポイントの追加
            // スクリプト Score コンポーネントを取得して
            // AddPoint () 関数を引数 point 値を指定して実行
            FindObjectOfType<Score>().AddPoint(point);
            // 爆発処理
            // スクリプト Spaceship の関数 Explosion() を実行
            spaceship.Explosion();
            // 敵機の削除
            Destroy(gameObject);
        }
        //上記以外の場合
        else
        {
            // アニメーションステートの遷移
            // スクリプト Spaceship の関数 GetAnimator() を実行し
            //Animator コンポーネント のトリガー Damage をセット
            spaceship.GetAnimator().SetTrigger("Damage");
        }
    }

    // 弾の発射処理(コルーチン)
    IEnumerator Shot()
    {
        // canShotがfalseの場合、ここでコルーチンを終了させる
        if (spaceship.canShot == false)
        {
            // 処理の停止
            yield break;
        }
        // 繰り返し処理
        while (true)
        {
            // 子要素(弾の発射位置のオブジェクト)を全て取得する
            for (int i = 0; i < transform.childCount; i++)
            {
                // Transform コンポーネント shotPosition を作成して子要素を格納
                Transform shotPosition = transform.GetChild(i);
                // 弾をプレイヤーと同じ位置/角度で作成
                // スクリプト Spaceship の関数Shot() を実行
                spaceship.Shot(shotPosition);
            }
            // スクリプト Spaceship の 変数 shotDelayの値の時間処理を中断
            yield return new WaitForSeconds(spaceship.shotDelay);
        }
    }
}

ハイスコアの保存

スクリプト Manager の内容にコメントを加えました。ここではチュートリアルと異なりコルーチン IEnumerator ShowGameOver() の処理でハイスコアの保存を行っています。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Manager : MonoBehaviour
{
    // 自機を格納する変数
    public GameObject player;
    // テキストオブジェクトを格納する変数
    public GameObject textTitle;
    // ゲームオーバーテキストオブジェクトを格納する変数
    public GameObject textGameOver;

    // ゲームのスタート時の処理
    void Start()
    {
        textGameOver.SetActive(false);
    }

    // ゲーム実行中の繰り返し処理
    void Update()
    {
        // ゲーム中ではなく、さらにXキーが押されたらtrueを返す。
        if (IsPlaying() == false && Input.GetKeyDown(KeyCode.X))
        {
            // ゲーム開始処理を実行
            GameStart();
        }
    }

    // ゲーム開始処理
    void GameStart()
    {
        // タイトルオブジェクトを非表示にする
        textTitle.SetActive(false);
        // 自機を生成する
        Instantiate(player, player.transform.position, player.transform.rotation);
    }

    // ゲームオーバー時の処理
    public void GameOver()
    {
        // テキストオブジェクト表示のコルーチンを実行
        StartCoroutine("ShowGameOver");
    }

    // ゲームプレイ中か判定する処理
    public bool IsPlaying()
    {
        // タイトルオブジェクトが非表示であれば true を返す
        return textTitle.activeSelf == false;
    }

    // ゲームオーバー時にテキストオブジェクトを表示する処理(コルーチン)
    private IEnumerator ShowGameOver()
    {
        // ゲームオーバーテキストオブジェクトを表示する
        textGameOver.SetActive(true);
        //3秒後に処理を中断
        yield return new WaitForSeconds(3f);
        // ゲームオーバーテキストオブジェクトを非表示にする
        textGameOver.SetActive(false);
        // タイトルテキストオブジェクトを表示する
        textTitle.SetActive(true);
        // ハイスコアの保存
        // スクリプト Score コンポーネントを取得して Saave() 関数を実行
        FindObjectOfType<Score>().Save();
    }
}

WebGL

ここまでの内容を動作確認用にWebGLでビルドしてみました。チュートリアルではまだモバイル編の手順がありますが、これで一通り完成です。
画像クリックで再生(ファイルサイズ:約7MB)

corevale

View Comments