LoginSignup
5
4

More than 3 years have passed since last update.

Imageを拡張してSpriteAtlasをEditModeで表示する[Unity]

Last updated at Posted at 2018-04-30

追記

こちら、UnityのSpriteAtlasへの理解が完全に間違っていたため使用しないでください!

atlas.gif

uGUIのImageをNGUIのUISpriteっぽく使えるように拡張しました.

スクリーンショット 2018-04-30 21.42.15.png

ImageのパラメータにAtlasとSpriteNameを追加しました.

使い方

  1. SpriteAtlasを作る
  2. Pack PreviewでAtlasを作る
  3. Atlas ImageをアタッチしてAtlasを選択
  4. SpriteNameでAtlasに含まれる画像を設定する

スクリプト

AtlasImage.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.U2D;

public class AtlasImage : Image
{
    [SerializeField] SpriteAtlas m_Atlas;
    public SpriteAtlas atlas{ get{ return m_Atlas; } set{ m_Atlas = value;}}
    [SerializeField] string m_SpriteName;
    public string spriteName{
        get{return m_SpriteName; }
        set {
            m_SpriteName = value; 

            if (atlas != null) {
                this.sprite = atlas.GetSprite (m_SpriteName);
            }
        }
    }

    protected override void OnEnable(){
        base.OnEnable ();
        if (atlas != null)
            this.sprite = atlas.GetSprite (spriteName);
    }
}

AtlasImageEditor.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using UnityEditor.UI;
using UnityEngine.U2D;
using System.Linq;
using UnityEditor.AnimatedValues;
using UnityEngine.UI;

[CustomEditor(typeof(AtlasImage), true)]
[CanEditMultipleObjects]
public class AtlasImageEditor : ImageEditor {

    SerializedProperty m_Atlas;
    SerializedProperty m_SpriteName;

    AnimBool m_ShowSpriteName;

    string[] atlasSpriteNames;
    int spriteNameIndex = 0;

    protected override void OnEnable ()
    {
        m_Atlas = serializedObject.FindProperty ("m_Atlas");
        m_SpriteName = serializedObject.FindProperty ("m_SpriteName");
        m_ShowSpriteName = new AnimBool (m_Atlas.objectReferenceValue != null);
        m_ShowSpriteName.valueChanged.AddListener (Repaint);

        ResetAtlasSpriteNames ();
        ResetSpriteNameIndex ();
        base.OnEnable ();
    }

    protected override void OnDisable ()
    {
        m_ShowSpriteName.valueChanged.RemoveListener (Repaint);
        base.OnDisable ();
    }

    public override void OnInspectorGUI()
    {
        serializedObject.Update ();
        AtlasGUI ();

        m_ShowSpriteName.target = m_Atlas.objectReferenceValue != null;
        if (EditorGUILayout.BeginFadeGroup (m_ShowSpriteName.faded))
            SpriteNameGUI ();
        EditorGUILayout.EndFadeGroup ();

        serializedObject.ApplyModifiedProperties ();

        base.OnInspectorGUI ();
    }

    protected virtual void AtlasGUI(){
        EditorGUI.BeginChangeCheck ();
        EditorGUILayout.PropertyField (m_Atlas);

        if (EditorGUI.EndChangeCheck ()) {
            ResetAtlasSpriteNames ();
            ResetSpriteNameIndex ();
        }
    }

    // 現在の名前からindexを求める
    void ResetSpriteNameIndex(){
        if (atlasSpriteNames == null || atlasSpriteNames.Length == 0)
            return;

        string currentName = m_SpriteName.stringValue;
        int tempIndex = 0;
        for (int i = 0; i < atlasSpriteNames.Length; i++) {
            if (currentName == atlasSpriteNames [i]) {
                tempIndex = i;
                break;
            }
        }
        spriteNameIndex = tempIndex;
        m_SpriteName.stringValue = atlasSpriteNames [spriteNameIndex];
        UpdateSourceImage ();
    }

    void ResetAtlasSpriteNames(){
        var newAtlas = m_Atlas.objectReferenceValue as SpriteAtlas;
        if (newAtlas) {
            atlasSpriteNames = GetAllSprite (newAtlas)
            .Select (x => x.name.Replace ("(Clone)", ""))
            .ToArray ();
        }
    }

    protected virtual void SpriteNameGUI(){
        EditorGUI.BeginChangeCheck ();
        if (atlasSpriteNames != null)
            spriteNameIndex = EditorGUILayout.Popup ("SpriteName", spriteNameIndex, atlasSpriteNames);

        if (EditorGUI.EndChangeCheck ()) {
            m_SpriteName.stringValue = atlasSpriteNames [spriteNameIndex];
            UpdateSourceImage ();
        }
    }


    protected virtual void UpdateSourceImage(){
        SerializedProperty m_Type = serializedObject.FindProperty("m_Type");
        SerializedProperty m_Sprite = serializedObject.FindProperty("m_Sprite");

        var currentAtlas = m_Atlas.objectReferenceValue as SpriteAtlas;

        if (currentAtlas == null)
            return;

        var newSprite = currentAtlas.GetSprite (m_SpriteName.stringValue);

        m_Sprite.objectReferenceValue = newSprite;
        if (newSprite)
        {
            Image.Type oldType = (Image.Type)m_Type.enumValueIndex;
            if (newSprite.border.SqrMagnitude() > 0)
            {
                m_Type.enumValueIndex = (int)Image.Type.Sliced;
            }
            else if (oldType == Image.Type.Sliced)
            {
                m_Type.enumValueIndex = (int)Image.Type.Simple;
            }
        }
    }

    static IEnumerable<Sprite> GetAllSprite(SpriteAtlas spriteAtlas){
        //spriteの空の配列を作成、サイズはAtlasに含まれるSpriteの数
        Sprite[] spriteArray = new Sprite[spriteAtlas.spriteCount];

        //spriteArrayに全Spriteを設定
        spriteAtlas.GetSprites(spriteArray);
        foreach (var sprite in spriteArray) {
            yield return sprite;
        }
    }
}

AtlasImageEditor.csはEditorという名前のフォルダを作ってその中に作成してください.

# まとめ

AtlasImage.csの方は最小限のコードしかしれていないので,今後拡張していくつもりです.

AssetBundleの仕様変更がきたときに改修かけると思います.

もっと良い方法あれば教えていただけると嬉しいです!

# 参考
http://kan-kikuchi.hatenablog.com/entry/SpriteAtlas

5
4
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
4