kotonagaのブログ

Unityとか

Unityで2DRPGを作ってみる 4日目

忙しくて長らくUnityを触れていなかったのですが、前の記事から半年経ってるので何か書かねばと思い立ちました。
3日目まではUnity4.6で作っていたのですが、昨日Unityのサイトを見ていたら、Unity5.0.2ってのが出てたので早速ダウンロードして使ってみました。

4.6との違い

正直まだ良くわかっていませんw
ただ、1日目に作ったクラス kotonaga.hatenablog.com
がエラー出まくりになりましたw

問題の確認

UnityEditorInternal関係のクラスが殆ど(全部?)obsoleteになっていました。
代わりにUnityEditor.Animationsを使えってことなので、それを使うことにしました。

プログラムの変更

何か色々苦労したのでもはや覚えていないのですが、UnityEditor.Animationsの中のクラスが、前のUnityEditorInternalのクラスと名前が同じでも使い方が違ったり、メソッドが異なる等で結構書き換えました。

こんな感じ

/*
The MIT License (MIT)

Copyright (c) 2015 Kotonaga

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

#if UNITY_EDITOR
using UnityEngine;
using UnityEditor;
using UnityEditor.Animations;

[ExecuteInEditMode()]
public class Character : MonoBehaviour
{
    /// 
    /// ウディタ用キャラクタ画像素材
    /// 
    public Texture2D m_image;
    /// 
    ///  1セルの幅
    /// 
    public int m_cropWidth;
    /// 
    /// 1セルの高さ
    /// 
    public int m_cropHeight;
    
    void Awake ()
    {
        if(this.m_image==null)
            return;
        
        // スプライトレンダラの取得
        SpriteRenderer spriteRenderer = gameObject.GetComponent ();
        // アニメータの取得
        Animator animator = gameObject.GetComponent ();
        // ぼやけを除去
        this.m_image.filterMode = FilterMode.Point;
        
        // 15フレームに一回アニメーションする
        float frameLength = 15f / 60f;
        // 画像は横にアニメーションする
        int frameCount = this.m_image.width / this.m_cropWidth;
        // 画像は縦に種類が並んでいる
        int stateCount = this.m_image.height / this.m_cropHeight;
        bool extendedCharaChipSet = false;
        
        // ただし、8方向のチップセットが存在するので、それに対処する
        if(frameCount==6 || frameCount==10){
            frameCount >>= 1;
            stateCount <<= 1;
            extendedCharaChipSet = true;
        }
        
        // スプライト配列の作成
        Sprite[,] sprites = new Sprite[stateCount, frameCount];

        // Blend Tree 設定用のVector2配列の準備
        Vector2[] positions = {
            new Vector2(0, 1),
            new Vector2(1, 0),
            new Vector2(-1, 0),
            new Vector2(0, -1),
            new Vector2(1, 1),
            new Vector2(-1, 1),
            new Vector2(1, -1),
            new Vector2(-1, -1),
        };
        
        // アニメータコントローラの作成
        AnimatorController animatorController = new AnimatorController ();
        // 名前はテクスチャ名にする
        animatorController.name = this.m_image.name;
        //向きと状態指定用のパラメータを追加
        animatorController.AddParameter ("DirectionX", AnimatorControllerParameterType.Float);
        animatorController.AddParameter ("DirectionY", AnimatorControllerParameterType.Float);
        animatorController.AddParameter ("Walking", AnimatorControllerParameterType.Bool);
        
        // アニメータコントローラにベースレイヤを追加
        animatorController.AddLayer ("Base");
        // 歩き状態を追加する
        BlendTree walkBlendTree;
        AnimatorState walkState =  animatorController.CreateBlendTreeInController("Walk", out walkBlendTree);
        walkBlendTree.name = "Blend Tree";
        
        // 歩き状態は歩く方向によってアニメーションが変化する
        walkBlendTree.blendType = BlendTreeType.SimpleDirectional2D;
        walkBlendTree.blendParameter = "DirectionX";
        walkBlendTree.blendParameterY = "DirectionY";
        
        // 状態の数だけループ
        for (int y=0; y=(stateCount>>1)){
                offsetX = frameCount;
                offsetY = -(stateCount>>1);
            }
            // スプライトの切り出しと普通のアニメーションの作成
            for (int x=0; x1枚目とアニメーションする
            for (int x=1; x>=0; x--)
            {
                int index = frameCount + 1 -x;
                keyFrames [index] = new ObjectReferenceKeyframe{time=index*frameLength, value=sprites[y,x]};
            }
            
            // アニメーションクリップの作成
            // 名前は状態のインデックスにする
            AnimationClip clip = new AnimationClip ();
            clip.name = y.ToString ();
            // はみ出た部分は消す
            clip.wrapMode = WrapMode.Clamp;
            // カーブの作成
            EditorCurveBinding curveBinding = new EditorCurveBinding ();
            // ファイルは存在しない
            curveBinding.path = string.Empty;
            // スプライトをアニメーションするのでtypeにSpriteRenderer
            // propertyNameにはm_Spriteを指定
            curveBinding.type = typeof(SpriteRenderer);
            curveBinding.propertyName = "m_Sprite";
            // クリップとカーブにキーフレームをバインド
            AnimationUtility.SetObjectReferenceCurve (clip, curveBinding, keyFrames);
            // LoopTimeが直接設定出来ないので一旦シリアライズする
            SerializedObject serializedClip = new SerializedObject (clip);
            // アニメーションクリップ設定の取り出し
            AnimationClipSettings animationClipSettings = new AnimationClipSettings (serializedClip.FindProperty ("m_AnimationClipSettings"));
            // LoopTimeを有効にする
            animationClipSettings.LoopTime = true;
            // 設定を書き戻す
            serializedClip.ApplyModifiedProperties ();
            // 状態を歩き状態のブレンドツリーに追加
            walkBlendTree.AddChild (clip, positions[y]);
        }
        
        // 止まり状態を追加する
        BlendTree waitBlendTree;
        AnimatorState waitState =  animatorController.CreateBlendTreeInController("Wait", out waitBlendTree);
        waitBlendTree.name = "Blend Tree";
        
        // 止まり状態はアニメーションしないが
        // 方向によってスプライトが変化する
        waitBlendTree.blendType = BlendTreeType.SimpleDirectional2D;
        waitBlendTree.blendParameter = "DirectionX";
        waitBlendTree.blendParameterY = "DirectionY";
        
        // 状態の数だけループ
        for (int i=0; i歩きのトランジションを作成
        AnimatorStateTransition waitToWalk = waitState.AddTransition(walkState);
        // Walkingフラグがtrueの時
        waitToWalk.AddCondition(AnimatorConditionMode.If,0,"Walking");
        
        // 歩き->止まりのトランジションを作成
        AnimatorStateTransition walkToWait = walkState.AddTransition(waitState);
        // Walkingフラグがfalseの時
        walkToWait.AddCondition(AnimatorConditionMode.IfNot,0,"Walking");
        
        // アニメータコントローラに設定
        animator.runtimeAnimatorController = (animatorController as RuntimeAnimatorController);
        
        // とりあえず0,0のスプライトをデフォルトにセット
        spriteRenderer.sprite = sprites[0,0];
    }
}

/// 
/// AnimationClipSettingsの設定用クラス
/// 
class AnimationClipSettings
{
    SerializedProperty m_property;
    
    public AnimationClipSettings (SerializedProperty prop)
    {
        this.m_property = prop;
    }
    
    private SerializedProperty Get (string property)
    {
        return this.m_property.FindPropertyRelative (property);
    }
    
    public bool LoopTime
    {
        get
        {
            return this.Get ("m_LoopTime").boolValue;
        }
        set
        {
            this.Get ("m_LoopTime").boolValue = value;
        }
    }
}
#endif

まとめ

変更点はまだ良く分かっていません。
とりあえずこのクラスだけ直したら、他は前のままで動くようになりました。
フィールドマップを早く実装したい所ですが、まだ出来ていません…