ぺんたんがゲーム開発やアプリ開発、最近の気になる話題、特にスマホやIT関連について語る場所

ぺんごや

Unity Unity2D Unity初心者

【Unity】数字を画像で描画する方法(gUIじゃないよ)

更新日:

Unityでゲームを作っていると、数字を画像として表示させたいケースが出てきます。

例えばRPGでよくあるダメージの表示とか。

その方法をご紹介します。

数字画像の準備

0~9を並べた画像を準備しておきます。

数字画像のスプライト化

準備しておいた画像ファイルをプロジェクトウィンドウにドロップします。

画像ファイルをドロップしたらインスペクターでスプライトモードを「複数」に変更。パッキングタグと1ユニットのピクセル数はご自身の環境に合わせてお好きに。

次に「Sprite Editor」を立ち上げ数字を1桁ずつ分割します。

スライスのタイプを「Grid By Cell Count」にし、Cを「10」に設定します。そして「スライス」をクリックし画像を分割します。

すると数字画像が各数字ごとに分割されます。

ここまでできれば数字画像の準備完了です。

スポンサードサーチ

数字を画像として描画する手順

ではさくっと手順を説明します。

スプライトファイルを2つ作成

下記の「Number_test.cs」と「NumCtrl.cs」の2つのスクリプトを作成しておきます。

コードの詳細については後述。

Number_test.cs

using UnityEngine;
using UnityEngine.Rendering;

public class Number_test : MonoBehaviour {

    //表示位置
    Vector3 init_pos;

    //表示関連
    private int point;      //表示する値
    private float size = 1; //表示サイズ

    private static int dam_sort = 0;    //数字の表示順
    private const int SORT_MAX = 30000;

    // Start is called before the first frame update
    void Start() {
        //初期化
        //ここではテスト用にスタートで初期化しているけど、数字を表示させたいタイミングで呼び出すのがベター
        Init(125, new Vector3(0, 0, 0));

    }

    public void Init(int point, Vector3 pos) {
        //必要な情報を格納
        this.point = point;
 
        //表示用のダメージを作る
        CreateNum(point);

        init_pos = pos;

        //表示順を一番上に
        GetComponent<SortingGroup>().sortingOrder = dam_sort;


        dam_sort++;
        if (dam_sort > SORT_MAX) {
            dam_sort = 0;
        }

    }

    //描画用の数字を作る
    private void CreateNum(int point) {

        //桁を割り出す
        int digit = ChkDigit(point);

        //数字プレハブを読み込む、テスト用のフォルダとファイル名
        GameObject obj = LoadGObject( "test", "pref_num_test");


        //桁の分だけオブジェクトを作り登録していく
        for (int i = 0; i < digit; i++) {

            GameObject numObj = Instantiate(obj) as GameObject;

            //子供として登録
            numObj.transform.parent = transform;

            //現在チェックしている桁の数字を割り出す
            int digNum = GetPointDigit(point, i + 1);

            //ポイントから数字を切り替える
            numObj.GetComponent<NumCtrl>().ChangeSprite(digNum);

            //サイズをゲットする
            float size_w = numObj.GetComponent<SpriteRenderer>().bounds.size.x;

            //位置をずらす
            float ajs_x = size_w * i - (size_w * digit) / 2;
            Vector3 pos = new Vector3(numObj.transform.position.x - ajs_x, numObj.transform.position.y, numObj.transform.position.z);
            numObj.transform.position = pos;

            numObj = null;
        }

    }


    // Update is called once per frame
    void Update() {

        
    }

    /**-----------------------------------------------------------------------------------
     * 以下の関数はテスト用にここに記載しているけど、別のスクリプトファイルとしたほうが使い勝手がいいかも
     * ----------------------------------------------------------------------------------/

    /**
    * 整数の桁数を返す
    * */
    public static int ChkDigit(int num) {

        //0の場合1桁として返す
        if (num == 0) return 1;

        //対数とやらを使って返す
        return (num == 0) ? 1 : ((int)Mathf.Log10(num) + 1);

    }
    /**
    * 数値の中から指定した桁の値をかえす
    * */
    public static int GetPointDigit(int num, int digit) {

        int res = 0;
        int pow_dig = (int)Mathf.Pow(10, digit);
        if (digit == 1) {
            res = num - (num / pow_dig) * pow_dig;
        } else {
            res = (num - (num / pow_dig) * pow_dig) / (int)Mathf.Pow(10, (digit - 1));
        }

        return res;
    }
    /**
    * オブジェクトを読み込む
    * リソースフォルダから読み込む
    * */
    public static GameObject LoadGObject(string dir_name, string filename) {

        GameObject obj;

        //リソースから読み込むパターン
        obj = (GameObject)Resources.Load(dir_name + "/" + filename);
       
        return obj;

    }
}

NumCtrl.cs

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

public class NumCtrl_test : MonoBehaviour {
    [SerializeField] private Sprite[] sp = new Sprite[10];

    public void ChangeSprite(int no) {

        if (no > 9 || no < 0) no = 0;

        SpriteRenderer spriteRenderer = gameObject.GetComponent<SpriteRenderer>();
        spriteRenderer.sprite = sp[no];

    }
}

数字オブジェクト格納用のゲームオブジェクト作成

 

表示する数字を格納するための空のゲームオブジェクトを作ります。

今回は「Number_test」で作りました。

 

そして作成したゲームオブジェクトに先ほど作った「Number_test.cs」をアタッチします。

それに加えてソーティングレイヤーも追加しています。

ソート用レイヤーに今回は「damage」レイヤーを選択していますが、これは「default」より上位のレイヤーを選択すればOKです。

ソーティングレイヤーを設定する目的は数字画像を最前面に表示させるためです。

数字オブジェクト作成

数字画像を格納するための「2Dオブジェクト > スプライト」でオブジェクトを作成します、

今度は「pref_num_test」という名前で作りました。

そして作成したオブジェクトに「NumCtrl.cs」をアタッチします。

なお、スプライトレンダラーのスプライトは「なし」のままでOKです。

次に、実際に表示するための画像を格納していきます。

インスペクター内、Num Ctrl_testのSpを展開し、各要素に最初に分割しておいた数字画像ファイルを1つずつ割り当てます。少し面倒ですが!

ここまで出来たらオブジェクトをプレハブ化します。プレハブ化したら元のオブジェクトは不要なので削除してきましょう。

今回はResourcesフォルダに「test」フォルダを作り、その中にプレハブを置きました。

動作確認

ここまで出来たらプロジェクトを実行してみましょう。

画面中央に数字が表示されていれば成功です。

スポンサードサーチ

処理の流れ

CreateNum関数が描画用数字を作る個所となります。

GameObject obj = LoadGObject( “test”, “pref_num_test”);
プレハブ化していた数字オブジェクトを読み込みます。

 

そして描画したい数字の桁数の分だけ以下の処理を実行します。

GameObject numObj = Instantiate(obj) as GameObject;
読み込んだプレハブをオブジェクト化します。

numObj.transform.parent = transform;
オブジェクト化した数字を子オブジェクトとして登録。

int digNum = GetPointDigit(point, i + 1);
numObj.GetComponent().ChangeSprite(digNum);
今チェックしている桁の数字オブジェクトの画像を表示したい数字画像に変更する。

float size_w = numObj.GetComponent().bounds.size.x;
float ajs_x = size_w * i – (size_w * digit) / 2;
Vector3 pos = new Vector3(numObj.transform.position.x – ajs_x, numObj.transform.position.y, numObj.transform.position.z);
numObj.transform.position = pos;
数字画像のサイズを取得し、描画する桁ごとに描画する位置をずらす。

初期化処理について

今回はテスト用なのでStart内で初期化していますが、実際に使うときは数字を表示したいタイミングで初期化するといいでしょう。

数字を消したいとき

この描画方法では一度描画を始めると、ずっと描画され続けてしまいます。

描画をやめたくなったらオブジェクトそのものを消せばOKです。

今回のケースでは、数字画像格納用に作成した「Number_test」オブジェクトをDestroyしてあげれば消えます。

応用

今回の描画方法を応用すればこんな風に元気に飛び跳ねるダメージ表示なんかもできます。

この応用手順についてはいずれ何かでまとめてご紹介できればと思います。

-Unity, Unity2D, Unity初心者

Copyright© ぺんごや , 2024 All Rights Reserved Powered by STINGER.