③ スタッフ4人・ロボット2台 が 35.9 分で止まった件。直さずに原因だけ調べました。 コードを読んで分かったことと、数字で確かめられたことを分けて書きます。 ════════════════════════════════════════════════════════ 結論(いちばんの原因) ════════════════════════════════════════════════════════ **スタッフは、ロボットに 0.75 m より近づけません。 なのに、立ち往生を助ける仕事は「0.35 m まで近づく」ことを着いた条件にしています。 つまり、歩いて助けに行く仕事は、最初から**ぜったいに終わりません**。** 人がロボットをよける処理(PersonRobotYield.KeepClear)は、 ロボットの近くにいる人を毎コマ押しのけます。押しのける先は personRadius 0.2 + ロボットの半径 0.25 + robotKeepClearM 0.3 = **0.75 m**(中心どうし) 一方、私が入れた Rescue の仕事は「ロボットの位置」を行き先にしていて、 着いたとみなす距離は NavMeshAgent の stoppingDistance 0.3 + 0.05 = **0.35 m**(StaffAgent.Update の到着判定) 0.75 m > 0.35 m なので、押しのけが働いているかぎり到着しません。 さらに NavMeshAgent どうしのよけ合いも効きます(ロボットの avoidancePriority 0 = 強い、 スタッフ 50 = 弱い)ので、スタッフ側が必ずよけます。半径だけでも 0.2+0.25=0.45 m 空きます。 細い通路の中だと、もっと手前で追い返されます(robotFaceToFaceM 1.5 m = 中心どうし 1.95 m 以内で「下がる」に入る。下がっている間は到着判定そのものをしない)。 v5 の前は、動けなくなったロボットは 15 秒で受け渡し口へ移していたので、 この矛盾が表に出ませんでした。移すのをやめた(v5 3章)ことで出ました。 ──────────────────────────────────────────────────────── 1. 立ち往生で呼ばれたスタッフが、互いにふさぎ合っていないか ──────────────────────────────────────────────────────── (1) 1台に呼ぶのは **1人だけ**です(重ねて呼んではいません) ・EnterStuck は「すでに StuckWait なら何もしない」ので、 1回の立ち往生につき呼び出しは1件だけ出ます ・仕事板から取れるのは1人だけです(TakeNextJob が taken を立てる) ・立ち往生3回 = 呼び出しも3件。2台なので、同時にあったのは多くて2件です (2) ですが、**同じ場所に人が集まる作りになっています** ・手の空いたスタッフが待つ点は、パントリーのすぐ横に **0.608 m 間隔で縦に6つ**並んでいます StaffStandby (13.75, 6.804) (13.75, 7.412) (13.75, 8.021) (13.75, 8.629) … 受け渡し口・パントリーの点は (15.3, 5.95) ・仕事が無いスタッフは、ここへ戻ります(StaffAgent.Idle → StandbyPoint) ・ロボットの待機場所も (16.9, 6.05) (17.7, 6.05) と、同じ角です → パントリーの角にロボットが止まると、**待つ点・ロボットの通り道・助けに行く人**が ぜんぶ 0.75 m の押しのけの輪の中で重なります。これが「3人で囲んだまま」の形です。 (3) 行き先が重なる作りも1つあります(今回これが起きたかは分かりません) Rescue の行き先は、仕事を**始めた瞬間のロボットの位置**を点として覚えます (StaffAgent.Begin が RobotPoint を _steps に入れる)。 そのあとロボットが動いても、その人は古い点へ歩き続けます。 ──────────────────────────────────────────────────────── 2. あきらめたのは誰か(82回) ──────────────────────────────────────────────────────── 「あきらめた」を記録するのは4か所だけです。 客 … ドリンクバー・トイレ・帰る(座っている組だけ) 組 … 会計・片付けで止まったまま(座っている組だけ) スタッフ … 行き先へ 60 秒で着けなかったとき 今回は **1組も着席していません**(帰った0・待ち0で、34組ぜんぶが案内待ち)。 客も組も座っていないので、**82回はすべてスタッフ**のはずです。 数も合います。スタッフ 4 人 × 60 秒ごとに1回 = 1分あたり最大4回。 詰まっていた時間を 20 分とすると 4 × 20 = 80 回。観測は 82 回です。 行き先は give_ups.csv の to_x / to_z に残りますが、今回は書き出していないので 私の側では確かめられません(4. のとおり、途中で止めても書けるようにできます)。 仕事の名前(job 欄)が「立ち往生を動かす」なら Rescue、「案内」なら案内です。 あきらめ方には、もうひとつ落とし穴があります。 ・同じ仕事を3回あきらめたら、その場所へ**体を移して**仕事を済ませます(B1) ・ただしこの回数は **スタッフ1人ずつが別々に数えています**(StaffAgent._tries)。 仕事が人から人へ回ると、誰も3回に届かないまま回り続けます ・Rescue では、移したあとも押しのけですぐ 0.75 m まで離されるので、 「移した → 着いたと認められない → 回数が 0 に戻る → また 60 秒」 を繰り返します(移した瞬間に経路を引き直すので、その1コマは到着と見なされません) ──────────────────────────────────────────────────────── 3. 案内が、立ち往生の呼び出しに押されて後回しになっていないか ──────────────────────────────────────────────────────── **なっています。** 仕組みは2つです。 (1) Rescue は優先度 0(案内・料理・呼び出し・会計は 1、片付けは 2)で、 仕事板の**先頭**に入れています。TakeNextJob は優先度 0 を見つけた時点で打ち切るので、 手が空いたスタッフは、案内より先に必ず Rescue を取ります。 (2) その Rescue は終わりません(上の結論)。60 秒であきらめて板に戻り、 次に手が空いた人がまた取ります。**1〜2人がこれに取られっぱなし**になります。 そのうえで、残りのスタッフも同じ角で押しのけ合っているので、案内も 60 秒で あきらめ続けます。結果、34組ぶんの案内の仕事が板に積まれたまま進みません。 「待ち0」は、空き卓が無いという意味ではありません。空の店なので 34 組ぜんぶに 卓がすぐ割り当てられ、**案内の仕事待ち**に移っています(だから待ち0・帰った0)。 ──────────────────────────────────────────────────────── 4. 途中で止めても give_ups.csv と summary.json を書き出せるか ──────────────────────────────────────────────────────── **できます。** いまは書き出しが FinishJob の中だけにあり、 Play を止めると OnDisable で .asset を戻すだけで、何も書かずに終わります。 やり方(入れるなら) ・ExperimentRunner に「いま持っている分を書き出す」処理を切り出し、 OnDisable(または OnApplicationQuit)から、回している最中なら1回だけ呼ぶ ・run_info.json の stopped_early を true にし、summary.json の site_run にも 「途中で止めた」と分かる印を入れる(everyone_left は false のまま) ・書き出し中に失敗しても Play を抜けられるよう、try/catch で包む 気をつける点 ・Play を抜けるときは、ほかの部品が先に壊れていることがあります。 記録そのもの(TripLogger)はただの C# の入れ物なので安全ですが、 書き出しの中で新しくオブジェクトを探したり消したりしないこと ・途中で止めた回は計測に使えないので、フォルダ名に _stopped を付けて そうと分かるようにするのがよいと思います ──────────────────────────────────────────────────────── 5. .asset がサイトの値のまま残っていないか ──────────────────────────────────────────────────────── **残っていません。元に戻っていました**(Play を抜けるときの OnDisable が働いています)。 ファイルを直接読んで確かめました。 PeopleSpec.asset staffCount 2(サイトの条件では 4) staffDwellAtPassSec 3(サイトの条件では 0) staffSpeed 1 / warmupOccupancy 0.8 ServiceSpec.asset arrivalsPerHourByCrowd 25 / 35 / 45(サイトの条件では 42 固定) trays 3・peakMinutes 120・guideSec 45・paySec 90 ほか、元のまま RobotSpec.asset tableDwellSec 25(サイトと同じ値なので、どちらでも同じ) Unity の Inspector でも、PeopleSpec の「スタッフの人数 2」「受け渡し口で料理を取る時間 3」 になっていることだけ、目で確かめていただけると確実です。 ──────────────────────────────────────────────────────── 6. 直すとしたら(まだ何もしていません) ──────────────────────────────────────────────────────── いちばん小さい直しは「助けに行く人は、その台をよけない」だと思います。 ・Rescue の仕事を持っているスタッフは、その台について KeepClear と 下がる・待つ・回り道をしない(ほかの台にはこれまでどおりよける) ・行き先を「ロボットの位置」ではなく「ロボットの手前 0.8 m くらいの点」にして、 着いたとみなす距離と矛盾しないようにする あわせて見直したほうがよさそうな点 ・あきらめた回数を仕事ごと(人ごとではなく)に数える ・Rescue を取れるのは1件につき1人のままでよいが、 案内が長く止まらないよう、取られっぱなしを防ぐ区切りを入れる ・手の空いたスタッフの待つ点が、受け渡し口・ロボットの待機場所と同じ角にある どれを入れるかはご指示をください。