【Unity入門】2Dアクションを作ろう【UI作成】

この記事は本のように順を追って解説しています。この記事は途中のページになります。
この記事を見ていて、現在の状況がわからない場合や忘れてしまった事などが出てきたら↓のリンクから目次ページへ飛べますので立ち戻って見てください。

<画面に表示するUIを作成しよう>

さて、前回ゲームマネージャーを作成しました。ゲームマネージャーを作成したことにより、多くのパラメーターを全体で管理できるようになりました。

ゲームマネージャーの作成がまだの人は↓の記事を参考にしてください。

ゲームマネージャーを使用して、画面に情報を表示させましょう。

今回作ろうと思う情報は

・スコア表示
・残機表示
・現在のステージ表示

この3つを実装していきます。

UGUIを使って実装していこうと思います。

UGUIの使い方を忘れてしまった人、わからない人は↓の記事を参考にしてみてください。

<スコア表示>

UGUIで画面にスコアを表示しよう

UGUIのTextを使用してスコアを画面に表示していきます。ステージのシーンに移動してください。

可能な限りTextのfontSizeは同じにした方がいいので、タイトルで作成したTextのfontSizeと同じ値を使いましょう。

fontSizeを設定し、Alignmentを右詰、上詰にして、Horizontal OverflowとVertical OverflowをOverflowに変更して、Colorを黄色にし、Outlineのコンポーネントを追加しました。

右詰にする事でスコアがいくつになっても定位置になるようにしています。

set score text

はい、これでスコアの表示を作る事ができました。ここに正しい値を入れるようにスクリプトを作っていきましょう。

UGUIにスクリプトから値を渡そう

クリックすると展開します
 using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class score : MonoBehaviour
{
    private Text scoreText;
    private int oldScore;
    
    void Start()
    {
        scoreText = GetComponent<Text>();
        if (scoreText != null && GManager.instance != null)
        {
             scoreText.text = "Score " + GManager.instance.score.ToString();
        }
    }

    void Update()
    {
        if (scoreText != null && GManager.instance != null)
        {
            if (oldScore != GManager.instance.score)
            {
                scoreText.text = "Score " + GManager.instance.score.ToString();
                oldScore = GManager.instance.score;
            }
        }
    }
}

はい、これで完成です。ゲームマネージャーを作っていたおかげで非常に簡単に作る事ができました。

UGUIを使うので

 using UnityEngine.UI;

と宣言するのを忘れずに。

Updateで毎フレームTextの中身を変更するのはよろしくないので、

             if (oldScore != GManager.instance.score)
             {
                 scoreText.text = "Score " + GManager.instance.score.ToString();
                 oldScore = GManager.instance.score;
             }

oldScoreという前のスコアを記録しておいて、現在のスコアと違った場合のみテキストに書き込みに行くようにします。

このように差分があった時のみ更新するようになっている為、Start内で普通に値を入れて初期化しています。

Textに突っ込むので値は「文字列」でなければなりません。その為、数字の部分をToString()という命令で数字を文字列に変換しています。

このスクリプトをUGUIのTextと同じゲームオブジェクトにくっつけましょう。

ゲームマネージャーをうまく使おう

さて、ここで問題があります。ゲームマネージャーがないとスコアが反映されません。しかしながらゲームマネージャーはタイトルシーンに置いてあります。

ゲームのテストプレイを行うのにいちいちタイトル画面に戻るのはめんどくさいです。

ゲームマネージャーをプレハブにしてしまってステージシーンに置いてしまいましょう。

prefab game manager

こんな事をしてしまうと各シーンにゲームマネージャーが置かれてしまって「ただ一つの」という条件を破ってしまうように思えますが、2つ目が登場した際にDestroyするようにしているので問題ないです。

まぁ、処理的に無駄なものが発生してしまいますが、これくらいなら開発しやすさを取ってもいいかなと思います。

スコアを加算しよう

敵が踏まれてやられたらスコアを加算するようにしましょう。

ゲームマネージャーのところで紹介したように敵が踏まれた判定のところでスコアを加算してあげればOKです。

クリックすると展開します
 using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class enemy_zako1 : MonoBehaviour
{
    #region//インスペクターで設定する
    [Header("加算スコア")] public int myScore; //New!
    [Header("移動速度")] public float speed;
    [Header("重力")] public float gravity;
    [Header("画面外でも行動する")] public bool nonVisibleAct;
    [Header("接触判定")] public EnemyCollisionCheck checkCollision;
    #endregion

    #region//プライベート変数
    private Rigidbody2D rb = null;
    private SpriteRenderer sr = null;
    private Animator anim = null;
    private ObjectCollision oc = null;
    private BoxCollider2D col = null;
    private bool rightTleftF = false;
    private bool isDead = false;
    private float deadTimer = 0.0f;
    #endregion

    // Start is called before the first frame update
    void Start()
    {
        rb = GetComponent<Rigidbody2D>();
        sr = GetComponent<SpriteRenderer>();
        anim = GetComponent<Animator>();
        oc = GetComponent<ObjectCollision>();
        col = GetComponent<BoxCollider2D>();
    }

    void FixedUpdate()
    {
        if (!oc.playerStepOn)
        {
            if (sr.isVisible || nonVisibleAct)
            {
                if (checkCollision.isOn)
                {
                    rightTleftF = !rightTleftF;
                }
                int xVector = -1;
                if (rightTleftF)
                {
                    xVector = 1;
                    transform.localScale = new Vector3(-1, 1, 1);
                }
                else
                {
                    transform.localScale = new Vector3(1, 1, 1);
                }
                rb.velocity = new Vector2(xVector * speed, -gravity);
                anim.SetBool("walk", true);
            }
            else
            {
                anim.SetBool("walk", false);
            }
        }
        else
        {
            if (!isDead)
            {
                anim.Play("dead");
                rb.velocity = new Vector2(0, -gravity);
                isDead = true;
                col.enabled = false;

                //New!
                if(GManager.instance != null)
                {
                    GManager.instance.score += myScore;
                }
            }
            else
            {
                transform.Rotate(new Vector3(0, 0, 5));
                if (deadTimer > 3.0f)
                {
                    Destroy(this.gameObject);
                }
                else
                {
                    deadTimer += Time.deltaTime;
                }
            }
        }
    }
}

インスペクターで加算するスコアを設定できるようにしています。

スコアを加算するアイテムを作ろう

ついでにマリオでいうコインのようなアイテムを作りましょう。

star

例によって下書きなので適当でOKです。

set score item

Box Collider 2DをつけてIs Triggerをセットします。

クリックすると展開します
 using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ScoreItem : MonoBehaviour
{
    [Header("加算スコア")] public int myScore;

    private string playerTag = "Player";

    private void OnTriggerEnter2D(Collider2D collision)
    {
        if (collision.tag == playerTag)
        {
            if (GManager.instance != null)
            {
                GManager.instance.score += myScore;
                Destroy(this.gameObject);
            }
        }
    }
}

OnTriggerEnter2Dでプレイヤーを感知して、中に入ったらスコアを加算して消えるようにしました。

player tag

プレイヤーのタグを変更するのを忘れずに

アイテムのスコアを10、敵のスコアを20に設定しました。この状態で再生すると

score-add-action

こんな感じでスコアが加算されている事がわかります。

<残機表示・ステージ数表示>

さて、ここまでくれば残機表示も、現在のステージを表示するのも簡単だと思います。

heart

また適当に残機アイコンを描いてみました。相変わらず下書きです

同じようにテキストを駆使すると

game ugui set text

割とゲームっぽくなってきましたね。

テキストの配置ポイントとして、Scoreは右詰でしたが、ステージ表記と残機数は左詰にしましょう。

スコアの時と同じようにゲームマネージャーを見て各種値をセットするようにしましょう。

クリックすると展開します
 using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class GManager : MonoBehaviour
{
    public static GManager instance = null;

    public int score = 0;
    public int stageNum = 1;
    public int continueNum = 0;
    public int heartNum = 3;

    private void Awake()
    {
        if(instance == null)
        {
            instance = this;
            DontDestroyOnLoad(this.gameObject);
        }
        else
        {
            Destroy(this.gameObject);
        }
    }
}
 using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class stageNum : MonoBehaviour
{
    private Text stageText;
    private int oldStageNum;
    
    void Start()
    {
        stageText = GetComponent<Text>();
        if (stageText != null && GManager.instance != null)
        {
            stageText.text = "Stage " + GManager.instance.stageNum.ToString();
        }
    }

    void Update()
    {
        if (stageText != null && GManager.instance != null)
        {
            if (oldStageNum != GManager.instance.stageNum)
            {
                stageText.text = "Stage " + GManager.instance.stageNum.ToString();
                oldStageNum = GManager.instance.stageNum;
            }
        }
    }
}
 using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class heart : MonoBehaviour
{
    private Text heartText;
    private int oldHeartNum;
    
    void Start()
    {
        heartText = GetComponent<Text>();
        if (heartText != null && GManager.instance != null)
        {
            heartText.text = "× " + GManager.instance.heartNum.ToString();
        }
    }

    void Update()
    {
        if (heartText != null && GManager.instance != null)
        {
            if (oldHeartNum != GManager.instance.heartNum)
            {
                heartText.text = "× " + GManager.instance.heartNum.ToString();
                oldHeartNum = GManager.instance.heartNum;
            }
        }
    }
}

いちいち最初にプラスするのはめんどくさいのでステージ番号とハートの数を入れてしまいましょう。

game test play

はい。ものすごく簡単にステージ数と残機数の表示が完了しました。

もし、0になってしまう方がいたらインスペクターの値を疑ってください。

game manager inspector

一回シリアライズされたものはスクリプトから値を変更できないので注意が必要です。

しかしながらここをインスペクターから触れるようにしておく事で、デバッグ中に残機無限にしたり、コンティニュー場所を最初から指定できたりできるようになるのでこのように外に出しておくと便利です。

<わからない事、質問等があれば>

このサイトの説明ではよくわからなかったとか、もっと知りたい事などがあれば

自分の Youtubeの動画にコメントで質問していただければ動画でお答えしようと思います。

文章同士のやり取りだと伝わりづらいし、ラリーに時間がかかりそうなので動画で回答します。

↓の動画が回答の一例になります。どの動画でもいいのでご遠慮なくコメントしてください

できたらチャンネル登録よろしくお願いします!



タイトルとURLをコピーしました