UX updates

This commit is contained in:
Savya Bikram Shah
2026-06-05 18:00:22 +05:45
parent dee4b004bd
commit e27d0e54cb
30 changed files with 3177 additions and 154 deletions

BIN
Assets/.DS_Store vendored

Binary file not shown.

Binary file not shown.

View File

@@ -1,5 +1,6 @@
using System.Threading;
using Cysharp.Threading.Tasks;
using Darkmatter.Core.Enums.Features.Tutorial;
using UnityEngine;
namespace Darkmatter.Core.Contracts.Features.Tutorial
@@ -18,19 +19,23 @@ namespace Darkmatter.Core.Contracts.Features.Tutorial
/// Spotlight a single tap target. When <paramref name="target"/> is null the dim/hole are
/// skipped and only a centered bubble is shown (a non-blocking hint).
/// When <paramref name="blockInput"/> is true every touch outside the hole is swallowed.
/// <paramref name="placement"/> overrides where the instruction bubble sits; <paramref name="offset"/>
/// nudges it from that slot (px, +x right / +y up).
/// </summary>
void ShowTap(RectTransform target, string message, bool blockInput);
void ShowTap(RectTransform target, string message, bool blockInput, BubblePlacement placement = BubblePlacement.Auto, Vector2 offset = default);
/// <summary>
/// Spotlight a drag gesture from <paramref name="from"/> to <paramref name="to"/>. Input is
/// never blocked here, so the dragged piece can render above the dim.
/// <paramref name="placement"/> overrides where the instruction bubble sits; <paramref name="offset"/>
/// nudges it from that slot (px, +x right / +y up).
/// </summary>
void ShowDrag(RectTransform from, RectTransform to, string message);
void ShowDrag(RectTransform from, RectTransform to, string message, BubblePlacement placement = BubblePlacement.Auto, Vector2 offset = default);
/// <summary>Hide everything immediately (used across scene swaps).</summary>
void HideInstant();
/// <summary>Show a centered celebratory bubble for a short beat, then hide.</summary>
UniTask ShowToastAsync(string message, CancellationToken ct);
UniTask ShowToastAsync(string message, CancellationToken ct, BubblePlacement placement = BubblePlacement.Auto, Vector2 offset = default);
}
}

View File

@@ -0,0 +1,10 @@
namespace Darkmatter.Core.Data.Signals.Features.Coloring
{
/// <summary>
/// Raised the moment every region of the current drawing has been painted away from its authored
/// (uncoloured) default — i.e. the picture is fully coloured. Published right after the
/// <see cref="ColorAppliedSignal"/> that completes it. Used by the onboarding tutorial to hold the
/// "Tap Next" prompt until the child has coloured the whole picture.
/// </summary>
public record struct AllRegionsColoredSignal;
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 381ea33520a140d8b5639279c5390d2c

View File

@@ -6,9 +6,13 @@ namespace Darkmatter.Core.Data.Static.Features.ShapeBuilder
menuName = "Darkmatter/ShapeBuilder/Config")]
public sealed class ShapeBuilderConfig : ScriptableObject
{
[Header("Radii (canvas units; reference resolution 2048x2048)")]
[SerializeField] private float snapRadius = 100f;
[SerializeField] private float previewRadius = 200f;
// Single catch radius for both preview and snap, expressed as a multiple of
// EACH slot's own half-diagonal — so a big slot gets a big catch and a small
// slot a small one, instead of one flat distance for all. 1 = exactly the
// slot's circumscribed circle; larger = more forgiving. Computed in canvas
// reference units, so it feels the same on every screen resolution/aspect.
[Header("Catch radius (multiple of slot half-diagonal)")]
[SerializeField, Range(0.25f, 2.5f)] private float catchRadiusScale = 1.1f;
[Header("Tween durations (seconds)")]
[SerializeField] private float snapDuration = 0.25f;
@@ -18,16 +22,11 @@ namespace Darkmatter.Core.Data.Static.Features.ShapeBuilder
[SerializeField, Range(1f, 2f)] private float dragScale = 1.15f;
[SerializeField, Range(0f, 1f)] private float dragAlpha = 0.7f;
[Header("Preview easing")]
[SerializeField] private AnimationCurve previewCurve = AnimationCurve.EaseInOut(0, 0, 1, 1);
public float SnapRadius => snapRadius;
public float PreviewRadius => previewRadius;
public float CatchRadiusScale => catchRadiusScale;
public float SnapDuration => snapDuration;
public float ReturnDuration => returnDuration;
public float DragScale => dragScale;
public float DragAlpha => dragAlpha;
public AnimationCurve PreviewCurve => previewCurve;
public Vector2 DragSizeDelta(ShapeSO shape) =>
shape != null ? shape.DefaultSizeDelta : new Vector2(256, 256);

View File

@@ -1,3 +1,4 @@
using Darkmatter.Core.Enums.Features.Tutorial;
using UnityEngine;
namespace Darkmatter.Core.Data.Static.Features.Tutorial
@@ -17,9 +18,28 @@ namespace Darkmatter.Core.Data.Static.Features.Tutorial
[SerializeField] private string finishText = "Now finish the puzzle!";
[SerializeField] private string colorText = "Choose a color!";
[SerializeField] private string paintText = "Tap the picture to color it!";
[SerializeField] private string finishColoringText = "Color the whole picture!";
[SerializeField] private string nextText = "Tap Next when you're done!";
[SerializeField] private string doneText = "Yay! You did it!";
[Header("Bubble placement + offset per step (Auto = smart; offset nudges from the slot in px, +x right / +y up)")]
[SerializeField] private BubblePlacement pickBubble = BubblePlacement.Auto;
[SerializeField] private Vector2 pickBubbleOffset;
[SerializeField] private BubblePlacement dragBubble = BubblePlacement.Auto;
[SerializeField] private Vector2 dragBubbleOffset;
[SerializeField] private BubblePlacement finishBubble = BubblePlacement.Auto;
[SerializeField] private Vector2 finishBubbleOffset;
[SerializeField] private BubblePlacement colorBubble = BubblePlacement.Auto;
[SerializeField] private Vector2 colorBubbleOffset;
[SerializeField] private BubblePlacement paintBubble = BubblePlacement.Auto;
[SerializeField] private Vector2 paintBubbleOffset;
[SerializeField] private BubblePlacement finishColoringBubble = BubblePlacement.Auto;
[SerializeField] private Vector2 finishColoringBubbleOffset;
[SerializeField] private BubblePlacement nextBubble = BubblePlacement.Auto;
[SerializeField] private Vector2 nextBubbleOffset;
[SerializeField] private BubblePlacement doneBubble = BubblePlacement.Auto;
[SerializeField] private Vector2 doneBubbleOffset;
[Header("Watchdog")]
[Tooltip("Timeout (s) while waiting for a SYSTEM precondition (scene/catalog/regions ready). If it " +
"doesn't arrive the tutorial fails open so the player is never trapped.")]
@@ -34,9 +54,28 @@ namespace Darkmatter.Core.Data.Static.Features.Tutorial
public string FinishText => finishText;
public string ColorText => colorText;
public string PaintText => paintText;
public string FinishColoringText => finishColoringText;
public string NextText => nextText;
public string DoneText => doneText;
public BubblePlacement PickBubble => pickBubble;
public BubblePlacement DragBubble => dragBubble;
public BubblePlacement FinishBubble => finishBubble;
public BubblePlacement ColorBubble => colorBubble;
public BubblePlacement PaintBubble => paintBubble;
public BubblePlacement FinishColoringBubble => finishColoringBubble;
public BubblePlacement NextBubble => nextBubble;
public BubblePlacement DoneBubble => doneBubble;
public Vector2 PickBubbleOffset => pickBubbleOffset;
public Vector2 DragBubbleOffset => dragBubbleOffset;
public Vector2 FinishBubbleOffset => finishBubbleOffset;
public Vector2 ColorBubbleOffset => colorBubbleOffset;
public Vector2 PaintBubbleOffset => paintBubbleOffset;
public Vector2 FinishColoringBubbleOffset => finishColoringBubbleOffset;
public Vector2 NextBubbleOffset => nextBubbleOffset;
public Vector2 DoneBubbleOffset => doneBubbleOffset;
public float StepTimeoutSeconds => stepTimeoutSeconds;
public float ActionTimeoutSeconds => actionTimeoutSeconds;
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 4b28ea43ea1b942cab1264b52ec34a60
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,16 @@
namespace Darkmatter.Core.Enums.Features.Tutorial
{
/// <summary>
/// Where the tutorial instruction bubble sits for a given step. <see cref="Auto"/> keeps the
/// smart default (sits opposite the spotlighted target so it never covers it; pinned to a screen
/// edge for the drag step; upper-centre for target-less hints). The other values override that
/// with a fixed vertical slot, horizontally centred.
/// </summary>
public enum BubblePlacement
{
Auto,
Top,
Center,
Bottom,
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 61e68e58d45cf4314886e2a414e3856d

View File

@@ -79,6 +79,21 @@ public class ColoringController : IColoringController, IDisposable
if (from != color)
_history.Push(new ColorRegionCommand(region, from, color));
_bus.Publish(new ColorAppliedSignal(regionId, color));
if (AllRegionsColored())
_bus.Publish(new AllRegionsColoredSignal());
}
// True once every region has been painted away from its authored (uncoloured) default.
private bool AllRegionsColored()
{
if (_regions.Count == 0) return false;
foreach (var region in _regions)
{
if (region == null) continue;
if (_authoredColors.TryGetValue(region.RegionId, out var authored) && region.Color == authored)
return false;
}
return true;
}
public IReadOnlyDictionary<string, Color> GetCurrentColors()

View File

@@ -97,7 +97,10 @@ namespace Darkmatter.Features.ShapeBuilder.UI
_bus = bus;
_undo = undo;
_trayPos = trayPos;
_traySize = shape.DefaultSizeDelta;
// Keep the piece at the prefab Image's authored size. Sourcing this from
// shape.DefaultSizeDelta let each ShapeSO override the image's default size;
// the prefab (with preserveAspect) is the single source of truth now.
_traySize = RectTransform.sizeDelta;
_dragRoot = dragRoot;
_homeParent = RectTransform.parent;
@@ -151,7 +154,7 @@ namespace Darkmatter.Features.ShapeBuilder.UI
if (_locked) return;
var pointerLocal = ScreenToLocal(e.position) + _grabOffset;
var hovered = FindSlotUnder(e.position);
var hovered = FindSlotForCatch(e.position);
bool insidePreview = hovered != null;
if (insidePreview && !_inPreview)
@@ -187,7 +190,11 @@ namespace Darkmatter.Features.ShapeBuilder.UI
SetAlpha(_dragOrigAlpha);
var target = FindSlotUnder(e.position);
// If a slot is already previewing, releasing commits to it. Otherwise catch
// a quick drop with no prior preview using the same per-slot radius.
var target = _inPreview && _activeSlot != null
? _activeSlot
: FindSlotForCatch(e.position);
if (target != null)
{
_activeSlot = target;
@@ -200,17 +207,45 @@ namespace Darkmatter.Features.ShapeBuilder.UI
}
}
private SlotMarker FindSlotUnder(Vector2 screenPos)
// Nearest slot whose per-slot catch circle contains the pointer. Each slot's
// radius is derived from its own size (see SlotCatchRadius), so big slots catch
// from farther than small ones. All distances are in PaperRoot local space —
// ScreenPointToLocalPointInRectangle and InverseTransformVector both strip the
// CanvasScaler factor, so the catch feels identical on every screen resolution.
private SlotMarker FindSlotForCatch(Vector2 screenPos)
{
if (_candidateSlots == null) return null;
Vector2 pointerLocal = ScreenToLocal(screenPos);
SlotMarker best = null;
float bestSqr = float.MaxValue;
foreach (var s in _candidateSlots)
{
if (s == null) continue;
if (s.IsOccupied && s != _activeSlot) continue;
if (RectTransformUtility.RectangleContainsScreenPoint(s.RectTransform, screenPos, _eventCam))
return s;
var srt = s.RectTransform;
Vector2 slotLocal = _parentRect.InverseTransformPoint(srt.position);
float sqr = (slotLocal - pointerLocal).sqrMagnitude;
float radius = SlotCatchRadius(srt);
if (sqr <= radius * radius && sqr < bestSqr)
{
bestSqr = sqr;
best = s;
}
}
return null;
return best;
}
// Catch radius for one slot, in PaperRoot local units: half the slot's diagonal
// (its size mapped into parent space, so any slot rotation/mirror/scale is
// accounted for) times the config multiplier. Scales per slot — not one flat
// distance for all.
private float SlotCatchRadius(RectTransform slot)
{
Vector2 size = slot.rect.size;
Vector2 prX = _parentRect.InverseTransformVector(slot.TransformVector(new Vector3(size.x, 0f, 0f)));
Vector2 prY = _parentRect.InverseTransformVector(slot.TransformVector(new Vector3(0f, size.y, 0f)));
float halfDiagonal = 0.5f * new Vector2(prX.magnitude, prY.magnitude).magnitude;
return halfDiagonal * _cfg.CatchRadiusScale;
}
private void AnimatePreviewPose(bool toSlot)

View File

@@ -11,6 +11,7 @@ using Darkmatter.Core.Data.Signals.Features.GameplayFlow; // DrawingCompletedSig
using Darkmatter.Core.Data.Signals.Features.ShapeBuilder; // ShapeBuilderStarted/PieceSnapped/ShapeAssembled
using Darkmatter.Core.Data.Signals.Features.Tutorial;
using Darkmatter.Core.Data.Static.Features.Tutorial;
using Darkmatter.Core.Enums.Features.Tutorial; // BubblePlacement
using Darkmatter.Features.Coloring.UI; // ColorButton, ColorRegionView
using Darkmatter.Features.DrawingCatalog; // DrawingCatalogButton
using Darkmatter.Features.GameplayFlow.UI; // NextButtonView
@@ -44,6 +45,7 @@ namespace Darkmatter.Features.Tutorial.Systems
private CancellationTokenSource _runCts;
private CancellationToken _ct;
private bool _completed;
private bool _drawingCompleted;
private bool _suspended;
private Action _reshow;
private int _stepIndex;
@@ -74,6 +76,10 @@ namespace Darkmatter.Features.Tutorial.Systems
_navSubs.Add(_bus.Subscribe<ReturnToMainMenuSignal>(_ => Suspend()));
_navSubs.Add(_bus.Subscribe<OpenColorBookSignal>(_ => Resume()));
_navSubs.Add(_bus.Subscribe<DrawingCatalogReadySignal>(OnCatalogReadyGlobal));
// The drawing being completed (Next pressed) is the run's true end — even if the child
// finds Next early during free-paint. Flag it so the catalog reload that follows isn't
// mistaken for a Back-navigation and doesn't restart the tutorial.
_navSubs.Add(_bus.Subscribe<DrawingCompletedSignal>(_ => _drawingCompleted = true));
StartRun(skipCatalogWait: false);
}
@@ -86,6 +92,7 @@ namespace Darkmatter.Features.Tutorial.Systems
_ct = _runCts.Token;
_gen++;
_suspended = false;
_drawingCompleted = false;
_reshow = null;
_stepIndex = 0;
_overlay.HideInstant();
@@ -108,11 +115,11 @@ namespace Darkmatter.Features.Tutorial.Systems
}
// The catalog re-appeared while we were mid-gameplay -> the player went Back. Restart from
// step 1 (the catalog is already on screen, so skip the wait). Excludes step 6+, whose own
// completion loads the catalog.
// step 1 (the catalog is already on screen, so skip the wait). Excludes step 7+ (the Next
// press), whose own completion loads the catalog.
private void OnCatalogReadyGlobal(DrawingCatalogReadySignal _)
{
if (!_completed && _stepIndex >= 2 && _stepIndex <= 5)
if (!_completed && !_drawingCompleted && _stepIndex >= 2 && _stepIndex <= 6)
StartRun(skipCatalogWait: true);
}
@@ -154,7 +161,7 @@ namespace Darkmatter.Features.Tutorial.Systems
if (!await WaitForSignalAsync<DrawingCatalogReadySignal>()) return;
}
await UniTask.NextFrame(_ct);
ShowStep(() => ShowBlockingTap(FindFirstCatalogCell(), _config.PickText));
ShowStep(() => ShowBlockingTap(FindFirstCatalogCell(), _config.PickText, _config.PickBubble, _config.PickBubbleOffset));
if (!await WaitForActionAsync<DrawingSelectedSignal>()) return;
EndStep("pick", 1);
@@ -165,7 +172,7 @@ namespace Darkmatter.Features.Tutorial.Systems
ShowStep(() =>
{
var (pieceRect, slotRect) = FindFirstPieceAndSlot();
if (pieceRect != null) _overlay.ShowDrag(pieceRect, slotRect, _config.DragText);
if (pieceRect != null) _overlay.ShowDrag(pieceRect, slotRect, _config.DragText, _config.DragBubble, _config.DragBubbleOffset);
else Debug.LogWarning("[Tutorial] No draggable piece found for the drag step.");
});
if (!await WaitForActionAsync<PieceSnappedSignal>()) return; // any snap teaches the gesture
@@ -173,7 +180,7 @@ namespace Darkmatter.Features.Tutorial.Systems
// Step 3 — finish the rest of the puzzle freely (non-blocking hint).
_stepIndex = 3;
ShowStep(() => _overlay.ShowTap(null, _config.FinishText, blockInput: false));
ShowStep(() => _overlay.ShowTap(null, _config.FinishText, blockInput: false, _config.FinishBubble, _config.FinishBubbleOffset));
if (!await WaitForActionAsync<ShapeAssembledSignal>()) return;
EndStep("finish", 3);
@@ -181,32 +188,55 @@ namespace Darkmatter.Features.Tutorial.Systems
_stepIndex = 4;
if (!await WaitForSignalAsync<RegionsInitializedSignal>()) return;
await UniTask.NextFrame(_ct);
ShowStep(() => ShowBlockingTap(FindFirstColorButton(), _config.ColorText));
ShowStep(() => ShowBlockingTap(FindFirstColorButton(), _config.ColorText, _config.ColorBubble, _config.ColorBubbleOffset));
if (!await WaitForActionAsync<ColorSelectedSignal>()) return;
EndStep("color", 4);
// Step 5 — paint a region.
// Step 5 — paint the first region (teaches the tap by spotlighting one region).
_stepIndex = 5;
ShowStep(() => ShowBlockingTap(FindLargestRegion(), _config.PaintText));
// Watch full-colour completion across both this taught tap and the free-paint step that
// follows. A one-region drawing is finished by this very tap, so its signal would fire
// before step 6 could subscribe — the flag lets us skip the free-paint step instead of
// stranding the child on a hint with nothing left to colour.
var fullyColored = false;
using var fullColorSub = _bus.Subscribe<AllRegionsColoredSignal>(_ => fullyColored = true);
ShowStep(() => ShowBlockingTap(FindLargestRegion(), _config.PaintText, _config.PaintBubble, _config.PaintBubbleOffset));
if (!await WaitForActionAsync<ColorAppliedSignal>()) return;
EndStep("paint", 5);
// Step 6 — press Next.
// Step 6 — colour the rest of the picture freely (non-blocking hint). Hold here until
// every region is filled, so the "Tap Next" prompt only appears once colouring is done.
// The child can still reach the live Next button during this open step; if they finish
// the drawing early that way, take it as done rather than waiting on a fill that can't come.
_stepIndex = 6;
await UniTask.NextFrame(_ct);
ShowStep(() => ShowBlockingTap(FindNextButton(), _config.NextText));
if (!await WaitForActionAsync<DrawingCompletedSignal>()) return;
EndStep("next", 6);
if (!fullyColored)
{
ShowStep(() => _overlay.ShowTap(null, _config.FinishColoringText, blockInput: false, _config.FinishColoringBubble, _config.FinishColoringBubbleOffset));
await UniTask.WhenAny(
WaitForActionAsync<AllRegionsColoredSignal>(),
WaitForActionAsync<DrawingCompletedSignal>());
}
EndStep("finishColoring", 6);
// Step 7 — celebrate.
_stepIndex = 7;
await _overlay.ShowToastAsync(_config.DoneText, _ct);
// Step 7 — press Next (skipped if the drawing was already completed early).
if (!_drawingCompleted)
{
_stepIndex = 7;
await UniTask.NextFrame(_ct);
ShowStep(() => ShowBlockingTap(FindNextButton(), _config.NextText, _config.NextBubble, _config.NextBubbleOffset));
if (!await WaitForActionAsync<DrawingCompletedSignal>()) return;
EndStep("next", 7);
}
// Step 8 — celebrate.
_stepIndex = 8;
await _overlay.ShowToastAsync(_config.DoneText, _ct, _config.DoneBubble, _config.DoneBubbleOffset);
}
private void ShowBlockingTap(RectTransform target, string message)
private void ShowBlockingTap(RectTransform target, string message, BubblePlacement placement, Vector2 offset)
{
if (target == null) Debug.LogWarning($"[Tutorial] No target found for step: \"{message}\"");
_overlay.ShowTap(target, message, blockInput: target != null);
_overlay.ShowTap(target, message, blockInput: target != null, placement, offset);
}
private void EndStep(string id, int index)

View File

@@ -2,6 +2,7 @@ using System;
using System.Threading;
using Cysharp.Threading.Tasks;
using Darkmatter.Core.Contracts.Features.Tutorial;
using Darkmatter.Core.Enums.Features.Tutorial;
using PrimeTween;
using TMPro;
using UnityEngine;
@@ -45,6 +46,8 @@ namespace Darkmatter.Features.Tutorial.UI
[SerializeField] private float fadeDuration = 0.25f;
[SerializeField] private float toastSeconds = 1.6f;
[SerializeField] private float bubbleGap = 60f;
[Tooltip("Margin (px) from the top/bottom edge for the Top/Bottom bubble placement presets.")]
[SerializeField] private float bubbleEdgeMargin = 150f;
[SerializeField] private float haloPulseScale = 1.18f;
[SerializeField] private float pulseDuration = 0.6f;
[SerializeField] private float dragHandDuration = 1.1f;
@@ -60,6 +63,8 @@ namespace Darkmatter.Features.Tutorial.UI
private RectTransform _area;
private Camera _overlayCam;
private Mode _mode = Mode.Hidden;
private BubblePlacement _placement = BubblePlacement.Auto;
private Vector2 _bubbleOffset;
private RectTransform _target; // tap target
private RectTransform _dragFrom; // the piece (drag start)
private RectTransform _dragTo; // the slot (drag destination)
@@ -91,11 +96,13 @@ namespace Darkmatter.Features.Tutorial.UI
// ── ITutorialOverlay ─────────────────────────────────────────────────
public void ShowTap(RectTransform target, string message, bool blockInput)
public void ShowTap(RectTransform target, string message, bool blockInput, BubblePlacement placement = BubblePlacement.Auto, Vector2 offset = default)
{
CacheRefs();
KillAnims();
SetText(message);
_placement = placement;
_bubbleOffset = offset;
_dragFrom = null;
_dragTo = null;
@@ -122,11 +129,13 @@ namespace Darkmatter.Features.Tutorial.UI
FadeInQuick();
}
public void ShowDrag(RectTransform from, RectTransform to, string message)
public void ShowDrag(RectTransform from, RectTransform to, string message, BubblePlacement placement = BubblePlacement.Auto, Vector2 offset = default)
{
CacheRefs();
KillAnims();
SetText(message);
_placement = placement;
_bubbleOffset = offset;
// No dim and no blocking — the piece lives under the overlay and must stay visible and
// draggable. Halo + hand travel together along the piece -> slot path, recomputed live.
@@ -153,11 +162,13 @@ namespace Darkmatter.Features.Tutorial.UI
FadeInQuick();
}
public async UniTask ShowToastAsync(string message, CancellationToken ct)
public async UniTask ShowToastAsync(string message, CancellationToken ct, BubblePlacement placement = BubblePlacement.Auto, Vector2 offset = default)
{
CacheRefs();
KillAnims();
SetText(message);
_placement = placement;
_bubbleOffset = offset;
_mode = Mode.Centered;
_target = null;
@@ -238,8 +249,10 @@ namespace Darkmatter.Features.Tutorial.UI
if (hand != null)
hand.anchoredPosition = centerLocal + new Vector2(0f, -radiusLocal * 0.5f);
PositionBubble(centerLocal.y, centerLocal.y + radiusLocal, centerLocal.y - radiusLocal,
_area.rect.height * 0.5f);
if (_placement == BubblePlacement.Auto)
PositionBubble(centerLocal.y, centerLocal.y + radiusLocal, centerLocal.y - radiusLocal);
else
PositionBubblePreset(_placement);
}
// Drag: halo + hand glide piece -> slot, recomputed live so it tracks the real positions.
@@ -283,27 +296,59 @@ namespace Darkmatter.Features.Tutorial.UI
// The drag path spans the play area, so pin the bubble to a screen edge instead of hugging
// the piece — keeps it off the shapes.
PositionBubbleAtEdge(dragBubbleAtTop, dragBubbleEdgeMargin);
if (_placement == BubblePlacement.Auto)
PositionBubbleAtEdge(dragBubbleAtTop, dragBubbleEdgeMargin);
else
PositionBubblePreset(_placement);
}
private void LayoutCentered()
{
if (bubbleRoot == null) return;
if (_placement != BubblePlacement.Auto) { PositionBubblePreset(_placement); return; }
float halfH = _area.rect.height * 0.5f;
float bubbleHalf = bubbleRoot.rect.height * 0.5f;
bubbleRoot.anchoredPosition =
new Vector2(0f, Mathf.Clamp(halfH * 0.45f, -halfH + bubbleHalf, halfH - bubbleHalf));
SetBubbleAnchored(new Vector2(0f, halfH * 0.45f));
}
private void PositionBubble(float holeCenterY, float holeTopY, float holeBottomY, float halfH)
// Applies the per-step offset to a computed base position and clamps so the bubble always
// stays fully on-screen, then commits it. Every bubble-positioning path routes through here.
private void SetBubbleAnchored(Vector2 baseLocal)
{
if (bubbleRoot == null) return;
float halfW = _area.rect.width * 0.5f;
float halfH = _area.rect.height * 0.5f;
float bubbleHalfW = bubbleRoot.rect.width * 0.5f;
float bubbleHalfH = bubbleRoot.rect.height * 0.5f;
Vector2 p = baseLocal + _bubbleOffset;
p.x = Mathf.Clamp(p.x, -halfW + bubbleHalfW, halfW - bubbleHalfW);
p.y = Mathf.Clamp(p.y, -halfH + bubbleHalfH, halfH - bubbleHalfH);
bubbleRoot.anchoredPosition = p;
}
private void PositionBubble(float holeCenterY, float holeTopY, float holeBottomY)
{
if (bubbleRoot == null) return;
float bubbleHalf = bubbleRoot.rect.height * 0.5f;
float y = holeCenterY <= 0f
? holeTopY + bubbleGap + bubbleHalf
: holeBottomY - bubbleGap - bubbleHalf;
y = Mathf.Clamp(y, -halfH + bubbleHalf, halfH - bubbleHalf);
bubbleRoot.anchoredPosition = new Vector2(0f, y);
SetBubbleAnchored(new Vector2(0f, y));
}
// Fixed-slot placement chosen per step (Top/Center/Bottom). Horizontally centred; clamped so
// the bubble always stays fully on-screen.
private void PositionBubblePreset(BubblePlacement placement)
{
if (bubbleRoot == null) return;
float halfH = _area.rect.height * 0.5f;
float bubbleHalf = bubbleRoot.rect.height * 0.5f;
float y = placement switch
{
BubblePlacement.Top => halfH - bubbleHalf - bubbleEdgeMargin,
BubblePlacement.Bottom => -halfH + bubbleHalf + bubbleEdgeMargin,
_ => 0f, // Center
};
SetBubbleAnchored(new Vector2(0f, y));
}
// Pins the bubble to the top or bottom edge (used for the drag step, whose target spans the
@@ -314,8 +359,7 @@ namespace Darkmatter.Features.Tutorial.UI
float halfH = _area.rect.height * 0.5f;
float bubbleHalf = bubbleRoot.rect.height * 0.5f;
float y = top ? halfH - bubbleHalf - margin : -halfH + bubbleHalf + margin;
y = Mathf.Clamp(y, -halfH + bubbleHalf, halfH - bubbleHalf);
bubbleRoot.anchoredPosition = new Vector2(0f, y);
SetBubbleAnchored(new Vector2(0f, y));
}
// ── Coordinate conversion (camera-agnostic) ──────────────────────────
@@ -405,6 +449,8 @@ namespace Darkmatter.Features.Tutorial.UI
private void ApplyHiddenState()
{
_mode = Mode.Hidden;
_placement = BubblePlacement.Auto;
_bubbleOffset = Vector2.zero;
_target = null;
_dragFrom = null;
_dragTo = null;

View File

@@ -12,6 +12,7 @@ GameObject:
- component: {fileID: 501846013816502432}
- component: {fileID: 8665832532240036901}
- component: {fileID: 8513459380562180911}
- component: {fileID: 7638529631096518376}
m_Layer: 5
m_Name: Recatngle
m_TagString: Untagged
@@ -90,3 +91,18 @@ MonoBehaviour:
m_EditorClassIdentifier: Features.ShapeBuilder::Darkmatter.Features.ShapeBuilder.UI.SlotMarker
shape: {fileID: 11400000, guid: 4a67406eb6fe043628d2b6a4e0c970ba, type: 2}
outline: {fileID: 0}
--- !u!114 &7638529631096518376
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4279528263583881541}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: e19747de3f5aca642ab2be37e372fb86, type: 3}
m_Name:
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.Outline
m_EffectColor: {r: 0, g: 0, b: 0, a: 0.5}
m_EffectDistance: {x: 2.5, y: -2.5}
m_UseGraphicAlpha: 1

View File

@@ -75,8 +75,8 @@ MonoBehaviour:
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Name:
m_EditorClassIdentifier:
m_UiScaleMode: 1
m_ReferencePixelsPerUnit: 100
m_ScaleFactor: 1
@@ -98,8 +98,8 @@ MonoBehaviour:
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: dc42784cf147c0c48a680349fa168899, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Name:
m_EditorClassIdentifier:
m_IgnoreReversedGraphics: 1
m_BlockingObjects: 0
m_BlockingMask:
@@ -127,8 +127,8 @@ MonoBehaviour:
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 97ce2c486cc8541d1ab1d83fda7f8eda, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Name:
m_EditorClassIdentifier:
overlayView: {fileID: 100106}
config: {fileID: 11400000, guid: 71357eb1222bb4151ab4e5697a1decd3, type: 2}
--- !u!1 &100110
@@ -182,8 +182,8 @@ MonoBehaviour:
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 4ecf127118699405ebcd0e0712d7373d, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Name:
m_EditorClassIdentifier:
canvas: {fileID: 100102}
rootGroup: {fileID: 100105}
cutout: {fileID: 100204}
@@ -198,6 +198,9 @@ MonoBehaviour:
haloPulseScale: 1.18
pulseDuration: 0.6
dragHandDuration: 1.1
dragHandTipOffset: {x: 0, y: 70}
dragBubbleAtTop: 1
dragBubbleEdgeMargin: 150
--- !u!225 &6008915593776814208
CanvasGroup:
m_ObjectHideFlags: 0
@@ -266,8 +269,8 @@ MonoBehaviour:
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 0, g: 0, b: 0, a: 0.72}
m_RaycastTarget: 1
@@ -296,8 +299,8 @@ MonoBehaviour:
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 29c836b3d2ed343e6a810f6e7548f487, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Name:
m_EditorClassIdentifier:
cutoutShader: {fileID: 4800000, guid: 57d1ed1c62afa45db97a7c8e9ace795c, type: 3}
dimImage: {fileID: 100203}
--- !u!1 &100600
@@ -352,11 +355,11 @@ MonoBehaviour:
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 100600}
m_Enabled: 1
m_Enabled: 0
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 0.9}
m_RaycastTarget: 0
@@ -410,7 +413,7 @@ RectTransform:
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: 130, y: 130}
m_SizeDelta: {x: 200, y: 200}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &100702
CanvasRenderer:
@@ -430,8 +433,8 @@ MonoBehaviour:
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_RaycastTarget: 0
@@ -465,7 +468,7 @@ GameObject:
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
m_IsActive: 0
--- !u!224 &100801
RectTransform:
m_ObjectHideFlags: 0
@@ -524,7 +527,7 @@ RectTransform:
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 1, y: 1}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 91}
m_SizeDelta: {x: -235, y: 91}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &100902
CanvasRenderer:
@@ -544,8 +547,8 @@ MonoBehaviour:
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 0.96}
m_RaycastTarget: 0
@@ -574,7 +577,7 @@ MonoBehaviour:
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 3245ec927659c4140ac4f8d17403cc18, type: 3}
m_Name:
m_Name:
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.ContentSizeFitter
m_HorizontalFit: 2
m_VerticalFit: 0
@@ -588,7 +591,7 @@ MonoBehaviour:
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 59f8146938fff824cb5fd77236b75775, type: 3}
m_Name:
m_Name:
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.VerticalLayoutGroup
m_Padding:
m_Left: 100
@@ -639,8 +642,8 @@ RectTransform:
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 0, y: 1}
m_AnchoredPosition: {x: 463.445, y: -95.50001}
m_SizeDelta: {x: 0, y: 0}
m_AnchoredPosition: {x: 207.45999, y: -95.50001}
m_SizeDelta: {x: 214.92, y: 72.61}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &101002
CanvasRenderer:
@@ -660,7 +663,7 @@ MonoBehaviour:
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3}
m_Name:
m_Name:
m_EditorClassIdentifier: Unity.TextMeshPro::TMPro.TextMeshProUGUI
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 1}
@@ -752,7 +755,7 @@ MonoBehaviour:
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 3e37e2b5f1962004c8f10779a2fcf23a, type: 3}
m_Name:
m_Name:
m_EditorClassIdentifier: uLayout::Poke.UI.LayoutText
m_log: 0
m_ignoreLayout: 0

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

After

Width:  |  Height:  |  Size: 22 KiB

View File

@@ -49,7 +49,7 @@ TextureImporter:
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 270, y: 191, z: 255, w: 110}
spriteBorder: {x: 741, y: 322, z: 925, w: 337}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1

View File

@@ -12,32 +12,8 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: 52d6fdba64cc3491880636e34ed593d0, type: 3}
m_Name: ShapeBuilderConfig
m_EditorClassIdentifier: Core::Darkmatter.Core.Data.Static.Features.ShapeBuilder.ShapeBuilderConfig
snapRadius: 200
previewRadius: 300
catchRadiusScale: 1.5
snapDuration: 0.25
returnDuration: 0.25
dragScale: 1.15
previewCurve:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 0
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0
outWeight: 0
- serializedVersion: 3
time: 1
value: 1
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0
outWeight: 0
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
dragAlpha: 0.7

View File

@@ -17,6 +17,24 @@ MonoBehaviour:
finishText: Now finish the puzzle!
colorText: Choose a color!
paintText: Tap the picture to color it!
finishColoringText: Color the whole picture!
nextText: Tap Next when you're done!
doneText: Yay! You did it!
pickBubble: 0
pickBubbleOffset: {x: 0, y: 0}
dragBubble: 1
dragBubbleOffset: {x: 200, y: 0}
finishBubble: 1
finishBubbleOffset: {x: 200, y: 0}
colorBubble: 0
colorBubbleOffset: {x: 0, y: 0}
paintBubble: 0
paintBubbleOffset: {x: 0, y: 0}
finishColoringBubble: 1
finishColoringBubbleOffset: {x: 200, y: 0}
nextBubble: 0
nextBubbleOffset: {x: 0, y: 0}
doneBubble: 0
doneBubbleOffset: {x: 0, y: 0}
stepTimeoutSeconds: 45
actionTimeoutSeconds: 0

View File

@@ -2505,22 +2505,70 @@ PrefabInstance:
propertyPath: m_LocalEulerAnglesHint.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 100603, guid: 7d10b17c0a1e4e7d9b2f8c6a5d4e3f22, type: 3}
propertyPath: m_Enabled
- target: {fileID: 100105, guid: 7d10b17c0a1e4e7d9b2f8c6a5d4e3f22, type: 3}
propertyPath: m_Alpha
value: 0
objectReference: {fileID: 0}
- target: {fileID: 100701, guid: 7d10b17c0a1e4e7d9b2f8c6a5d4e3f22, type: 3}
propertyPath: m_SizeDelta.x
value: 200
propertyPath: m_LocalScale.x
value: 1.2599487
objectReference: {fileID: 0}
- target: {fileID: 100701, guid: 7d10b17c0a1e4e7d9b2f8c6a5d4e3f22, type: 3}
propertyPath: m_SizeDelta.y
value: 200
propertyPath: m_LocalScale.y
value: 1.2599487
objectReference: {fileID: 0}
- target: {fileID: 100701, guid: 7d10b17c0a1e4e7d9b2f8c6a5d4e3f22, type: 3}
propertyPath: m_LocalScale.z
value: 1.2599487
objectReference: {fileID: 0}
- target: {fileID: 100800, guid: 7d10b17c0a1e4e7d9b2f8c6a5d4e3f22, type: 3}
propertyPath: m_IsActive
value: 1
objectReference: {fileID: 0}
- target: {fileID: 100901, guid: 7d10b17c0a1e4e7d9b2f8c6a5d4e3f22, type: 3}
propertyPath: m_AnchorMax.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 100901, guid: 7d10b17c0a1e4e7d9b2f8c6a5d4e3f22, type: 3}
propertyPath: m_AnchorMax.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 100901, guid: 7d10b17c0a1e4e7d9b2f8c6a5d4e3f22, type: 3}
propertyPath: m_SizeDelta.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 100901, guid: 7d10b17c0a1e4e7d9b2f8c6a5d4e3f22, type: 3}
propertyPath: m_SizeDelta.y
value: 710
objectReference: {fileID: 0}
- target: {fileID: 100901, guid: 7d10b17c0a1e4e7d9b2f8c6a5d4e3f22, type: 3}
propertyPath: m_LocalScale.x
value: 0.22292544
objectReference: {fileID: 0}
- target: {fileID: 100901, guid: 7d10b17c0a1e4e7d9b2f8c6a5d4e3f22, type: 3}
propertyPath: m_LocalScale.y
value: 0.22292544
objectReference: {fileID: 0}
- target: {fileID: 100901, guid: 7d10b17c0a1e4e7d9b2f8c6a5d4e3f22, type: 3}
propertyPath: m_LocalScale.z
value: 0.22292544
objectReference: {fileID: 0}
- target: {fileID: 100901, guid: 7d10b17c0a1e4e7d9b2f8c6a5d4e3f22, type: 3}
propertyPath: m_AnchoredPosition.x
value: -52
objectReference: {fileID: 0}
- target: {fileID: 100901, guid: 7d10b17c0a1e4e7d9b2f8c6a5d4e3f22, type: 3}
propertyPath: m_AnchoredPosition.y
value: 87
objectReference: {fileID: 0}
- target: {fileID: 100903, guid: 7d10b17c0a1e4e7d9b2f8c6a5d4e3f22, type: 3}
propertyPath: m_Type
value: 1
objectReference: {fileID: 0}
- target: {fileID: 100903, guid: 7d10b17c0a1e4e7d9b2f8c6a5d4e3f22, type: 3}
propertyPath: m_PreserveAspect
value: 1
objectReference: {fileID: 0}
- target: {fileID: 101001, guid: 7d10b17c0a1e4e7d9b2f8c6a5d4e3f22, type: 3}
propertyPath: m_AnchorMax.y
value: 1
@@ -2537,18 +2585,62 @@ PrefabInstance:
propertyPath: m_SizeDelta.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 101001, guid: 7d10b17c0a1e4e7d9b2f8c6a5d4e3f22, type: 3}
propertyPath: m_LocalScale.x
value: 5.2138014
objectReference: {fileID: 0}
- target: {fileID: 101001, guid: 7d10b17c0a1e4e7d9b2f8c6a5d4e3f22, type: 3}
propertyPath: m_LocalScale.y
value: 5.2138014
objectReference: {fileID: 0}
- target: {fileID: 101001, guid: 7d10b17c0a1e4e7d9b2f8c6a5d4e3f22, type: 3}
propertyPath: m_LocalScale.z
value: 5.2138014
objectReference: {fileID: 0}
- target: {fileID: 101001, guid: 7d10b17c0a1e4e7d9b2f8c6a5d4e3f22, type: 3}
propertyPath: m_AnchoredPosition.x
value: 207.45999
value: 1913.019
objectReference: {fileID: 0}
- target: {fileID: 101001, guid: 7d10b17c0a1e4e7d9b2f8c6a5d4e3f22, type: 3}
propertyPath: m_AnchoredPosition.y
value: -95.50001
value: -337.5
objectReference: {fileID: 0}
- target: {fileID: 101003, guid: 7d10b17c0a1e4e7d9b2f8c6a5d4e3f22, type: 3}
propertyPath: m_text
value: Tutorial is not my name
objectReference: {fileID: 0}
- target: {fileID: 101003, guid: 7d10b17c0a1e4e7d9b2f8c6a5d4e3f22, type: 3}
propertyPath: m_fontSize
value: 60
objectReference: {fileID: 0}
- target: {fileID: 101003, guid: 7d10b17c0a1e4e7d9b2f8c6a5d4e3f22, type: 3}
propertyPath: m_fontColor.b
value: 1
objectReference: {fileID: 0}
- target: {fileID: 101003, guid: 7d10b17c0a1e4e7d9b2f8c6a5d4e3f22, type: 3}
propertyPath: m_fontColor.g
value: 1
objectReference: {fileID: 0}
- target: {fileID: 101003, guid: 7d10b17c0a1e4e7d9b2f8c6a5d4e3f22, type: 3}
propertyPath: m_fontColor.r
value: 1
objectReference: {fileID: 0}
- target: {fileID: 101003, guid: 7d10b17c0a1e4e7d9b2f8c6a5d4e3f22, type: 3}
propertyPath: m_fontColor32.rgba
value: 4294967295
objectReference: {fileID: 0}
- target: {fileID: 3730188213376167672, guid: 7d10b17c0a1e4e7d9b2f8c6a5d4e3f22, type: 3}
propertyPath: m_Padding.m_Top
value: -35
objectReference: {fileID: 0}
- target: {fileID: 3730188213376167672, guid: 7d10b17c0a1e4e7d9b2f8c6a5d4e3f22, type: 3}
propertyPath: m_Padding.m_Left
value: 261
objectReference: {fileID: 0}
- target: {fileID: 3730188213376167672, guid: 7d10b17c0a1e4e7d9b2f8c6a5d4e3f22, type: 3}
propertyPath: m_Padding.m_Right
value: 303
objectReference: {fileID: 0}
m_RemovedComponents: []
m_RemovedGameObjects: []
m_AddedGameObjects: []

View File

@@ -2067,7 +2067,7 @@ RectTransform:
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 1, y: 1}
m_AnchoredPosition: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: -0.0006763566}
m_SizeDelta: {x: 0, y: 0}
m_Pivot: {x: 0, y: 1}
--- !u!114 &1155451093
@@ -2098,11 +2098,11 @@ MonoBehaviour:
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.VerticalLayoutGroup
m_Padding:
m_Left: 0
m_Right: 0
m_Right: 41
m_Top: 0
m_Bottom: 0
m_ChildAlignment: 1
m_Spacing: 30
m_Spacing: 120
m_ChildForceExpandWidth: 0
m_ChildForceExpandHeight: 0
m_ChildControlWidth: 0
@@ -2339,8 +2339,8 @@ RectTransform:
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: -82.37799}
m_SizeDelta: {x: -191.90698, y: -574.56104}
m_AnchoredPosition: {x: 0, y: -115.30393}
m_SizeDelta: {x: -191.907, y: -626.817}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &1281354569
MonoBehaviour:

View File

@@ -1 +1 @@
<?xml version="1.0" encoding="utf-8"?><resources><string name="com.crashlytics.android.build_id" translatable="false">d9c2677e-729d-44d9-a1d9-424ef65bf9cc</string></resources>
<?xml version="1.0" encoding="utf-8"?><resources><string name="com.crashlytics.android.build_id" translatable="false">0c6158dd-d802-4446-8aeb-6fcf7eafa7d1</string></resources>