外部アセット表示の対応方法 例:Spine


投稿日:2018年10月7日 | 最終更新日:2024年5月26日

宴ではプレハブをロードして単純に表示するだけであれば、簡単に拡張ができます。
これを利用すれば、外部のアセットの表示も可能です。
以下、SpineのUnityアセットを例に外部アセットへの対応方法を解説します。

拡張プログラムを書く

表示するプレハブを宴で表示するためのコンポーネントを自作して、それを使う必要があります。
コンポーネントは、IAdvGraphicObjectCustom, IAdvGraphicObjectCustomCommandというインターフェースを継承する必要があります。
これらのインターフェースを実装することで、宴のシステムと繋げたり、エクセルに記述された描画コマンドの引数などを読み取って描画に反映することが可能になります。
インターフェースは、以下のメソッドを持っていますので、必要に応じた実装をしてください。
特に、SetCommandArgでエクセルで記述してある描画コマンドの記述を拾ってこれますので、必要に応じて適用してください。

    /// カスタム機能つきのオブジェクト表示のインターフェース
    public interface IAdvGraphicObjectCustom
    {
        //描画時のリソース変更
        void ChangeResourceOnDrawSub(AdvGraphicInfo graphic);

        //エフェクト用の色が変化したとき
        void OnEffectColorsChange(AdvEffectColor color);
    }

    /// カスタム機能つきのオブジェクト表示のインターフェース
    public interface IAdvGraphicObjectCustomCommand
    {
        //********描画時の引数適用********//
        void SetCommandArg(AdvCommand command);
    }

セーブデータの拡張が必要な場合

独自のモーションのパラメーターの記録など、セーブデータを拡張する必要がある場合はIAdvGraphicObjectCustomSaveを使います。
不要な場合はこのインターフェースは不要です。

    public interface IAdvGraphicObjectCustomSave
    {
        void WriteSaveDataCustom(BinaryWriter writer);
        void ReadSaveDataCustom(BinaryReader reader);
    }

Spineの通常オブジェクトを表示するサンプル

using UnityEngine;
using UtageExtensions;
using Spine.Unity;
using System.IO;

namespace Utage
{
    [AddComponentMenu("Utage/ADV/Internal/GraphicObject/Spine/Default")]
    internal class AdvGraphicObjectSpine : MonoBehaviour
        , IAdvGraphicObjectCustom
        , IAdvGraphicObjectCustomCommand
        , IAdvGraphicObjectCustomSave
    {
        SkeletonAnimation SkeletonAnimation { get { return this.GetComponentCache<SkeletonAnimation>(ref skeletonAnimation); } }
        SkeletonAnimation skeletonAnimation;

        AdvGraphicObjectCustom AdvObj
        {
            get
            {
                if (advObj == null)
                {
                    advObj = this.GetComponentInParent<AdvGraphicObjectCustom>();
                }
                return advObj;
            }
        }
        AdvGraphicObjectCustom advObj;

        //描画時のリソース変更
        public void ChangeResourceOnDrawSub(AdvGraphicInfo graphic)
        {
            SetSortingOrder(this.AdvObj.Layer.Canvas.sortingOrder, this.AdvObj.Layer.Canvas.sortingLayerName);
        }

        //描画順の設定
        void SetSortingOrder(int sortingOrder, string sortingLayerName)
        {
            Renderer render = GetComponent<Renderer>();
            render.sortingOrder = sortingOrder;
            render.sortingLayerName = sortingLayerName;
        }

        //エフェクト用の色が変化したとき
        public void OnEffectColorsChange(AdvEffectColor color)
        {
//          SkeletonAnimation.color = color.MulColor;
        }

        //********描画時の引数適用********//
        public void SetCommandArg(AdvCommand command)
        {
            string animationName = command.ParseCellOptional<string>(AdvColumnName.Arg2, "");
            if (string.IsNullOrEmpty(animationName)) return;

//          float fadeTime = command.ParseCellOptional<float>(AdvColumnName.Arg6, 0.2f);
            SkeletonAnimation.state.SetAnimation(0, animationName, true);
        }
        const int Version = 0;
        public void WriteSaveDataCustom(BinaryWriter writer)
        {
            writer.Write(Version);
            writer.Write(CurrentAnimationName());
        }

        string CurrentAnimationName()
        {
            var track = SkeletonAnimation.state.GetCurrent(0);
            if (track == null) return "";
            var anim = track.Animation;
            if (anim == null) return "";
            return  anim.Name;
        }

        public void ReadSaveDataCustom(BinaryReader reader)
        {
            int version = reader.ReadInt32();
            string animationName = reader.ReadString();
            if(!string.IsNullOrEmpty(animationName))
            {
                SkeletonAnimation.state.SetAnimation(0, animationName, true);
            }
        }
    }
}

uGUIに対応した表示

「IAdvGraphicObjectCustom」というインターフェースを使う必要があります。

using UnityEngine;
using UtageExtensions;
using Spine.Unity;
using System.IO;

namespace Utage
{
    [AddComponentMenu("Utage/ADV/Internal/GraphicObject/Spine/Graphic")]
    internal class AdvGraphicObjectSpineGraphic : MonoBehaviour
        , IAdvGraphicObjectCustom
        , IAdvGraphicObjectCustomCommand
        , IAdvGraphicObjectCustomSave
    {
        SkeletonGraphic SkeletonGraphic { get { return this.GetComponentCache<SkeletonGraphic>(ref skeletonGraphic); } }
        SkeletonGraphic skeletonGraphic;

        AdvGraphicObjectCustom2D AdvObj
        {
            get
            {
                if (advObj == null)
                {
                    advObj = this.GetComponentInParent<AdvGraphicObjectCustom2D>();
                }
                return advObj;
            }
        }
        AdvGraphicObjectCustom2D advObj;

        //描画時のリソース変更
        public void ChangeResourceOnDrawSub(AdvGraphicInfo graphic)
        {
        }

        //エフェクト用の色が変化したとき
        public void OnEffectColorsChange(AdvEffectColor color)
        {
            SkeletonGraphic.color = color.MulColor;
        }

        //********描画時の引数適用********//
        public void SetCommandArg(AdvCommand command)
        {
            string animationName = command.ParseCellOptional<string>(AdvColumnName.Arg2, "");
            if (string.IsNullOrEmpty(animationName)) return;

            //          float fadeTime = command.ParseCellOptional<float>(AdvColumnName.Arg6, 0.2f);
            SkeletonGraphic.AnimationState.SetAnimation(0, animationName, true);
        }

        const int Version = 0;
        public void WriteSaveDataCustom(BinaryWriter writer)
        {
            writer.Write(Version);
            writer.Write(CurrentAnimationName());
        }

        string CurrentAnimationName()
        {
            var track = SkeletonGraphic.AnimationState.GetCurrent(0);
            if (track == null) return "";
            var anim = track.Animation;
            if (anim == null) return "";
            return  anim.Name;
        }

        public void ReadSaveDataCustom(BinaryReader reader)
        {
            int version = reader.ReadInt32();
            string animationName = reader.ReadString();
            if(!string.IsNullOrEmpty(animationName))
            {
                SkeletonGraphic.AnimationState.SetAnimation(0, animationName, true);
            }
        }
    }
}

表示したいオブジェクトをプレハブ化

表示したいオブジェクトをプレハブ化して、宴のリソース管理フォルダ(Characterフォルダなど)の下に置き、
上記のコンポーネントをAddComponentします。

CharacterシートやTextureシートにプレハブを追加

CharacterシートなどでFileNameにプレハブのパスを
FileTypeに「Custom」、uGUIに対応した表示の場合は「Custom2D」と設定します。

表示テスト

上記の対応で、通常の宴のオブジェクト同じように表示可能です。
ただし、テクスチャ書き込み機能は表示するオブジェクトがテクスチャ書き込みに対応していない場合は使用できません。
特に、半透明のオブジェクトの場合は、殆ど対応していないと思います。

シナリオデータに任意の名前の列を追加して、その値を利用する

宴のデフォルトで用意しているArg1~6はコマンド仕様と結びついているので、それを使って拡張しようとするとうまく動かないことがあります。
その場合は、シナリオデータ(エクセルデータ)に、任意の列を追加して渡したいデータを追加することも可能です。

サンプル

シナリオデータにArg7やArg8という列を追加。

プログラムから、その追加した列のセルの内容を取得するには、下記のように文字列で追加した列名を指定します。

int i = command.ParseCell("Arg7");
float f = command.ParseCellOptional("Arg8", 0.0f);