第12回 Waveを5個にする、スコアの実装
現状ではWaveが1つしかありません。これを5つまで増やし、更にスコアを実装します。
Waveをさらに4つ増やします。第07回で作成したWaveプレハブを複製したものを改良していきます。Waveのエネミーの配置は同じにしなくても問題ありません。例として4つのWaveを紹介します。
弾を打たない、HPが4の大量のエネミー
弾を撃つ、HP10のエネミー
左右から登場する弾を撃つ、HP10のエネミー
大きさが3倍で、弾を一度に大量に撃つ、HP100のエネミー
作成できたらEmitterゲームオブジェクトをクリックし、インスペクターのWavesへドラッグ&ドロップしてWaveを追加します。
ゲームを再生してみましょう。Wave → Wave 2 → Wave 3 → Wave 4 → Wave 5 → Wave ... と延々とループしているはずです。 少し難しいと感じたら自分で難易度を調整してみましょう。エネミーのHPや向きや移動スピード、ShotPositionゲームオブジェクトの増減で調整可能です。
動かなかったらこちらを参考に https://windbell.hatenadiary.jp/entry/20150912/p1
最後の要素として「スコア」を実装します。 今回はゲーム中に獲得した現在のスコアと、今までのハイスコアを実装します。
スコアを画面に表示するためにGUITextを配置します。 空のゲームオブジェクトを作成し、名前をScore GUIとしましょう。TransformのPositionは X 0 Y 0 Z 0にしてください。
もう一つ空のゲームオブジェクトを作成し、インスペクターのAdd Componentボタンを押してGUI Textを追加してください。"GUI..."という風に名前を入力してフィルターすることも出来ます。 これで、GUI Textコンポーネントが付いたゲームオブジェクトが作成されます。
同じものをもう1つ作成し、Score GUIの子要素とします。そして、名前をScoreとHighScoreにしましょう。
ScoreとHighScoreの設定を行います。 TransformのPosition、GUITextのText、Anchor、Font、Font Sizeを図12.1と図12.2を見ながら設定しましょう。
図12.1:
図12.2:
正しく設定を行うと図12.3のようにゲームビューの右上と右下に0と表示が行われます。
図12.3:
Score.csをScriptsフォルダ配下に作成してください。
今回、スコアの保存はPlayerPrefs
クラスを使用して保存します。
このクラスはゲームで保存しておきたいデータを保存するためのクラスです。 例えばゲームの進行度やサウンドのボリューム、ハイスコア、ランキング、などはPlayerPrefsでデータを保持することで実現できます。 細かな制限もあるので、詳しくはドキュメントの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.csにポイントを保持する変数を加えましょう。 そして、OnTriggerEnter2Dメソッド内で爆発する時にスコアにポイントを追加する処理を追加します。
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でポイントを調整します。HPが高いほど高得点にしたり、難易度によって得点を変化させてみましょう。
ゲームを再生してみましょう。敵を倒すとスコアにポイントが加算され、ハイスコアを更新すれば右下のハイスコアがリアルタイムで更新されていきます。
最後にゲームオーバーの時にハイスコアを保存するようにします。 Manager.csのGameOverメソッドに追記します。
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;
}
}
お疲れ様でした。ゲーム制作編は以上で終了となります。
今回はここで終了です。つまずいてしまった方はプロジェクトファイルをダウンロードして新たな気持ちで次の回へ進みましょう。
第01回 スプライトとスプライトアニメーションの作成
第02回 プレイヤーの移動
第03回 プレイヤーから弾を撃つ
第04回 敵を作成しよう
第05回 当たり判定とアニメーションイベントとレイヤー
第06回 背景を作る
第07回 Wave型の仕組み作り
第08回 音をつける
第09回 プレイヤーの移動制限と様々な修正
第10回 タイトルを付ける
第11回 エネミーのHP、弾の攻撃力、アニメーションの追加
第12回 Waveを5個にする、スコアの実装
第01回 複数の解像度に対応する(黒帯を追加する)
第02回 複数の解像度に対応する(引き伸ばす)
第03回 タッチパネル対応
第04回 バーチャルジョイスティック対応