From fa3ae41bf38de318d49d3099734618882ce9cf74 Mon Sep 17 00:00:00 2001 From: papacoder Date: Mon, 24 Nov 2025 19:07:29 +0900 Subject: [PATCH] feat(vs): add Scratch control blocks --- Docs/VS_Scratch_Mapping.md | 25 ++++--- .../Units/ScratchUnits/ConditionUnits.cs | 66 ++++++++++++++++- .../Units/ScratchUnits/LoopUnits.cs | 71 +++++++++++++++++++ .../Units/ScratchUnits/WaitSecondsUnit.cs | 60 ++++++++++++++++ 4 files changed, 209 insertions(+), 13 deletions(-) diff --git a/Docs/VS_Scratch_Mapping.md b/Docs/VS_Scratch_Mapping.md index 1084a94..4727aa3 100644 --- a/Docs/VS_Scratch_Mapping.md +++ b/Docs/VS_Scratch_Mapping.md @@ -67,17 +67,20 @@ Scratch ブロックと FUnity 独自 Visual Scripting Unit の対応関係で ## 制御 | Scratch ブロック (日本語) | FUnity Unit クラス | UnitTitle | UnitCategory | 備考 | | --- | --- | --- | --- | --- | -| ○回繰り返す | FUnity.Runtime.Integrations.VisualScripting.Units.ScratchUnits.RepeatNUnit | ○回繰り返す | FUnity/Scratch/制御 | 指定回数ループ。定義: Runtime/.../LoopUnits.cs | -| ずっと | FUnity.Runtime.Integrations.VisualScripting.Units.ScratchUnits.ForeverUnit | ずっと | FUnity/Scratch/制御 | 永続ループ。Visual Scripting 標準の `ControlInputCoroutine` で Flow コルーチンを回し、`body` を毎フレーム実行してから 1 フレーム待機する。定義: Runtime/.../LoopUnits.cs | -| ○秒待つ | FUnity.Runtime.Integrations.VisualScripting.Units.ScratchUnits.WaitSecondsUnit | ○秒待つ | FUnity/Scratch/制御 | 指定時間待機。Visual Scripting 標準のコルーチン経由で待機し、完了後に後続フローへ進む。定義: Runtime/.../WaitSecondsUnit.cs | -| 自分のクローンを作る | FUnity.Runtime.Integrations.VisualScripting.Units.ScratchUnits.CreateCloneOfSelfUnit | 自分のクローンを作る | FUnity/Scratch/制御 | 自身を複製。定義: Runtime/.../CloneUnits.cs | -| ○のクローンを作る | FUnity.Runtime.Integrations.VisualScripting.Units.ScratchUnits.CreateCloneOfDisplayNameUnit | ○のクローンを作る | FUnity/Scratch/制御 | 指定俳優を複製。CloneAdapter 出力は廃止済み。定義: Runtime/.../CloneUnits.cs | -| クローンされたとき | FUnity.Runtime.Integrations.VisualScripting.Units.ScratchUnits.WhenIStartAsCloneUnit | クローンされたとき | Events/FUnity/Scratch/制御 | クローン生成時に発火する Scratch スクリプトの入口。`flow.StartCoroutine(trigger)` で起動後、`ScratchUnitUtil.RegisterScratchFlow` により Flow をスレッド登録して停止ブロックと連動させる。Flow の破棄は Visual Scripting のコルーチン側で行う。定義: Runtime/.../CloneUnits.cs | -| このクローンを削除する | FUnity.Runtime.Integrations.VisualScripting.Units.ScratchUnits.DeleteThisCloneUnit | このクローンを削除する | FUnity/Scratch/制御 | クローンを破棄。定義: Runtime/.../CloneUnits.cs | -| すべてを止める | FUnity.Runtime.Integrations.VisualScripting.Units.ScratchUnits.StopAllUnit | すべてを止める | FUnity/Scratch/制御 | Scratch 用スレッドテーブル経由で全スレッド停止。定義: Runtime/.../StopControlUnits.cs | -| このスクリプトを止める | FUnity.Runtime.Integrations.VisualScripting.Units.ScratchUnits.StopThisScriptUnit | このスクリプトを止める | FUnity/Scratch/制御 | Flow.variables から ActorId/ThreadId を取得し、`FUnityScriptThreadManager.StopScratchThread(actorId, threadId)` で自身のみ停止。定義: Runtime/.../StopControlUnits.cs | -| スプライトの他のスクリプトを止める | FUnity.Runtime.Integrations.VisualScripting.Units.ScratchUnits.StopOtherScriptsInSpriteUnit | スプライトの他のスクリプトを止める | FUnity/Scratch/制御 | 同俳優の他 Scratch スレッド停止。定義: Runtime/.../StopControlUnits.cs | -| もし○なら | FUnity.Runtime.Integrations.VisualScripting.Units.ScratchUnits.IfThenUnit | もし○なら | FUnity/Scratch/制御 | 条件成立時のみ本体を実行。定義: Runtime/.../ConditionUnits.cs | +| ○回繰り返す | FUnity.Runtime.Integrations.VisualScripting.Units.ScratchUnits.RepeatNUnit | ○回繰り返す | FUnity/Blocks/制御 | 指定回数ループ。定義: Runtime/.../LoopUnits.cs | +| ずっと | FUnity.Runtime.Integrations.VisualScripting.Units.ScratchUnits.ForeverUnit | ずっと | FUnity/Blocks/制御 | 永続ループ。Visual Scripting 標準の `ControlInputCoroutine` で Flow コルーチンを回し、`body` を毎フレーム実行してから 1 フレーム待機する。定義: Runtime/.../LoopUnits.cs | +| ○まで繰り返す | FUnity.Runtime.Integrations.VisualScripting.Units.ScratchUnits.RepeatUntilUnit | ○まで繰り返す | FUnity/Blocks/制御 | 条件が真になるまで body を実行し、毎反復で 1 フレーム待機する。定義: Runtime/.../LoopUnits.cs | +| ○秒待つ | FUnity.Runtime.Integrations.VisualScripting.Units.ScratchUnits.WaitSecondsUnit | ○秒待つ | FUnity/Blocks/制御 | 指定時間待機。Visual Scripting 標準のコルーチン経由で待機し、完了後に後続フローへ進む。定義: Runtime/.../WaitSecondsUnit.cs | +| ○まで待つ | FUnity.Runtime.Integrations.VisualScripting.Units.ScratchUnits.WaitUntilUnit | ○まで待つ | FUnity/Blocks/制御 | 条件成立まで 1 フレームずつ待機し、成立後に exit へ進む。定義: Runtime/.../WaitSecondsUnit.cs | +| 自分のクローンを作る | FUnity.Runtime.Integrations.VisualScripting.Units.ScratchUnits.CreateCloneOfSelfUnit | 自分のクローンを作る | FUnity/Blocks/制御 | 自身を複製。定義: Runtime/.../CloneUnits.cs | +| ○のクローンを作る | FUnity.Runtime.Integrations.VisualScripting.Units.ScratchUnits.CreateCloneOfDisplayNameUnit | ○のクローンを作る | FUnity/Blocks/制御 | 指定俳優を複製。CloneAdapter 出力は廃止済み。定義: Runtime/.../CloneUnits.cs | +| クローンされたとき | FUnity.Runtime.Integrations.VisualScripting.Units.ScratchUnits.WhenIStartAsCloneUnit | クローンされたとき | Events/FUnity/Blocks/制御 | クローン生成時に発火する Scratch スクリプトの入口。`flow.StartCoroutine(trigger)` で起動後、`ScratchUnitUtil.RegisterScratchFlow` により Flow をスレッド登録して停止ブロックと連動させる。Flow の破棄は Visual Scripting のコルーチン側で行う。定義: Runtime/.../CloneUnits.cs | +| このクローンを削除する | FUnity.Runtime.Integrations.VisualScripting.Units.ScratchUnits.DeleteThisCloneUnit | このクローンを削除する | FUnity/Blocks/制御 | クローンを破棄。定義: Runtime/.../CloneUnits.cs | +| すべてを止める | FUnity.Runtime.Integrations.VisualScripting.Units.ScratchUnits.StopAllUnit | すべてを止める | FUnity/Blocks/制御 | Scratch 用スレッドテーブル経由で全スレッド停止。定義: Runtime/.../StopControlUnits.cs | +| このスクリプトを止める | FUnity.Runtime.Integrations.VisualScripting.Units.ScratchUnits.StopThisScriptUnit | このスクリプトを止める | FUnity/Blocks/制御 | Flow.variables から ActorId/ThreadId を取得し、`FUnityScriptThreadManager.StopScratchThread(actorId, threadId)` で自身のみ停止。定義: Runtime/.../StopControlUnits.cs | +| スプライトの他のスクリプトを止める | FUnity.Runtime.Integrations.VisualScripting.Units.ScratchUnits.StopOtherScriptsInSpriteUnit | スプライトの他のスクリプトを止める | FUnity/Blocks/制御 | 同俳優の他 Scratch スレッド停止。定義: Runtime/.../StopControlUnits.cs | +| もし○なら | FUnity.Runtime.Integrations.VisualScripting.Units.ScratchUnits.IfThenUnit | もし○なら | FUnity/Blocks/制御 | 条件成立時のみ本体を実行。定義: Runtime/.../ConditionUnits.cs | +| もし○なら でなければ | FUnity.Runtime.Integrations.VisualScripting.Units.ScratchUnits.IfElseUnit | もし ○ なら でなければ | FUnity/Blocks/制御 | 条件の真偽で ifTrue/ifFalse へ分岐させる。定義: Runtime/.../ConditionUnits.cs | ### 停止ブロック diff --git a/Runtime/Integrations/VisualScripting/Units/ScratchUnits/ConditionUnits.cs b/Runtime/Integrations/VisualScripting/Units/ScratchUnits/ConditionUnits.cs index 926f25c..136b783 100644 --- a/Runtime/Integrations/VisualScripting/Units/ScratchUnits/ConditionUnits.cs +++ b/Runtime/Integrations/VisualScripting/Units/ScratchUnits/ConditionUnits.cs @@ -74,6 +74,68 @@ private IEnumerator Run(Flow flow) } } - // 将来的には Scratch の「もし〇〇なら、でなければ」ブロックに対応する Unit を追加予定です。 - // 追加時には IfThenUnit と同じ即時実行ポリシーを踏襲します。 + /// + /// Scratch の「もし〇なら でなければ」ブロックを再現し、条件が真偽のどちらでも後続を分岐させる Unit です。 + /// + [UnitTitle("もし ○ なら でなければ")] + [UnitShortTitle("もし〜なら/でなければ")] + [UnitCategory("FUnity/Blocks/制御")] + [UnitSubtitle("制御")] + [TypeIcon(typeof(FUnityScratchUnitIcon))] + public sealed class IfElseUnit : Unit + { + /// 制御フローの入力ポートです。 + [DoNotSerialize] + private ControlInput m_Enter; + + /// 条件が真のときに発火する ControlOutput です。 + [DoNotSerialize] + private ControlOutput m_IfTrue; + + /// 条件が偽のときに発火する ControlOutput です。 + [DoNotSerialize] + private ControlOutput m_IfFalse; + + /// 判定に使用する条件値を受け取る ValueInput です。 + [DoNotSerialize] + private ValueInput m_Condition; + + /// enter ポートへの参照を公開します。 + public ControlInput Enter => m_Enter; + + /// 条件が真だった場合に進むポートへの参照を公開します。 + public ControlOutput IfTrue => m_IfTrue; + + /// 条件が偽だった場合に進むポートへの参照を公開します。 + public ControlOutput IfFalse => m_IfFalse; + + /// 条件入力ポートへの参照を公開します。 + public ValueInput Condition => m_Condition; + + /// + /// ポート定義を行い、条件評価後に真偽それぞれの出力へ遷移できるよう設定します。 + /// + protected override void Definition() + { + m_Enter = ControlInput("enter", OnEnter); + m_IfTrue = ControlOutput("ifTrue"); + m_IfFalse = ControlOutput("ifFalse"); + m_Condition = ValueInput("condition", false); + + Succession(m_Enter, m_IfTrue); + Succession(m_Enter, m_IfFalse); + Requirement(m_Condition, m_Enter); + } + + /// + /// 条件を評価し、真なら ifTrue、偽なら ifFalse へ制御を分岐させます。 + /// + /// 現在のフロー情報。 + /// 分岐先の ControlOutput。 + private ControlOutput OnEnter(Flow flow) + { + var condition = flow.GetValue(m_Condition); + return condition ? m_IfTrue : m_IfFalse; + } + } } diff --git a/Runtime/Integrations/VisualScripting/Units/ScratchUnits/LoopUnits.cs b/Runtime/Integrations/VisualScripting/Units/ScratchUnits/LoopUnits.cs index b3c019d..50a4912 100644 --- a/Runtime/Integrations/VisualScripting/Units/ScratchUnits/LoopUnits.cs +++ b/Runtime/Integrations/VisualScripting/Units/ScratchUnits/LoopUnits.cs @@ -125,4 +125,75 @@ private IEnumerator OnEnterCoroutine(Flow flow) } } } + + /// + /// Scratch の「〇まで繰り返す」ブロックを再現し、条件が成立するまで本体を反復実行するカスタム Unit です。 + /// + [UnitTitle("○まで繰り返す")] + [UnitCategory("FUnity/Blocks/制御")] + [UnitSubtitle("制御")] + [TypeIcon(typeof(FUnityScratchUnitIcon))] + public sealed class RepeatUntilUnit : ScratchCoroutineUnitBase + { + /// ループ開始を受け取る ControlInput です。 + [DoNotSerialize] + private ControlInput m_Enter; + + /// 各反復で実行する本体ポートです。 + [DoNotSerialize] + private ControlOutput m_Body; + + /// ループ終了後に後続へ進む ControlOutput です。 + [DoNotSerialize] + private ControlOutput m_Exit; + + /// 終了条件を受け取る ValueInput です。 + [DoNotSerialize] + private ValueInput m_Condition; + + /// enter ポートへの参照を公開します。 + public ControlInput Enter => m_Enter; + + /// body ポートへの参照を公開します。 + public ControlOutput Body => m_Body; + + /// exit ポートへの参照を公開します。 + public ControlOutput Exit => m_Exit; + + /// condition ポートへの参照を公開します。 + public ValueInput Condition => m_Condition; + + /// + /// ポート定義を行い、条件成立までコルーチンで body を繰り返す設定を行います。 + /// + protected override void Definition() + { + m_Exit = ControlOutput("exit"); + m_Body = ControlOutput("body"); + m_Condition = ValueInput("condition", false); + m_Enter = CreateScratchCoroutineInput("enter", RunCoroutine); + + Succession(m_Enter, m_Body); + Succession(m_Body, m_Body); + Succession(m_Enter, m_Exit); + Requirement(m_Condition, m_Enter); + } + + /// + /// 条件が真になるまで body を実行し、毎反復の終わりに 1 フレーム待機します。 + /// 条件成立後は exit ポートへ制御を返します。 + /// + /// 現在のフロー情報。 + /// ループ処理を行う列挙子。 + private IEnumerator RunCoroutine(Flow flow) + { + while (!flow.GetValue(m_Condition)) + { + yield return m_Body; + yield return null; + } + + yield return m_Exit; + } + } } diff --git a/Runtime/Integrations/VisualScripting/Units/ScratchUnits/WaitSecondsUnit.cs b/Runtime/Integrations/VisualScripting/Units/ScratchUnits/WaitSecondsUnit.cs index 56fcc27..17f1aef 100644 --- a/Runtime/Integrations/VisualScripting/Units/ScratchUnits/WaitSecondsUnit.cs +++ b/Runtime/Integrations/VisualScripting/Units/ScratchUnits/WaitSecondsUnit.cs @@ -70,4 +70,64 @@ private IEnumerator RunCoroutine(Flow flow) yield return m_Exit; } } + + /// + /// Scratch の「〇まで待つ」ブロックを再現し、条件が成立するまで毎フレーム待機するユニットです。 + /// + [UnitTitle("○まで待つ")] + [UnitShortTitle("○まで待つ")] + [UnitCategory("FUnity/Blocks/制御")] + [UnitSubtitle("制御")] + [TypeIcon(typeof(FUnityScratchUnitIcon))] + public sealed class WaitUntilUnit : ScratchCoroutineUnitBase + { + /// 待機を開始する ControlInput です。 + [DoNotSerialize] + private ControlInput m_Enter; + + /// 条件成立後に後続へ進む ControlOutput です。 + [DoNotSerialize] + private ControlOutput m_Exit; + + /// 待機判定に使用する条件値を受け取る ValueInput です。 + [DoNotSerialize] + private ValueInput m_Condition; + + /// enter ポートへの参照を公開します。 + public ControlInput Enter => m_Enter; + + /// exit ポートへの参照を公開します。 + public ControlOutput Exit => m_Exit; + + /// condition ポートへの参照を公開します。 + public ValueInput Condition => m_Condition; + + /// + /// ポート定義を行い、条件成立までコルーチンで待機する入力を登録します。 + /// + protected override void Definition() + { + m_Exit = ControlOutput("exit"); + m_Condition = ValueInput("condition", false); + m_Enter = CreateScratchCoroutineInput("enter", RunCoroutine); + + Succession(m_Enter, m_Exit); + Requirement(m_Condition, m_Enter); + } + + /// + /// 条件が true になるまで 1 フレームずつ待機し、成立後に exit へ遷移します。 + /// + /// 現在のフロー情報。 + /// 待機処理を行う列挙子。 + private IEnumerator RunCoroutine(Flow flow) + { + while (!flow.GetValue(m_Condition)) + { + yield return null; + } + + yield return m_Exit; + } + } }