hildsoftのコード置き場

プログラム関連で調べたことやコードの保管場所です

UnityでuGUIを使ったUIに3Dオブジェクトを表示させたい

UnityでuGUIを使ったUIに3Dオブジェクトを表示させたい

f:id:hildsoft:20180110045224p:plain

検証環境

Unity:2017.2.0f3

Canvasの設定

CanvasにはRender Modeというプロパティがあります。

f:id:hildsoft:20180110031805p:plain

  • Screen Space - Overlay
  • Screen Space - Camera
  • World Space

Screen Space - Overlay

f:id:hildsoft:20180110033127p:plain

Overlayは被せるとか覆うという意味があります。

文字通り、カメラで映し出した映像の上にCanvasの情報を上書きします。

UIは通常画面の一番手前に表示され、他のもので隠されることは無いためこの使い方が一般的です。


Screen Space - Camera

f:id:hildsoft:20180110033356p:plain

この設定は、カメラから一定の位置にCanvasを配置するものです。

OverlayではUIが最前面に表示されるので3Dオブジェクトを配置することができません。

そこで、UI上でも3Dオブジェクトを使う場合は、UIをScene内に入れてしまいます。

今回はこの設定でUI上に3Dオブジェクトを表示させます。


World Space

f:id:hildsoft:20180110034327p:plain

せっかくなので、ついでにもう一つの設定も軽く見ておきましょう。

この設定は文字通り、ワールドスペース内にCanvasをオブジェクトとして配置します。

実際に空間内に存在するので、カメラを移動してもCanvasは動かないため、空間に固定されたものになります。

使ったことは無いですがVRなどで使用されるのかな?

ゲーム内でキャラクターが操作するパネルとして使用することも可能だと思います。


UI用のカメラを作成する

f:id:hildsoft:20180110033356p:plain

この例にもあるように、同じカメラを使用してしまうと位置関係がややこしくなったり、ボタンが隠れてしまったりするのでUI専用のカメラを用意します。

f:id:hildsoft:20180110035341p:plain

Hierarchyで右クリックして、Cameraを追加します。

ここでは「UI Camera」としておきます。

f:id:hildsoft:20180110035637p:plain

Cameraを追加するとAudio Listenerコンポーネントも付いてきますが、Main Cameraにもあるため、2個になってしまいます。

UIでは必要がないのと警告が出るので、これは削除します。

Canvasにカメラを設定

f:id:hildsoft:20180110040012p:plain

これでUI Cameraを移動してもCanvasは自動でUI Cameraに付いてきて、UI Cameraの視界内に入る3Dオブジェクトを描画することができます。


映したいものと映したくないものを分ける

UI用のカメラが3Dオブジェクトを映せるようになると一つ問題が出てきます。

UIだけに映したくてもMainカメラの視界内にUIのオブジェクトが存在すると表示されてしまいます。逆もしかりです。

そこで使用するのがレイヤー機能です。

f:id:hildsoft:20180110041700p:plain

レイヤーはオブジェクトを選択して、Inspectprから変更可能です。

f:id:hildsoft:20180110041854p:plain

0~7までの8個はシステムに予約されていますが、8~31までの24個はユーザーが自由に使用できます。

UI用のカメラに表示したい物を扱うレイヤーを追加します。ここでは「UI 3D Object」とします。


レイヤーを追加しただけでは何も変化はありません。

カメラ側の設定で、何を映すかを指定する必要があります。

f:id:hildsoft:20180110042456p:plain

メインカメラの設定ではUIに関する物を映さない様にCulling Maskから「UI」と「UI 3D Object」を外します。

f:id:hildsoft:20180110042625p:plain

UIカメラの設定ではUIに関する物を映す様にCulling Maskに「UI」と「UI 3D Object」をチェックします。

必要なら、Lightの設定も同様に変更してください。


カメラの描画順

このままではMain Camera描画後に、UI Cameraの映したものを上書きしてしまいます。

なので、あとから描画するUI Cameraの方は必要なところだけを上書きするようにします。

f:id:hildsoft:20180110043215p:plain

Clear FlagsをDepth onlyにすると、必要な個所だけが上書きで更新されます。

また、Depthの値がMain Cameraより大きな値になっていることを確認してください。(初期状態では問題無いと思います)


完成するとこんな感じに

f:id:hildsoft:20180110045224p:plain

作成した3Dオブジェクトは、紐づくUIの子要素にしておくことでカメラの回転やUI要素の移動時にも対応可能になります。

ただし、移動の際はパースの問題が出るため、カメラのProjectionを「Orthographic」にしておいた方がいいかもしれません

Arbor2を使ってみよう その6 ParameterContainer

前回の記事はこちら

code.hildsoft.com

検証バージョン

Unity 2017.1.1p1
Arbor 2.1.7

ParameterContainer

ParameterContainerの役割

ParameterContainerは複数のArborFSMから参照、更新するための変数を保持するためのコンポーネントです。

複数作成することもできますが、グローバル変数のようなものなので、無計画に増やしすぎると管理しづらくなるので注意してください。


f:id:hildsoft:20170929154910j:plain

GameObjectに追加して作成します。


f:id:hildsoft:20170929154919j:plain

空のGameObjectと一緒に作成することもできます。


パラメータの追加方法

f:id:hildsoft:20170929170140j:plain

右上にある+をクリックしてメニューを出し、追加したいクラスを選択するだけです。


パラメータの種類

f:id:hildsoft:20170929170319j:plain

よく使うクラスは一通りそろっているので、自分で拡張する必要は恐らく無いと思います。

Quaternionは内部ではw,x,y,zの4変数で持っている物を変換してx,y,zのオイラー回転で表示しているので直接入力すると若干ズレることがあります。

基本的にQuaternionは手作業で修正するものではないので、Arborやスクリプトから直接Quaternionとして操作した方が良いでしょう。


GlobalParameterContainerの役割

GlobalParameterContainerは、ParameterContainerをシーンを跨いで使用したいときに使います。

ParameterContainerと同じように変数を持つのではなく、ParameterContainerを管理する感じです。


f:id:hildsoft:20170929161747j:plain

まず、ParameterContainerをPrefab化する必要があります。


f:id:hildsoft:20170929161804j:plain

そして、Prefab化したものを登録します。


f:id:hildsoft:20170929162635j:plain

シーン起動時に存在しなければ自動で作成され、存在していれば何も起こりません。

複数のシーンで使用するものは初期化のタイミングや重複などに気を付けないといけないのですが、Prefab化してGlobalParameterContainerを使用するとその煩わしさを回避できます。


ParameterContainerの実際の使い方などは、また別途記事を作成したいと思います。

Arbor2を使ってみよう その5 Calculator

前回の記事はこちら

code.hildsoft.com

検証バージョン

Unity 2017.1.1p1
Arbor 2.1.7

Calculator

Calculatorの役割

f:id:hildsoft:20170925033442j:plain

Calculatorは変数を計算したり変換したりする時に使用します。


Behaviourの設定と接続

f:id:hildsoft:20170925034002j:plain

BehaviourでCalculatorの値を使う場合は、▼をクリックしてメニューを出してから「Calculator」を選択します。


f:id:hildsoft:20170925034321j:plain

変数のタイプをCalculatorにすると、Calculatorの出力からドラッグ&ドロップで紐づけすることができます。


f:id:hildsoft:20170925041250j:plain

接続することのできる入出力は、同じ型(クラス)でなければいけません。

変数のタイプは、Calculatorの欄にカーソルを合わせると、型(クラス)情報が表示されます。


Calculatorの出力値

f:id:hildsoft:20170925040410j:plain

一部の型のCalculatorは実行時にどのような値が出力されているのかを目視確認できます。


Calculatorの実行タイミング

CalculatorはBehaviourが必要としたタイミングで初めて計算されます。

また、キャッシュを持っているため、Calculatorに渡される入力値に変更がない場合は再計算されずキャッシュされた同じ値を返します。


Calculatorの用途

Calculatorは基本的な物しか用意されていません。

RPGでのダメージ計算や自キャラの一番近くの敵を探すなど、作るゲームで必要なものを作成していくことになります。


無いものは作る

Behaviourもそうですが、Arborは基本的な機能を提供し、必要な物を自前で作るという設計思想のようです。

新しくBehaviourやCalculatorを作成するにはこちらを参照してください。

http://arbor.caitsithware.com/manual/customize/

この辺を上手く作るにはプログラマが必要になると思います。


code.hildsoft.com

Arbor2を使ってみよう その4 処理の流れ

前回の記事はこちら

code.hildsoft.com

検証バージョン

Unity 2017.1.1p1
Arbor 2.1.7

処理の流れ

処理実行順

f:id:hildsoft:20170830043703j:plain

Arbor2を使ってみよう その1 概要 - hildsoftのコード置き場

で紹介した簡単なパターンから見ていきます。


f:id:hildsoft:20170919095504j:plain

Arbor2の処理は開始ステートから始まります。

Behaviourはステートごとに上から順に全て実行されます。

ステートは有効になった時に1度だけ実行されます。 そのステート中であれば常に実行されるというわけではないので注意してください。

(Tween系は更新処理があるので、UpdateやFixedUpdate内での時間経過処理が実行されますが、開始処理は有効になった時のみです)


f:id:hildsoft:20170919202253j:plain

ただし、Transition系(ステートを変更するもの)は、Updateメソッドを持っているため毎フレーム実行されています。

これはUnityのUpdateと同じ仕様で実行順は不確定ですので、並び順の通りに処理されることを期待してはいけません

BehaviourのUpdateが実行された時に有効であれば移動先は上書きされてしまいます。 (Behaviourの条件が満たされている中で、最後に呼ばれたものに移動します)

なので、左右両方のキーを押した状態だと、どちらが有効になるかは保証されていません。


ステート更新のタイミング

ステートの変更はUnityのLateUpdateメソッド呼び出し時に更新されます。

ステートが変更されたときに実行されるBehaviourの処理もここで実行されます。

上記のFSMでは入力チェックと移動が分かれているため、キーを押しっぱなしにしても1フレームおきに移動します。

その結果、カクカクとした動きになってしまいます。

Unityのイベント呼び出しの順番はこちらを参照してください。
Unity - Manual: Execution Order of Event Functions


Immediate Transition

f:id:hildsoft:20170919101925j:plain

Transition系には、追加の設定があり、名前(初期値:Next State)の変更、矢印の色変更ができます。

また、処理に関わる重要な設定に、Immediate Transitionがあります。

このチェックがオンの状態だとLateUpdateを待たず、すぐにステートが切り替わって次のステートの処理も引き続き実行します。


常駐ステート

f:id:hildsoft:20170919204347j:plain

常駐ステートは、常に有効になっているステートになります。

ここでも注意しないといけないのが、ステートは1度だけ実行されることです。

Updateを持たないBehaviourは起動時に一度だけ実行されて、毎フレーム呼ばれるわけではありません。


処理の順番

f:id:hildsoft:20170919205414j:plain

画面の左側のTransitionはImmediate Transitionをオンに、右側をオフにしています。


f:id:hildsoft:20170919205348j:plain

現在のステートと、常駐ステートにKey Transitionで同じキーを監視しているBehaviourがあります。

右キーを押したとき、Updateが早く呼ばれた方のBehaviourのステートへ変更されます。


f:id:hildsoft:20170919210924j:plain

現在のステートにあるKey Transitionが先にUpdateを呼び出されたとします。

このとき、Immediate Transitionの設定のため、Updateでステートが更新されます。

通常はLateUpdateで実行されるステートの変更呼び出しもUpdate内で呼ばれることになります。

また、Go To Transitionでステート変更が予約されています。


f:id:hildsoft:20170919210932j:plain

全てのオブジェクトのUpdateが呼び出され、最後にLateUpdateが呼び出されます。

Go To Transitionで予約されていたステートに更新されるため、先ほどのステートまで戻ります。

Key TransitionはUpdateで処理を待つだけなので、実質なにも処理は行われません。

そして次のフレームのUpdateで再びキー入力を待ち受けます。


2017/09/19 21:18
仕様を誤解していましたので、大幅に書きなおしました。申し訳ありません。

code.hildsoft.com

Arbor2を使ってみよう その3 基本操作

前回の記事はこちら

code.hildsoft.com

検証バージョン

Unity 2017.1.0p4
Arbor 2.1.6

ArborFSM Componentの追加

まずはArborFSM Componentを追加することから始まります。

操作はUnity標準のコンポーネントと同じです。

他にも方法はありますが、この2パターンが多いかと思います。

f:id:hildsoft:20170903004136j:plain

Hierarchyから追加したいオブジェクトを右クリックしてArbor>ArborFSM


f:id:hildsoft:20170903004359j:plain

追加したいオブジェクトをInspectorに表示させて、Add ComponentからArbor>ArborFSM


ArborFSM Componentを追加したあと、InspectorにあるOpenEditorでグラフを開きます。

f:id:hildsoft:20170903005927j:plain


Arbor Editor

ステートの追加

f:id:hildsoft:20170903010727j:plain

Arbor Editorを開いた何もない状態です。


f:id:hildsoft:20170903010909j:plain

まずはステートを追加します。

ステートには、ステート、常駐ステートの2種類があります。

ステートのうち一つは開始ステートのフラグが設定されます。

シーンが開始されると、開始ステートから処理が始まります。


f:id:hildsoft:20170903011728j:plain

ステートの操作はギアのアイコンをクリックして出るメニューで行います。

開始ステートに設定をクリックすると、メニューを出したステートが開始ステートに設定されます。
常駐ステートは開始ステートにすることはできません。


Behaviourの追加

ステートにはBehaviourを追加できます。

f:id:hildsoft:20170912023243j:plain

ギアをクリックしてメニューを出し、挙動追加をクリックします。


f:id:hildsoft:20170912024117j:plain

追加メニューが表示されますので、選択します。


f:id:hildsoft:20170912024157j:plain

今回はStateAとStateBにKeyDownTransitionを追加してみました。


Behaviourの接続

ステートを変更するBehaviourにはNext Stateボタンがあります。

f:id:hildsoft:20170912024750j:plain

このボタンをドラッグドロップで別のステートに接続することで、次の移動先が決まっていきます。

どのような条件で移動するかはBehaviourに依りますが、ここでの説明は割愛してもう少し先の回で説明していく予定です。


Calculatorの追加

Calculatorはステートと同様にグラフ上で単独に作成します。

f:id:hildsoft:20170912025727j:plain

右クリックメニューから演算ノード作成を選択します。


f:id:hildsoft:20170912031703j:plain

追加メニューが表示されますので、選択します。


f:id:hildsoft:20170912031137j:plain

今回はTransform.Getを追加してみました。

CalculatorもBehaviourと同じく沢山ありますが、ここでの説明は割愛します。

また接続方法も処理の流れを含めて次回解説します。 (注:先に解説するものがあったので、次々回になります)


code.hildsoft.com

Arbor2を使ってみよう その2 主要な構成部品

前回の記事はこちら

code.hildsoft.com

検証バージョン

Unity 2017.1.0p4
Arbor 2.1.6

Arbor2を構成する主なパーツ

Arbor2は大きく分けて

  • Component
  • Behaviour
  • Calculator

の3つで構成されています。


Component

ComponentはUnityでGameObjectに対して付加します。

f:id:hildsoft:20170831071034j:plain

ArborFSM:ステート管理するオブジェクトに対して1つ追加します。

ParameterContainer GlobalParameterContainer:今は変数を保存する物という程度の認識でokです。

AgentControllerは少し特殊な用途なので、ここでの説明は割愛します。


Behaviour

BehaviourはArborエディタでステートに対して付加します。

f:id:hildsoft:20170831073152j:plain

これは沢山ありますが、大きく2つに分類できます。

処理を行うだけの物と、ステートを変更するものです。

f:id:hildsoft:20170831072153j:plain

ステートを変更するものは、条件を満たしたときのみステートを変更します。

Behaviourは、よく行う処理をFSMの中で記述できるようにしたものです。

オブジェクトの大きさや位置を変更したり、音やアニメーションを制御したり、ステートが変わるタイミングで用いられる処理が用意されています。

もちろん、自分でBehaviourスクリプトを書いて追加することも可能です。

ここでは、ステートの変更を含め、定型処理をしてくれるものとだけ覚えてもらえばokです。


Calculator

CalculatorはArborエディタ上で単独で作成し、BehaviourやCalculatorと結び付けて使用します。

f:id:hildsoft:20170831073259j:plain

これは変換するためのメソッドと理解しておけば大丈夫です。

f:id:hildsoft:20170831074609j:plain

Behaviourで使用する値を作ったり、他から参照したりするために橋渡しをすることができます。

値を受け取ったり渡したりできるので、簡単な処理はこれを使い、複雑な処理はスクリプトを書くことになります。

BehaviourとCalculatorの使い方

どのようなBehaviourやCalculatorがあるか、作らなければいけないかを判断して使っていくことになります。

Behaviour、Calculator共に結構な数がありますが、いくつかに分類できますので、覚える量はそれほど多くありません。

こんなこと出来ないかな?と思った時に探してみて、それっぽいものが合ったらリファレンスで確認して使いながら覚えていくくらいで十分です。

code.hildsoft.com

Arbor2を使ってみよう その1 概要

Arbor2って何?

アセットストアで販売されている、有償のエディタ拡張アセットです。

これを使用することで、FSM(finite automaton machine)をグラフで操作しながらプログラムの見通しをよくすることができます。

Playmakerでも同様のことはできるようですが、Arbor2のメリットは

  • 開発者が日本人なので、日本語で質問でき、日本語ドキュメントも用意されている
  • ソースコードが開示されているので、開発終了しても独自拡張で使っていける
  • Playmakerより安い

です。

デメリットとしては

  • まだまだ使用例が少ない
  • C#を読み書きできることを前提とした設計

です。

全てFSMだけで処理を書くことは無理で、ある程度はコードを書かなければいけません。

しかし、上記のメリットにもありますが、ソースはあるので魔改造して全てFSMで片づけるシステムを社内開発することも可能だと思います。

過度にリフレクションを多用すると処理速度の面で問題があるので、Arbor2に分岐処理を殆ど任せるような書き方をしたり、処理の重いシステムだとそのままリリースは出来ないかもしれませんが、少なくともモックを高速に作り上げることができるのは大きなメリットになります。


試用版もありますので、まずは購入前に試すことをお勧めします。

また、公式サイトで説明がありますので、一度目を通すと良いかと思います。

arbor.caitsithware.com

試用版でもUnityエディタ上では制限が無く、複雑な処理を書くこともできるので、十分試した上で購入しても良いでしょう。


ちなみに、unity1weekというゲームジャムでArbor2を使い一つゲームを作ってみたので、こちらも参考になれば幸いです。

backyard.hildsoft.com


Arbor2を使ったら何が便利になるの?

まだ完全には使いこなせていないので、ごく一部の例としてご覧ください。

f:id:hildsoft:20170830035004j:plain

よく、アクションゲームでキャラクターをこのように操作しようとするとき、

public float _Speed = 10f; // 移動速度

void Update () {
  // 右移動
  if (Input.GetKey(KeyCode.RightArrow))
  {
    transform.Translate(_Speed * Time.deltaTime, 0f, 0f);
  }
  // 左移動
  else if (Input.GetKey(KeyCode.LeftArrow))
  {
    transform.Translate(-_Speed * Time.deltaTime, 0f, 0f);
  }
}

と、if文での分岐を書くことがあると思います。

これをArbor2で書くと、この2つのメソッドに切り分け

// 右移動
public void MoveRight()
{
  transform.Translate(_Speed * Time.deltaTime, 0f, 0f);
}
// 左移動
public void MoveLeft()
{
  transform.Translate(-_Speed * Time.deltaTime, 0f, 0f);
}

このようなFSMを書くだけでokです。

f:id:hildsoft:20170830043703j:plain

ここまでは単純なので、特に問題は無いでしょう。

むしろこの程度の処理であれば、最初に提示したソースコードの方がシンプルで可読性も高いです。

しかし、アクションゲームですから、いろいろなことができなければいけません。

では仕様を追加することを考えてみましょう。


コーディングだけで仕様追加に耐えられるか

  • ジャンプキーでジャンプができる
  • ジャンプができるのは地上にいるときだけ(2段ジャンプ禁止)
  • 空中では姿勢制御ができない(ジャンプしたときの横方向の速度を維持)
  • 敵からの攻撃を受けると、反対方向にn秒だけノックバック
  • ノックバック中の操作は受け付けない
  • 壁にぶつかるとそれ以上進まない

とまぁ、このくらいはどんなアクションゲームでもありがちな設定で、

  • 三角跳び
  • 減速滑空
  • 空中ダッシュ
  • ハイジャンプ
  • 移動床
  • ロープアクション
  • イベント中の操作無効or強制移動

などなど、仕様を増やせば増やすほど複雑になっていきます。

これを一つのUpdateメソッド内でif文やswitch文で処理するとバグの温床になりかねません。

勿論プログラムに慣れている人であればバグ無しで書き上げることも可能ですし、コード上でFSMを書き上げるでしょう。

ですが、書いて暫く経ったコードであれば忘れている可能性もありますし、解読に時間もかかると思います。

まして、他人が書いたコードをレビューしたり機能追加やバグ修正ともなるとスパゲティな状態だと自分の読み間違いでバグを生み出さないかと精神的な苦痛を伴います。(ユニットテストでもあれば良いのですが、ゲームだと使えない部分も多々ありますから……)


グラフで示すことで、これらの可能性をゼロとは言わないまでも、減らすことが可能になります。

何より視覚的に状態を切り分けすることで、考える部分を限定することができてスッキリします。


今後の予定

Arbor2の普及運動も兼ねて、基礎的な使い方をまず最初に発信していこうと思います。

そのあとにまだまだ書ききれていない便利な使い方や、FSMとスクリプトのどちらに書くかの判断基準などを紹介していけたらと考えています。

code.hildsoft.com