Unityでキャラクターを動かす方法

Unityでキャラクターアニメーションの表示を行い、キーボード操作でアニメーションを変化させるスクリプトを組み込んでみます。
今回使用する環境は以下の通りです。

旧バージョン SS6Player for Unity v1系の組み込み方法については、「Unityでキャラクターを動かす方法(v1.0.36)」をご確認ください。

目次

作成手順

アニメーションデータ準備

今回使用するキャラクターアニメーションテンプレートを下記ページより ダウンロードします。

「ダウンロード」を押すと、OPTPiX_SpriteStudio_Animation_Template_20180220.zip というファイルがダウンロードされるので展開します。

今回は、展開したファイルを
E:¥SpriteStudioData¥OPTPiX_SpriteStudio_Animation_Template
に保存して説明を行います。

新しくプロジェクトを作成

Unityを開き、Fileメニューから「New Project」を選択し、新しくプロジェクトを作成します。SS6Player for Unity をセッティング
SS6Player for Unity をプロジェクトに加えます。
詳しい方法は「Unityにアニメーションを表示する」を参照してください。

フォルダを準備

1. ファルダー作成

キャラクターコントロールに使用するデータ、スクリプトを入れるフォルダーを設けます。
Projectウィンドウを右クリックし、コンテキストメニューの「Create」→「Folder」でフォルダーを作成します。

今回は Assets フォルダーの下に Sample という名称でフォルダーを作成しました。

2. サブフォルダー作成

このフォルダに、スクリプトを納めるフォルダーと、リソースを納めるフォルダーを作成します。
今回は以下の名前のフォルダーを作成しています。

  • Resources
    リソースを納めます
  • Script
    スクリプトを納めます

リソースを納めるフォルダーの綴りに気を付けましょう。「Resources」に格納されているデータを参照する仕様になっているためです。
フォルダー名に誤りがあるとインポートしたアニメーションを参照できず、NULLエラーが発生します。

sspjインポート

再生したいsspjをインポートします。
インポートの詳しい手順は「Unityにアニメーションを表示する」の下記項目を参照してください

1. インポートするフォルダー指定

インポート先は、先程準備した
Assets/Sample/Resources
を指定します。

2. ツールダイアログを開きインポート準備

Tools > SpriteStudio6 > Importer を選択して
Import Mode 「SpriteStudio6 Player」を選択します。

3. SpriteStudioのデータをインポート

「Import」を押して、指定するファイルは前項でダウンロードしたサンプル内

E:¥SpriteStudioData¥OPTPiX_SpriteStudio_Animation_Template¥character_sample1

フォルダーにある character_sample1.sspj を指定します。

インポートに成功すると
character_sample1
が登録されます。

これでアニメーションデータの準備が完了しました。

スクリプト作成

次にキャラクターを制御するスクリプトを準備します。

1. スクリプト作成

ProjectウィンドウのScriptフォルダ上で右クリックし、コンテキストメニューの「Create」→「C# Script」でスクリプトを作成します。

2. ファイル名設定

今回は「CharacterControl」という名称のスクリプトを作成しました。

3. スクリプト記載

Scriptファイルを開いてスクリプトを記載します。

準備したスクリプトにキャラクター制御について記載します。
今回使用したスクリプトは「スクリプト解説」の項に掲載しています。
スクリプトについては、コピーして貼り付けていただくだけで各種設定可能になります、準備してから次の項目へ進んでください。

これでスクリプトの準備が完了しました。

キャラクター制御の準備

1. GameObject 作成

Hierarchy ウィンドウのコンテキストメニューを開いて、Create Emptyを選択、空のGameObjectを作成します。

2. 名称変更

今回は名前を分かりやすくするため、クリックして名称を「CharacterControlObject 」に変えます。

3. スクリプトセット

Assets/Sample/Scriptを開き、先ほど作成した CharacterControl スクリプトをドラッグして、Hierarchy ウィンドウ の CharacterControlObject へドロップします。

設定方法は、ドラッグ&ドロップ以外に下記の方法もあります

  1. Hierarchy ウィンドウ の CharacterControlObject をクリック
  2. Inspectorへ表示された Add Component をクリック
  3. 開いたプルダウンメニューから Scripts を選択
  4. CharacterControl を選択

4. アニメーション数の設定

スクリプトが設定されると Inspector に「Size」を設定する項目が追加されます。
これはスクリプトで使用するssaeデータを設定する枠数を示します。
今回は 1つ使用しますので、「1」と入力してください。

5. Select Object ウィンドウを開く

「Element 0」の欄に使用するアニメーションの prefab を設定します。
Element 0 欄の端にある を押して Select Object ウィンドウを開いてください。

6. アニメーションのprefabを設定

使用する character_template_3head を選択してウィンドウを閉じます。

7. 設定確認

下記のように選択した prefab が設定されていたら完了です。

prefab の設定は PrefabAnimation にある prefab を直接 ドラッグ&ドロップすることで設定も可能です。

これでキャラクター制御の準備が完了しました。

カメラの確認

SS6Player for Unity をセッティングする際に、アニメーションが表示されるカメラ調整済の場合は、本項目の手順はスキップしてください。

1. Main Camera を選択

Hierarchy ウィンドウにて Main Camera を選択してください。

2. Inspector を確認

初期状態は下記のようになっていると思います。
このままではアニメーションが見えない状態のため調整します。

3. Transform の Position 変更

Position の Z を今回は -600 に設定しました。
これでアニメーション再生時に表示されるようになります。

これでカメラの準備が完了しました。

キャラクターを動かす

インポートしたssaeとスクリプトが動作するか確認します。

1. 作成したものを動かします。

▶を押して動作させます。

2. スタート

スクリーン中央に「PRESS SPACE」と表示されます。
スペースキーを押してください。

3. キャラクター表示

中央にキャラクターが表示されます。

4. 動かします

矢印キーで左右に走って移動。
Zキーでアタックのアニメーションが再生されます。

5. 完了

動作を確認して完了です。
スクリプトを変更して、他のアニメーションを再生することも可能です。
下記のスクリプト解説を参考に試してみてください。

スクリプト解説

今回組み込んだスクリプトについて解説します。
スクリプトについては、できるだけシンプルに記述しています。
SpriteStudio のデータを組み込み、制御する際の参考にしていただけると幸いです。

CharacterControl.cs

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

public class CharacterControl : MonoBehaviour {

    // 再生アニメーションのResourcesフォルダ内のサブパス
    [SerializeField]
    public Object[] AnimationList;

    // 再生アニメーション指定用 
    private enum AnimationPattern : int
    {
        Wait = 33,      // 待機
        Attack = 1,     // 攻撃 
        Run = 24,       // 走り 
        Count
    }

    // キャラクター管理用 
    private GameObject m_goCharacter = null;
    private GameObject m_goCharPos = null;
    private Vector3 m_vecCharacterPos;      // キャラクター位置 
    private Vector3 m_vecCharacterScale;    // キャラクタースケール 

    // 処理ステップ用 
    private enum Step : int
    {
        Init = 0,   // 初期化 
        Title,      // タイトル 
        Wait,       // 待機 
        Move,       // 移動 
        Attack,     // 攻撃
        End
    }

    // 処理ステップ管理用 
    private Step m_Step = Step.Init;

    // 汎用
    // いろいろ使いまわす用変数
    private int m_Count = 0;
    private bool m_SW = true;

    // Use this for initialization
    void Start () {

        // キャラクターパラメータ関連を設定 

        // 座標設定 
        m_vecCharacterPos.x = 0.0f;
        m_vecCharacterPos.y = -240.0f;
        m_vecCharacterPos.z = 0.0f;

        // スケール設定 
        m_vecCharacterScale.x = 0.5f;
        m_vecCharacterScale.y = 0.5f;
        m_vecCharacterScale.z = 1.0f;
    }

    // Update is called once per frame
    void Update () {
        switch(m_Step)
        {
            // 初期化
            case Step.Init:
                m_Count = 0;
                m_SW = true;
                m_Step = Step.Title;
                break;
            // タイトル
            case Step.Title:
                if (++m_Count > 90) {
                    m_SW = !m_SW;
                    m_Count = 0;
                }
                if( Input.GetKeyDown(KeyCode.Space) == true ) {
                    AnimationStart();   // アニメーション開始処理(設定)
                    m_Step = Step.Wait;
                }
                break;
            // 待機
            case Step.Wait:
                if (Input.GetKeyDown(KeyCode.Z) == true)        // 攻撃 
                {
                    // 攻撃に変更 
                    AnimationChange(AnimationPattern.Attack);
                    m_Step = Step.Attack;
                }
                else if (Input.GetKeyDown(KeyCode.LeftArrow) == true)   // 左移動 
                {
                    if (m_vecCharacterScale.x < 0)
                        m_vecCharacterScale.x *= -1;    // 左向きにします
                    m_goCharPos.transform.localScale = m_vecCharacterScale; // 向き設定 
                    // 走りに変更 
                    AnimationChange(AnimationPattern.Run);
                    m_Step = Step.Move;
                }
                else if (Input.GetKeyDown(KeyCode.RightArrow) == true)  // 右移動 
                {
                    if (m_vecCharacterScale.x > 0)
                        m_vecCharacterScale.x *= -1;    // 右向きにします
                    m_goCharPos.transform.localScale = m_vecCharacterScale; // 向き設定 
                    // 走りに変更 
                    AnimationChange(AnimationPattern.Run);
                    m_Step = Step.Move;
                }
                break;
            // 移動 
            case Step.Move:
                if (Input.GetKey(KeyCode.LeftArrow) == true)   // 左移動 
                {
                    if(m_vecCharacterPos.x > -560.0f)
                        m_vecCharacterPos.x -= 5.0f;
                }
                else if (Input.GetKey(KeyCode.RightArrow) == true)  // 右移動 
                {
                    if (m_vecCharacterPos.x < 560.0f)
                        m_vecCharacterPos.x += 5.0f;
                }
                else
                {
                    // 待機に変更 
                    AnimationChange(AnimationPattern.Wait);
                    m_Step = Step.Wait;
                }
                m_goCharPos.transform.localPosition = m_vecCharacterPos;    // 座標反映 
                break;
            // 攻撃中 
            case Step.Attack:
                if(IsAnimationPlay() == false)
                {
                    // 待機に変更 
                    AnimationChange(AnimationPattern.Wait);
                    m_Step = Step.Wait;
                }
                break;
            default:
                break;
        }
	}

    private void OnGUI()
    {
        // GUI変更
        GUIStyle guiStyle = new GUIStyle();
        GUIStyleState styleState = new GUIStyleState();

        switch (m_Step)
        {
            // タイトル
            case Step.Title:
                if (m_SW == true)
                {
                    styleState.textColor = Color.black; // 文字色 黒 
                    guiStyle.normal = styleState;       // スタイルの設定。
                    GUI.Label(new Rect(420, 180, 100, 50), "PRESS SPACE", guiStyle);
                }
                break;
            default:
                break;
        }
    }

    // アニメーション開始 
    private void AnimationStart()
    {
        Script_SpriteStudio6_Root scriptRoot = null;    // SpriteStudio Anime を操作するためのクラス
        int listLength = AnimationList.Length;

        // すでにアニメーション生成済 or リソース設定無い場合はreturn
        if (m_goCharacter != null || listLength<1)
            return;

        // 再生するリソース名をリストから取得して再生する
        Object resourceObject = AnimationList[0];
        if (resourceObject != null)
        {
            // アニメーションを実体化
            m_goCharacter = Instantiate(resourceObject, Vector3.zero, Quaternion.identity) as GameObject;
            if (m_goCharacter != null)
            {
                scriptRoot = Script_SpriteStudio6_Root.Parts.RootGet(m_goCharacter);
                if (scriptRoot != null)
                {
                    // 座標設定するためのGameObject作成
                    m_goCharPos = new GameObject();
                    if (m_goCharPos == null)
                    {
                        // 作成できないケース対応 
                        Destroy(m_goCharacter);
                        m_goCharacter = null;
                    }
                    else
                    {
                        // Object名変更 
                        m_goCharPos.name = "Comipo";

                        // 座標設定 
                        m_goCharacter.transform.parent = m_goCharPos.transform;

                        // 自分の子に移動して座標を設定
                        m_goCharPos.transform.parent = this.transform;
                        m_goCharPos.transform.localPosition = m_vecCharacterPos;
                        m_goCharPos.transform.localRotation = Quaternion.identity;
                        m_goCharPos.transform.localScale = m_vecCharacterScale;

                        //アニメーション再生
                        AnimationChange(AnimationPattern.Wait);
                    }
                }
            }
        }
    }

    // アニメーション 再生/変更 
    private void AnimationChange(AnimationPattern pattern)
    {
        Script_SpriteStudio6_Root scriptRoot = null;    // SpriteStudio Anime を操作するためのクラス
        int iTimesPlaey = 0;

        if (m_goCharacter == null)
            return;

        scriptRoot = Script_SpriteStudio6_Root.Parts.RootGet(m_goCharacter);
        if (scriptRoot != null)
        {
            switch (pattern)
            {
                case AnimationPattern.Wait:
                    iTimesPlaey = 0;    // ループ再生 
                    break;
                case AnimationPattern.Attack:
                    iTimesPlaey = 1;    // 1回だけ再生 
                    break;
                case AnimationPattern.Run:
                    iTimesPlaey = 0;    // ループ再生 
                    break;
                default:
                    break;
            }
            scriptRoot.AnimationPlay(-1, (int)pattern, iTimesPlaey);
        }
    }

    // アニメーションが再生中か停止中(エラー含)か取得します
    private bool IsAnimationPlay()
    {
        bool ret = false;

        Script_SpriteStudio6_Root scriptRoot = null;    // SpriteStudio Anime を操作するためのクラス

        if (m_goCharacter != null)
        {
            scriptRoot = Script_SpriteStudio6_Root.Parts.RootGet(m_goCharacter);
            if (scriptRoot != null)
            {
                // 再生回数を取得して、プレイ終了かを判断します
                int Remain = scriptRoot.PlayTimesGetRemain(0);
                if (Remain >= 0)
                    ret = true;
            }
        }

        return ret;
    }

}

関数解説

  • void Start ()
    キャラクターに関連するパラメータの初期化を行っています。
  • void Update ()
    毎フレーム行われる処理を m_Step の指定で処理が変化するように組んでいます。
  • void OnGUI()
    文字表示を行うために使用しています。
  • void AnimationStart()
    アニメーションを開始する処理をまとめています。
    プログラム上から、アニメーションのprefab を読み込んで、GameObjectを生成、座標指定しての表示を行っています。
  • void AnimationChange(AnimationPattern pattern)
    アニメーションパターンの切り替えを行っています。
  • bool IsAnimationPlay()
    アニメーションが再生中かどうか取得します。
    特定のアニメーションで終了を取得するために設けました。

関連ページ

SS6Player For Unity
 最新版、質問・要望は GitHubへ