Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions Docs/VS_Scratch_Mapping.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@ Scratch ブロックと FUnity 独自 Visual Scripting Unit の対応関係で
## 見た目
| Scratch ブロック (日本語) | FUnity Unit クラス | UnitTitle | UnitCategory | 備考 |
| --- | --- | --- | --- | --- |
| 背景を (背景の番号) にする | FUnity.Runtime.Integrations.VisualScripting.Units.ScratchUnits.SetBackgroundByIndexUnit | 背景を〇にする | FUnity/Blocks/見た目 | StageBackgroundInfo のリストを 1 始まり番号で参照し、FUnityManager 経由で StageBackgroundService を更新。定義: Runtime/.../BackgroundUnits.cs |
| 背景を (背景の名前) にする | FUnity.Runtime.Integrations.VisualScripting.Units.ScratchUnits.SetBackgroundByNameUnit | 背景を (名前) にする | FUnity/Blocks/見た目 | DisplayName 一致で背景を切替。未一致時は警告のみで維持。定義: Runtime/.../BackgroundUnits.cs |
| 次の背景にする | FUnity.Runtime.Integrations.VisualScripting.Units.ScratchUnits.NextBackgroundUnit | 次の背景にする | FUnity/Blocks/見た目 | 背景一覧を循環させ、末尾で先頭へ戻る。定義: Runtime/.../BackgroundUnits.cs |
| 背景の番号 | FUnity.Runtime.Integrations.VisualScripting.Units.ScratchUnits.GetBackgroundIndexUnit | 背景の番号 | FUnity/Blocks/見た目 | 現在の背景を 1 始まりの番号で返却。背景未設定時は 0。定義: Runtime/.../BackgroundUnits.cs |
| 背景の名前 | FUnity.Runtime.Integrations.VisualScripting.Units.ScratchUnits.GetBackgroundNameUnit | 背景の名前 | FUnity/Blocks/見た目 | 現在の背景 DisplayName を返却。定義: Runtime/.../BackgroundUnits.cs |
| コスチュームを ( ) にする | FUnity.Runtime.Integrations.VisualScripting.Units.ScratchUnits.SetCostumeNumberUnit | コスチュームを〇にする | FUnity/Scratch/見た目 | ActorState.CostumeIndex と FUnityActorData.Sprites を利用。定義: Runtime/.../CostumeUnits.cs |
| 次のコスチュームにする | FUnity.Runtime.Integrations.VisualScripting.Units.ScratchUnits.NextCostumeUnit | 次のコスチュームにする | FUnity/Scratch/見た目 | コスチュームを 1 → 2 → … → N → 1 と循環。定義: Runtime/.../CostumeUnits.cs |
| コスチュームの番号 | FUnity.Runtime.Integrations.VisualScripting.Units.ScratchUnits.CostumeNumberUnit | コスチュームの番号 | FUnity/Scratch/見た目 | 1 始まりの Scratch コスチューム番号を返す。定義: Runtime/.../CostumeUnits.cs |
Expand Down
289 changes: 286 additions & 3 deletions Runtime/Core/FUnityManager.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// Updated: 2025-02-14
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
Expand Down Expand Up @@ -134,6 +135,15 @@ private readonly Dictionary<VisualElement, EventCallback<PointerDownEvent>> m_Sp
/// <summary>マウス座標を監視し、Scratch 座標系へ変換するサービス。</summary>
private MousePositionService m_MousePositionService;

/// <summary>ステージに登録されている背景一覧。空コレクションは背景未登録を示す。</summary>
private IReadOnlyList<StageBackgroundInfo> m_StageBackgrounds = Array.Empty<StageBackgroundInfo>();

/// <summary>現在適用中の背景インデックス(0 始まり)。背景未設定時は -1。</summary>
private int m_CurrentBackgroundIndex = -1;

/// <summary>背景スケールのキーワード。StageData から取得し、背景差し替え時に再利用する。</summary>
private string m_CurrentBackgroundScale = FUnityStageData.BackgroundScaleContain;

/// <summary>変数モニターの UI 表示を担当する Presenter。</summary>
private VariableUiPresenter m_VariableUiPresenter;

Expand Down Expand Up @@ -1476,20 +1486,198 @@ private void ApplyStage(StageElement stageElement, FUnityStageData stage)
stageElement?.Configure(stage);
ApplyScratchStageSizing(stageElement);

UpdateStageBackgroundState(stage);
}

/// <summary>
/// ステージ背景の状態を更新し、現在の背景色・画像を StageBackgroundService へ適用する。
/// </summary>
/// <param name="stage">適用対象のステージ設定。null の場合は背景一覧を初期化する。</param>
private void UpdateStageBackgroundState(FUnityStageData stage)
{
if (stage == null)
{
m_StageBackgrounds = Array.Empty<StageBackgroundInfo>();
m_CurrentBackgroundIndex = -1;
m_CurrentBackgroundScale = FUnityStageData.BackgroundScaleContain;
return;
}

m_StageBackgrounds = stage.Backgrounds ?? Array.Empty<StageBackgroundInfo>();
m_CurrentBackgroundScale = stage.BackgroundScale;

m_StageBackgroundService.SetBackgroundColor(stage.BackgroundColor);

if (stage.BackgroundImage != null)
if (m_StageBackgrounds.Count == 0)
{
m_CurrentBackgroundIndex = -1;
m_StageBackgroundService.SetBackgroundFromResources(DefaultStageBackgroundName, m_CurrentBackgroundScale);
return;
}

var defaultIndex = Mathf.Clamp(stage.DefaultBackgroundIndex, 0, m_StageBackgrounds.Count - 1);
ApplyBackgroundByIndexInternal(defaultIndex, false);
}

/// <summary>
/// 指定したインデックスの背景を適用し、現在の背景インデックスを更新する。
/// </summary>
/// <param name="zeroBasedIndex">0 始まりの背景インデックス。</param>
/// <param name="allowWrap">範囲外の値を循環させる場合は true。</param>
private void ApplyBackgroundByIndexInternal(int zeroBasedIndex, bool allowWrap)
{
if (m_StageBackgrounds == null || m_StageBackgrounds.Count == 0)
{
Debug.LogWarning("[FUnity] Stage 背景が未登録のため背景を切り替えられません。");
return;
}

var count = m_StageBackgrounds.Count;
var normalized = zeroBasedIndex;

if (allowWrap)
{
normalized = ((zeroBasedIndex % count) + count) % count;
}

normalized = Mathf.Clamp(normalized, 0, count - 1);

var info = m_StageBackgrounds[normalized];
if (info == null)
{
m_StageBackgroundService.SetBackground(stage.BackgroundImage, stage.BackgroundScale);
Debug.LogWarning($"[FUnity] インデックス {normalized} の StageBackgroundInfo が null です。");
return;
}

m_StageBackgroundService.SetBackgroundFromResources(DefaultStageBackgroundName, stage.BackgroundScale);
m_CurrentBackgroundIndex = normalized;
ApplyBackgroundFromInfo(info);
}

/// <summary>
/// 背景情報から StageBackgroundService へテクスチャを適用する。
/// </summary>
/// <param name="info">適用対象の背景情報。</param>
private void ApplyBackgroundFromInfo(StageBackgroundInfo info)
{
if (info == null)
{
return;
}

if (info.Sprite != null && info.Sprite.texture != null)
{
m_StageBackgroundService.SetBackground(info.Sprite.texture, m_CurrentBackgroundScale);
return;
}

Debug.LogWarning($"[FUnity] 背景 '{info.DisplayName}' に Sprite が割り当てられていないため既定背景へフォールバックします。");
m_StageBackgroundService.SetBackgroundFromResources(DefaultStageBackgroundName, m_CurrentBackgroundScale);
}

/// <summary>
/// 背景数を返します。未設定時は 0 を返します。
/// </summary>
/// <returns>登録されている背景の数。</returns>
private int GetBackgroundCountInternal()
{
return m_StageBackgrounds?.Count ?? 0;
}

/// <summary>
/// 現在の背景番号(1 始まり)を返します。未設定時は 0。
/// </summary>
/// <returns>現在の背景番号。範囲外の場合は 0。</returns>
private int GetCurrentBackgroundNumberInternal()
{
if (m_CurrentBackgroundIndex < 0)
{
return 0;
}

return m_CurrentBackgroundIndex + 1;
}

/// <summary>
/// 現在の背景名を返します。未設定時は空文字列。
/// </summary>
/// <returns>背景表示名。</returns>
private string GetCurrentBackgroundNameInternal()
{
if (m_CurrentBackgroundIndex < 0 || m_StageBackgrounds == null || m_CurrentBackgroundIndex >= m_StageBackgrounds.Count)
{
return string.Empty;
}

var info = m_StageBackgrounds[m_CurrentBackgroundIndex];
return info != null ? info.DisplayName : string.Empty;
}

/// <summary>
/// 1 始まりの番号指定で背景を切り替える。
/// </summary>
/// <param name="backgroundNumber">ユーザー向けの背景番号。</param>
private void SetBackgroundByNumberInternal(int backgroundNumber)
{
if (m_StageBackgrounds == null || m_StageBackgrounds.Count == 0)
{
Debug.LogWarning("[FUnity] 背景が 1 件も登録されていないため切り替えできません。");
return;
}

var zeroBased = Mathf.Clamp(backgroundNumber - 1, 0, m_StageBackgrounds.Count - 1);
ApplyBackgroundByIndexInternal(zeroBased, false);
}

/// <summary>
/// 背景名で一致するエントリを探し、見つかれば適用する。
/// </summary>
/// <param name="backgroundName">検索する背景名。</param>
private void SetBackgroundByNameInternal(string backgroundName)
{
if (string.IsNullOrWhiteSpace(backgroundName))
{
Debug.LogWarning("[FUnity] 空の背景名が指定されたため切り替えをスキップします。");
return;
}

if (m_StageBackgrounds == null || m_StageBackgrounds.Count == 0)
{
Debug.LogWarning("[FUnity] 背景が 1 件も登録されていないため名前で切り替えできません。");
return;
}

for (var i = 0; i < m_StageBackgrounds.Count; i++)
{
var info = m_StageBackgrounds[i];
if (info == null)
{
continue;
}

if (string.Equals(info.DisplayName, backgroundName, StringComparison.Ordinal) ||
string.Equals(info.DisplayName, backgroundName, StringComparison.OrdinalIgnoreCase))
{
ApplyBackgroundByIndexInternal(i, false);
return;
}
}

Debug.LogWarning($"[FUnity] 背景名 '{backgroundName}' に一致するエントリが見つかりません。");
}

/// <summary>
/// 現在の背景を 1 つ進め、末尾に達したら先頭へ戻す。
/// </summary>
private void NextBackgroundInternal()
{
if (m_StageBackgrounds == null || m_StageBackgrounds.Count == 0)
{
Debug.LogWarning("[FUnity] 背景が 1 件も登録されていないため次の背景へ進めません。");
return;
}

var nextIndex = m_CurrentBackgroundIndex + 1;
ApplyBackgroundByIndexInternal(nextIndex, true);
}

/// <summary>
Expand Down Expand Up @@ -2159,6 +2347,101 @@ public static ActorPresenter CloneActor(ActorPresenter original)
return manager.CloneActorInternal(original);
}

/// <summary>
/// 登録済みの背景数を返します。マネージャー未初期化時は 0。
/// </summary>
/// <returns>背景の総数。</returns>
public static int GetBackgroundCount()
{
var manager = Instance != null ? Instance : FindObjectOfType<FUnityManager>();
if (manager == null)
{
Debug.LogWarning("[FUnity] FUnityManager.GetBackgroundCount: FUnityManager が見つからないため背景数を取得できません。");
return 0;
}

return manager.GetBackgroundCountInternal();
}

/// <summary>
/// 現在表示している背景番号(1 始まり)を返します。
/// </summary>
/// <returns>現在の背景番号。背景が無い場合は 0。</returns>
public static int GetCurrentBackgroundNumber()
{
var manager = Instance != null ? Instance : FindObjectOfType<FUnityManager>();
if (manager == null)
{
Debug.LogWarning("[FUnity] FUnityManager.GetCurrentBackgroundNumber: FUnityManager が見つからないため背景番号を取得できません。");
return 0;
}

return manager.GetCurrentBackgroundNumberInternal();
}

/// <summary>
/// 現在表示している背景名を返します。
/// </summary>
/// <returns>背景名。未設定時は空文字列。</returns>
public static string GetCurrentBackgroundName()
{
var manager = Instance != null ? Instance : FindObjectOfType<FUnityManager>();
if (manager == null)
{
Debug.LogWarning("[FUnity] FUnityManager.GetCurrentBackgroundName: FUnityManager が見つからないため背景名を取得できません。");
return string.Empty;
}

return manager.GetCurrentBackgroundNameInternal();
}

/// <summary>
/// 1 始まりの番号で背景を切り替えます。範囲外の値はクランプします。
/// </summary>
/// <param name="backgroundNumber">ユーザー向けの背景番号。</param>
public static void SetBackgroundByNumber(int backgroundNumber)
{
var manager = Instance != null ? Instance : FindObjectOfType<FUnityManager>();
if (manager == null)
{
Debug.LogWarning("[FUnity] FUnityManager.SetBackgroundByNumber: FUnityManager が見つからないため背景を切り替えできません。");
return;
}

manager.SetBackgroundByNumberInternal(backgroundNumber);
}

/// <summary>
/// 背景名で一致するエントリへ切り替えます。一致しない場合は変更しません。
/// </summary>
/// <param name="backgroundName">検索する背景名。</param>
public static void SetBackgroundByName(string backgroundName)
{
var manager = Instance != null ? Instance : FindObjectOfType<FUnityManager>();
if (manager == null)
{
Debug.LogWarning("[FUnity] FUnityManager.SetBackgroundByName: FUnityManager が見つからないため背景を切り替えできません。");
return;
}

manager.SetBackgroundByNameInternal(backgroundName);
}

/// <summary>
/// 次の背景へ進め、末尾では先頭へ戻します。
/// </summary>
public static void NextBackground()
{
var manager = Instance != null ? Instance : FindObjectOfType<FUnityManager>();
if (manager == null)
{
Debug.LogWarning("[FUnity] FUnityManager.NextBackground: FUnityManager が見つからないため背景を進められません。");
return;
}

manager.NextBackgroundInternal();
}

/// <summary>
/// Scratch の「緑の旗が押されたとき」イベントを全俳優(クローン除く)へ配信します。
/// </summary>
Expand Down
Loading