コミュ障だから明日が僕らをよんだって返事もろくにしなかった

何かを創る人に憧れたからブログをはじめたんだと思うよ

Unityで2Dシューティングつくったよの巻 ~後編 Part 2

Unityで2Dシューティングをつくろう

2Dとは言わずもがな二次元のことである。すなわち二次元のシューティングということである。ここで言うシューティングは、現実社会すなわち三次元に対しての鬱屈した感情・暴力性のはけ口のことを指す。人は誰しも高位の次元に対し尊敬の念を抱き、低位の次元に対しては憎悪の念を抱くものである。つまりは……。



えぇ……、ちょっと何を言っているのかわかりませんね。そして、この導入何度目ですかね……。じゃあやっていきます。

つくりゅ

それじゃあそろそろ、終わりに向けてやっていきましょう。
2Dシューティング - Unity

前回記事
inujini.hatenablog.com

前回はなんか色々やりました(雑)。なので今回はパラメータなどを調整していきます。まずは敵のHPとか攻撃力とかそういったやつを宣言して実装していきます。
HP処理:Enemy.cs_修正

public class Enemy : MonoBehaviour
{
    // ヒットポイント
    public int hp = 1;
    ~ 略 ~
    void OnTriggerEnter2D(Collider2D c)
    {
    ~ 略 ~
        // PlayerBulletのTransformを取得
        Transform playerBulletTransform = c.transform.parent;
        // Bulletコンポーネントを取得
        Bullet bullet = playerBulletTransform.GetComponent<Bullet>();
        // ヒットポイントを減らす
        hp = hp - bullet.power;       

        // ヒットポイントが0以下であれば
        if (hp <= 0)
        {
            // 爆発
            spaceship.Explosion();
            // エネミーの削除
            Destroy(gameObject);
        }
    }
}

弾の攻撃力:Bullet.cs_修正

public class Bullet : MonoBehaviour {
    // 攻撃力
    public int power = 1;
    ~ 略 ~
}

新しめのUnityだと元のコード、GetComponent使うときは明示的に宣言しろって怒られる。何入れるかわかんないけど、適当に入れて動かしていきましょう。ヒントはBulletコンポーネントなんだと思う。

これを動かすとこうです。とりあえずHP256にしてみた(バキュラかな…?)。

f:id:andron:20180713075115g:plain
めちゃ硬い。破壊できない……。


とりあえずできたのが確認できたので、ダメージアニメーションをつくっていきます。まずはAnimatorを開いてこれを作ります。ここの箇所はスクリプトのこととか考えず、わりと直感的に動かせていい感じです。Dummyを使って何もしない状態を管理していくってのは勉強になりました。
f:id:andron:20180713075159p:plain

んで、できたのでダメージ受けたときにアニメを呼び出す処理を書いていきます。
使いまわし Spaceship.cs_追記

public class Spaceship : MonoBehaviour
{
  // アニメーターコンポーネント
  private Animator animator;

  void Start ()
  {
    // アニメーターコンポーネントを取得
    animator = GetComponent<Animator> ();
  }
  // アニメーターコンポーネントの取得
  public Animator GetAnimator()
  {
    return animator;
  }
}

Enemy.cs_追記

public class Enemy : MonoBehaviour
{
  void OnTriggerEnter2D (Collider2D c)
  {
        if (hp <= 0)
        { ~略~ }
        else {
            spaceship.GetAnimator().SetTrigger("Damage");
        }
  }
}

作ったアニメーションをスクリプトのほうで呼び出してこうなるそうです。
f:id:andron:20180713075223g:plain

どうでもいいことですが、うっかりベースレイヤーを削除してしまい、このアニメーションにするのに偉い時間かかってしまった。バックアップ大事。ソース以外のところでつまづくというね……。

んで、アニメーションのやり方わかったのでついでに自機の無敵時間も追加していきます。無敵の判定処理って色々あるだろうけど、今回は敵との接触判定をなくすことで無敵にします。

f:id:andron:20180713075331g:plain
アニメーションの方で接触についての処理(Box Collider 2D)を書けちゃうせいでスクリプト全然書かない。すごい。


んじゃ、次はスコアを実装していきます。まずはスコアの文字を置きーの、スクリプトを書きーのとやっていきます。とりあえず適当に文字を配置していきます。GUITextが最新だと非推奨ってことなんで、UI使っていきます。前回オリチャー発動した時は、テキスト表示だけだったから特にスクリプトに影響することなかったけど今回はスコア何でバリバリコード書きますね。まあ何とかなるでしょう。
f:id:andron:20180713075434p:plain

置いたので、コード書きまーす。
Score.cs

using UnityEngine;
using UnityEngine.UI; // 追記
public class Score : MonoBehaviour
{
  // スコアを表示するGUIText -> UI
  //public GUIText scoreGUIText;
  public UI scoreGUIText;
 
  // ハイスコアを表示するGUIText -> UI
  //public GUIText highScoreGUIText;
  public Text scoreGUIText;

  // スコア
  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 ();
  }
}

書き換えはこんな感じでしょうか。まあ、また動かなくなったら確認しましょう。このままだと敵を倒した時のスコアが全然追加されないのでそっちの処理も書いていきます。セーブ&ロードはPlayerPrefsってのを使えばいいそうですね。
Unity - スクリプティング API: PlayerPrefs


スコア追加などの処理
Enemy.cs_追記

public class Enemy : MonoBehaviour
{
    // スコアのポイント
    public int point = 100;
    void OnTriggerEnter2D(Collider2D c)
    {
       if (hp <= 0)
        {
            // スコアコンポーネントを取得してポイントを追加
            FindObjectOfType<Score>().AddPoint(point);
         
        }else{ ~略~ }
       }
    }
}

Manager.cs_追記

public class Manager : MonoBehaviour
{
  public void GameOver ()
  {
    // ハイスコアの保存
    FindObjectOfType<Score>().Save();
    ~ 略 ~
  }
}

これでスコアとか、良い感じにやってくれるそうですよ(左上)。
f:id:andron:20180717070502g:plain

しれっと Wave の方も設定していますが、Wave は Emitter をいじればスクリプトをいじることなく動かせるそうです。
f:id:andron:20180717070950p:plain


とまあ、そんな感じで長きにわたって2Dシューティング作ってみました。途中脱線しなければ一週間もかからない内容だったんですけどねぇ……。どうしてこうなった……。そして、最初に作ったスプライトは結局使うことなかった……。いつかは完全版にしたいものです。


さて、残りはモバイル対応の話なんだけど、そっちは気が向いたら更新するかもしれないししないかもしれないってことでここで一旦終了です。次回は何を終わらせましょうかね……。他にもUnityやっている方がいて書籍とか挙げているんですけど、公式チュートリアルに書いてある以上の学びがあるのかどうかってところで手を出せずにいる。エフェクト関連の処理についてとかは結構気になるけどなにかないかね……。

まあいいや。次回も何作るか未定だけど公式から適当にチョイスしてやっていこうと思います。


おしまい