Page 1 of 1

FSMでの条件分岐につきまして

Posted: 2018/10/10 05:59
by moyashiking
お世話になっておりますm(_ _)m

if 文のような条件分岐をステートで実現したいと思いテストしてみましたが、期待通りに動作せず、どのように組み立てれば良いのか悩んでおります。
できるだけ単純にしたサンプルのスクショを添付いたします。
Unity 2018.2.11f1 Personal (64bit) - SampleScene.unity - renshu_SwipeCar(Arbor) - PC, Mac & Linux Standalone _DX11_ 2018-10-10 14.36.36.png
Unity 2018.2.11f1 Personal (64bit) - SampleScene.unity - renshu_SwipeCar(Arbor) - PC, Mac & Linux Standalone _DX11_ 2018-10-10 14.36.36.png (384.77 KiB) Viewed 9191 times
<期待した処理の内容>
①ループしている
②ループした回数をカウントしている
③マウス左ボタンをクリックして回数をカウントする

<実際の動作>
実際には③の処理がうまくいかず…分岐そのものは発生しているようですが、分岐先のカウント処理が実行されていません。
Arbor的な作法についての理解が足りないのだと考え、リファレンスマニュアルとにらめっこしておりますが解決に至りません。
ご面倒おかけしますが、何卒アドバイスのほど宜しくお願いいたします。

Re: FSMでの条件分岐につきまして

Posted: 2018/10/10 06:36
by moyashiking
レイアウトが見づらいので、再配置してみました。
Unity 2018.2.11f1 Personal (64bit) - SampleScene.unity - renshu_SwipeCar(Arbor) - PC, Mac & Linux Standalone _DX11_ 2018-10-10 15.33.37.png
Unity 2018.2.11f1 Personal (64bit) - SampleScene.unity - renshu_SwipeCar(Arbor) - PC, Mac & Linux Standalone _DX11_ 2018-10-10 15.33.37.png (272.5 KiB) Viewed 9189 times

Re: FSMでの条件分岐につきまして

Posted: 2018/10/10 07:04
by caitsithware
遷移先の決定方法についてですね。

まず、ArborFSMでは以下のような流れで1フレーム内での遷移先を決定しております。
  1. OnStateBeginやUpdate、OnStateUpdateなどで、何らかの条件に合致する場合にStateLinkをTransition
  2. TransitionTimingがImmediateであれば、Transition呼び出し内部で遷移処理。
  3. TransitionTimingがLateUpdateDontOverwriteであれば、LateUpdateでの遷移予約(すでに予約がある場合は上書きしない)。
  4. TransitionTimingがLateUpdateOverwriteであれば、LateUpdateでの遷移予約を上書き。
今回の場合ですと、
  • GoToTransitionでOnStateBeginの時に、LateUpdateDontOverwriteでいち早く遷移先を予約。
  • MouseButtonDownTransitionは内部的にUpdate()でInput.GetMouseButtonDown()を呼び出して、trueであればTransitionを呼び出し。
    ただし、TransitionTimingがLateUpdateDontOverwriteの場合は既に予約した遷移先があるので上書きしない。
という流れになっております。

同フレーム中に遷移先が変わるような流れを組む場合は、TransitionTimingをLateUpdateOverwriteで上書きするか、Immediateで即座に遷移するように設定してください。
(ただしImmediateのみで遷移をループさせる場合は無限ループになる可能性がある点にご注意ください)
今回の例でいえば、MouseButtonDownTransitionのNext StateのTransitionTimingをひとまずLateUpdateOverwriteに変更していただければ、ClickCntが増えるのを確認できるかと思います。

TransitionTimingの設定方法はこちらを参照してください。
マニュアル : TransitionTiming

また、遷移していないのにもかかわらず遷移ラインのカウントが増加している件については不具合ですので修正いたします。

Re: FSMでの条件分岐につきまして

Posted: 2018/10/11 02:56
by moyashiking
丁寧な解説ありがとうございますm(_ _)m
今回の例でいえば、MouseButtonDownTransitionのNext StateのTransitionTimingをひとまずLateUpdateOverwriteに変更していただければ、ClickCntが増えるのを確認できるかと思います。
こちらを試してみたところ、期待通りに動作いたしました。

よく見てみると、NextStateの横のアイコンはTransitionの動作によって使い分けられているのですね。
うっかり忘れないよう、アイコンを見るたびに思い出すようにします :D

Re: FSMでの条件分岐につきまして

Posted: 2018/10/11 03:55
by moyashiking
申し訳ありません、追加で質問がございます。
同フレーム中に遷移先が変わるような流れを組む場合は
とありますが、同フレームであることをどこで判断すれば宜しいでしょうか?
1つのステートの中に、MouseButtonDownTransition と GoToTransition を書いていることを指しておられるのでしょうか?

Re: FSMでの条件分岐につきまして

Posted: 2018/10/11 04:46
by caitsithware
moyashiking wrote: 2018/10/11 03:55 申し訳ありません、追加で質問がございます。
同フレーム中に遷移先が変わるような流れを組む場合は
とありますが、同フレームであることをどこで判断すれば宜しいでしょうか?
1つのステートの中に、MouseButtonDownTransition と GoToTransition を書いていることを指しておられるのでしょうか?
はい、1ステートに複数のStateBehaviourを追加している場合やStateBehaviourを自作して複数回遷移を呼び出している場合などは、条件によっては1フレーム中に何度もTransitionメソッドが呼び出されることになります。
ですので、どのStateBehaviourの遷移を優先させたいかをTransitionTimingで制御する形になります。

また、Transitionメソッドを呼び出しているタイミング(OnStateBegin()内など)も関係があり、例えば、OnStateBegin()はアクティブになったタイミングで呼び出されるため、全てのTransitionTimingがLateUpdateDontOverwriteの場合は、OnStateBegin()内の一番初めの遷移が優先されることになります。

今回の例ですと。
  • 「LMBを押す」ステートに入る。
    ステート内のStateBehaviourのOnStateBegin()を上から順に呼び出す。
    • MouseDownTransitionのOnStateBegin()を呼び出そうとする。オーバーライドしていないため何も処理しない。
    • GoToTransitionのOnStateBegin()が呼び出される。Next Stateに遷移予約。
      LateUpdateDontOverwriteであり、遷移予約はまだないため予約成功
  • MouseDownTransition.Update()処理。
    マウス左ボタン押下を確認。
    押下しているならNext Stateに遷移予約しようとする。
    TransitionTimingがLateUpdateDontOverwriteであり、すでにGoToTransitionのNext Stateが予約済みのため上書きされず。
  • ArborFSM.Update()処理。
    現在ステートのOnStateUpdate()を上から順に呼び出す。
    いずれもオーバーライドしていないため何も処理しない。
  • ArborFSM.LateUpdate()処理。
    • GoToTransitionのNext Stateが予約されているため、その遷移先である「ループ回数をカウント」ステートへ遷移。
という流れが同フレーム内で起きている感じです。
※今回は関係ないのですが、MouseDownTransition.Update()が先かArborFSM.Update()が先かはUnityの仕様にも依存します。

StateBehaviourの各メソッドの呼び出し順についてはこちらを参照してください。
マニュアル : StateBehaviourの呼び出し順

組み込みStateBehaviourのリファレンスですが、どのタイミング(OnStateBegin()内なのか等)で遷移処理しているかも追記したほうがよさそうですね。
今後の更新の際に追記いたします。

補足:
ここでは便宜上、「同フレーム」としていますが、TransitionTimingによっては遷移の呼び出しタイミングが違うため、
厳密には「前回の遷移から次のLateUpdateまでの間」が正しいです。
  • Immediateなら、Transitionメソッドを呼び出したタイミングから次のLateUpdateまでの間。
  • LateUpdate○○なら、LateUpdate内での遷移処理から次のLateUpdateまでの間。
そこまで意識する必要のある個所ではないですが、念のための補足でした。

Re: FSMでの条件分岐につきまして

Posted: 2018/10/11 06:21
by moyashiking
解説ありがとうございます、「LMBを押す」ステートの解釈~NextStateの予約~NextStateの上書き について、理解できました。
その他の処理については都度ひっかかりそうな予感がしますが、困ったらまたこちらの解説を読み直して見ることにいたします ;)

Re: FSMでの条件分岐につきまして

Posted: 2018/10/11 09:27
by moyashiking
五月雨の質問で申し訳ありません、触っていて気になったことがあります。
クリック回数が無事に取れるようになったわけですが、感度が悪いというかカウントの取りこぼしが目立ちます。
50回ほどポチポチポチとクリックすると、30回弱程度しかカウントできません。

(分岐の処理の仕方とは別件で)気にしないといけないポイントが異なると思いますので、別途トピックを立て直した上で改めてご相談させて頂いたほうが宜しいでしょうか?

Re: FSMでの条件分岐につきまして

Posted: 2018/10/11 11:10
by caitsithware
moyashiking wrote: 2018/10/11 09:27 50回ほどポチポチポチとクリックすると、30回弱程度しかカウントできません。
これも同様、TransitionTimingによって制御できます。

「クリック回数をカウント」ステートと「ループ回数をカウント」ステートのGoToTransitionのTransitionTimingをImmediateにすることで1フレーム1ループになり、MouseDownの取りこぼしが改善できるかと思います。

追記:

何故かというと、「クリック回数をカウント」ステートや「ループ回数をカウント」ステートがアクティブになっている時に「LMBを押す」ステートの処理がされないので、その間のGetMouseDownが処理されず、感度が悪く感じる、ということです。
(Unityの仕様上、Input.GetMouseDownは押した瞬間のフレームしかtrueにならないので、その関係で取りこぼす)

Re: FSMでの条件分岐につきまして

Posted: 2018/10/12 01:50
by moyashiking
ご指摘に従い TransitionのタイミングをImmediateに変更したところ、カウントがスムーズに実行されるようになりました。
Transition の設定がこういうところにも影響あるとは盲点でした…。
Transitionを使う場合(多用すると思いますがw)、特に設定には気をつけないといけないわけですね。

頂いたアドバイスは大変参考になりました。
差し支えなければ、これにて本件はクローズとさせて頂きます。
お忙しい中、迅速かつ丁寧な対応ありがとうございましたm(_ _)m