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

前回の記事はこちら
Unity:敵機のHPと弾の攻撃力とアニメーション~公式チュートリアル 2Dシューティングに挑戦
Waveを5個にする、スコアの実装
チュートリアルページ:Waveを5個にする、スコアの実装
このステップの手順は次の通りです。
- Waveの作成
- スコアの実装
敵機の種類を増やす
このチュートリアルの手順で作成する 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(新しく追加した敵機のスプライト)に変更します。

最後にオブジェクトを[Project]ウィンドウにドラッグ&ドロップでプレハブに変換して完了です。
同じ手順でプレハブ Enemy_C も作成。敵機のプレハブが3種類に増えました。

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

スコアの表示
チュートリアルでは GUIText コンポーネントを使用していますが、ここでは UIオブジェクトを使用します。
[Hierarchy]ウィンドウ > [Create]ボタン > UI > Text を選択。名前を Text Score に変更。
Text (Script)コンポーネントの設定はこのようにしました。文字整列の Paragraph > Alignment は右上寄せにしました。

ハイスコアのテキストは Text Score を複製(Ctrl キー+ D キー)して名前をText HighScore に変更します。
[Inspector]ウィンドウ > Rect Transform の設定はこのようにゲーム画面左上に配置しました。
Text (Script)コンポーネントの設定はこのようにしました。

スクリプトの作成
スクリプトのコードは 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 < score)
{
// ハイスコアの更新(score の値を highScore に渡す )
highScore = score;
}
// score の値を文字列としてスコアテキストコンポーネントのテキスト要素に格納
scoreGUIText.text = "SCORE " + score.ToString();
// highScore の値を文字列としてハイスコアテキストコンポーネントのテキスト要素に格納
highScoreGUIText.text = "HIGHSCORE " + highScore.ToString();
}
// ゲームのリセット処理
private void Initialize()
{
// スコアを0に戻す
score = 0;
// ハイスコアを取得する。保存されてなければ0を取得する。
highScore = PlayerPrefs.GetInt(highScoreKey, 0);
}
// ポイントの追加(引数 point)
public void AddPoint(int point)
{
// スコアの更新(引数 point の値に score を加えて score に渡す)
score = score + point;
}
// ハイスコアの保存処理
public void Save()
{
// ハイスコアを保存する
// キー highScoreKey に highScore の値をセット
PlayerPrefs.SetInt(highScoreKey, highScore);
// 保存処理
PlayerPrefs.Save();
// ゲームのリセット処理を実行
Initialize();
}
}
作成したスクリプト はオブジェクト 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)
コメント
敵機の画像借ります