From ac8730e15aae194892cd09dbfe6c2f2d5ab5f861 Mon Sep 17 00:00:00 2001 From: hatayama Date: Sat, 4 Jul 2026 15:43:08 +0900 Subject: [PATCH 1/4] Show sampled collider coverage in raycast annotations Use reachable raycast samples to derive both the representative click point and the PhysicsCollider bounds, so annotated screenshots show sampled hit coverage instead of a tiny marker around one point. Keep raw degenerate bounds in JSON and expand only the overlay drawing for visibility, preserving SimX/SimY as the actual click target. --- .../Tests/Editor/RaycastGridAnnotatorTests.cs | 105 +++++++++++++++++- .../Tests/Editor/UIElementAnnotatorTests.cs | 66 +++++++++++ .../Api/McpTools/Screenshot/Skill/SKILL.md | 2 +- .../Skill/references/annotated-elements.md | 8 +- .../src/Editor/Utils/RaycastGridAnnotator.cs | 63 ++++++++--- .../src/Editor/Utils/RaycastHitClusterer.cs | 73 ++++-------- .../src/Editor/Utils/UIElementAnnotator.cs | 76 ++++++++++++- 7 files changed, 315 insertions(+), 78 deletions(-) diff --git a/Assets/Tests/Editor/RaycastGridAnnotatorTests.cs b/Assets/Tests/Editor/RaycastGridAnnotatorTests.cs index dde95d7978..7aa1dc18f8 100644 --- a/Assets/Tests/Editor/RaycastGridAnnotatorTests.cs +++ b/Assets/Tests/Editor/RaycastGridAnnotatorTests.cs @@ -220,7 +220,37 @@ public void SelectReachableRepresentativeSample_WhenAllSamplesAreOccluded_Should } [Test] - public void CreatePhysicsColliderElement_ShouldKeepBoundsInTopLeftInputSpace() + public void CreateReachableCluster_WhenSamplesAreOccluded_ShouldExcludeOccludedSamples() + { + RaycastClusterSample reachableLeftSample = CreateSample(1, 0f, 0f); + RaycastClusterSample reachableRightSample = CreateSample(1, 10f, 0f); + RaycastClusterSample occludedSample = CreateSample(1, 100f, 100f); + List samples = new List + { + reachableLeftSample, + reachableRightSample, + occludedSample + }; + HashSet occludedSamples = new HashSet + { + occludedSample + }; + + RaycastClusterInfo reachableCluster = RaycastHitClusterer.CreateReachableCluster( + samples, + (RaycastClusterSample sample) => occludedSamples.Contains(sample)); + + Assert.That(reachableCluster, Is.Not.Null); + Assert.That(reachableCluster.SampleCount, Is.EqualTo(2)); + Assert.That(reachableCluster.Samples, Is.EqualTo(new List + { + reachableLeftSample, + reachableRightSample + })); + } + + [Test] + public void CreatePhysicsColliderElement_ShouldUseSampleBoundsInTopLeftInputSpace() { RaycastClusterInfo cluster = new RaycastClusterInfo { @@ -229,7 +259,13 @@ public void CreatePhysicsColliderElement_ShouldKeepBoundsInTopLeftInputSpace() InputX = 100f, InputY = 200f }, - SampleCount = 3 + SampleCount = 3, + Samples = new List + { + CreateSample(1, 80f, 180f), + CreateSample(1, 100f, 200f), + CreateSample(1, 130f, 220f) + } }; RaycastColliderMetadata metadata = new RaycastColliderMetadata { @@ -245,14 +281,60 @@ public void CreatePhysicsColliderElement_ShouldKeepBoundsInTopLeftInputSpace() Assert.That(element.Interaction, Is.EqualTo("Raycast")); Assert.That(element.SimX, Is.EqualTo(100f)); Assert.That(element.SimY, Is.EqualTo(200f)); - Assert.That(element.BoundsMinX, Is.EqualTo(91f)); - Assert.That(element.BoundsMinY, Is.EqualTo(191f)); - Assert.That(element.BoundsMaxX, Is.EqualTo(109f)); - Assert.That(element.BoundsMaxY, Is.EqualTo(209f)); + Assert.That(element.BoundsMinX, Is.EqualTo(80f)); + Assert.That(element.BoundsMinY, Is.EqualTo(180f)); + Assert.That(element.BoundsMaxX, Is.EqualTo(130f)); + Assert.That(element.BoundsMaxY, Is.EqualTo(220f)); Assert.That(element.SimX, Is.InRange(element.BoundsMinX, element.BoundsMaxX)); Assert.That(element.SimY, Is.InRange(element.BoundsMinY, element.BoundsMaxY)); } + [Test] + public void CreatePhysicsColliderElement_WhenSamplesFormLShape_ShouldUseAxisAlignedBoundingBox() + { + RaycastClusterInfo cluster = new RaycastClusterInfo + { + Representative = CreateSample(1, 0f, 0f), + SampleCount = 3, + Samples = new List + { + CreateSample(1, 0f, 0f), + CreateSample(1, 10f, 0f), + CreateSample(1, 0f, 10f) + } + }; + RaycastColliderMetadata metadata = CreateMetadata(); + + UIElementInfo element = RaycastGridAnnotator.CreatePhysicsColliderElement("R1", cluster, metadata); + + Assert.That(element.BoundsMinX, Is.EqualTo(0f)); + Assert.That(element.BoundsMinY, Is.EqualTo(0f)); + Assert.That(element.BoundsMaxX, Is.EqualTo(10f)); + Assert.That(element.BoundsMaxY, Is.EqualTo(10f)); + Assert.That(element.SimX, Is.EqualTo(0f)); + Assert.That(element.SimY, Is.EqualTo(0f)); + } + + [Test] + public void CreatePhysicsColliderElement_WhenClusterHasSingleSample_ShouldKeepDegenerateDataBounds() + { + RaycastClusterSample sample = CreateSample(1, 100f, 200f); + RaycastClusterInfo cluster = new RaycastClusterInfo + { + Representative = sample, + SampleCount = 1, + Samples = new List { sample } + }; + RaycastColliderMetadata metadata = CreateMetadata(); + + UIElementInfo element = RaycastGridAnnotator.CreatePhysicsColliderElement("R1", cluster, metadata); + + Assert.That(element.BoundsMinX, Is.EqualTo(100f)); + Assert.That(element.BoundsMinY, Is.EqualTo(200f)); + Assert.That(element.BoundsMaxX, Is.EqualTo(100f)); + Assert.That(element.BoundsMaxY, Is.EqualTo(200f)); + } + [Test] public void IsUiOcclusionRaycastResult_WhenGraphicRaycasterHit_ShouldReturnTrue() { @@ -407,5 +489,16 @@ private static RaycastGridPointInfo CreateLayerHitPoint( HitGameObjectPath = objectPath }; } + + private static RaycastColliderMetadata CreateMetadata() + { + return new RaycastColliderMetadata + { + Name = "Cube", + Path = "Cube", + Layer = "Default", + Components = new List { "BoxCollider" } + }; + } } } diff --git a/Assets/Tests/Editor/UIElementAnnotatorTests.cs b/Assets/Tests/Editor/UIElementAnnotatorTests.cs index 8c32ef28d2..43a9c25555 100644 --- a/Assets/Tests/Editor/UIElementAnnotatorTests.cs +++ b/Assets/Tests/Editor/UIElementAnnotatorTests.cs @@ -202,6 +202,72 @@ public void CreateAnnotationOverlay_WhenElementIsAnnotated_ShouldKeepLabelOutlin } } + [Test] + public void CreateAnnotationOverlay_WhenBoundsAreDegenerate_ShouldDrawMinimumVisibleBorderAroundSimPoint() + { + List elements = new List + { + new UIElementInfo + { + Label = "R1", + Type = "PhysicsCollider", + Interaction = "Raycast", + SimX = 50f, + SimY = 60f, + BoundsMinX = 50f, + BoundsMinY = 60f, + BoundsMaxX = 50f, + BoundsMaxY = 60f + } + }; + GameObject overlay = UIElementAnnotator.CreateAnnotationOverlay(elements, 1f); + + try + { + RectTransform innerTop = overlay.transform.Find("Border_DarkInner_Top").GetComponent(); + + Assert.That(innerTop.anchoredPosition, Is.EqualTo(new Vector2(41f, 67f))); + Assert.That(innerTop.sizeDelta, Is.EqualTo(new Vector2(18f, 2f))); + } + finally + { + UIElementAnnotator.DestroyAnnotationOverlay(overlay); + } + } + + [Test] + public void CreateAnnotationOverlay_WhenPhysicsBoundsAreNarrow_ShouldExpandAroundCoverageCenter() + { + List elements = new List + { + new UIElementInfo + { + Label = "R1", + Type = "PhysicsCollider", + Interaction = "Raycast", + SimX = 0f, + SimY = 5f, + BoundsMinX = 0f, + BoundsMinY = 0f, + BoundsMaxX = 10f, + BoundsMaxY = 10f + } + }; + GameObject overlay = UIElementAnnotator.CreateAnnotationOverlay(elements, 1f); + + try + { + RectTransform innerTop = overlay.transform.Find("Border_DarkInner_Top").GetComponent(); + + Assert.That(innerTop.anchoredPosition, Is.EqualTo(new Vector2(-4f, 12f))); + Assert.That(innerTop.sizeDelta, Is.EqualTo(new Vector2(18f, 2f))); + } + finally + { + UIElementAnnotator.DestroyAnnotationOverlay(overlay); + } + } + [Test] public void CreateAnnotationOverlay_WhenMultipleElementsAreAnnotated_ShouldDrawLabelsAboveAllBorders() { diff --git a/Packages/src/Editor/Api/McpTools/Screenshot/Skill/SKILL.md b/Packages/src/Editor/Api/McpTools/Screenshot/Skill/SKILL.md index e947b838f0..1435640bdc 100644 --- a/Packages/src/Editor/Api/McpTools/Screenshot/Skill/SKILL.md +++ b/Packages/src/Editor/Api/McpTools/Screenshot/Skill/SKILL.md @@ -118,5 +118,5 @@ When multiple windows match (e.g., multiple Inspector windows or when using `con - Use `ScreenshotToInputFormula` before passing raw image pixels to mouse tools. `AnnotatedElements[].SimX/SimY` and `RaycastGridPoints[].InputX/InputY` are already mouse-input coordinates. - To discover a useful physics layer, first run `--annotate-raycast-grid` without `--raycast-layer-mask`, inspect `RaycastLayerSummaries`, then rerun with `--raycast-layer-mask `. - Use `--raycast-layer-mask` with layer names from `find-game-objects` or project code when the game input code raycasts only specific layers. Layers hidden by Camera.main.cullingMask are not reported because they are not visible to the screenshot camera. -- Clustered `PhysicsCollider` entries avoid points where the frontmost EventSystem hit comes from a `GraphicRaycaster` UI element, including world-space Canvas UI. PhysicsRaycaster and other non-uGUI hits are not treated as UI occlusion. If the centroid-nearest sample is covered, the nearest uncovered sampled hit is used; if every sampled hit in the cluster is covered, that collider is omitted. +- Clustered `PhysicsCollider` entries avoid points where the frontmost EventSystem hit comes from a `GraphicRaycaster` UI element, including world-space Canvas UI. PhysicsRaycaster and other non-uGUI hits are not treated as UI occlusion. `BoundsMinX/Y` and `BoundsMaxX/Y` show the axis-aligned bbox of reachable sampled hits; use `SimX/SimY` for the actual click point. If every sampled hit in the cluster is covered, that collider is omitted. - Do not use `window` captures as mouse-input coordinates because they include Unity Editor chrome. diff --git a/Packages/src/Editor/Api/McpTools/Screenshot/Skill/references/annotated-elements.md b/Packages/src/Editor/Api/McpTools/Screenshot/Skill/references/annotated-elements.md index 90d016bb8d..a8f7d7633a 100644 --- a/Packages/src/Editor/Api/McpTools/Screenshot/Skill/references/annotated-elements.md +++ b/Packages/src/Editor/Api/McpTools/Screenshot/Skill/references/annotated-elements.md @@ -13,8 +13,8 @@ Read this when using `uloop screenshot --capture-mode rendering --annotate-eleme - `Interaction`: Derived interaction category (`Click`, `Drag`, `Drop`, `Text`) or `Raycast` for clustered physics collider entries. Use this to choose between `simulate-mouse-ui --action Click`, drag actions, or `simulate-mouse-input`/`raycast`. - `Layer`: Physics layer name for `PhysicsCollider` entries. Empty for UI entries. - `Components`: Collider and MonoBehaviour component type names from the hit GameObject for `PhysicsCollider` entries. Empty for UI entries. -- `SimX`, `SimY`: Center position in top-left Game View coordinates. Use these directly with `simulate-mouse-ui --x/--y`, `simulate-mouse-input --x/--y`, or `raycast --x/--y`. -- `BoundsMinX`, `BoundsMinY`, `BoundsMaxX`, `BoundsMaxY`: Bounding box in simulate-mouse coordinates +- `SimX`, `SimY`: Target click position in top-left Game View coordinates. For UI entries this is the element center; for `PhysicsCollider` entries this is a representative sampled hit. Use these directly with `simulate-mouse-ui --x/--y`, `simulate-mouse-input --x/--y`, or `raycast --x/--y`. +- `BoundsMinX`, `BoundsMinY`, `BoundsMaxX`, `BoundsMaxY`: Bounding box in simulate-mouse coordinates. For `PhysicsCollider` entries, this is the axis-aligned bounding box of reachable sampled raycast hits, not a guarantee that every interior point is clickable. - `SortingOrder`: Canvas sorting order. Higher values are in front. - `SiblingIndex`: Transform sibling index under the element's direct parent. Do not use it as a reliable z-order signal across nested UI hierarchies. @@ -40,11 +40,11 @@ input_y = image_y / resolutionScale + imageToInputOffsetY When `ResolutionScale` is `1.0` and `ImageToInputOffsetY` is `0`, raw image pixel coordinates already match mouse-input coordinates. `AnnotatedElements[].SimX/SimY` and `RaycastGridPoints[].InputX/InputY` are always returned as mouse-input coordinates, so pass those values directly. -For `PhysicsCollider` entries, `SimX/SimY` is a real sampled raycast hit nearest to the cluster centroid. This avoids synthetic center points that may fall into empty space for L-shaped or ring-shaped collider coverage. +For `PhysicsCollider` entries, `SimX/SimY` is a real sampled raycast hit nearest to the reachable cluster centroid. This avoids synthetic center points that may fall into empty space for L-shaped or ring-shaped collider coverage. Always use `SimX/SimY` for clicking; use `BoundsMinX/Y` and `BoundsMaxX/Y` only as a sampled coverage guide. `--raycast-layer-mask` filters by the requested physics layers and Camera.main.cullingMask. A layer that is requested but hidden from the active camera is treated as not visible and will not produce `PhysicsCollider` entries. -For clustered `PhysicsCollider` entries, points where the frontmost EventSystem hit comes from a `GraphicRaycaster` UI element are treated as covered by UI. This includes world-space Canvas UI. PhysicsRaycaster and other non-uGUI hits are not treated as UI occlusion. When the centroid-nearest sample is covered, the annotator promotes the nearest uncovered sampled hit; if every sampled hit in that collider cluster is covered, the collider is omitted from `AnnotatedElements`. +For clustered `PhysicsCollider` entries, points where the frontmost EventSystem hit comes from a `GraphicRaycaster` UI element are treated as covered by UI. This includes world-space Canvas UI. PhysicsRaycaster and other non-uGUI hits are not treated as UI occlusion. Bounds and `SimX/SimY` are both derived from the remaining reachable samples; if every sampled hit in that collider cluster is covered, the collider is omitted from `AnnotatedElements`. The mouse input tools convert internally to Unity Input System coordinates: diff --git a/Packages/src/Editor/Utils/RaycastGridAnnotator.cs b/Packages/src/Editor/Utils/RaycastGridAnnotator.cs index ec8b8670ca..c1eeeedf9b 100644 --- a/Packages/src/Editor/Utils/RaycastGridAnnotator.cs +++ b/Packages/src/Editor/Utils/RaycastGridAnnotator.cs @@ -128,19 +128,18 @@ internal static List CollectPhysicsColliderElements( for (int i = 0; i < clusters.Count; i++) { - RaycastClusterSample? representative = SelectUnoccludedRepresentative( + RaycastClusterInfo? reachableCluster = CreateReachableClusterForUiContext( clusters[i], uiRaycastContext, gameViewSize); - if (representative == null) + if (reachableCluster == null) { continue; } - clusters[i].Representative = representative; RaycastColliderMetadata metadata = - clusterCollection.MetadataByClusterKey[representative.ClusterKey]; - elements.Add(CreatePhysicsColliderElement($"R{elements.Count + 1}", clusters[i], metadata)); + clusterCollection.MetadataByClusterKey[reachableCluster.Representative.ClusterKey]; + elements.Add(CreatePhysicsColliderElement($"R{elements.Count + 1}", reachableCluster, metadata)); } return elements; @@ -392,8 +391,9 @@ internal static UIElementInfo CreatePhysicsColliderElement( RaycastClusterInfo cluster, RaycastColliderMetadata metadata) { + Debug.Assert(cluster.Samples.Count > 0, "Physics collider cluster must contain sampled hits."); RaycastClusterSample representative = cluster.Representative; - float halfSize = MARKER_SIZE / 2f; + RaycastSampleBounds sampleBounds = CalculateSampleBounds(cluster.Samples); UIElementInfo element = new UIElementInfo { @@ -404,10 +404,10 @@ internal static UIElementInfo CreatePhysicsColliderElement( Interaction = "Raycast", SimX = representative.InputX, SimY = representative.InputY, - BoundsMinX = representative.InputX - halfSize, - BoundsMinY = representative.InputY - halfSize, - BoundsMaxX = representative.InputX + halfSize, - BoundsMaxY = representative.InputY + halfSize, + BoundsMinX = sampleBounds.MinX, + BoundsMinY = sampleBounds.MinY, + BoundsMaxX = sampleBounds.MaxX, + BoundsMaxY = sampleBounds.MaxY, SortingOrder = 0, SiblingIndex = 0, Layer = metadata.Layer, @@ -423,6 +423,27 @@ internal static UIElementInfo CreatePhysicsColliderElement( return element; } + private static RaycastSampleBounds CalculateSampleBounds(List samples) + { + Debug.Assert(samples.Count > 0, "At least one raycast sample is required."); + + float minX = samples[0].InputX; + float minY = samples[0].InputY; + float maxX = samples[0].InputX; + float maxY = samples[0].InputY; + + for (int i = 1; i < samples.Count; i++) + { + RaycastClusterSample sample = samples[i]; + minX = Mathf.Min(minX, sample.InputX); + minY = Mathf.Min(minY, sample.InputY); + maxX = Mathf.Max(maxX, sample.InputX); + maxY = Mathf.Max(maxY, sample.InputY); + } + + return new RaycastSampleBounds(minX, minY, maxX, maxY); + } + private static UiRaycastHelper.RaycastContext? CreateUiRaycastContext() { EventSystem currentEventSystem = EventSystem.current; @@ -434,17 +455,17 @@ internal static UIElementInfo CreatePhysicsColliderElement( return new UiRaycastHelper.RaycastContext(currentEventSystem); } - private static RaycastClusterSample? SelectUnoccludedRepresentative( + private static RaycastClusterInfo? CreateReachableClusterForUiContext( RaycastClusterInfo cluster, UiRaycastHelper.RaycastContext? uiRaycastContext, Vector2 gameViewSize) { if (uiRaycastContext == null) { - return cluster.Representative; + return cluster; } - return RaycastHitClusterer.SelectReachableRepresentativeSample( + return RaycastHitClusterer.CreateReachableCluster( cluster.Samples, (RaycastClusterSample sample) => IsSampleOccludedByUi(sample, uiRaycastContext, gameViewSize)); } @@ -495,5 +516,21 @@ private static List GetRelevantComponentTypeNames(GameObject hitObject) return componentTypeNames; } + + private readonly struct RaycastSampleBounds + { + public readonly float MinX; + public readonly float MinY; + public readonly float MaxX; + public readonly float MaxY; + + public RaycastSampleBounds(float minX, float minY, float maxX, float maxY) + { + MinX = minX; + MinY = minY; + MaxX = maxX; + MaxY = maxY; + } + } } } diff --git a/Packages/src/Editor/Utils/RaycastHitClusterer.cs b/Packages/src/Editor/Utils/RaycastHitClusterer.cs index 78de77dec0..eca4afd95d 100644 --- a/Packages/src/Editor/Utils/RaycastHitClusterer.cs +++ b/Packages/src/Editor/Utils/RaycastHitClusterer.cs @@ -72,6 +72,14 @@ internal static RaycastClusterSample SelectRepresentativeSample(List samples, RaycastClusterSampleOcclusionCheck isOccluded) + { + RaycastClusterInfo? reachableCluster = CreateReachableCluster(samples, isOccluded); + return reachableCluster?.Representative; + } + + internal static RaycastClusterInfo? CreateReachableCluster( + List samples, + RaycastClusterSampleOcclusionCheck isOccluded) { System.Diagnostics.Debug.Assert(samples != null, "Raycast samples must not be null."); System.Diagnostics.Debug.Assert(isOccluded != null, "Raycast sample occlusion check must not be null."); @@ -79,18 +87,28 @@ internal static RaycastClusterSample SelectRepresentativeSample(List 0, "At least one raycast sample is required."); - List candidates = CreateSamplesOrderedByCentroidDistance(validSamples); - foreach (RaycastClusterSample candidate in candidates) + List reachableSamples = new List(); + foreach (RaycastClusterSample sample in validSamples) { - if (validIsOccluded(candidate)) + if (validIsOccluded(sample)) { continue; } - return candidate; + reachableSamples.Add(sample); + } + + if (reachableSamples.Count == 0) + { + return null; } - return null; + return new RaycastClusterInfo + { + Representative = SelectRepresentativeSample(reachableSamples), + SampleCount = reachableSamples.Count, + Samples = reachableSamples + }; } private static Vector2Like CalculateCentroid(List samples) @@ -117,51 +135,6 @@ private static float CalculateSquaredDistance(RaycastClusterSample sample, Vecto return deltaX * deltaX + deltaY * deltaY; } - private static List CreateSamplesOrderedByCentroidDistance( - List samples) - { - Vector2Like centroid = CalculateCentroid(samples); - List rankedSamples = new List(); - for (int i = 0; i < samples.Count; i++) - { - RaycastClusterSample sample = samples[i]; - rankedSamples.Add(new RankedRaycastClusterSample - { - Sample = sample, - OriginalIndex = i, - SquaredDistance = CalculateSquaredDistance(sample, centroid) - }); - } - - rankedSamples.Sort(CompareRankedSamples); - - List orderedSamples = new List(); - foreach (RankedRaycastClusterSample rankedSample in rankedSamples) - { - orderedSamples.Add(rankedSample.Sample); - } - - return orderedSamples; - } - - private static int CompareRankedSamples(RankedRaycastClusterSample left, RankedRaycastClusterSample right) - { - int distanceComparison = left.SquaredDistance.CompareTo(right.SquaredDistance); - if (distanceComparison != 0) - { - return distanceComparison; - } - - return left.OriginalIndex.CompareTo(right.OriginalIndex); - } - - private struct RankedRaycastClusterSample - { - public RaycastClusterSample Sample { get; set; } - public int OriginalIndex { get; set; } - public float SquaredDistance { get; set; } - } - private struct Vector2Like { public float X { get; set; } diff --git a/Packages/src/Editor/Utils/UIElementAnnotator.cs b/Packages/src/Editor/Utils/UIElementAnnotator.cs index 00a98bddbf..6d85f49e20 100644 --- a/Packages/src/Editor/Utils/UIElementAnnotator.cs +++ b/Packages/src/Editor/Utils/UIElementAnnotator.cs @@ -19,6 +19,7 @@ public static class UIElementAnnotator private const float LABEL_DARK_TEXT_LUMINANCE_THRESHOLD = 0.62f; private const float OUTPUT_LABEL_OUTLINE_DISTANCE = 2f; private const float OUTPUT_LABEL_TO_BORDER_GAP = 4f; + private const float MIN_VISIBLE_PHYSICS_COLLIDER_BOX_SIZE = 18f; private const string INTERACTION_CLICK = "Click"; private const string INTERACTION_DRAG = "Drag"; private const string INTERACTION_DROP = "Drop"; @@ -425,18 +426,69 @@ private static AnnotationDrawInfo CreateAnnotationDrawInfo(UIElementInfo element Color contrastColor = GetContrastingTextColor(color); AnnotationBorderColors borderColors = GetAnnotationBorderColors(color); string displayLabel = CreateDisplayLabel(element); + AnnotationBounds bounds = CreateAnnotationBounds(element); return new AnnotationDrawInfo( - element.BoundsMinX, - element.BoundsMinY, - element.BoundsMaxX, - element.BoundsMaxY, + bounds.MinX, + bounds.MinY, + bounds.MaxX, + bounds.MaxY, color, contrastColor, borderColors, displayLabel); } + private static AnnotationBounds CreateAnnotationBounds(UIElementInfo element) + { + AnnotationBounds bounds = new AnnotationBounds( + element.BoundsMinX, + element.BoundsMinY, + element.BoundsMaxX, + element.BoundsMaxY); + + if (element.Type != "PhysicsCollider") + { + return bounds; + } + + // JSON keeps the raw sampled-hit coverage; only the overlay expands tiny physics boxes so they remain visible. + return ExpandBoundsToMinimumSize( + bounds, + MIN_VISIBLE_PHYSICS_COLLIDER_BOX_SIZE); + } + + private static AnnotationBounds ExpandBoundsToMinimumSize( + AnnotationBounds bounds, + float minimumSize) + { + Debug.Assert(bounds.MaxX >= bounds.MinX, "Annotation max X must not be smaller than min X."); + Debug.Assert(bounds.MaxY >= bounds.MinY, "Annotation max Y must not be smaller than min Y."); + Debug.Assert(minimumSize >= 0f, "Minimum annotation size must not be negative."); + + float minX = bounds.MinX; + float minY = bounds.MinY; + float maxX = bounds.MaxX; + float maxY = bounds.MaxY; + float halfMinimumSize = minimumSize / 2f; + + if (maxX - minX < minimumSize) + { + float centerX = (bounds.MinX + bounds.MaxX) / 2f; + minX = centerX - halfMinimumSize; + maxX = centerX + halfMinimumSize; + } + + if (maxY - minY < minimumSize) + { + float centerY = (bounds.MinY + bounds.MaxY) / 2f; + minY = centerY - halfMinimumSize; + maxY = centerY + halfMinimumSize; + } + + return new AnnotationBounds(minX, minY, maxX, maxY); + } + private static void CreateBorder( Transform parent, string name, float minX, float minY, float maxX, float maxY, @@ -691,6 +743,22 @@ public AnnotationBorderColors(Color inner, Color middle, Color outer) } } + private readonly struct AnnotationBounds + { + public readonly float MinX; + public readonly float MinY; + public readonly float MaxX; + public readonly float MaxY; + + public AnnotationBounds(float minX, float minY, float maxX, float maxY) + { + MinX = minX; + MinY = minY; + MaxX = maxX; + MaxY = maxY; + } + } + private readonly struct AnnotationDrawInfo { public readonly float ScreenMinX; From 99e7d1fdf19f1c4e117977e6d355e5e60b68e70b Mon Sep 17 00:00:00 2001 From: hatayama Date: Sat, 4 Jul 2026 15:55:51 +0900 Subject: [PATCH 2/4] Expand raycast coverage bounds to sampled cells Treat each dense raycast hit as representing its sampled cell area, then clamp the resulting PhysicsCollider bounds to the captured Game View. This avoids frames that shrink inward from the visible collider area by half a sampling step. --- .../Tests/Editor/RaycastGridAnnotatorTests.cs | 83 ++++++++++++++----- .../Tests/Editor/UIElementAnnotatorTests.cs | 67 --------------- .../Api/McpTools/Screenshot/Skill/SKILL.md | 2 +- .../Skill/references/annotated-elements.md | 4 +- .../src/Editor/Utils/RaycastGridAnnotator.cs | 54 +++++++++--- .../src/Editor/Utils/RaycastHitClusterer.cs | 29 +++++++ .../src/Editor/Utils/UIElementAnnotator.cs | 76 +---------------- 7 files changed, 138 insertions(+), 177 deletions(-) diff --git a/Assets/Tests/Editor/RaycastGridAnnotatorTests.cs b/Assets/Tests/Editor/RaycastGridAnnotatorTests.cs index 7aa1dc18f8..371f1c9195 100644 --- a/Assets/Tests/Editor/RaycastGridAnnotatorTests.cs +++ b/Assets/Tests/Editor/RaycastGridAnnotatorTests.cs @@ -250,7 +250,7 @@ public void CreateReachableCluster_WhenSamplesAreOccluded_ShouldExcludeOccludedS } [Test] - public void CreatePhysicsColliderElement_ShouldUseSampleBoundsInTopLeftInputSpace() + public void CreatePhysicsColliderElement_ShouldUseSampleCellBoundsInTopLeftInputSpace() { RaycastClusterInfo cluster = new RaycastClusterInfo { @@ -267,30 +267,52 @@ public void CreatePhysicsColliderElement_ShouldUseSampleBoundsInTopLeftInputSpac CreateSample(1, 130f, 220f) } }; - RaycastColliderMetadata metadata = new RaycastColliderMetadata - { - Name = "Cube", - Path = "Cube", - Layer = "Default", - Components = new List { "BoxCollider" } - }; + RaycastColliderMetadata metadata = CreateMetadata(); + RaycastSampleCoverage coverage = CreateCoverage(5f, 10f, 0f, 0f, 200f, 300f); - UIElementInfo element = RaycastGridAnnotator.CreatePhysicsColliderElement("R1", cluster, metadata); + UIElementInfo element = + RaycastGridAnnotator.CreatePhysicsColliderElement("R1", cluster, metadata, coverage); Assert.That(element.Type, Is.EqualTo("PhysicsCollider")); Assert.That(element.Interaction, Is.EqualTo("Raycast")); Assert.That(element.SimX, Is.EqualTo(100f)); Assert.That(element.SimY, Is.EqualTo(200f)); - Assert.That(element.BoundsMinX, Is.EqualTo(80f)); - Assert.That(element.BoundsMinY, Is.EqualTo(180f)); - Assert.That(element.BoundsMaxX, Is.EqualTo(130f)); - Assert.That(element.BoundsMaxY, Is.EqualTo(220f)); + Assert.That(element.BoundsMinX, Is.EqualTo(75f)); + Assert.That(element.BoundsMinY, Is.EqualTo(170f)); + Assert.That(element.BoundsMaxX, Is.EqualTo(135f)); + Assert.That(element.BoundsMaxY, Is.EqualTo(230f)); Assert.That(element.SimX, Is.InRange(element.BoundsMinX, element.BoundsMaxX)); Assert.That(element.SimY, Is.InRange(element.BoundsMinY, element.BoundsMaxY)); } [Test] - public void CreatePhysicsColliderElement_WhenSamplesFormLShape_ShouldUseAxisAlignedBoundingBox() + public void CreatePhysicsColliderElement_WhenSamplesTouchViewportEdge_ShouldClampCellBounds() + { + RaycastClusterInfo cluster = new RaycastClusterInfo + { + Representative = CreateSample(1, 3f, 4f), + SampleCount = 1, + Samples = new List + { + CreateSample(1, 3f, 4f) + } + }; + RaycastSampleCoverage coverage = CreateCoverage(5f, 10f, 0f, 0f, 200f, 300f); + + UIElementInfo element = RaycastGridAnnotator.CreatePhysicsColliderElement( + "R1", + cluster, + CreateMetadata(), + coverage); + + Assert.That(element.BoundsMinX, Is.EqualTo(0f)); + Assert.That(element.BoundsMinY, Is.EqualTo(0f)); + Assert.That(element.BoundsMaxX, Is.EqualTo(8f)); + Assert.That(element.BoundsMaxY, Is.EqualTo(14f)); + } + + [Test] + public void CreatePhysicsColliderElement_WhenSamplesFormLShape_ShouldUseAxisAlignedCellBoundingBox() { RaycastClusterInfo cluster = new RaycastClusterInfo { @@ -304,19 +326,21 @@ public void CreatePhysicsColliderElement_WhenSamplesFormLShape_ShouldUseAxisAlig } }; RaycastColliderMetadata metadata = CreateMetadata(); + RaycastSampleCoverage coverage = CreateCoverage(5f, 5f, 0f, 0f, 100f, 100f); - UIElementInfo element = RaycastGridAnnotator.CreatePhysicsColliderElement("R1", cluster, metadata); + UIElementInfo element = + RaycastGridAnnotator.CreatePhysicsColliderElement("R1", cluster, metadata, coverage); Assert.That(element.BoundsMinX, Is.EqualTo(0f)); Assert.That(element.BoundsMinY, Is.EqualTo(0f)); - Assert.That(element.BoundsMaxX, Is.EqualTo(10f)); - Assert.That(element.BoundsMaxY, Is.EqualTo(10f)); + Assert.That(element.BoundsMaxX, Is.EqualTo(15f)); + Assert.That(element.BoundsMaxY, Is.EqualTo(15f)); Assert.That(element.SimX, Is.EqualTo(0f)); Assert.That(element.SimY, Is.EqualTo(0f)); } [Test] - public void CreatePhysicsColliderElement_WhenClusterHasSingleSample_ShouldKeepDegenerateDataBounds() + public void CreatePhysicsColliderElement_WhenClusterHasSingleSample_ShouldUseOneSampleCellBounds() { RaycastClusterSample sample = CreateSample(1, 100f, 200f); RaycastClusterInfo cluster = new RaycastClusterInfo @@ -326,13 +350,15 @@ public void CreatePhysicsColliderElement_WhenClusterHasSingleSample_ShouldKeepDe Samples = new List { sample } }; RaycastColliderMetadata metadata = CreateMetadata(); + RaycastSampleCoverage coverage = CreateCoverage(5f, 10f, 0f, 0f, 200f, 300f); - UIElementInfo element = RaycastGridAnnotator.CreatePhysicsColliderElement("R1", cluster, metadata); + UIElementInfo element = + RaycastGridAnnotator.CreatePhysicsColliderElement("R1", cluster, metadata, coverage); - Assert.That(element.BoundsMinX, Is.EqualTo(100f)); - Assert.That(element.BoundsMinY, Is.EqualTo(200f)); - Assert.That(element.BoundsMaxX, Is.EqualTo(100f)); - Assert.That(element.BoundsMaxY, Is.EqualTo(200f)); + Assert.That(element.BoundsMinX, Is.EqualTo(95f)); + Assert.That(element.BoundsMinY, Is.EqualTo(190f)); + Assert.That(element.BoundsMaxX, Is.EqualTo(105f)); + Assert.That(element.BoundsMaxY, Is.EqualTo(210f)); } [Test] @@ -500,5 +526,16 @@ private static RaycastColliderMetadata CreateMetadata() Components = new List { "BoxCollider" } }; } + + private static RaycastSampleCoverage CreateCoverage( + float halfStepX, + float halfStepY, + float minX, + float minY, + float maxX, + float maxY) + { + return new RaycastSampleCoverage(halfStepX, halfStepY, minX, minY, maxX, maxY); + } } } diff --git a/Assets/Tests/Editor/UIElementAnnotatorTests.cs b/Assets/Tests/Editor/UIElementAnnotatorTests.cs index 43a9c25555..7a3cf20bdc 100644 --- a/Assets/Tests/Editor/UIElementAnnotatorTests.cs +++ b/Assets/Tests/Editor/UIElementAnnotatorTests.cs @@ -202,73 +202,6 @@ public void CreateAnnotationOverlay_WhenElementIsAnnotated_ShouldKeepLabelOutlin } } - [Test] - public void CreateAnnotationOverlay_WhenBoundsAreDegenerate_ShouldDrawMinimumVisibleBorderAroundSimPoint() - { - List elements = new List - { - new UIElementInfo - { - Label = "R1", - Type = "PhysicsCollider", - Interaction = "Raycast", - SimX = 50f, - SimY = 60f, - BoundsMinX = 50f, - BoundsMinY = 60f, - BoundsMaxX = 50f, - BoundsMaxY = 60f - } - }; - GameObject overlay = UIElementAnnotator.CreateAnnotationOverlay(elements, 1f); - - try - { - RectTransform innerTop = overlay.transform.Find("Border_DarkInner_Top").GetComponent(); - - Assert.That(innerTop.anchoredPosition, Is.EqualTo(new Vector2(41f, 67f))); - Assert.That(innerTop.sizeDelta, Is.EqualTo(new Vector2(18f, 2f))); - } - finally - { - UIElementAnnotator.DestroyAnnotationOverlay(overlay); - } - } - - [Test] - public void CreateAnnotationOverlay_WhenPhysicsBoundsAreNarrow_ShouldExpandAroundCoverageCenter() - { - List elements = new List - { - new UIElementInfo - { - Label = "R1", - Type = "PhysicsCollider", - Interaction = "Raycast", - SimX = 0f, - SimY = 5f, - BoundsMinX = 0f, - BoundsMinY = 0f, - BoundsMaxX = 10f, - BoundsMaxY = 10f - } - }; - GameObject overlay = UIElementAnnotator.CreateAnnotationOverlay(elements, 1f); - - try - { - RectTransform innerTop = overlay.transform.Find("Border_DarkInner_Top").GetComponent(); - - Assert.That(innerTop.anchoredPosition, Is.EqualTo(new Vector2(-4f, 12f))); - Assert.That(innerTop.sizeDelta, Is.EqualTo(new Vector2(18f, 2f))); - } - finally - { - UIElementAnnotator.DestroyAnnotationOverlay(overlay); - } - } - - [Test] public void CreateAnnotationOverlay_WhenMultipleElementsAreAnnotated_ShouldDrawLabelsAboveAllBorders() { List elements = new List diff --git a/Packages/src/Editor/Api/McpTools/Screenshot/Skill/SKILL.md b/Packages/src/Editor/Api/McpTools/Screenshot/Skill/SKILL.md index 1435640bdc..49ebeaaa7d 100644 --- a/Packages/src/Editor/Api/McpTools/Screenshot/Skill/SKILL.md +++ b/Packages/src/Editor/Api/McpTools/Screenshot/Skill/SKILL.md @@ -118,5 +118,5 @@ When multiple windows match (e.g., multiple Inspector windows or when using `con - Use `ScreenshotToInputFormula` before passing raw image pixels to mouse tools. `AnnotatedElements[].SimX/SimY` and `RaycastGridPoints[].InputX/InputY` are already mouse-input coordinates. - To discover a useful physics layer, first run `--annotate-raycast-grid` without `--raycast-layer-mask`, inspect `RaycastLayerSummaries`, then rerun with `--raycast-layer-mask `. - Use `--raycast-layer-mask` with layer names from `find-game-objects` or project code when the game input code raycasts only specific layers. Layers hidden by Camera.main.cullingMask are not reported because they are not visible to the screenshot camera. -- Clustered `PhysicsCollider` entries avoid points where the frontmost EventSystem hit comes from a `GraphicRaycaster` UI element, including world-space Canvas UI. PhysicsRaycaster and other non-uGUI hits are not treated as UI occlusion. `BoundsMinX/Y` and `BoundsMaxX/Y` show the axis-aligned bbox of reachable sampled hits; use `SimX/SimY` for the actual click point. If every sampled hit in the cluster is covered, that collider is omitted. +- Clustered `PhysicsCollider` entries avoid points where the frontmost EventSystem hit comes from a `GraphicRaycaster` UI element, including world-space Canvas UI. PhysicsRaycaster and other non-uGUI hits are not treated as UI occlusion. `BoundsMinX/Y` and `BoundsMaxX/Y` show the axis-aligned sampled-cell coverage bbox from reachable hits; use `SimX/SimY` for the actual click point. If every sampled hit in the cluster is covered, that collider is omitted. - Do not use `window` captures as mouse-input coordinates because they include Unity Editor chrome. diff --git a/Packages/src/Editor/Api/McpTools/Screenshot/Skill/references/annotated-elements.md b/Packages/src/Editor/Api/McpTools/Screenshot/Skill/references/annotated-elements.md index a8f7d7633a..da1083ff51 100644 --- a/Packages/src/Editor/Api/McpTools/Screenshot/Skill/references/annotated-elements.md +++ b/Packages/src/Editor/Api/McpTools/Screenshot/Skill/references/annotated-elements.md @@ -14,7 +14,7 @@ Read this when using `uloop screenshot --capture-mode rendering --annotate-eleme - `Layer`: Physics layer name for `PhysicsCollider` entries. Empty for UI entries. - `Components`: Collider and MonoBehaviour component type names from the hit GameObject for `PhysicsCollider` entries. Empty for UI entries. - `SimX`, `SimY`: Target click position in top-left Game View coordinates. For UI entries this is the element center; for `PhysicsCollider` entries this is a representative sampled hit. Use these directly with `simulate-mouse-ui --x/--y`, `simulate-mouse-input --x/--y`, or `raycast --x/--y`. -- `BoundsMinX`, `BoundsMinY`, `BoundsMaxX`, `BoundsMaxY`: Bounding box in simulate-mouse coordinates. For `PhysicsCollider` entries, this is the axis-aligned bounding box of reachable sampled raycast hits, not a guarantee that every interior point is clickable. +- `BoundsMinX`, `BoundsMinY`, `BoundsMaxX`, `BoundsMaxY`: Bounding box in simulate-mouse coordinates. For `PhysicsCollider` entries, this is the axis-aligned sampled-cell coverage box from reachable raycast hits, not a guarantee that every interior point is clickable. - `SortingOrder`: Canvas sorting order. Higher values are in front. - `SiblingIndex`: Transform sibling index under the element's direct parent. Do not use it as a reliable z-order signal across nested UI hierarchies. @@ -46,6 +46,8 @@ For `PhysicsCollider` entries, `SimX/SimY` is a real sampled raycast hit nearest For clustered `PhysicsCollider` entries, points where the frontmost EventSystem hit comes from a `GraphicRaycaster` UI element are treated as covered by UI. This includes world-space Canvas UI. PhysicsRaycaster and other non-uGUI hits are not treated as UI occlusion. Bounds and `SimX/SimY` are both derived from the remaining reachable samples; if every sampled hit in that collider cluster is covered, the collider is omitted from `AnnotatedElements`. +`PhysicsCollider` bounds expand each reachable sample by half the dense raycast sampling step in X and Y, then clamp the result to the captured Game View area. This makes the frame approximate the covered raycast cells instead of shrinking to the sample centers. It may extend up to half a sample step past the visible collider edge, and it still does not guarantee that every interior point is clickable. + The mouse input tools convert internally to Unity Input System coordinates: ```text diff --git a/Packages/src/Editor/Utils/RaycastGridAnnotator.cs b/Packages/src/Editor/Utils/RaycastGridAnnotator.cs index c1eeeedf9b..40ce38cfd5 100644 --- a/Packages/src/Editor/Utils/RaycastGridAnnotator.cs +++ b/Packages/src/Editor/Utils/RaycastGridAnnotator.cs @@ -125,6 +125,8 @@ internal static List CollectPhysicsColliderElements( List elements = new List(); UiRaycastHelper.RaycastContext? uiRaycastContext = CreateUiRaycastContext(); Vector2 gameViewSize = GameViewCoordinateUtility.GetMainGameViewSize(); + RaycastSampleCoverage sampleCoverage = + CreateClusterSampleCoverage(renderingImageSize, imageToInputOffsetY); for (int i = 0; i < clusters.Count; i++) { @@ -139,7 +141,11 @@ internal static List CollectPhysicsColliderElements( RaycastColliderMetadata metadata = clusterCollection.MetadataByClusterKey[reachableCluster.Representative.ClusterKey]; - elements.Add(CreatePhysicsColliderElement($"R{elements.Count + 1}", reachableCluster, metadata)); + elements.Add(CreatePhysicsColliderElement( + $"R{elements.Count + 1}", + reachableCluster, + metadata, + sampleCoverage)); } return elements; @@ -389,11 +395,12 @@ private static RaycastColliderMetadata CreateColliderMetadata(Collider collider) internal static UIElementInfo CreatePhysicsColliderElement( string label, RaycastClusterInfo cluster, - RaycastColliderMetadata metadata) + RaycastColliderMetadata metadata, + RaycastSampleCoverage sampleCoverage) { Debug.Assert(cluster.Samples.Count > 0, "Physics collider cluster must contain sampled hits."); RaycastClusterSample representative = cluster.Representative; - RaycastSampleBounds sampleBounds = CalculateSampleBounds(cluster.Samples); + RaycastSampleBounds sampleBounds = CalculateSampleCellBounds(cluster.Samples, sampleCoverage); UIElementInfo element = new UIElementInfo { @@ -423,25 +430,46 @@ internal static UIElementInfo CreatePhysicsColliderElement( return element; } - private static RaycastSampleBounds CalculateSampleBounds(List samples) + private static RaycastSampleCoverage CreateClusterSampleCoverage( + Vector2 renderingImageSize, + int imageToInputOffsetY) + { + float stepX = renderingImageSize.x / (CLUSTERED_GRID_COLUMNS + 1f); + float stepY = renderingImageSize.y / (CLUSTERED_GRID_ROWS + 1f); + return new RaycastSampleCoverage( + stepX / 2f, + stepY / 2f, + 0f, + imageToInputOffsetY, + renderingImageSize.x, + imageToInputOffsetY + renderingImageSize.y); + } + + private static RaycastSampleBounds CalculateSampleCellBounds( + List samples, + RaycastSampleCoverage sampleCoverage) { Debug.Assert(samples.Count > 0, "At least one raycast sample is required."); - float minX = samples[0].InputX; - float minY = samples[0].InputY; - float maxX = samples[0].InputX; - float maxY = samples[0].InputY; + float minX = samples[0].InputX - sampleCoverage.HalfStepX; + float minY = samples[0].InputY - sampleCoverage.HalfStepY; + float maxX = samples[0].InputX + sampleCoverage.HalfStepX; + float maxY = samples[0].InputY + sampleCoverage.HalfStepY; for (int i = 1; i < samples.Count; i++) { RaycastClusterSample sample = samples[i]; - minX = Mathf.Min(minX, sample.InputX); - minY = Mathf.Min(minY, sample.InputY); - maxX = Mathf.Max(maxX, sample.InputX); - maxY = Mathf.Max(maxY, sample.InputY); + minX = Mathf.Min(minX, sample.InputX - sampleCoverage.HalfStepX); + minY = Mathf.Min(minY, sample.InputY - sampleCoverage.HalfStepY); + maxX = Mathf.Max(maxX, sample.InputX + sampleCoverage.HalfStepX); + maxY = Mathf.Max(maxY, sample.InputY + sampleCoverage.HalfStepY); } - return new RaycastSampleBounds(minX, minY, maxX, maxY); + return new RaycastSampleBounds( + Mathf.Clamp(minX, sampleCoverage.MinX, sampleCoverage.MaxX), + Mathf.Clamp(minY, sampleCoverage.MinY, sampleCoverage.MaxY), + Mathf.Clamp(maxX, sampleCoverage.MinX, sampleCoverage.MaxX), + Mathf.Clamp(maxY, sampleCoverage.MinY, sampleCoverage.MaxY)); } private static UiRaycastHelper.RaycastContext? CreateUiRaycastContext() diff --git a/Packages/src/Editor/Utils/RaycastHitClusterer.cs b/Packages/src/Editor/Utils/RaycastHitClusterer.cs index eca4afd95d..da938c3331 100644 --- a/Packages/src/Editor/Utils/RaycastHitClusterer.cs +++ b/Packages/src/Editor/Utils/RaycastHitClusterer.cs @@ -188,4 +188,33 @@ internal sealed class RaycastClusterCollection public Dictionary MetadataByClusterKey { get; set; } = new Dictionary(); } + + /// + /// Describes the screen-space cell area represented by each dense raycast sample. + /// + internal readonly struct RaycastSampleCoverage + { + public readonly float HalfStepX; + public readonly float HalfStepY; + public readonly float MinX; + public readonly float MinY; + public readonly float MaxX; + public readonly float MaxY; + + public RaycastSampleCoverage( + float halfStepX, + float halfStepY, + float minX, + float minY, + float maxX, + float maxY) + { + HalfStepX = halfStepX; + HalfStepY = halfStepY; + MinX = minX; + MinY = minY; + MaxX = maxX; + MaxY = maxY; + } + } } diff --git a/Packages/src/Editor/Utils/UIElementAnnotator.cs b/Packages/src/Editor/Utils/UIElementAnnotator.cs index 6d85f49e20..00a98bddbf 100644 --- a/Packages/src/Editor/Utils/UIElementAnnotator.cs +++ b/Packages/src/Editor/Utils/UIElementAnnotator.cs @@ -19,7 +19,6 @@ public static class UIElementAnnotator private const float LABEL_DARK_TEXT_LUMINANCE_THRESHOLD = 0.62f; private const float OUTPUT_LABEL_OUTLINE_DISTANCE = 2f; private const float OUTPUT_LABEL_TO_BORDER_GAP = 4f; - private const float MIN_VISIBLE_PHYSICS_COLLIDER_BOX_SIZE = 18f; private const string INTERACTION_CLICK = "Click"; private const string INTERACTION_DRAG = "Drag"; private const string INTERACTION_DROP = "Drop"; @@ -426,69 +425,18 @@ private static AnnotationDrawInfo CreateAnnotationDrawInfo(UIElementInfo element Color contrastColor = GetContrastingTextColor(color); AnnotationBorderColors borderColors = GetAnnotationBorderColors(color); string displayLabel = CreateDisplayLabel(element); - AnnotationBounds bounds = CreateAnnotationBounds(element); return new AnnotationDrawInfo( - bounds.MinX, - bounds.MinY, - bounds.MaxX, - bounds.MaxY, + element.BoundsMinX, + element.BoundsMinY, + element.BoundsMaxX, + element.BoundsMaxY, color, contrastColor, borderColors, displayLabel); } - private static AnnotationBounds CreateAnnotationBounds(UIElementInfo element) - { - AnnotationBounds bounds = new AnnotationBounds( - element.BoundsMinX, - element.BoundsMinY, - element.BoundsMaxX, - element.BoundsMaxY); - - if (element.Type != "PhysicsCollider") - { - return bounds; - } - - // JSON keeps the raw sampled-hit coverage; only the overlay expands tiny physics boxes so they remain visible. - return ExpandBoundsToMinimumSize( - bounds, - MIN_VISIBLE_PHYSICS_COLLIDER_BOX_SIZE); - } - - private static AnnotationBounds ExpandBoundsToMinimumSize( - AnnotationBounds bounds, - float minimumSize) - { - Debug.Assert(bounds.MaxX >= bounds.MinX, "Annotation max X must not be smaller than min X."); - Debug.Assert(bounds.MaxY >= bounds.MinY, "Annotation max Y must not be smaller than min Y."); - Debug.Assert(minimumSize >= 0f, "Minimum annotation size must not be negative."); - - float minX = bounds.MinX; - float minY = bounds.MinY; - float maxX = bounds.MaxX; - float maxY = bounds.MaxY; - float halfMinimumSize = minimumSize / 2f; - - if (maxX - minX < minimumSize) - { - float centerX = (bounds.MinX + bounds.MaxX) / 2f; - minX = centerX - halfMinimumSize; - maxX = centerX + halfMinimumSize; - } - - if (maxY - minY < minimumSize) - { - float centerY = (bounds.MinY + bounds.MaxY) / 2f; - minY = centerY - halfMinimumSize; - maxY = centerY + halfMinimumSize; - } - - return new AnnotationBounds(minX, minY, maxX, maxY); - } - private static void CreateBorder( Transform parent, string name, float minX, float minY, float maxX, float maxY, @@ -743,22 +691,6 @@ public AnnotationBorderColors(Color inner, Color middle, Color outer) } } - private readonly struct AnnotationBounds - { - public readonly float MinX; - public readonly float MinY; - public readonly float MaxX; - public readonly float MaxY; - - public AnnotationBounds(float minX, float minY, float maxX, float maxY) - { - MinX = minX; - MinY = minY; - MaxX = maxX; - MaxY = maxY; - } - } - private readonly struct AnnotationDrawInfo { public readonly float ScreenMinX; From e14f8680169660598aa7aadae395f228145ec341 Mon Sep 17 00:00:00 2001 From: hatayama Date: Sat, 4 Jul 2026 16:16:20 +0900 Subject: [PATCH 3/4] Show reachable raycast coverage cells Make annotated screenshots display the sampled reachable cells behind each PhysicsCollider bbox so the visual overlay reflects UI occlusion and sparse collider shapes more clearly. Add a maintained raycast annotation demo scene for manual visual checks without adding heavy PlayMode screenshot tests. --- .../Scenes/RaycastAnnotationDemoScene.unity | 2474 +++++++++++++++++ .../RaycastAnnotationDemoScene.unity.meta | 7 + .../Tests/Editor/RaycastGridAnnotatorTests.cs | 49 + .../Tests/Editor/UIElementAnnotatorTests.cs | 37 + .../Api/McpTools/Screenshot/Skill/SKILL.md | 12 +- .../Skill/references/annotated-elements.md | 2 + .../Api/McpTools/Screenshot/UIElementInfo.cs | 1 + .../src/Editor/Utils/RaycastGridAnnotator.cs | 73 +- .../src/Editor/Utils/RaycastHitClusterer.cs | 19 + .../src/Editor/Utils/UIElementAnnotator.cs | 62 +- 10 files changed, 2715 insertions(+), 21 deletions(-) create mode 100644 Assets/Scenes/RaycastAnnotationDemoScene.unity create mode 100644 Assets/Scenes/RaycastAnnotationDemoScene.unity.meta diff --git a/Assets/Scenes/RaycastAnnotationDemoScene.unity b/Assets/Scenes/RaycastAnnotationDemoScene.unity new file mode 100644 index 0000000000..aecc2642e9 --- /dev/null +++ b/Assets/Scenes/RaycastAnnotationDemoScene.unity @@ -0,0 +1,2474 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 9 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 0 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 0} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 12 + m_GIWorkflowMode: 1 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 1 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 12 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_FinalGather: 0 + m_FinalGatherFiltering: 1 + m_FinalGatherRayCount: 256 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 1 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 512 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 256 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 1 + m_PVRDenoiserTypeDirect: 1 + m_PVRDenoiserTypeIndirect: 1 + m_PVRDenoiserTypeAO: 1 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 1 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 0} + m_LightingSettings: {fileID: 0} +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 3 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + buildHeightMesh: 0 + maxJobWorkers: 0 + preserveTilesOutsideBounds: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &128138856 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 128138857} + - component: {fileID: 128138860} + - component: {fileID: 128138859} + - component: {fileID: 128138858} + m_Layer: 0 + m_Name: Tile_R2_C1 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &128138857 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 128138856} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: -1, y: 0, z: 1} + m_LocalScale: {x: 1.45, y: 0.18, z: 1.45} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1532071732} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!23 &128138858 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 128138856} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2072082154} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 1 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!65 &128138859 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 128138856} + m_Material: {fileID: 0} + m_IncludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_ExcludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_LayerOverridePriority: 0 + m_IsTrigger: 0 + m_ProvidesContacts: 0 + m_Enabled: 1 + serializedVersion: 3 + m_Size: {x: 1, y: 1, z: 1} + m_Center: {x: 0, y: 0, z: 0} +--- !u!33 &128138860 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 128138856} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!1 &184452851 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 184452854} + - component: {fileID: 184452853} + - component: {fileID: 184452852} + m_Layer: 0 + m_Name: Main Camera + m_TagString: MainCamera + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &184452852 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 184452851} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: c49b4cc203aa6414fae5c798d1d0e7d6, type: 3} + m_Name: + m_EditorClassIdentifier: + m_EventMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_MaxRayIntersections: 0 +--- !u!20 &184452853 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 184452851} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 2 + m_BackGroundColor: {r: 0.09, g: 0.1, b: 0.11, a: 1} + m_projectionMatrixMode: 1 + m_GateFitMode: 2 + m_FOVAxisMode: 0 + m_Iso: 200 + m_ShutterSpeed: 0.005 + m_Aperture: 16 + m_FocusDistance: 10 + m_FocalLength: 50 + m_BladeCount: 5 + m_Curvature: {x: 2, y: 11} + m_BarrelClipping: 0.25 + m_Anamorphism: 0 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.3 + far clip plane: 1000 + field of view: 60 + orthographic: 1 + orthographic size: 5.1 + m_Depth: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 1 + m_AllowMSAA: 1 + m_AllowDynamicResolution: 0 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 +--- !u!4 &184452854 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 184452851} + serializedVersion: 2 + m_LocalRotation: {x: 0.7071068, y: 0, z: 0, w: 0.7071068} + m_LocalPosition: {x: 0, y: 9, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &185973232 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 185973233} + - component: {fileID: 185973235} + - component: {fileID: 185973234} + m_Layer: 0 + m_Name: Blocker Label + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &185973233 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 185973232} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1775107324} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &185973234 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 185973232} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0, g: 0, b: 0, a: 1} + m_RaycastTarget: 0 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 26 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 10 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: 'GraphicRaycaster UI blocker + + covered cells should be omitted' +--- !u!222 &185973235 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 185973232} + m_CullTransparentMesh: 1 +--- !u!1 &409953280 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 409953283} + - component: {fileID: 409953282} + - component: {fileID: 409953281} + m_Layer: 0 + m_Name: EventSystem + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &409953281 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 409953280} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4f231c4fb786f3946a6b90b886c48677, type: 3} + m_Name: + m_EditorClassIdentifier: + m_SendPointerHoverToParent: 1 + m_HorizontalAxis: Horizontal + m_VerticalAxis: Vertical + m_SubmitButton: Submit + m_CancelButton: Cancel + m_InputActionsPerSecond: 10 + m_RepeatDelay: 0.5 + m_ForceModuleActive: 0 +--- !u!114 &409953282 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 409953280} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 76c392e42b5098c458856cdf6ecaaaa1, type: 3} + m_Name: + m_EditorClassIdentifier: + m_FirstSelected: {fileID: 0} + m_sendNavigationEvents: 1 + m_DragThreshold: 10 +--- !u!4 &409953283 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 409953280} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &414012158 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 414012159} + - component: {fileID: 414012162} + - component: {fileID: 414012161} + - component: {fileID: 414012160} + m_Layer: 0 + m_Name: Tile_R3_C2 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &414012159 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 414012158} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 1, y: 0, z: 3} + m_LocalScale: {x: 1.45, y: 0.18, z: 1.45} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1532071732} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!23 &414012160 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 414012158} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2072082154} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 1 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!65 &414012161 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 414012158} + m_Material: {fileID: 0} + m_IncludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_ExcludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_LayerOverridePriority: 0 + m_IsTrigger: 0 + m_ProvidesContacts: 0 + m_Enabled: 1 + serializedVersion: 3 + m_Size: {x: 1, y: 1, z: 1} + m_Center: {x: 0, y: 0, z: 0} +--- !u!33 &414012162 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 414012158} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!1 &520917552 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 520917553} + - component: {fileID: 520917556} + - component: {fileID: 520917555} + - component: {fileID: 520917554} + m_Layer: 0 + m_Name: Tile_R0_C1 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &520917553 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 520917552} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: -1, y: 0, z: -3} + m_LocalScale: {x: 1.45, y: 0.18, z: 1.45} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1532071732} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!23 &520917554 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 520917552} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2072082154} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 1 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!65 &520917555 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 520917552} + m_Material: {fileID: 0} + m_IncludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_ExcludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_LayerOverridePriority: 0 + m_IsTrigger: 0 + m_ProvidesContacts: 0 + m_Enabled: 1 + serializedVersion: 3 + m_Size: {x: 1, y: 1, z: 1} + m_Center: {x: 0, y: 0, z: 0} +--- !u!33 &520917556 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 520917552} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!1 &697539236 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 697539237} + - component: {fileID: 697539240} + - component: {fileID: 697539239} + - component: {fileID: 697539238} + m_Layer: 0 + m_Name: Tile_R2_C3 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &697539237 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 697539236} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 3, y: 0, z: 1} + m_LocalScale: {x: 1.45, y: 0.18, z: 1.45} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1532071732} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!23 &697539238 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 697539236} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2072082154} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 1 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!65 &697539239 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 697539236} + m_Material: {fileID: 0} + m_IncludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_ExcludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_LayerOverridePriority: 0 + m_IsTrigger: 0 + m_ProvidesContacts: 0 + m_Enabled: 1 + serializedVersion: 3 + m_Size: {x: 1, y: 1, z: 1} + m_Center: {x: 0, y: 0, z: 0} +--- !u!33 &697539240 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 697539236} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!1 &1135534140 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1135534142} + - component: {fileID: 1135534141} + m_Layer: 0 + m_Name: Directional Light + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!108 &1135534141 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1135534140} + m_Enabled: 1 + serializedVersion: 10 + m_Type: 1 + m_Shape: 0 + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_Intensity: 1.4 + m_Range: 10 + m_SpotAngle: 30 + m_InnerSpotAngle: 21.80208 + m_CookieSize: 10 + m_Shadows: + m_Type: 0 + m_Resolution: -1 + m_CustomResolution: -1 + m_Strength: 1 + m_Bias: 0.05 + m_NormalBias: 0.4 + m_NearPlane: 0.2 + m_CullingMatrixOverride: + e00: 1 + e01: 0 + e02: 0 + e03: 0 + e10: 0 + e11: 1 + e12: 0 + e13: 0 + e20: 0 + e21: 0 + e22: 1 + e23: 0 + e30: 0 + e31: 0 + e32: 0 + e33: 1 + m_UseCullingMatrixOverride: 0 + m_Cookie: {fileID: 0} + m_DrawHalo: 0 + m_Flare: {fileID: 0} + m_RenderMode: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingLayerMask: 1 + m_Lightmapping: 4 + m_LightShadowCasterMode: 0 + m_AreaSize: {x: 1, y: 1} + m_BounceIntensity: 1 + m_ColorTemperature: 6570 + m_UseColorTemperature: 0 + m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} + m_UseBoundingSphereOverride: 0 + m_UseViewFrustumForShadowCasterCull: 1 + m_ShadowRadius: 0 + m_ShadowAngle: 0 +--- !u!4 &1135534142 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1135534140} + serializedVersion: 2 + m_LocalRotation: {x: 0.40821794, y: -0.23456973, z: 0.10938166, w: 0.8754261} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1142728930 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1142728931} + - component: {fileID: 1142728934} + - component: {fileID: 1142728933} + - component: {fileID: 1142728932} + m_Layer: 0 + m_Name: Tile_R1_C2 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1142728931 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1142728930} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 1, y: 0, z: -1} + m_LocalScale: {x: 1.45, y: 0.18, z: 1.45} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1532071732} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!23 &1142728932 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1142728930} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2072082154} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 1 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!65 &1142728933 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1142728930} + m_Material: {fileID: 0} + m_IncludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_ExcludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_LayerOverridePriority: 0 + m_IsTrigger: 0 + m_ProvidesContacts: 0 + m_Enabled: 1 + serializedVersion: 3 + m_Size: {x: 1, y: 1, z: 1} + m_Center: {x: 0, y: 0, z: 0} +--- !u!33 &1142728934 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1142728930} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!1 &1158729131 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1158729134} + - component: {fileID: 1158729133} + - component: {fileID: 1158729132} + m_Layer: 0 + m_Name: GraphicRaycaster UI Blocker Canvas + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1158729132 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1158729131} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: dc42784cf147c0c48a680349fa168899, type: 3} + m_Name: + m_EditorClassIdentifier: + m_IgnoreReversedGraphics: 1 + m_BlockingObjects: 0 + m_BlockingMask: + serializedVersion: 2 + m_Bits: 4294967295 +--- !u!223 &1158729133 +Canvas: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1158729131} + m_Enabled: 1 + serializedVersion: 3 + m_RenderMode: 0 + m_Camera: {fileID: 0} + m_PlaneDistance: 100 + m_PixelPerfect: 0 + m_ReceivesEvents: 1 + m_OverrideSorting: 0 + m_OverridePixelPerfect: 0 + m_SortingBucketNormalizedSize: 0 + m_VertexColorAlwaysGammaSpace: 0 + m_AdditionalShaderChannelsFlag: 0 + m_UpdateRectTransformForStandalone: 0 + m_SortingLayerID: 0 + m_SortingOrder: 100 + m_TargetDisplay: 0 +--- !u!224 &1158729134 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1158729131} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0, y: 0, z: 0} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 1775107324} + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0, y: 0} +--- !u!1 &1199182480 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1199182481} + - component: {fileID: 1199182484} + - component: {fileID: 1199182483} + - component: {fileID: 1199182482} + m_Layer: 0 + m_Name: Tile_R1_C3 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1199182481 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1199182480} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 3, y: 0, z: -1} + m_LocalScale: {x: 1.45, y: 0.18, z: 1.45} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1532071732} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!23 &1199182482 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1199182480} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2072082154} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 1 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!65 &1199182483 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1199182480} + m_Material: {fileID: 0} + m_IncludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_ExcludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_LayerOverridePriority: 0 + m_IsTrigger: 0 + m_ProvidesContacts: 0 + m_Enabled: 1 + serializedVersion: 3 + m_Size: {x: 1, y: 1, z: 1} + m_Center: {x: 0, y: 0, z: 0} +--- !u!33 &1199182484 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1199182480} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!1 &1330802383 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1330802384} + - component: {fileID: 1330802387} + - component: {fileID: 1330802386} + - component: {fileID: 1330802385} + m_Layer: 0 + m_Name: Tile_R3_C1 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1330802384 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1330802383} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: -1, y: 0, z: 3} + m_LocalScale: {x: 1.45, y: 0.18, z: 1.45} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1532071732} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!23 &1330802385 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1330802383} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2072082154} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 1 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!65 &1330802386 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1330802383} + m_Material: {fileID: 0} + m_IncludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_ExcludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_LayerOverridePriority: 0 + m_IsTrigger: 0 + m_ProvidesContacts: 0 + m_Enabled: 1 + serializedVersion: 3 + m_Size: {x: 1, y: 1, z: 1} + m_Center: {x: 0, y: 0, z: 0} +--- !u!33 &1330802387 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1330802383} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!1 &1373835101 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1373835102} + - component: {fileID: 1373835105} + - component: {fileID: 1373835104} + - component: {fileID: 1373835103} + m_Layer: 0 + m_Name: Tile_R0_C2 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1373835102 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1373835101} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 1, y: 0, z: -3} + m_LocalScale: {x: 1.45, y: 0.18, z: 1.45} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1532071732} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!23 &1373835103 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1373835101} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2072082154} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 1 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!65 &1373835104 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1373835101} + m_Material: {fileID: 0} + m_IncludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_ExcludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_LayerOverridePriority: 0 + m_IsTrigger: 0 + m_ProvidesContacts: 0 + m_Enabled: 1 + serializedVersion: 3 + m_Size: {x: 1, y: 1, z: 1} + m_Center: {x: 0, y: 0, z: 0} +--- !u!33 &1373835105 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1373835101} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!1 &1507164498 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1507164499} + - component: {fileID: 1507164502} + - component: {fileID: 1507164501} + - component: {fileID: 1507164500} + m_Layer: 0 + m_Name: Tile_R3_C0 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1507164499 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1507164498} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: -3, y: 0, z: 3} + m_LocalScale: {x: 1.45, y: 0.18, z: 1.45} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1532071732} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!23 &1507164500 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1507164498} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2072082154} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 1 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!65 &1507164501 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1507164498} + m_Material: {fileID: 0} + m_IncludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_ExcludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_LayerOverridePriority: 0 + m_IsTrigger: 0 + m_ProvidesContacts: 0 + m_Enabled: 1 + serializedVersion: 3 + m_Size: {x: 1, y: 1, z: 1} + m_Center: {x: 0, y: 0, z: 0} +--- !u!33 &1507164502 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1507164498} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!1 &1515363959 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1515363960} + - component: {fileID: 1515363963} + - component: {fileID: 1515363962} + - component: {fileID: 1515363961} + m_Layer: 0 + m_Name: Tile_R1_C1 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1515363960 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1515363959} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: -1, y: 0, z: -1} + m_LocalScale: {x: 1.45, y: 0.18, z: 1.45} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1532071732} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!23 &1515363961 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1515363959} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2072082154} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 1 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!65 &1515363962 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1515363959} + m_Material: {fileID: 0} + m_IncludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_ExcludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_LayerOverridePriority: 0 + m_IsTrigger: 0 + m_ProvidesContacts: 0 + m_Enabled: 1 + serializedVersion: 3 + m_Size: {x: 1, y: 1, z: 1} + m_Center: {x: 0, y: 0, z: 0} +--- !u!33 &1515363963 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1515363959} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!1 &1532071731 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1532071732} + m_Layer: 0 + m_Name: Reachable BoxCollider Tiles + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1532071732 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1532071731} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 2090378474} + - {fileID: 520917553} + - {fileID: 1373835102} + - {fileID: 1889137173} + - {fileID: 1742766827} + - {fileID: 1515363960} + - {fileID: 1142728931} + - {fileID: 1199182481} + - {fileID: 1921642720} + - {fileID: 128138857} + - {fileID: 1541081035} + - {fileID: 697539237} + - {fileID: 1507164499} + - {fileID: 1330802384} + - {fileID: 414012159} + - {fileID: 2100127633} + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1541081034 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1541081035} + - component: {fileID: 1541081038} + - component: {fileID: 1541081037} + - component: {fileID: 1541081036} + m_Layer: 0 + m_Name: Tile_R2_C2 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1541081035 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1541081034} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 1, y: 0, z: 1} + m_LocalScale: {x: 1.45, y: 0.18, z: 1.45} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1532071732} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!23 &1541081036 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1541081034} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2072082154} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 1 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!65 &1541081037 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1541081034} + m_Material: {fileID: 0} + m_IncludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_ExcludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_LayerOverridePriority: 0 + m_IsTrigger: 0 + m_ProvidesContacts: 0 + m_Enabled: 1 + serializedVersion: 3 + m_Size: {x: 1, y: 1, z: 1} + m_Center: {x: 0, y: 0, z: 0} +--- !u!33 &1541081038 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1541081034} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!1 &1742766826 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1742766827} + - component: {fileID: 1742766830} + - component: {fileID: 1742766829} + - component: {fileID: 1742766828} + m_Layer: 0 + m_Name: Tile_R1_C0 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1742766827 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1742766826} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: -3, y: 0, z: -1} + m_LocalScale: {x: 1.45, y: 0.18, z: 1.45} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1532071732} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!23 &1742766828 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1742766826} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2072082154} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 1 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!65 &1742766829 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1742766826} + m_Material: {fileID: 0} + m_IncludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_ExcludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_LayerOverridePriority: 0 + m_IsTrigger: 0 + m_ProvidesContacts: 0 + m_Enabled: 1 + serializedVersion: 3 + m_Size: {x: 1, y: 1, z: 1} + m_Center: {x: 0, y: 0, z: 0} +--- !u!33 &1742766830 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1742766826} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!1 &1775107323 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1775107324} + - component: {fileID: 1775107326} + - component: {fileID: 1775107325} + m_Layer: 0 + m_Name: Center UI Raycast Blocker + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1775107324 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1775107323} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 185973233} + m_Father: {fileID: 1158729134} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 620, y: 340} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1775107325 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1775107323} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.8, g: 0.95, b: 0.85, a: 0.55} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 0} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1775107326 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1775107323} + m_CullTransparentMesh: 1 +--- !u!1 &1889137172 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1889137173} + - component: {fileID: 1889137176} + - component: {fileID: 1889137175} + - component: {fileID: 1889137174} + m_Layer: 0 + m_Name: Tile_R0_C3 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1889137173 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1889137172} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 3, y: 0, z: -3} + m_LocalScale: {x: 1.45, y: 0.18, z: 1.45} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1532071732} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!23 &1889137174 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1889137172} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2072082154} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 1 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!65 &1889137175 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1889137172} + m_Material: {fileID: 0} + m_IncludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_ExcludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_LayerOverridePriority: 0 + m_IsTrigger: 0 + m_ProvidesContacts: 0 + m_Enabled: 1 + serializedVersion: 3 + m_Size: {x: 1, y: 1, z: 1} + m_Center: {x: 0, y: 0, z: 0} +--- !u!33 &1889137176 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1889137172} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!1 &1921642719 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1921642720} + - component: {fileID: 1921642723} + - component: {fileID: 1921642722} + - component: {fileID: 1921642721} + m_Layer: 0 + m_Name: Tile_R2_C0 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1921642720 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1921642719} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: -3, y: 0, z: 1} + m_LocalScale: {x: 1.45, y: 0.18, z: 1.45} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1532071732} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!23 &1921642721 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1921642719} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2072082154} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 1 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!65 &1921642722 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1921642719} + m_Material: {fileID: 0} + m_IncludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_ExcludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_LayerOverridePriority: 0 + m_IsTrigger: 0 + m_ProvidesContacts: 0 + m_Enabled: 1 + serializedVersion: 3 + m_Size: {x: 1, y: 1, z: 1} + m_Center: {x: 0, y: 0, z: 0} +--- !u!33 &1921642723 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1921642719} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!21 &2072082154 +Material: + serializedVersion: 8 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Universal Render Pipeline/Lit + m_Shader: {fileID: 4800000, guid: 933532a4fcc9baf4fa0491de14d08ed7, type: 3} + m_Parent: {fileID: 0} + m_ModifiedSerializedProperties: 0 + m_ValidKeywords: [] + m_InvalidKeywords: [] + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_LockedProperties: + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BaseMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _SpecGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_Lightmaps: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_LightmapsInd: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_ShadowMasks: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Ints: [] + m_Floats: + - _AlphaClip: 0 + - _AlphaToMask: 0 + - _Blend: 0 + - _BlendModePreserveSpecular: 1 + - _BumpScale: 1 + - _ClearCoatMask: 0 + - _ClearCoatSmoothness: 0 + - _Cull: 2 + - _Cutoff: 0.5 + - _DetailAlbedoMapScale: 1 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _DstBlendAlpha: 0 + - _EnvironmentReflections: 1 + - _GlossMapScale: 0 + - _Glossiness: 0 + - _GlossyReflections: 0 + - _Metallic: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.005 + - _QueueOffset: 0 + - _ReceiveShadows: 1 + - _Smoothness: 0.5 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _SrcBlendAlpha: 1 + - _Surface: 0 + - _WorkflowMode: 1 + - _ZWrite: 1 + m_Colors: + - _BaseColor: {r: 0.05, g: 0.95, b: 0.25, a: 1} + - _Color: {r: 1, g: 1, b: 1, a: 1} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} + - _SpecColor: {r: 0.19999996, g: 0.19999996, b: 0.19999996, a: 1} + m_BuildTextureStacks: [] +--- !u!1 &2090378473 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2090378474} + - component: {fileID: 2090378477} + - component: {fileID: 2090378476} + - component: {fileID: 2090378475} + m_Layer: 0 + m_Name: Tile_R0_C0 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &2090378474 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2090378473} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: -3, y: 0, z: -3} + m_LocalScale: {x: 1.45, y: 0.18, z: 1.45} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1532071732} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!23 &2090378475 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2090378473} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2072082154} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 1 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!65 &2090378476 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2090378473} + m_Material: {fileID: 0} + m_IncludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_ExcludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_LayerOverridePriority: 0 + m_IsTrigger: 0 + m_ProvidesContacts: 0 + m_Enabled: 1 + serializedVersion: 3 + m_Size: {x: 1, y: 1, z: 1} + m_Center: {x: 0, y: 0, z: 0} +--- !u!33 &2090378477 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2090378473} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!1 &2100127632 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2100127633} + - component: {fileID: 2100127636} + - component: {fileID: 2100127635} + - component: {fileID: 2100127634} + m_Layer: 0 + m_Name: Tile_R3_C3 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &2100127633 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2100127632} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 3, y: 0, z: 3} + m_LocalScale: {x: 1.45, y: 0.18, z: 1.45} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1532071732} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!23 &2100127634 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2100127632} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2072082154} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 1 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!65 &2100127635 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2100127632} + m_Material: {fileID: 0} + m_IncludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_ExcludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_LayerOverridePriority: 0 + m_IsTrigger: 0 + m_ProvidesContacts: 0 + m_Enabled: 1 + serializedVersion: 3 + m_Size: {x: 1, y: 1, z: 1} + m_Center: {x: 0, y: 0, z: 0} +--- !u!33 &2100127636 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2100127632} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!1660057539 &9223372036854775807 +SceneRoots: + m_ObjectHideFlags: 0 + m_Roots: + - {fileID: 184452854} + - {fileID: 1135534142} + - {fileID: 1532071732} + - {fileID: 409953283} + - {fileID: 1158729134} diff --git a/Assets/Scenes/RaycastAnnotationDemoScene.unity.meta b/Assets/Scenes/RaycastAnnotationDemoScene.unity.meta new file mode 100644 index 0000000000..fd43425996 --- /dev/null +++ b/Assets/Scenes/RaycastAnnotationDemoScene.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 259bd0cea4f8c423fa6c0341f14d80b2 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Tests/Editor/RaycastGridAnnotatorTests.cs b/Assets/Tests/Editor/RaycastGridAnnotatorTests.cs index 371f1c9195..69a978b90e 100644 --- a/Assets/Tests/Editor/RaycastGridAnnotatorTests.cs +++ b/Assets/Tests/Editor/RaycastGridAnnotatorTests.cs @@ -361,6 +361,42 @@ public void CreatePhysicsColliderElement_WhenClusterHasSingleSample_ShouldUseOne Assert.That(element.BoundsMaxY, Is.EqualTo(210f)); } + [Test] + public void CreateSampleCoverageCells_WhenSamplesFormLShape_ShouldPreserveHitCellShape() + { + List samples = new List + { + CreateSample(1, 20f, 20f), + CreateSample(1, 30f, 20f), + CreateSample(1, 20f, 30f) + }; + RaycastSampleCoverage coverage = CreateCoverage(5f, 5f, 0f, 0f, 100f, 100f); + + List coverageCells = + RaycastGridAnnotator.CreateSampleCoverageCells(samples, coverage); + + Assert.That(coverageCells.Count, Is.EqualTo(3)); + AssertCoverageCell(coverageCells[0], 15f, 15f, 25f, 25f); + AssertCoverageCell(coverageCells[1], 25f, 15f, 35f, 25f); + AssertCoverageCell(coverageCells[2], 15f, 25f, 25f, 35f); + } + + [Test] + public void CreateSampleCoverageCells_WhenSampleTouchesViewportEdge_ShouldClampCell() + { + List samples = new List + { + CreateSample(1, 3f, 4f) + }; + RaycastSampleCoverage coverage = CreateCoverage(5f, 10f, 0f, 0f, 200f, 300f); + + List coverageCells = + RaycastGridAnnotator.CreateSampleCoverageCells(samples, coverage); + + Assert.That(coverageCells.Count, Is.EqualTo(1)); + AssertCoverageCell(coverageCells[0], 0f, 0f, 8f, 14f); + } + [Test] public void IsUiOcclusionRaycastResult_WhenGraphicRaycasterHit_ShouldReturnTrue() { @@ -537,5 +573,18 @@ private static RaycastSampleCoverage CreateCoverage( { return new RaycastSampleCoverage(halfStepX, halfStepY, minX, minY, maxX, maxY); } + + private static void AssertCoverageCell( + RaycastCoverageCell coverageCell, + float minX, + float minY, + float maxX, + float maxY) + { + Assert.That(coverageCell.MinX, Is.EqualTo(minX)); + Assert.That(coverageCell.MinY, Is.EqualTo(minY)); + Assert.That(coverageCell.MaxX, Is.EqualTo(maxX)); + Assert.That(coverageCell.MaxY, Is.EqualTo(maxY)); + } } } diff --git a/Assets/Tests/Editor/UIElementAnnotatorTests.cs b/Assets/Tests/Editor/UIElementAnnotatorTests.cs index 7a3cf20bdc..a9ded64950 100644 --- a/Assets/Tests/Editor/UIElementAnnotatorTests.cs +++ b/Assets/Tests/Editor/UIElementAnnotatorTests.cs @@ -172,6 +172,43 @@ public void CreateAnnotationOverlay_WhenElementIsAnnotated_ShouldUseThickerColor } } + [Test] + public void CreateAnnotationOverlay_WhenRaycastCoverageCellsExist_ShouldDrawFillBelowBorders() + { + UIElementInfo element = new UIElementInfo + { + Label = "A", + Type = "PhysicsCollider", + Interaction = "Raycast", + BoundsMinX = 10f, + BoundsMinY = 20f, + BoundsMaxX = 110f, + BoundsMaxY = 70f + }; + element.RaycastCoverageCells.Add(new RaycastCoverageCell(12f, 24f, 42f, 54f)); + List elements = new List { element }; + GameObject overlay = UIElementAnnotator.CreateAnnotationOverlay(elements, 1f); + + try + { + Transform fill = overlay.transform.Find("RaycastCoverageFill_0"); + Transform border = overlay.transform.Find("Border_DarkInner_Top"); + Assert.That(fill, Is.Not.Null); + Assert.That(fill.GetSiblingIndex(), Is.LessThan(border.GetSiblingIndex())); + + RectTransform fillRect = fill.GetComponent(); + Image fillImage = fill.GetComponent(); + Assert.That(fillRect.anchoredPosition, Is.EqualTo(new Vector2(12f, 24f))); + Assert.That(fillRect.sizeDelta, Is.EqualTo(new Vector2(30f, 30f))); + Assert.That(fillImage.color.a, Is.EqualTo(0.25f).Within(0.001f)); + Assert.That(fillImage.raycastTarget, Is.False); + } + finally + { + UIElementAnnotator.DestroyAnnotationOverlay(overlay); + } + } + [Test] public void CreateAnnotationOverlay_WhenElementIsAnnotated_ShouldKeepLabelOutlineAwayFromBorder() { diff --git a/Packages/src/Editor/Api/McpTools/Screenshot/Skill/SKILL.md b/Packages/src/Editor/Api/McpTools/Screenshot/Skill/SKILL.md index 49ebeaaa7d..2f04544e9c 100644 --- a/Packages/src/Editor/Api/McpTools/Screenshot/Skill/SKILL.md +++ b/Packages/src/Editor/Api/McpTools/Screenshot/Skill/SKILL.md @@ -118,5 +118,15 @@ When multiple windows match (e.g., multiple Inspector windows or when using `con - Use `ScreenshotToInputFormula` before passing raw image pixels to mouse tools. `AnnotatedElements[].SimX/SimY` and `RaycastGridPoints[].InputX/InputY` are already mouse-input coordinates. - To discover a useful physics layer, first run `--annotate-raycast-grid` without `--raycast-layer-mask`, inspect `RaycastLayerSummaries`, then rerun with `--raycast-layer-mask `. - Use `--raycast-layer-mask` with layer names from `find-game-objects` or project code when the game input code raycasts only specific layers. Layers hidden by Camera.main.cullingMask are not reported because they are not visible to the screenshot camera. -- Clustered `PhysicsCollider` entries avoid points where the frontmost EventSystem hit comes from a `GraphicRaycaster` UI element, including world-space Canvas UI. PhysicsRaycaster and other non-uGUI hits are not treated as UI occlusion. `BoundsMinX/Y` and `BoundsMaxX/Y` show the axis-aligned sampled-cell coverage bbox from reachable hits; use `SimX/SimY` for the actual click point. If every sampled hit in the cluster is covered, that collider is omitted. +- Clustered `PhysicsCollider` entries avoid points where the frontmost EventSystem hit comes from a `GraphicRaycaster` UI element, including world-space Canvas UI. PhysicsRaycaster and other non-uGUI hits are not treated as UI occlusion. `BoundsMinX/Y` and `BoundsMaxX/Y` show the axis-aligned sampled-cell coverage bbox from reachable hits; use `SimX/SimY` for the actual click point. In annotated screenshots, translucent filled cells show the sampled reachable coverage, the frame shows the `Bounds` bbox, and the marker shows `SimX/SimY`. If every sampled hit in the cluster is covered, that collider is omitted. + +### Raycast Annotation Demo Scene + +Use `Assets/Scenes/RaycastAnnotationDemoScene.unity` as the maintained visual fixture for raycast annotation checks. Enter PlayMode, then run: + +```bash +uloop screenshot --capture-mode rendering --annotate-raycast-grid true --raycast-layer-mask Default --resolution-scale 1 +``` + +The scene contains a deterministic 4x4 set of `BoxCollider` tiles and a center `GraphicRaycaster` UI blocker. Verify relative behavior rather than fixed pixel coordinates: translucent cells should appear only where raycast samples remain reachable, center tiles should shrink around the blocker, frames should wrap those reachable cells, and `SimX/SimY` should stay inside each frame. - Do not use `window` captures as mouse-input coordinates because they include Unity Editor chrome. diff --git a/Packages/src/Editor/Api/McpTools/Screenshot/Skill/references/annotated-elements.md b/Packages/src/Editor/Api/McpTools/Screenshot/Skill/references/annotated-elements.md index da1083ff51..f018cb36c5 100644 --- a/Packages/src/Editor/Api/McpTools/Screenshot/Skill/references/annotated-elements.md +++ b/Packages/src/Editor/Api/McpTools/Screenshot/Skill/references/annotated-elements.md @@ -48,6 +48,8 @@ For clustered `PhysicsCollider` entries, points where the frontmost EventSystem `PhysicsCollider` bounds expand each reachable sample by half the dense raycast sampling step in X and Y, then clamp the result to the captured Game View area. This makes the frame approximate the covered raycast cells instead of shrinking to the sample centers. It may extend up to half a sample step past the visible collider edge, and it still does not guarantee that every interior point is clickable. +In annotated screenshots, translucent filled cells show the sampled reachable coverage at the current raycast grid resolution. The frame is the `BoundsMinX/Y` to `BoundsMaxX/Y` bbox around those cells, and the marker is the verified click point `SimX/SimY`. The filled shape can still differ from the exact rendered collider edge by up to half a sample step. + The mouse input tools convert internally to Unity Input System coordinates: ```text diff --git a/Packages/src/Editor/Api/McpTools/Screenshot/UIElementInfo.cs b/Packages/src/Editor/Api/McpTools/Screenshot/UIElementInfo.cs index 1127409204..4ad1600a12 100644 --- a/Packages/src/Editor/Api/McpTools/Screenshot/UIElementInfo.cs +++ b/Packages/src/Editor/Api/McpTools/Screenshot/UIElementInfo.cs @@ -19,5 +19,6 @@ public class UIElementInfo public string Label { get; set; } = ""; public int SortingOrder { get; set; } public int SiblingIndex { get; set; } + internal List RaycastCoverageCells { get; set; } = new List(); } } diff --git a/Packages/src/Editor/Utils/RaycastGridAnnotator.cs b/Packages/src/Editor/Utils/RaycastGridAnnotator.cs index 40ce38cfd5..1e5a5aadff 100644 --- a/Packages/src/Editor/Utils/RaycastGridAnnotator.cs +++ b/Packages/src/Editor/Utils/RaycastGridAnnotator.cs @@ -400,7 +400,9 @@ internal static UIElementInfo CreatePhysicsColliderElement( { Debug.Assert(cluster.Samples.Count > 0, "Physics collider cluster must contain sampled hits."); RaycastClusterSample representative = cluster.Representative; - RaycastSampleBounds sampleBounds = CalculateSampleCellBounds(cluster.Samples, sampleCoverage); + List coverageCells = + CreateSampleCoverageCells(cluster.Samples, sampleCoverage); + RaycastSampleBounds sampleBounds = CalculateSampleCellBounds(coverageCells); UIElementInfo element = new UIElementInfo { @@ -418,7 +420,8 @@ internal static UIElementInfo CreatePhysicsColliderElement( SortingOrder = 0, SiblingIndex = 0, Layer = metadata.Layer, - Components = new List(metadata.Components) + Components = new List(metadata.Components), + RaycastCoverageCells = coverageCells }; Debug.Assert( @@ -445,31 +448,65 @@ private static RaycastSampleCoverage CreateClusterSampleCoverage( imageToInputOffsetY + renderingImageSize.y); } - private static RaycastSampleBounds CalculateSampleCellBounds( + internal static List CreateSampleCoverageCells( List samples, RaycastSampleCoverage sampleCoverage) { Debug.Assert(samples.Count > 0, "At least one raycast sample is required."); - float minX = samples[0].InputX - sampleCoverage.HalfStepX; - float minY = samples[0].InputY - sampleCoverage.HalfStepY; - float maxX = samples[0].InputX + sampleCoverage.HalfStepX; - float maxY = samples[0].InputY + sampleCoverage.HalfStepY; + List coverageCells = new List(samples.Count); + foreach (RaycastClusterSample sample in samples) + { + coverageCells.Add(CreateSampleCoverageCell(sample, sampleCoverage)); + } + + return coverageCells; + } + + private static RaycastCoverageCell CreateSampleCoverageCell( + RaycastClusterSample sample, + RaycastSampleCoverage sampleCoverage) + { + float minX = Mathf.Clamp( + sample.InputX - sampleCoverage.HalfStepX, + sampleCoverage.MinX, + sampleCoverage.MaxX); + float minY = Mathf.Clamp( + sample.InputY - sampleCoverage.HalfStepY, + sampleCoverage.MinY, + sampleCoverage.MaxY); + float maxX = Mathf.Clamp( + sample.InputX + sampleCoverage.HalfStepX, + sampleCoverage.MinX, + sampleCoverage.MaxX); + float maxY = Mathf.Clamp( + sample.InputY + sampleCoverage.HalfStepY, + sampleCoverage.MinY, + sampleCoverage.MaxY); + + return new RaycastCoverageCell(minX, minY, maxX, maxY); + } + + private static RaycastSampleBounds CalculateSampleCellBounds( + List coverageCells) + { + Debug.Assert(coverageCells.Count > 0, "At least one raycast coverage cell is required."); + + float minX = coverageCells[0].MinX; + float minY = coverageCells[0].MinY; + float maxX = coverageCells[0].MaxX; + float maxY = coverageCells[0].MaxY; - for (int i = 1; i < samples.Count; i++) + for (int i = 1; i < coverageCells.Count; i++) { - RaycastClusterSample sample = samples[i]; - minX = Mathf.Min(minX, sample.InputX - sampleCoverage.HalfStepX); - minY = Mathf.Min(minY, sample.InputY - sampleCoverage.HalfStepY); - maxX = Mathf.Max(maxX, sample.InputX + sampleCoverage.HalfStepX); - maxY = Mathf.Max(maxY, sample.InputY + sampleCoverage.HalfStepY); + RaycastCoverageCell coverageCell = coverageCells[i]; + minX = Mathf.Min(minX, coverageCell.MinX); + minY = Mathf.Min(minY, coverageCell.MinY); + maxX = Mathf.Max(maxX, coverageCell.MaxX); + maxY = Mathf.Max(maxY, coverageCell.MaxY); } - return new RaycastSampleBounds( - Mathf.Clamp(minX, sampleCoverage.MinX, sampleCoverage.MaxX), - Mathf.Clamp(minY, sampleCoverage.MinY, sampleCoverage.MaxY), - Mathf.Clamp(maxX, sampleCoverage.MinX, sampleCoverage.MaxX), - Mathf.Clamp(maxY, sampleCoverage.MinY, sampleCoverage.MaxY)); + return new RaycastSampleBounds(minX, minY, maxX, maxY); } private static UiRaycastHelper.RaycastContext? CreateUiRaycastContext() diff --git a/Packages/src/Editor/Utils/RaycastHitClusterer.cs b/Packages/src/Editor/Utils/RaycastHitClusterer.cs index da938c3331..ecd129389e 100644 --- a/Packages/src/Editor/Utils/RaycastHitClusterer.cs +++ b/Packages/src/Editor/Utils/RaycastHitClusterer.cs @@ -217,4 +217,23 @@ public RaycastSampleCoverage( MaxY = maxY; } } + + /// + /// Describes one visible raycast sample cell in screen-space coordinates. + /// + internal readonly struct RaycastCoverageCell + { + public readonly float MinX; + public readonly float MinY; + public readonly float MaxX; + public readonly float MaxY; + + public RaycastCoverageCell(float minX, float minY, float maxX, float maxY) + { + MinX = minX; + MinY = minY; + MaxX = maxX; + MaxY = maxY; + } + } } diff --git a/Packages/src/Editor/Utils/UIElementAnnotator.cs b/Packages/src/Editor/Utils/UIElementAnnotator.cs index 00a98bddbf..d913509e79 100644 --- a/Packages/src/Editor/Utils/UIElementAnnotator.cs +++ b/Packages/src/Editor/Utils/UIElementAnnotator.cs @@ -19,6 +19,7 @@ public static class UIElementAnnotator private const float LABEL_DARK_TEXT_LUMINANCE_THRESHOLD = 0.62f; private const float OUTPUT_LABEL_OUTLINE_DISTANCE = 2f; private const float OUTPUT_LABEL_TO_BORDER_GAP = 4f; + private const float RAYCAST_COVERAGE_FILL_ALPHA = 0.25f; private const string INTERACTION_CLICK = "Click"; private const string INTERACTION_DRAG = "Drag"; private const string INTERACTION_DROP = "Drop"; @@ -120,6 +121,11 @@ public static GameObject CreateAnnotationOverlay(List elements, f drawInfos.Add(CreateAnnotationDrawInfo(element)); } + foreach (AnnotationDrawInfo drawInfo in drawInfos) + { + CreateRaycastCoverageFillForElement(root.transform, drawInfo); + } + foreach (AnnotationDrawInfo drawInfo in drawInfos) { CreateAnnotationBorderForElement(root.transform, drawInfo, borderMetrics); @@ -434,7 +440,56 @@ private static AnnotationDrawInfo CreateAnnotationDrawInfo(UIElementInfo element color, contrastColor, borderColors, - displayLabel); + displayLabel, + element.RaycastCoverageCells); + } + + private static void CreateRaycastCoverageFillForElement( + Transform parent, + AnnotationDrawInfo drawInfo) + { + if (drawInfo.RaycastCoverageCells.Count == 0) + { + return; + } + + Color fillColor = drawInfo.Color; + fillColor.a = RAYCAST_COVERAGE_FILL_ALPHA; + for (int i = 0; i < drawInfo.RaycastCoverageCells.Count; i++) + { + CreateRaycastCoverageFillCell( + parent, + i, + drawInfo.RaycastCoverageCells[i], + fillColor); + } + } + + private static void CreateRaycastCoverageFillCell( + Transform parent, + int index, + RaycastCoverageCell coverageCell, + Color color) + { + Debug.Assert(coverageCell.MaxX >= coverageCell.MinX, "Coverage cell maxX must not be smaller than minX."); + Debug.Assert(coverageCell.MaxY >= coverageCell.MinY, "Coverage cell maxY must not be smaller than minY."); + + GameObject fillGo = new GameObject($"RaycastCoverageFill_{index}"); + fillGo.hideFlags = HideFlags.HideAndDontSave; + fillGo.transform.SetParent(parent, false); + + RectTransform rt = fillGo.AddComponent(); + rt.anchorMin = Vector2.zero; + rt.anchorMax = Vector2.zero; + rt.pivot = Vector2.zero; + rt.anchoredPosition = new Vector2(coverageCell.MinX, coverageCell.MinY); + rt.sizeDelta = new Vector2( + coverageCell.MaxX - coverageCell.MinX, + coverageCell.MaxY - coverageCell.MinY); + + Image image = fillGo.AddComponent(); + image.color = color; + image.raycastTarget = false; } private static void CreateBorder( @@ -701,6 +756,7 @@ private readonly struct AnnotationDrawInfo public readonly Color ContrastColor; public readonly AnnotationBorderColors BorderColors; public readonly string DisplayLabel; + public readonly List RaycastCoverageCells; public AnnotationDrawInfo( float screenMinX, @@ -710,7 +766,8 @@ public AnnotationDrawInfo( Color color, Color contrastColor, AnnotationBorderColors borderColors, - string displayLabel) + string displayLabel, + List raycastCoverageCells) { ScreenMinX = screenMinX; ScreenMinY = screenMinY; @@ -720,6 +777,7 @@ public AnnotationDrawInfo( ContrastColor = contrastColor; BorderColors = borderColors; DisplayLabel = displayLabel; + RaycastCoverageCells = raycastCoverageCells; } } From ad9c737d708a303a08f2716409e268ac7f7d6720 Mon Sep 17 00:00:00 2001 From: hatayama Date: Sat, 4 Jul 2026 16:26:48 +0900 Subject: [PATCH 4/4] Remove raycast coverage fill overlay Drop the translucent sampled-cell fill after user feedback showed the bbox-only annotation is easier to read. Keep the sampled-cell bbox behavior and the maintained raycast annotation demo scene for future visual checks. --- .../Tests/Editor/RaycastGridAnnotatorTests.cs | 49 ------------- .../Tests/Editor/UIElementAnnotatorTests.cs | 37 ---------- .../Api/McpTools/Screenshot/Skill/SKILL.md | 4 +- .../Skill/references/annotated-elements.md | 2 - .../Api/McpTools/Screenshot/UIElementInfo.cs | 1 - .../src/Editor/Utils/RaycastGridAnnotator.cs | 73 +++++-------------- .../src/Editor/Utils/RaycastHitClusterer.cs | 18 ----- .../src/Editor/Utils/UIElementAnnotator.cs | 62 +--------------- 8 files changed, 22 insertions(+), 224 deletions(-) diff --git a/Assets/Tests/Editor/RaycastGridAnnotatorTests.cs b/Assets/Tests/Editor/RaycastGridAnnotatorTests.cs index 69a978b90e..371f1c9195 100644 --- a/Assets/Tests/Editor/RaycastGridAnnotatorTests.cs +++ b/Assets/Tests/Editor/RaycastGridAnnotatorTests.cs @@ -361,42 +361,6 @@ public void CreatePhysicsColliderElement_WhenClusterHasSingleSample_ShouldUseOne Assert.That(element.BoundsMaxY, Is.EqualTo(210f)); } - [Test] - public void CreateSampleCoverageCells_WhenSamplesFormLShape_ShouldPreserveHitCellShape() - { - List samples = new List - { - CreateSample(1, 20f, 20f), - CreateSample(1, 30f, 20f), - CreateSample(1, 20f, 30f) - }; - RaycastSampleCoverage coverage = CreateCoverage(5f, 5f, 0f, 0f, 100f, 100f); - - List coverageCells = - RaycastGridAnnotator.CreateSampleCoverageCells(samples, coverage); - - Assert.That(coverageCells.Count, Is.EqualTo(3)); - AssertCoverageCell(coverageCells[0], 15f, 15f, 25f, 25f); - AssertCoverageCell(coverageCells[1], 25f, 15f, 35f, 25f); - AssertCoverageCell(coverageCells[2], 15f, 25f, 25f, 35f); - } - - [Test] - public void CreateSampleCoverageCells_WhenSampleTouchesViewportEdge_ShouldClampCell() - { - List samples = new List - { - CreateSample(1, 3f, 4f) - }; - RaycastSampleCoverage coverage = CreateCoverage(5f, 10f, 0f, 0f, 200f, 300f); - - List coverageCells = - RaycastGridAnnotator.CreateSampleCoverageCells(samples, coverage); - - Assert.That(coverageCells.Count, Is.EqualTo(1)); - AssertCoverageCell(coverageCells[0], 0f, 0f, 8f, 14f); - } - [Test] public void IsUiOcclusionRaycastResult_WhenGraphicRaycasterHit_ShouldReturnTrue() { @@ -573,18 +537,5 @@ private static RaycastSampleCoverage CreateCoverage( { return new RaycastSampleCoverage(halfStepX, halfStepY, minX, minY, maxX, maxY); } - - private static void AssertCoverageCell( - RaycastCoverageCell coverageCell, - float minX, - float minY, - float maxX, - float maxY) - { - Assert.That(coverageCell.MinX, Is.EqualTo(minX)); - Assert.That(coverageCell.MinY, Is.EqualTo(minY)); - Assert.That(coverageCell.MaxX, Is.EqualTo(maxX)); - Assert.That(coverageCell.MaxY, Is.EqualTo(maxY)); - } } } diff --git a/Assets/Tests/Editor/UIElementAnnotatorTests.cs b/Assets/Tests/Editor/UIElementAnnotatorTests.cs index a9ded64950..7a3cf20bdc 100644 --- a/Assets/Tests/Editor/UIElementAnnotatorTests.cs +++ b/Assets/Tests/Editor/UIElementAnnotatorTests.cs @@ -172,43 +172,6 @@ public void CreateAnnotationOverlay_WhenElementIsAnnotated_ShouldUseThickerColor } } - [Test] - public void CreateAnnotationOverlay_WhenRaycastCoverageCellsExist_ShouldDrawFillBelowBorders() - { - UIElementInfo element = new UIElementInfo - { - Label = "A", - Type = "PhysicsCollider", - Interaction = "Raycast", - BoundsMinX = 10f, - BoundsMinY = 20f, - BoundsMaxX = 110f, - BoundsMaxY = 70f - }; - element.RaycastCoverageCells.Add(new RaycastCoverageCell(12f, 24f, 42f, 54f)); - List elements = new List { element }; - GameObject overlay = UIElementAnnotator.CreateAnnotationOverlay(elements, 1f); - - try - { - Transform fill = overlay.transform.Find("RaycastCoverageFill_0"); - Transform border = overlay.transform.Find("Border_DarkInner_Top"); - Assert.That(fill, Is.Not.Null); - Assert.That(fill.GetSiblingIndex(), Is.LessThan(border.GetSiblingIndex())); - - RectTransform fillRect = fill.GetComponent(); - Image fillImage = fill.GetComponent(); - Assert.That(fillRect.anchoredPosition, Is.EqualTo(new Vector2(12f, 24f))); - Assert.That(fillRect.sizeDelta, Is.EqualTo(new Vector2(30f, 30f))); - Assert.That(fillImage.color.a, Is.EqualTo(0.25f).Within(0.001f)); - Assert.That(fillImage.raycastTarget, Is.False); - } - finally - { - UIElementAnnotator.DestroyAnnotationOverlay(overlay); - } - } - [Test] public void CreateAnnotationOverlay_WhenElementIsAnnotated_ShouldKeepLabelOutlineAwayFromBorder() { diff --git a/Packages/src/Editor/Api/McpTools/Screenshot/Skill/SKILL.md b/Packages/src/Editor/Api/McpTools/Screenshot/Skill/SKILL.md index 2f04544e9c..cfea5d46a3 100644 --- a/Packages/src/Editor/Api/McpTools/Screenshot/Skill/SKILL.md +++ b/Packages/src/Editor/Api/McpTools/Screenshot/Skill/SKILL.md @@ -118,7 +118,7 @@ When multiple windows match (e.g., multiple Inspector windows or when using `con - Use `ScreenshotToInputFormula` before passing raw image pixels to mouse tools. `AnnotatedElements[].SimX/SimY` and `RaycastGridPoints[].InputX/InputY` are already mouse-input coordinates. - To discover a useful physics layer, first run `--annotate-raycast-grid` without `--raycast-layer-mask`, inspect `RaycastLayerSummaries`, then rerun with `--raycast-layer-mask `. - Use `--raycast-layer-mask` with layer names from `find-game-objects` or project code when the game input code raycasts only specific layers. Layers hidden by Camera.main.cullingMask are not reported because they are not visible to the screenshot camera. -- Clustered `PhysicsCollider` entries avoid points where the frontmost EventSystem hit comes from a `GraphicRaycaster` UI element, including world-space Canvas UI. PhysicsRaycaster and other non-uGUI hits are not treated as UI occlusion. `BoundsMinX/Y` and `BoundsMaxX/Y` show the axis-aligned sampled-cell coverage bbox from reachable hits; use `SimX/SimY` for the actual click point. In annotated screenshots, translucent filled cells show the sampled reachable coverage, the frame shows the `Bounds` bbox, and the marker shows `SimX/SimY`. If every sampled hit in the cluster is covered, that collider is omitted. +- Clustered `PhysicsCollider` entries avoid points where the frontmost EventSystem hit comes from a `GraphicRaycaster` UI element, including world-space Canvas UI. PhysicsRaycaster and other non-uGUI hits are not treated as UI occlusion. `BoundsMinX/Y` and `BoundsMaxX/Y` show the axis-aligned sampled-cell coverage bbox from reachable hits; use `SimX/SimY` for the actual click point. If every sampled hit in the cluster is covered, that collider is omitted. ### Raycast Annotation Demo Scene @@ -128,5 +128,5 @@ Use `Assets/Scenes/RaycastAnnotationDemoScene.unity` as the maintained visual fi uloop screenshot --capture-mode rendering --annotate-raycast-grid true --raycast-layer-mask Default --resolution-scale 1 ``` -The scene contains a deterministic 4x4 set of `BoxCollider` tiles and a center `GraphicRaycaster` UI blocker. Verify relative behavior rather than fixed pixel coordinates: translucent cells should appear only where raycast samples remain reachable, center tiles should shrink around the blocker, frames should wrap those reachable cells, and `SimX/SimY` should stay inside each frame. +The scene contains a deterministic 4x4 set of `BoxCollider` tiles and a center `GraphicRaycaster` UI blocker. Verify relative behavior rather than fixed pixel coordinates: center tile frames should shrink around the blocker, frames should wrap the reachable sampled-cell bbox, and `SimX/SimY` should stay inside each frame. - Do not use `window` captures as mouse-input coordinates because they include Unity Editor chrome. diff --git a/Packages/src/Editor/Api/McpTools/Screenshot/Skill/references/annotated-elements.md b/Packages/src/Editor/Api/McpTools/Screenshot/Skill/references/annotated-elements.md index f018cb36c5..da1083ff51 100644 --- a/Packages/src/Editor/Api/McpTools/Screenshot/Skill/references/annotated-elements.md +++ b/Packages/src/Editor/Api/McpTools/Screenshot/Skill/references/annotated-elements.md @@ -48,8 +48,6 @@ For clustered `PhysicsCollider` entries, points where the frontmost EventSystem `PhysicsCollider` bounds expand each reachable sample by half the dense raycast sampling step in X and Y, then clamp the result to the captured Game View area. This makes the frame approximate the covered raycast cells instead of shrinking to the sample centers. It may extend up to half a sample step past the visible collider edge, and it still does not guarantee that every interior point is clickable. -In annotated screenshots, translucent filled cells show the sampled reachable coverage at the current raycast grid resolution. The frame is the `BoundsMinX/Y` to `BoundsMaxX/Y` bbox around those cells, and the marker is the verified click point `SimX/SimY`. The filled shape can still differ from the exact rendered collider edge by up to half a sample step. - The mouse input tools convert internally to Unity Input System coordinates: ```text diff --git a/Packages/src/Editor/Api/McpTools/Screenshot/UIElementInfo.cs b/Packages/src/Editor/Api/McpTools/Screenshot/UIElementInfo.cs index 4ad1600a12..1127409204 100644 --- a/Packages/src/Editor/Api/McpTools/Screenshot/UIElementInfo.cs +++ b/Packages/src/Editor/Api/McpTools/Screenshot/UIElementInfo.cs @@ -19,6 +19,5 @@ public class UIElementInfo public string Label { get; set; } = ""; public int SortingOrder { get; set; } public int SiblingIndex { get; set; } - internal List RaycastCoverageCells { get; set; } = new List(); } } diff --git a/Packages/src/Editor/Utils/RaycastGridAnnotator.cs b/Packages/src/Editor/Utils/RaycastGridAnnotator.cs index 1e5a5aadff..40ce38cfd5 100644 --- a/Packages/src/Editor/Utils/RaycastGridAnnotator.cs +++ b/Packages/src/Editor/Utils/RaycastGridAnnotator.cs @@ -400,9 +400,7 @@ internal static UIElementInfo CreatePhysicsColliderElement( { Debug.Assert(cluster.Samples.Count > 0, "Physics collider cluster must contain sampled hits."); RaycastClusterSample representative = cluster.Representative; - List coverageCells = - CreateSampleCoverageCells(cluster.Samples, sampleCoverage); - RaycastSampleBounds sampleBounds = CalculateSampleCellBounds(coverageCells); + RaycastSampleBounds sampleBounds = CalculateSampleCellBounds(cluster.Samples, sampleCoverage); UIElementInfo element = new UIElementInfo { @@ -420,8 +418,7 @@ internal static UIElementInfo CreatePhysicsColliderElement( SortingOrder = 0, SiblingIndex = 0, Layer = metadata.Layer, - Components = new List(metadata.Components), - RaycastCoverageCells = coverageCells + Components = new List(metadata.Components) }; Debug.Assert( @@ -448,65 +445,31 @@ private static RaycastSampleCoverage CreateClusterSampleCoverage( imageToInputOffsetY + renderingImageSize.y); } - internal static List CreateSampleCoverageCells( + private static RaycastSampleBounds CalculateSampleCellBounds( List samples, RaycastSampleCoverage sampleCoverage) { Debug.Assert(samples.Count > 0, "At least one raycast sample is required."); - List coverageCells = new List(samples.Count); - foreach (RaycastClusterSample sample in samples) - { - coverageCells.Add(CreateSampleCoverageCell(sample, sampleCoverage)); - } - - return coverageCells; - } - - private static RaycastCoverageCell CreateSampleCoverageCell( - RaycastClusterSample sample, - RaycastSampleCoverage sampleCoverage) - { - float minX = Mathf.Clamp( - sample.InputX - sampleCoverage.HalfStepX, - sampleCoverage.MinX, - sampleCoverage.MaxX); - float minY = Mathf.Clamp( - sample.InputY - sampleCoverage.HalfStepY, - sampleCoverage.MinY, - sampleCoverage.MaxY); - float maxX = Mathf.Clamp( - sample.InputX + sampleCoverage.HalfStepX, - sampleCoverage.MinX, - sampleCoverage.MaxX); - float maxY = Mathf.Clamp( - sample.InputY + sampleCoverage.HalfStepY, - sampleCoverage.MinY, - sampleCoverage.MaxY); - - return new RaycastCoverageCell(minX, minY, maxX, maxY); - } - - private static RaycastSampleBounds CalculateSampleCellBounds( - List coverageCells) - { - Debug.Assert(coverageCells.Count > 0, "At least one raycast coverage cell is required."); - - float minX = coverageCells[0].MinX; - float minY = coverageCells[0].MinY; - float maxX = coverageCells[0].MaxX; - float maxY = coverageCells[0].MaxY; + float minX = samples[0].InputX - sampleCoverage.HalfStepX; + float minY = samples[0].InputY - sampleCoverage.HalfStepY; + float maxX = samples[0].InputX + sampleCoverage.HalfStepX; + float maxY = samples[0].InputY + sampleCoverage.HalfStepY; - for (int i = 1; i < coverageCells.Count; i++) + for (int i = 1; i < samples.Count; i++) { - RaycastCoverageCell coverageCell = coverageCells[i]; - minX = Mathf.Min(minX, coverageCell.MinX); - minY = Mathf.Min(minY, coverageCell.MinY); - maxX = Mathf.Max(maxX, coverageCell.MaxX); - maxY = Mathf.Max(maxY, coverageCell.MaxY); + RaycastClusterSample sample = samples[i]; + minX = Mathf.Min(minX, sample.InputX - sampleCoverage.HalfStepX); + minY = Mathf.Min(minY, sample.InputY - sampleCoverage.HalfStepY); + maxX = Mathf.Max(maxX, sample.InputX + sampleCoverage.HalfStepX); + maxY = Mathf.Max(maxY, sample.InputY + sampleCoverage.HalfStepY); } - return new RaycastSampleBounds(minX, minY, maxX, maxY); + return new RaycastSampleBounds( + Mathf.Clamp(minX, sampleCoverage.MinX, sampleCoverage.MaxX), + Mathf.Clamp(minY, sampleCoverage.MinY, sampleCoverage.MaxY), + Mathf.Clamp(maxX, sampleCoverage.MinX, sampleCoverage.MaxX), + Mathf.Clamp(maxY, sampleCoverage.MinY, sampleCoverage.MaxY)); } private static UiRaycastHelper.RaycastContext? CreateUiRaycastContext() diff --git a/Packages/src/Editor/Utils/RaycastHitClusterer.cs b/Packages/src/Editor/Utils/RaycastHitClusterer.cs index ecd129389e..0116c7f51f 100644 --- a/Packages/src/Editor/Utils/RaycastHitClusterer.cs +++ b/Packages/src/Editor/Utils/RaycastHitClusterer.cs @@ -218,22 +218,4 @@ public RaycastSampleCoverage( } } - /// - /// Describes one visible raycast sample cell in screen-space coordinates. - /// - internal readonly struct RaycastCoverageCell - { - public readonly float MinX; - public readonly float MinY; - public readonly float MaxX; - public readonly float MaxY; - - public RaycastCoverageCell(float minX, float minY, float maxX, float maxY) - { - MinX = minX; - MinY = minY; - MaxX = maxX; - MaxY = maxY; - } - } } diff --git a/Packages/src/Editor/Utils/UIElementAnnotator.cs b/Packages/src/Editor/Utils/UIElementAnnotator.cs index d913509e79..00a98bddbf 100644 --- a/Packages/src/Editor/Utils/UIElementAnnotator.cs +++ b/Packages/src/Editor/Utils/UIElementAnnotator.cs @@ -19,7 +19,6 @@ public static class UIElementAnnotator private const float LABEL_DARK_TEXT_LUMINANCE_THRESHOLD = 0.62f; private const float OUTPUT_LABEL_OUTLINE_DISTANCE = 2f; private const float OUTPUT_LABEL_TO_BORDER_GAP = 4f; - private const float RAYCAST_COVERAGE_FILL_ALPHA = 0.25f; private const string INTERACTION_CLICK = "Click"; private const string INTERACTION_DRAG = "Drag"; private const string INTERACTION_DROP = "Drop"; @@ -121,11 +120,6 @@ public static GameObject CreateAnnotationOverlay(List elements, f drawInfos.Add(CreateAnnotationDrawInfo(element)); } - foreach (AnnotationDrawInfo drawInfo in drawInfos) - { - CreateRaycastCoverageFillForElement(root.transform, drawInfo); - } - foreach (AnnotationDrawInfo drawInfo in drawInfos) { CreateAnnotationBorderForElement(root.transform, drawInfo, borderMetrics); @@ -440,56 +434,7 @@ private static AnnotationDrawInfo CreateAnnotationDrawInfo(UIElementInfo element color, contrastColor, borderColors, - displayLabel, - element.RaycastCoverageCells); - } - - private static void CreateRaycastCoverageFillForElement( - Transform parent, - AnnotationDrawInfo drawInfo) - { - if (drawInfo.RaycastCoverageCells.Count == 0) - { - return; - } - - Color fillColor = drawInfo.Color; - fillColor.a = RAYCAST_COVERAGE_FILL_ALPHA; - for (int i = 0; i < drawInfo.RaycastCoverageCells.Count; i++) - { - CreateRaycastCoverageFillCell( - parent, - i, - drawInfo.RaycastCoverageCells[i], - fillColor); - } - } - - private static void CreateRaycastCoverageFillCell( - Transform parent, - int index, - RaycastCoverageCell coverageCell, - Color color) - { - Debug.Assert(coverageCell.MaxX >= coverageCell.MinX, "Coverage cell maxX must not be smaller than minX."); - Debug.Assert(coverageCell.MaxY >= coverageCell.MinY, "Coverage cell maxY must not be smaller than minY."); - - GameObject fillGo = new GameObject($"RaycastCoverageFill_{index}"); - fillGo.hideFlags = HideFlags.HideAndDontSave; - fillGo.transform.SetParent(parent, false); - - RectTransform rt = fillGo.AddComponent(); - rt.anchorMin = Vector2.zero; - rt.anchorMax = Vector2.zero; - rt.pivot = Vector2.zero; - rt.anchoredPosition = new Vector2(coverageCell.MinX, coverageCell.MinY); - rt.sizeDelta = new Vector2( - coverageCell.MaxX - coverageCell.MinX, - coverageCell.MaxY - coverageCell.MinY); - - Image image = fillGo.AddComponent(); - image.color = color; - image.raycastTarget = false; + displayLabel); } private static void CreateBorder( @@ -756,7 +701,6 @@ private readonly struct AnnotationDrawInfo public readonly Color ContrastColor; public readonly AnnotationBorderColors BorderColors; public readonly string DisplayLabel; - public readonly List RaycastCoverageCells; public AnnotationDrawInfo( float screenMinX, @@ -766,8 +710,7 @@ public AnnotationDrawInfo( Color color, Color contrastColor, AnnotationBorderColors borderColors, - string displayLabel, - List raycastCoverageCells) + string displayLabel) { ScreenMinX = screenMinX; ScreenMinY = screenMinY; @@ -777,7 +720,6 @@ public AnnotationDrawInfo( ContrastColor = contrastColor; BorderColors = borderColors; DisplayLabel = displayLabel; - RaycastCoverageCells = raycastCoverageCells; } }