ゲームデータについて(7)テキストデータの差し替え処理

本記事ではこちらの記事で軽く触れた、テキストデータの一部をゲームの状況に応じて特定の文字列に差し替える処理の実装について説明します。

文字列の差し替え処理の実装

テキストデータにタグを埋め込んで、タグの種類に応じた文字列を差し替える処理を実装します。
差し替えられる種類は数値・文字列・モンスター名とし、それぞれにタグを用意します。

Assets/Editor/GameData/textData.xlsm のSystemシートに文字列差し替えタグを含めた文字列を追加します。

Assets/GameData/TextData/TextDataManager.csを下記のように修正します。

using UnityEngine;
using UnityEngine.Assertions;
using System.Collections.Generic;     // これを追加.
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;

public static class TextDataManager
{
    private static TextData textData = null;

    // ここからを追加.
    // 差し替えタイプ.
    private enum REPLACE_TYPE
    {
        NUMBER = 0, // 数値.
        STRING,     // 文字列.
        MONSTER,    // モンスター名.

        NUM
    };
    // 差し替えタグ.
    private static string[] replaceTags =
    {
        "{NUM}",
        "{STR}",
        "{MONSTER}",
    };

    // 差し替えパラメータ.
    private static List<int> replaceNumParams = new List<int>();
    private static List<string> replaceStrParams = new List<string>();
    private static List<int> replaceMonsterParams = new List<int>();
    // 差し替えカウンタ(タイプ毎の配列).
    private static byte[] replaceCount = new byte[(int)REPLACE_TYPE.NUM];
    // ここまでを追加.

    static TextDataManager()
    {
    }

    public static bool Serialize()
    {
        TextAsset serializeFile = Resources.Load("TextData/TextData") as TextAsset;
        using (MemoryStream memoryStream = new MemoryStream(serializeFile.bytes))
        {
            BinaryFormatter binaryFormatter = new BinaryFormatter();
            textData = binaryFormatter.Deserialize(memoryStream) as TextData;
        }

        return true;
    }

    // ここからを削除.
    //public static string GetText(TEXT_LABEL textLabel)
    //{
    //    Assert.IsTrue(textLabel < TEXT_LABEL.NUM);

    //    // テキストデータ取得.
    //    return textData.TextList[(int)textLabel];
    //}
    // ここまでを削除.

    // ここからを追加.
    public static void ClearReplaceParams()
    {
        replaceNumParams.Clear();
        replaceStrParams.Clear();
        replaceMonsterParams.Clear();
    }

    private static void ClearReplaceCounter()
    {
        for (int i = 0; i < (int)replaceCount.Length; ++i)
        {
            replaceCount[i] = 0;
        }
    }

    public static void SetNumber(List<int> nums)
    {
        replaceNumParams = nums;
    }

    public static void SetString(List<string> strings)
    {
        replaceStrParams = strings;
    }

    public static void SetMonster(List<int> ids)
    {
        replaceMonsterParams = ids;
    }

    /***********************************************************
    文字列の差し替え処理.
    差し替えた文字列をstrTextに返す.
    ***********************************************************/
    private static void ReplaceText(ref string strText)
    {
        // 差し替えカウンタを初期化.
        ClearReplaceCounter();

        int index = 0;

        for (; ; )
        {
            // テキストの最後まで検索した.
            if (index >= strText.Length)
            {
                break;
            }

            // 差し替えタグ文字を探す.
            index = strText.IndexOf('{', index);

            // タグ文字がなかった.
            if (index < 0)
            {
                break;
            }

            int indexEnd = strText.IndexOf('}', index);

            string strTag = strText.Substring(index, indexEnd - index + 1);
            for (int i = 0; i < (int)REPLACE_TYPE.NUM; i++)
            {
                // 差し替えタグ一致チェック.
                if (strTag == replaceTags[i])
                {
                    // 差し替え.
                    int replacedLength = ReplaceTextSub(ref strText, (REPLACE_TYPE)i, index);
                    if (replacedLength <= 0)
                    {
                        // エラー.
                        index = -1;
                    }
                    else
                    {
                        index += replacedLength;
                    }
                    break;
                }
            }

            // 差し替えのエラーによる終了.
            if (index < 0)
            {
                Debug.LogWarning("文字列の差し替えエラー");
                break;
            }
        }
    }

    /***********************************************************
    文字列の差し替え処理のサブルーチン.
    差し替えタグが検出されると呼ばれてタイプに応じたパラメータの値で差し替える.
    差し替えた文字列をstrTextに返す.
    差し替えた文字の長さを返り値とする.
    ***********************************************************/
    private static int ReplaceTextSub(ref string strText, REPLACE_TYPE replaceType, int index)
    {
        Assert.IsNotNull(strText);
        Assert.IsTrue(replaceType < REPLACE_TYPE.NUM);

        // 差し替えタグを削除.
        int removeLength = replaceTags[(int)replaceType].Length;
        string strReplace = strText.Remove(index, removeLength);
        // 差し替え内容.
        string strAdd = "";
        // 差し替えカウンタ.
        int counter = replaceCount[(int)replaceType];

        switch (replaceType)
        {
            // 数値.
            case REPLACE_TYPE.NUMBER:
                {
                    if(counter >= replaceNumParams.Count)
                    {
                        Assert.IsTrue(false);
                        break;
                    }
                    strAdd = replaceNumParams[counter].ToString();
                }
                break;

            // 文字列.
            case REPLACE_TYPE.STRING:
                {
                    if (counter >= replaceStrParams.Count)
                    {
                        Assert.IsTrue(false);
                        break;
                    }
                    strAdd = replaceStrParams[counter];
                }
                break;

            // モンスター名.
            case REPLACE_TYPE.MONSTER:
                {
                    if (counter >= replaceMonsterParams.Count)
                    {
                        Assert.IsTrue(false);
                        break;
                    }
                    int id = replaceMonsterParams[counter];
                    strAdd = FixedDataManager.GetMonsterData(id).GetName();
                }
                break;

            default:
                {
                    return 0;
                }
        }

        // 差し替えの実行.
        if (strAdd != null)
        {
            strReplace = strReplace.Insert(index, strAdd);
        }

        // 元の文字列に代入.
        strText = strReplace;

        // 差し替えカウンタを増やす.
        replaceCount[(int)replaceType]++;

        // 差し替え内容の長さを返す.
        return strAdd.Length;
    }

    public static string GetText(TEXT_LABEL textLabel)
    {
        Assert.IsTrue(textLabel < TEXT_LABEL.NUM);

        // テキストデータ取得.
        string strText = textData.TextList[(int)textLabel];

        // タグによる差し替え処理.
        ReplaceText(ref strText);
        // 差し替えパラメータのクリア.
        ClearReplaceParams();

        return strText;
    }
    // ここまでを追加.
}

次記事でざっくりと解説します。