From 3c2e48652901d22d7d6a4f6c637d13e0c338e3ef Mon Sep 17 00:00:00 2001 From: Savya Bikram Shah Date: Thu, 28 May 2026 12:13:26 +0545 Subject: [PATCH] Basic Setup For Shape Builder --- .../Features/Progression/DrawingProgress.cs | 8 +- .../Features/Progression/RegionColorEntry.cs | 3 +- .../ShapeBuilder/PieceSnappedSignal.cs | 4 + .../ShapeBuilder/PieceSnappedSignal.cs.meta | 2 + .../ShapeBuilder/PieceUnsnappedSignal.cs | 4 + .../ShapeBuilder/PieceUnsnappedSignal.cs.meta | 2 + .../ShapeBuilder/ShapeBuilderConfig.cs | 30 + .../ShapeBuilder/ShapeBuilderConfig.cs.meta | 2 + .../Static/Features/ShapeBuilder/ShapeSO.cs | 1 + .../Code/Core/Enums/Services/Audio/SfxId.cs | 12 +- .../Code/Features/ShapeBuilder.meta | 8 + .../Code/Features/ShapeBuilder/Commands.meta | 8 + .../ShapeBuilder/Commands/SnapPieceCommand.cs | 35 + .../Commands/SnapPieceCommand.cs.meta | 2 + .../ShapeBuilder/Features.ShapeBuilder.asmdef | 22 + .../Features.ShapeBuilder.asmdef.meta | 7 + .../Features/ShapeBuilder/Installers.meta | 8 + .../Installers/ShapeBuilderFeatureModule.cs | 21 + .../ShapeBuilderFeatureModule.cs.meta | 2 + .../Code/Features/ShapeBuilder/Systems.meta | 8 + .../Code/Features/ShapeBuilder/UI.meta | 8 + .../Features/ShapeBuilder/UI/ShapePiece.cs | 203 +++++ .../ShapeBuilder/UI/ShapePiece.cs.meta | 2 + .../Features/ShapeBuilder/UI/SlotMarker.cs | 21 + .../ShapeBuilder/UI/SlotMarker.cs.meta | 2 + Assets/Darkmatter/Scenes/GamePlay.unity | 46 ++ Readme.docx | Bin 68737 -> 77646 bytes Readme.md | 755 ++++++++++++------ 28 files changed, 961 insertions(+), 265 deletions(-) create mode 100644 Assets/Darkmatter/Code/Core/Data/Signals/Features/ShapeBuilder/PieceSnappedSignal.cs create mode 100644 Assets/Darkmatter/Code/Core/Data/Signals/Features/ShapeBuilder/PieceSnappedSignal.cs.meta create mode 100644 Assets/Darkmatter/Code/Core/Data/Signals/Features/ShapeBuilder/PieceUnsnappedSignal.cs create mode 100644 Assets/Darkmatter/Code/Core/Data/Signals/Features/ShapeBuilder/PieceUnsnappedSignal.cs.meta create mode 100644 Assets/Darkmatter/Code/Core/Data/Static/Features/ShapeBuilder/ShapeBuilderConfig.cs create mode 100644 Assets/Darkmatter/Code/Core/Data/Static/Features/ShapeBuilder/ShapeBuilderConfig.cs.meta create mode 100644 Assets/Darkmatter/Code/Features/ShapeBuilder.meta create mode 100644 Assets/Darkmatter/Code/Features/ShapeBuilder/Commands.meta create mode 100644 Assets/Darkmatter/Code/Features/ShapeBuilder/Commands/SnapPieceCommand.cs create mode 100644 Assets/Darkmatter/Code/Features/ShapeBuilder/Commands/SnapPieceCommand.cs.meta create mode 100644 Assets/Darkmatter/Code/Features/ShapeBuilder/Features.ShapeBuilder.asmdef create mode 100644 Assets/Darkmatter/Code/Features/ShapeBuilder/Features.ShapeBuilder.asmdef.meta create mode 100644 Assets/Darkmatter/Code/Features/ShapeBuilder/Installers.meta create mode 100644 Assets/Darkmatter/Code/Features/ShapeBuilder/Installers/ShapeBuilderFeatureModule.cs create mode 100644 Assets/Darkmatter/Code/Features/ShapeBuilder/Installers/ShapeBuilderFeatureModule.cs.meta create mode 100644 Assets/Darkmatter/Code/Features/ShapeBuilder/Systems.meta create mode 100644 Assets/Darkmatter/Code/Features/ShapeBuilder/UI.meta create mode 100644 Assets/Darkmatter/Code/Features/ShapeBuilder/UI/ShapePiece.cs create mode 100644 Assets/Darkmatter/Code/Features/ShapeBuilder/UI/ShapePiece.cs.meta create mode 100644 Assets/Darkmatter/Code/Features/ShapeBuilder/UI/SlotMarker.cs create mode 100644 Assets/Darkmatter/Code/Features/ShapeBuilder/UI/SlotMarker.cs.meta diff --git a/Assets/Darkmatter/Code/Core/Data/Dynamic/Features/Progression/DrawingProgress.cs b/Assets/Darkmatter/Code/Core/Data/Dynamic/Features/Progression/DrawingProgress.cs index a3c682b..c59dab6 100644 --- a/Assets/Darkmatter/Code/Core/Data/Dynamic/Features/Progression/DrawingProgress.cs +++ b/Assets/Darkmatter/Code/Core/Data/Dynamic/Features/Progression/DrawingProgress.cs @@ -10,8 +10,8 @@ namespace Darkmatter.Core.Data.Dynamic.Features.Progression { public string templateId; public DrawingPhase phase; - public List SnappedPieces; - public List RegionColors; + public List snappedPieces; + public List regionColors; public bool hasThumbnail; public bool hasBeenCompleted; @@ -26,8 +26,8 @@ namespace Darkmatter.Core.Data.Dynamic.Features.Progression { this.templateId = templateId; this.phase = phase; - SnappedPieces = snappedPieces; - RegionColors = regionColors; + this.snappedPieces = snappedPieces; + this.regionColors = regionColors; this.hasThumbnail = hasThumbnail; this.hasBeenCompleted = hasBeenCompleted; this.completionCount = completionCount; diff --git a/Assets/Darkmatter/Code/Core/Data/Dynamic/Features/Progression/RegionColorEntry.cs b/Assets/Darkmatter/Code/Core/Data/Dynamic/Features/Progression/RegionColorEntry.cs index ddc78d1..24933e7 100644 --- a/Assets/Darkmatter/Code/Core/Data/Dynamic/Features/Progression/RegionColorEntry.cs +++ b/Assets/Darkmatter/Code/Core/Data/Dynamic/Features/Progression/RegionColorEntry.cs @@ -1,4 +1,5 @@ using System; +using UnityEngine; namespace Darkmatter.Core.Data.Dynamic.Features.Progression { @@ -6,6 +7,6 @@ namespace Darkmatter.Core.Data.Dynamic.Features.Progression public struct RegionColorEntry { public string regionId; - public float r, g, b, a; + public Color color; } } \ No newline at end of file diff --git a/Assets/Darkmatter/Code/Core/Data/Signals/Features/ShapeBuilder/PieceSnappedSignal.cs b/Assets/Darkmatter/Code/Core/Data/Signals/Features/ShapeBuilder/PieceSnappedSignal.cs new file mode 100644 index 0000000..10c4017 --- /dev/null +++ b/Assets/Darkmatter/Code/Core/Data/Signals/Features/ShapeBuilder/PieceSnappedSignal.cs @@ -0,0 +1,4 @@ +namespace Darkmatter.Core.Data.Signals.Features.ShapeBuilder +{ + public record struct PieceSnappedSignal(string PieceId); +} diff --git a/Assets/Darkmatter/Code/Core/Data/Signals/Features/ShapeBuilder/PieceSnappedSignal.cs.meta b/Assets/Darkmatter/Code/Core/Data/Signals/Features/ShapeBuilder/PieceSnappedSignal.cs.meta new file mode 100644 index 0000000..e8b6059 --- /dev/null +++ b/Assets/Darkmatter/Code/Core/Data/Signals/Features/ShapeBuilder/PieceSnappedSignal.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: d4a88ca1eb07044daa9fd7a15c3dcc19 \ No newline at end of file diff --git a/Assets/Darkmatter/Code/Core/Data/Signals/Features/ShapeBuilder/PieceUnsnappedSignal.cs b/Assets/Darkmatter/Code/Core/Data/Signals/Features/ShapeBuilder/PieceUnsnappedSignal.cs new file mode 100644 index 0000000..eae223f --- /dev/null +++ b/Assets/Darkmatter/Code/Core/Data/Signals/Features/ShapeBuilder/PieceUnsnappedSignal.cs @@ -0,0 +1,4 @@ +namespace Darkmatter.Core.Data.Signals.Features.ShapeBuilder +{ + public record struct PieceUnsnappedSignal(string PieceId); +} diff --git a/Assets/Darkmatter/Code/Core/Data/Signals/Features/ShapeBuilder/PieceUnsnappedSignal.cs.meta b/Assets/Darkmatter/Code/Core/Data/Signals/Features/ShapeBuilder/PieceUnsnappedSignal.cs.meta new file mode 100644 index 0000000..504295b --- /dev/null +++ b/Assets/Darkmatter/Code/Core/Data/Signals/Features/ShapeBuilder/PieceUnsnappedSignal.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: d16116e16ea0a40b9afdc4765ba8881c \ No newline at end of file diff --git a/Assets/Darkmatter/Code/Core/Data/Static/Features/ShapeBuilder/ShapeBuilderConfig.cs b/Assets/Darkmatter/Code/Core/Data/Static/Features/ShapeBuilder/ShapeBuilderConfig.cs new file mode 100644 index 0000000..37948e8 --- /dev/null +++ b/Assets/Darkmatter/Code/Core/Data/Static/Features/ShapeBuilder/ShapeBuilderConfig.cs @@ -0,0 +1,30 @@ +using UnityEngine; + +namespace Darkmatter.Core.Data.Static.Features.ShapeBuilder +{ + [CreateAssetMenu(fileName = "ShapeBuilderConfig", + menuName = "Darkmatter/ShapeBuilder/Config")] + public sealed class ShapeBuilderConfig : ScriptableObject + { + [Header("Radii (canvas units; reference resolution 2048x2048)")] + [SerializeField] private float snapRadius = 100f; + [SerializeField] private float snapGraceMultiplier = 1.5f; + [SerializeField] private float previewRadius = 200f; + + [Header("Tween durations (seconds)")] + [SerializeField] private float snapDuration = 0.25f; + [SerializeField] private float returnDuration = 0.25f; + + [Header("Preview easing")] + [SerializeField] private AnimationCurve previewCurve = AnimationCurve.EaseInOut(0, 0, 1, 1); + + public float SnapRadius => snapRadius; + public float PreviewRadius => previewRadius; + public float SnapDuration => snapDuration; + public float ReturnDuration => returnDuration; + public AnimationCurve PreviewCurve => previewCurve; + + public Vector2 DragSizeDelta(ShapeSO shape) => + shape != null ? shape.DefaultSizeDelta : new Vector2(256, 256); + } +} diff --git a/Assets/Darkmatter/Code/Core/Data/Static/Features/ShapeBuilder/ShapeBuilderConfig.cs.meta b/Assets/Darkmatter/Code/Core/Data/Static/Features/ShapeBuilder/ShapeBuilderConfig.cs.meta new file mode 100644 index 0000000..29c5edd --- /dev/null +++ b/Assets/Darkmatter/Code/Core/Data/Static/Features/ShapeBuilder/ShapeBuilderConfig.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 52d6fdba64cc3491880636e34ed593d0 \ No newline at end of file diff --git a/Assets/Darkmatter/Code/Core/Data/Static/Features/ShapeBuilder/ShapeSO.cs b/Assets/Darkmatter/Code/Core/Data/Static/Features/ShapeBuilder/ShapeSO.cs index 219e650..b720285 100644 --- a/Assets/Darkmatter/Code/Core/Data/Static/Features/ShapeBuilder/ShapeSO.cs +++ b/Assets/Darkmatter/Code/Core/Data/Static/Features/ShapeBuilder/ShapeSO.cs @@ -7,5 +7,6 @@ namespace Darkmatter.Core.Data.Static.Features.ShapeBuilder { [field: SerializeField] public string Id { get; private set; } [field: SerializeField] public Sprite Sprite { get; private set; } + [field: SerializeField] public Vector2 DefaultSizeDelta { get; private set; } = new(256, 256); } } \ No newline at end of file diff --git a/Assets/Darkmatter/Code/Core/Enums/Services/Audio/SfxId.cs b/Assets/Darkmatter/Code/Core/Enums/Services/Audio/SfxId.cs index b2a6e9e..9863533 100644 --- a/Assets/Darkmatter/Code/Core/Enums/Services/Audio/SfxId.cs +++ b/Assets/Darkmatter/Code/Core/Enums/Services/Audio/SfxId.cs @@ -3,14 +3,8 @@ namespace Darkmatter.Core.Enums.Services.Audio public enum SfxId { None = 0, - - WiperUp = 100, - WiperDown = 101, - - BlinkerTick = 200, - - GearShift = 300, - - ReverseBeep = 400, + ShapeHover = 100, + ShapeSnap = 101, + ShapeReturn = 102, } } diff --git a/Assets/Darkmatter/Code/Features/ShapeBuilder.meta b/Assets/Darkmatter/Code/Features/ShapeBuilder.meta new file mode 100644 index 0000000..57845fc --- /dev/null +++ b/Assets/Darkmatter/Code/Features/ShapeBuilder.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c12a68c64c45647dab002508c06ec8cd +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Darkmatter/Code/Features/ShapeBuilder/Commands.meta b/Assets/Darkmatter/Code/Features/ShapeBuilder/Commands.meta new file mode 100644 index 0000000..c7c3a61 --- /dev/null +++ b/Assets/Darkmatter/Code/Features/ShapeBuilder/Commands.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 32ae4b246e57f4379baa7b98cffeb8c2 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Darkmatter/Code/Features/ShapeBuilder/Commands/SnapPieceCommand.cs b/Assets/Darkmatter/Code/Features/ShapeBuilder/Commands/SnapPieceCommand.cs new file mode 100644 index 0000000..44b038a --- /dev/null +++ b/Assets/Darkmatter/Code/Features/ShapeBuilder/Commands/SnapPieceCommand.cs @@ -0,0 +1,35 @@ +using Darkmatter.Core.Contracts.Features.History; +using Darkmatter.Features.ShapeBuilder.UI; +using UnityEngine; + +namespace Darkmatter.Features.ShapeBuilder.Commands +{ + /// + /// Undoable snap. Captures the piece's pre-snap pose + parent at ctor time; + /// Execute drives the normal snap tween; Undo restores the pre-snap state + /// and re-enables drag. + /// + internal sealed class SnapPieceCommand : ICommand + { + private readonly ShapePiece _piece; + private readonly Vector2 _prevPos; + private readonly Vector2 _prevSize; + private readonly Quaternion _prevRot; + private readonly Transform _prevParent; + + public SnapPieceCommand(ShapePiece piece) + { + _piece = piece; + + var rt = piece.RectTransform; + _prevPos = rt.anchoredPosition; + _prevSize = rt.sizeDelta; + _prevRot = rt.localRotation; + _prevParent = rt.parent; + } + + public void Execute() => _piece.SnapInternal(); + + public void Undo() => _piece.UnsnapInternal(_prevParent, _prevPos, _prevSize, _prevRot); + } +} diff --git a/Assets/Darkmatter/Code/Features/ShapeBuilder/Commands/SnapPieceCommand.cs.meta b/Assets/Darkmatter/Code/Features/ShapeBuilder/Commands/SnapPieceCommand.cs.meta new file mode 100644 index 0000000..61fae22 --- /dev/null +++ b/Assets/Darkmatter/Code/Features/ShapeBuilder/Commands/SnapPieceCommand.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 7565e0dc60eca451c9877bd23dddb901 \ No newline at end of file diff --git a/Assets/Darkmatter/Code/Features/ShapeBuilder/Features.ShapeBuilder.asmdef b/Assets/Darkmatter/Code/Features/ShapeBuilder/Features.ShapeBuilder.asmdef new file mode 100644 index 0000000..56a7974 --- /dev/null +++ b/Assets/Darkmatter/Code/Features/ShapeBuilder/Features.ShapeBuilder.asmdef @@ -0,0 +1,22 @@ +{ + "name": "Features.ShapeBuilder", + "rootNamespace": "Darkmatter.Features.ShapeBuilder", + "references": [ + "GUID:6a0a834eb41764f12ba55c3fb04a40cb", + "GUID:c1c03c0e5b2f4412b9f2be1c20d6a9b1", + "GUID:c176ee863a5e74e88a6517f9f102cf92", + "GUID:b4c9f7fbf1e144933a1797dc208ece5f", + "GUID:b0214a6008ed146ff8f122a6a9c2f6cc", + "GUID:f51ebe6a0ceec4240a699833d6309b23", + "GUID:80ecb87cae9c44d19824e70ea7229748" + ], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/Assets/Darkmatter/Code/Features/ShapeBuilder/Features.ShapeBuilder.asmdef.meta b/Assets/Darkmatter/Code/Features/ShapeBuilder/Features.ShapeBuilder.asmdef.meta new file mode 100644 index 0000000..17032cc --- /dev/null +++ b/Assets/Darkmatter/Code/Features/ShapeBuilder/Features.ShapeBuilder.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 2ca8c3a66565544118d3d52d3922933b +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Darkmatter/Code/Features/ShapeBuilder/Installers.meta b/Assets/Darkmatter/Code/Features/ShapeBuilder/Installers.meta new file mode 100644 index 0000000..353399c --- /dev/null +++ b/Assets/Darkmatter/Code/Features/ShapeBuilder/Installers.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f8f128ba2fede4ab2971c98f4f83819a +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Darkmatter/Code/Features/ShapeBuilder/Installers/ShapeBuilderFeatureModule.cs b/Assets/Darkmatter/Code/Features/ShapeBuilder/Installers/ShapeBuilderFeatureModule.cs new file mode 100644 index 0000000..017748e --- /dev/null +++ b/Assets/Darkmatter/Code/Features/ShapeBuilder/Installers/ShapeBuilderFeatureModule.cs @@ -0,0 +1,21 @@ +using Darkmatter.Core.Data.Static.Features.ShapeBuilder; +using Darkmatter.Libs.Installers; +using UnityEngine; +using VContainer; + +namespace Darkmatter.Features.ShapeBuilder.Installers +{ + public class ShapeBuilderFeatureModule : MonoBehaviour, IModule + { + [SerializeField] private ShapeBuilderConfig config; + + public void Register(IContainerBuilder builder) + { + if (config != null) + builder.RegisterInstance(config); + + // ShapePiece instances are MonoBehaviours instantiated by the + // ShapeBuilderController; nothing to register here for them. + } + } +} diff --git a/Assets/Darkmatter/Code/Features/ShapeBuilder/Installers/ShapeBuilderFeatureModule.cs.meta b/Assets/Darkmatter/Code/Features/ShapeBuilder/Installers/ShapeBuilderFeatureModule.cs.meta new file mode 100644 index 0000000..684c1ff --- /dev/null +++ b/Assets/Darkmatter/Code/Features/ShapeBuilder/Installers/ShapeBuilderFeatureModule.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: d6323fd2530234772b15e4b2d169df47 \ No newline at end of file diff --git a/Assets/Darkmatter/Code/Features/ShapeBuilder/Systems.meta b/Assets/Darkmatter/Code/Features/ShapeBuilder/Systems.meta new file mode 100644 index 0000000..9c34fd0 --- /dev/null +++ b/Assets/Darkmatter/Code/Features/ShapeBuilder/Systems.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 679f7a317a1b7445aaa719055bca4a6d +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Darkmatter/Code/Features/ShapeBuilder/UI.meta b/Assets/Darkmatter/Code/Features/ShapeBuilder/UI.meta new file mode 100644 index 0000000..263d27b --- /dev/null +++ b/Assets/Darkmatter/Code/Features/ShapeBuilder/UI.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: cdbdbbcc180884694930e5ce1dbbb7d4 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Darkmatter/Code/Features/ShapeBuilder/UI/ShapePiece.cs b/Assets/Darkmatter/Code/Features/ShapeBuilder/UI/ShapePiece.cs new file mode 100644 index 0000000..4e11b19 --- /dev/null +++ b/Assets/Darkmatter/Code/Features/ShapeBuilder/UI/ShapePiece.cs @@ -0,0 +1,203 @@ +using Darkmatter.Core.Contracts.Features.History; +using Darkmatter.Core.Contracts.Services.Audio; +using Darkmatter.Core.Data.Signals.Features.ShapeBuilder; +using Darkmatter.Core.Data.Static.Features.ShapeBuilder; +using Darkmatter.Core.Enums.Services.Audio; +using Darkmatter.Features.ShapeBuilder.Commands; +using Darkmatter.Libs.Observer; +using PrimeTween; +using UnityEngine; +using UnityEngine.EventSystems; +using UnityEngine.UI; + +namespace Darkmatter.Features.ShapeBuilder.UI +{ + /// + /// Single-MB shape piece. Handles drag, reactive preview lerp, snap, + /// and return-to-tray. Snap is wrapped in a + /// pushed onto the shared so it participates in + /// the same undo/redo flow as coloring. + /// + [RequireComponent(typeof(RectTransform))] + public sealed class ShapePiece : MonoBehaviour, + IBeginDragHandler, IDragHandler, IEndDragHandler + { + [SerializeField] private Image image; + + // Bound by Setup + private ShapeSO _shape; + private SlotMarker _slot; + private ShapeBuilderConfig _cfg; + private ISfxPlayer _sfx; + private IEventBus _bus; + private IUndoStack _undo; + private Vector2 _trayPos; + private Vector2 _traySize; + + // Per-drag state + private RectTransform _rt; + private RectTransform _parentRect; + private Camera _eventCam; + private Vector2 _grabOffset; + private bool _locked; + private bool _inPreview; + + public ShapeSO Shape => _shape; + public string PieceId => _shape != null ? _shape.Id : null; + public bool IsLocked => _locked; + public RectTransform RectTransform => _rt != null ? _rt : (_rt = (RectTransform)transform); + + public void Setup( + ShapeSO shape, + SlotMarker slot, + ShapeBuilderConfig cfg, + ISfxPlayer sfx, + IEventBus bus, + IUndoStack undo, + Vector2 trayPos, + bool preSnapped) + { + _shape = shape; + _slot = slot; + _cfg = cfg; + _sfx = sfx; + _bus = bus; + _undo = undo; + _trayPos = trayPos; + _traySize = shape.DefaultSizeDelta; + + image.sprite = shape.Sprite; + ApplyTrayPose(); + + if (preSnapped) SnapInstantly(); + } + + public void OnBeginDrag(PointerEventData e) + { + if (_locked) return; + _parentRect = (RectTransform)RectTransform.parent; + _eventCam = e.pressEventCamera; + _grabOffset = RectTransform.anchoredPosition - ScreenToLocal(e.position); + _inPreview = false; + } + + public void OnDrag(PointerEventData e) + { + if (_locked) return; + + var pointerLocal = ScreenToLocal(e.position) + _grabOffset; + var slotPos = _slot.RectTransform.anchoredPosition; + float dist = Vector2.Distance(pointerLocal, slotPos); + + if (dist <= _cfg.PreviewRadius) + { + if (!_inPreview) + { + _inPreview = true; + _sfx.Play(SfxId.ShapeHover); + } + ApplyPreviewLerp(pointerLocal, dist); + } + else + { + _inPreview = false; + RectTransform.anchoredPosition = pointerLocal; + RectTransform.sizeDelta = _traySize; + RectTransform.localRotation = Quaternion.identity; + } + } + + public void OnEndDrag(PointerEventData e) + { + if (_locked) return; + + float dist = Vector2.Distance( + RectTransform.anchoredPosition, + _slot.RectTransform.anchoredPosition); + + if (dist <= _cfg.SnapRadius) + _undo.Push(new SnapPieceCommand(this)); // Push calls Execute → SnapInternal + else + ReturnToTray(); + } + + private void ApplyPreviewLerp(Vector2 pointerLocal, float dist) + { + float t = Mathf.Clamp01(1f - dist / _cfg.PreviewRadius); + if (_cfg.PreviewCurve != null) t = _cfg.PreviewCurve.Evaluate(t); + + var slot = _slot.RectTransform; + RectTransform.anchoredPosition = Vector2.Lerp(pointerLocal, slot.anchoredPosition, t); + RectTransform.sizeDelta = Vector2.Lerp(_traySize, slot.sizeDelta, t); + RectTransform.localRotation = Quaternion.Slerp(Quaternion.identity, slot.localRotation, t); + } + + // ---- Command-driven snap / un-snap ---- + internal void SnapInternal() + { + Lock(); + var slot = _slot.RectTransform; + + Tween.UIAnchoredPosition(RectTransform, slot.anchoredPosition, _cfg.SnapDuration, Ease.OutBack); + Tween.UISizeDelta (RectTransform, slot.sizeDelta, _cfg.SnapDuration, Ease.OutBack); + Tween.LocalRotation (RectTransform, slot.localRotation, _cfg.SnapDuration, Ease.OutBack); + + _sfx.Play(SfxId.ShapeSnap); + _bus.Publish(new PieceSnappedSignal(_shape.Id)); + } + + internal void UnsnapInternal(Transform parent, Vector2 pos, Vector2 size, Quaternion rot) + { + _locked = false; + image.raycastTarget = true; + + RectTransform.SetParent(parent, worldPositionStays: false); + + Tween.UIAnchoredPosition(RectTransform, pos, _cfg.ReturnDuration, Ease.OutQuad); + Tween.UISizeDelta (RectTransform, size, _cfg.ReturnDuration, Ease.OutQuad); + Tween.LocalRotation (RectTransform, rot, _cfg.ReturnDuration, Ease.OutQuad); + + _sfx.Play(SfxId.ShapeReturn); + _bus.Publish(new PieceUnsnappedSignal(_shape.Id)); + } + + private void SnapInstantly() + { + Lock(); + var slot = _slot.RectTransform; + RectTransform.anchoredPosition = slot.anchoredPosition; + RectTransform.sizeDelta = slot.sizeDelta; + RectTransform.localRotation = slot.localRotation; + } + + private void ReturnToTray() + { + _sfx.Play(SfxId.ShapeReturn); + Sequence.Create() + .Group(Tween.UIAnchoredPosition(RectTransform, _trayPos, _cfg.ReturnDuration, Ease.OutQuad)) + .Group(Tween.UISizeDelta (RectTransform, _traySize, _cfg.ReturnDuration, Ease.OutQuad)) + .Group(Tween.LocalRotation (RectTransform, Quaternion.identity, _cfg.ReturnDuration, Ease.OutQuad)); + } + + private void Lock() + { + _locked = true; + image.raycastTarget = false; + RectTransform.SetParent(_slot.RectTransform.parent, worldPositionStays: false); + } + + private void ApplyTrayPose() + { + RectTransform.anchoredPosition = _trayPos; + RectTransform.sizeDelta = _traySize; + RectTransform.localRotation = Quaternion.identity; + } + + private Vector2 ScreenToLocal(Vector2 screenPos) + { + RectTransformUtility.ScreenPointToLocalPointInRectangle( + _parentRect, screenPos, _eventCam, out var local); + return local; + } + } +} diff --git a/Assets/Darkmatter/Code/Features/ShapeBuilder/UI/ShapePiece.cs.meta b/Assets/Darkmatter/Code/Features/ShapeBuilder/UI/ShapePiece.cs.meta new file mode 100644 index 0000000..c0df7eb --- /dev/null +++ b/Assets/Darkmatter/Code/Features/ShapeBuilder/UI/ShapePiece.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 189fa0409d676438abe96e8707e29ad0 \ No newline at end of file diff --git a/Assets/Darkmatter/Code/Features/ShapeBuilder/UI/SlotMarker.cs b/Assets/Darkmatter/Code/Features/ShapeBuilder/UI/SlotMarker.cs new file mode 100644 index 0000000..6aecf01 --- /dev/null +++ b/Assets/Darkmatter/Code/Features/ShapeBuilder/UI/SlotMarker.cs @@ -0,0 +1,21 @@ +using Darkmatter.Core.Data.Static.Features.ShapeBuilder; +using UnityEngine; +using UnityEngine.UI; + +namespace Darkmatter.Features.ShapeBuilder.UI +{ + public sealed class SlotMarker : MonoBehaviour + { + [SerializeField] private ShapeSO shape; + [SerializeField] private Image outline; + + public ShapeSO Shape => shape; + public string SlotId => shape != null ? shape.Id : null; + public RectTransform RectTransform => (RectTransform)transform; + + public void SetOutlineVisible(bool visible) + { + if (outline != null) outline.enabled = visible; + } + } +} diff --git a/Assets/Darkmatter/Code/Features/ShapeBuilder/UI/SlotMarker.cs.meta b/Assets/Darkmatter/Code/Features/ShapeBuilder/UI/SlotMarker.cs.meta new file mode 100644 index 0000000..82bcb78 --- /dev/null +++ b/Assets/Darkmatter/Code/Features/ShapeBuilder/UI/SlotMarker.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 5d79b18d536324085b58d842648372a8 \ No newline at end of file diff --git a/Assets/Darkmatter/Scenes/GamePlay.unity b/Assets/Darkmatter/Scenes/GamePlay.unity index a8a149d..f7e02fb 100644 --- a/Assets/Darkmatter/Scenes/GamePlay.unity +++ b/Assets/Darkmatter/Scenes/GamePlay.unity @@ -324,8 +324,54 @@ Transform: m_ConstrainProportionsScale: 0 m_Children: - {fileID: 1551649428} + - {fileID: 1991184379} m_Father: {fileID: 1224714932} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1991184378 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1991184379} + - component: {fileID: 1991184380} + m_Layer: 0 + m_Name: ShapeBuilderFeatureModule + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1991184379 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1991184378} + 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: 1965442263} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1991184380 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1991184378} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d6323fd2530234772b15e4b2d169df47, type: 3} + m_Name: + m_EditorClassIdentifier: Features.ShapeBuilder::Darkmatter.Features.ShapeBuilder.Installers.ShapeBuilderFeatureModule + config: {fileID: 0} --- !u!1 &2069155637 GameObject: m_ObjectHideFlags: 0 diff --git a/Readme.docx b/Readme.docx index a2cd684864dca9223279e77bb6a0e6aa34e73708..9ef6d64ee27eeeccaae8e6aeeeaed95e9af87b40 100644 GIT binary patch delta 70242 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 M9c~vEA`$R^0OF()`), it should run once, in order: +No `AppBoot` class exists yet — today `RootLifetimeScope` only registers services and stops. When `AppBoot` is added (as an `IAsyncStartable` registered via `RootLifetimeScope`), it should run once, in order: -1. Initialize `IAssetProviderService` (Addressables init). -2. Preload essential bundles (palettes, UI sounds). -3. Load `IProgressionService` from disk. -4. Load `MainMenu` scene. +1. `IAssetProviderService.InitializeAsync()` — Addressables init. +2. `IProgressionSystem.LoadAsync()` — hydrate per-template state from PlayerPrefs. +3. `IDrawingTemplateCatalog.InitializeAsync()` — batch-load all `DrawingTemplateSO`s by Addressables label. +4. Optional: preload UI sounds, palette assets. +5. `ISceneService.LoadAsync(MainMenu)`. Failures show a child-friendly retry screen; never crash. @@ -563,54 +616,55 @@ public readonly struct PaperSavedSignal { ### `ShapeBuilder` -- Listens to `DrawingSelectedSignal`. -- Loads template, instantiates the single piece prefab once per `ShapeSO` in the template, parents under the HUD tray panel (`ColorBookSceneRefs.TrayPanel`). Each instance is `Assign(shape)`ed to its `ShapeSO`. -- `SlotMarker`s in the drawing's per-drawing prefab (under `ColorBookSceneRefs.SlotsParent`) provide target poses + matching `ShapeSO` refs. -- Each piece has `IBeginDragHandler` / `IDragHandler` / `IEndDragHandler` plus a per-piece `ShapePieceFsm`. Drag updates `RectTransform.anchoredPosition` directly from `PointerEventData`, converted to canvas-local via `RectTransformUtility.ScreenPointToLocalPointInRectangle`. -- On entering preview radius of the matching slot: reactive `Lerp` of `anchoredPosition` / `sizeDelta` / `localRotation` toward `SlotMarker`'s `RectTransform`. Drives off pointer distance, not time. -- On `OnEndDrag` inside snap radius: piece reparents to `ColorBookSceneRefs.PiecesParent`, DOTween ease-out to exact slot pose, disable input. Otherwise DOTween back to tray slot. -- Fires `ShapeAssembledSignal` when all pieces locked. +- Listens to `DrawingSelectedSignal` (raised by the Colorbook scene before scene change; resume reads `LastOpenedTemplateId` in Gameplay scope startup). +- Loads the per-drawing prefab via `IDrawingTemplateCatalog`, instantiates it under `GameplaySceneRefs.PaperRoot`. The prefab carries the `SlotMarker`s at their authored poses. +- Spawns one **`ShapePiece` MonoBehaviour** per `ShapeSO` in the template via `Instantiate(piecePrefab, tray)` and calls `piece.Setup(shape, slot, cfg, sfx, bus, trayPos, preSnapped)`. If `progress.Phase == ShapeBuilding`, pieces in `progress.SnappedPieces` are pre-snapped (start locked). +- `ShapePiece` is a single MB handling all three behaviors inline: drag (Unity UI `IBeginDrag / IDrag / IEndDrag`), reactive preview lerp when within `cfg.PreviewRadius`, snap (PrimeTween — `Tween.UIAnchoredPosition` / `UISizeDelta` / `LocalRotation`) on release inside `cfg.SnapRadius`, otherwise tween back to tray. No FSM, no factory — just the MB. +- Publishes `PieceSnappedSignal(pieceId)` on lock. Controller counts against expected; fires `ShapeAssembledSignal(templateId)` when all locked. ### `Coloring` - Listens to `ShapeAssembledSignal`. -- Spawns one UI `Image` per `ColorRegionDTO` under `ColorBookSceneRefs.RegionsParent`. Each region's `Image.alphaHitTestMinimumThreshold = 0.5f` so taps on transparent pixels pass through to the next region. +- Spawns one UI `Image` per `ColorRegionDTO` under `GameplaySceneRefs.RegionsParent`. Each region's `Image.alphaHitTestMinimumThreshold = 0.5f` so taps on transparent pixels pass through to the next region below. - Each region has `IPointerClickHandler`. On click → `ColoringController.PaintRegion(view)`. - Listens to palette selection (current color held in `ColoringStateRepository`). -- Controller builds `PaintRegionCommand(regionId, oldColor, newColor)` and pushes to `IUndoStack`. -- Command sets `Image.color` on undo/redo. -- Fires `ColorAppliedSignal` for SFX / sparkle effects. +- Controller builds `PaintRegionCommand(regionId, oldColor, newColor)` and pushes to `IUndoStack`. Command sets `Image.color` on Execute/Undo. +- Publishes `ColorAppliedSignal` for SFX / sparkle effects. +- **Resume:** if `progress.RegionColors` is non-empty, spawned regions are initialized with those saved colors instead of `region.InitialColor`. +- **Autosave hook:** after each `PaintRegion`, debounces 500 ms then calls `GameplayFlowController.AutosaveAsync` so the colors hit disk without thumbnail re-render. See §13. ### `History` -- Owns the scoped `IUndoStack` for the current ColorBook session. -- Cleared on `DrawingSelectedSignal` (new drawing = fresh history). -- Capped at 20 entries (memory + cognitive simplicity). -- UI: two big arrow buttons; disabled state when `CanUndo / CanRedo` is false. +- Owns the scoped `IUndoStack` for the current Gameplay session. +- Cleared on Gameplay scope startup (new drawing = fresh history). +- Capped at 20 entries. +- UI: two big arrow buttons; disabled state when `CanUndo` / `CanRedo` is false. ### `Capture` -- Bound to the "Save" button (and triggered silently by "Next"). -- `CaptureController.SaveAsync(templateId)`: - 1. `_capture.CaptureAsync()` → PNG bytes (one-shot `CaptureCamera.Render()` into a temp RT) - 2. Publish `PaperCapturedSignal(templateId)` - 3. `_gallery.SaveToDeviceAsync(bytes, "Color Book")` → native plugin writes into phone's Photos - 4. Publish `PaperSavedSignal(templateId)` -- HUD shows a brief "Saved to Photos" toast on `PaperSavedSignal`. -- `CaptureController` is the only place that orchestrates capture-then-save. Other features never call `IGalleryService` directly. +- Wraps `ICaptureService.CaptureAsync()` (one-shot `CaptureCamera.Render()` into a temp RT, ReadPixels, EncodeToPNG). Returns raw PNG bytes. +- The **Capture feature does NOT decide what to do with the bytes** — `GameplayFlowController` calls it, then routes to gallery + thumbnail cache depending on the trigger. See §13. ### `Progression` -- Tracks completed template IDs and the in-progress draft. -- On "Next" button: silently runs `CaptureController.SaveAsync`, marks current as completed, calls `IDrawingTemplateCatalog.NextUnseen()`. -- Persists JSON via `Libs.PlayerPrefs` (`ProtectedPlayerPrefs`). +- Single source of truth for per-template user state. Implements `IProgressionSystem`, persists `DrawingProgress` records via `Libs.PlayerPrefs` (single JSON blob under `PlayerPrefsKeys.Progression`). +- Internally stores thumbnails per template as PNG files in `Application.persistentDataPath/thumbs/{safeId}.png` (large blobs don't belong in PlayerPrefs). +- `ProgressionRepository` does the IO; `ProgressionSystem` keeps an in-memory cache and exposes a clean API. +- Exposes: `GetProgress(id)`, `SaveProgressAsync(progress)`, `SaveProgressAsync(progress, png)`, `ClearProgressAsync(id)`, `IsCompleted(id)`, `CompletedTemplateIds`, `LastOpenedTemplateId / SetLastOpened`, `GetCachedThumbnailAsync(id)`. +- See §13 for the full save matrix. -### `ColorBookFlow` +### `ColorbookFlow` (in `Colorbook.unity`) -- The only orchestrator inside ColorBook scope. -- Subscribes to flow-relevant signals and toggles UI panels (catalog → builder → coloring). -- Coordinates "Next" sequence: `CaptureController.SaveAsync` → `IProgressionService.MarkCompleted` → `IDrawingTemplateCatalog.Release(currentId)` → load next. -- Built as a small FSM (`Catalog → Building → Coloring → Done`). +- The orchestrator for the catalog scene. +- On scope start: calls `_drawingCatalog.InitializeAsync()` to populate the visible-IDs list. +- Subscribes to `DrawingSelectedSignal`: `_progression.SetLastOpened(id)` + `_scenes.LoadAsync(Gameplay)`. + +### `GameplayFlow` (in `Gameplay.unity`) + +- The orchestrator for the active drawing scene. +- On scope start: reads `_progression.LastOpenedTemplateId`, fetches its `DrawingProgress`, enters either Building (no progress / Phase==ShapeBuilding) or Coloring (Phase==Coloring) state. +- Handles all save points (§13): Back button, ShapeAssembled transition, Save button, Next button, app lifecycle pause/quit. +- Uses `Libs.FSM` (StateMachine) for `Building` ↔ `Coloring` runtime states. --- @@ -740,6 +794,92 @@ Notes: --- +## 12b. Save System + +Everything the user does that affects their drawing state must end up persisted. `GameplayFlowController` is the **single owner** of all save calls — feature controllers expose getters; the flow controller assembles the `DrawingProgress` record and hands it to `IProgressionSystem`. + +### What is saved + +| Field on `DrawingProgress` | Meaning | +|---|---| +| `templateId` | Which drawing this record is about | +| `phase` | `ShapeBuilding` or `Coloring` — where to resume | +| `snappedPieces` | Pieces locked into slots (relevant in ShapeBuilding) | +| `regionColors` | Per-region color (relevant in Coloring) | +| `hasThumbnail` | Whether a thumbnail PNG exists on disk for catalog display | +| `hasBeenCompleted` | Flipped true on first Next; never flips back | +| `completionCount` | Number of times Next was pressed (optional stats) | +| `updatedUtcIso` / `firstCompletedUtcIso` | Timestamps (ISO 8601 strings for JsonUtility) | + +### Save matrix + +| Trigger | Phase saved | Snapped pieces | Region colors | Thumbnail? | Native gallery? | +|---|---|---|---|---|---| +| **ShapeAssembledSignal** (Building → Coloring transition) | `Coloring` | all | empty | **yes** (bare-assembled paper) | no | +| **Each paint** (debounced 500 ms) | `Coloring` | all | current | no | no | +| **Save button** | `Coloring` | all | current | **yes** | **yes** | +| **Next button** | `Coloring` | all | current | **yes** | **yes** | +| **Back button (during Building)** | `ShapeBuilding` | current | empty | no | no | +| **Back button (during Coloring)** | `Coloring` | all | current | **yes** | no | +| **OnApplicationPause(true) / OnApplicationQuit** | current phase | current | current | no | no | + +Two design principles drive the matrix: + +- **Thumbnail capture is expensive** (render + ReadPixels + PNG encode). Skip it on partial-assembly saves and per-paint autosaves. Only generate a thumbnail when the user takes an explicit save-style action. +- **Defensive saves never block UX.** App pause/quit saves whatever is in memory without capturing — fast path, no awaitable IO holding up shutdown. + +### `Next` adds two extras + +- Flips `hasBeenCompleted = true` (preserves first `firstCompletedUtcIso`); increments `completionCount`. +- Plays completion animation, then calls `AdvanceToNextDrawing` → `Catalog.NextUnseen(currentId)` → reload Gameplay scope for the new drawing. + +### Storage layout + +| What | Where | +|---|---| +| `DrawingProgress` records + `lastOpened` | One JSON blob in `ProtectedPlayerPrefs[PlayerPrefsKeys.Progression]` (see `ProgressionRootDto`) | +| Thumbnail PNGs | `Application.persistentDataPath/thumbs/{safeId}.png` (one file per template that has a thumbnail) | + +`safeId` replaces `/` and `\` with `_` so `animals/elephant` becomes `animals_elephant.png`. + +### Resume / load decision + +On Gameplay scope startup: + +```csharp +var id = _progression.LastOpenedTemplateId; +var progress = _progression.GetProgress(id); // null if untouched + +if (progress == null || progress.Value.phase == DrawingPhase.ShapeBuilding) { + fsm.Go(Building); // spawn pieces in tray, pre-snap any in progress.snappedPieces +} else { + fsm.Go(Coloring); // skip ShapeBuilder; auto-snap pieces; spawn regions with progress.regionColors +} +``` + +### Catalog cells reflect saves automatically + +The Colorbook scene reloads on Back. Its presenter calls `_progression.GetCachedThumbnailAsync(id)` per cell → returns the most recent save's PNG. Drawings the user touched display their progress; untouched drawings fall back to `IDrawingTemplate.DefaultThumbnail`. No live-update plumbing needed — re-entry is the refresh. + +### Files touching the save system + +| Path | Role | +|---|---| +| `Core/Contracts/Features/Progression/IProgressionSystem.cs` | Contract | +| `Core/Data/Dynamic/Features/Progression/DrawingProgress.cs` | The struct | +| `Core/Data/Dynamic/Features/Progression/ProgressionRootDto.cs` | JSON root (records + lastOpened) | +| `Core/Data/Dynamic/Features/Progression/RegionColorEntry.cs` | Flattened color entry (JsonUtility-friendly) | +| `Core/Enums/Features/Progression/DrawingPhase.cs` | Phase enum | +| `Features/Progression/Systems/ProgressionSystem.cs` | In-memory cache + write serialization (SemaphoreSlim) | +| `Features/Progression/Systems/ProgressionRepository.cs` | PlayerPrefs JSON + thumbnail file IO | +| `Features/Progression/Installers/ProgressionFeatureModule.cs` | Registers `IProgressionSystem` as Singleton in Root scope | + +### Single rule + +> Only `GameplayFlowController` calls `_progression.SaveProgressAsync(...)`. Feature controllers expose getters; they never touch the tracker themselves. This means there is exactly one place to audit when save behavior changes. + +--- + ## 13. Communication Rules | Use case | Mechanism | @@ -1145,44 +1285,109 @@ Same shape repeats for every feature's UI. ## 26. ShapeBuilder — Snap Algorithm -All math is in canvas-local space — `anchoredPosition`, `sizeDelta`, `localRotation`. No world coords. +All math is in canvas-local space — `anchoredPosition`, `sizeDelta`, `localRotation`. No world coords. Behavior lives inline in `ShapePiece : MonoBehaviour` — no FSM, no factory, no state classes. Three behaviors expressed across three Unity drag handlers. + +### `OnDrag` — reactive preview lerp ```csharp -// In ShapePieceFsm.OnDragEnd (state: Dragging or Preview): -public void OnDragEnd() { - var pieceRT = _ui.RectTransform; - var slotRT = _targetSlot.RectTransform; - var d = Vector2.Distance(pieceRT.anchoredPosition, slotRT.anchoredPosition); +public void OnDrag(PointerEventData e) +{ + if (_locked) return; - if (d <= _cfg.SnapRadius) { - SnapToSlot(); - } else if (d <= _cfg.SnapRadius * 1.5f) { - // Toddler grace zone — snap anyway, play happy sound - SnapToSlot(); - _audio.PlayOneShot(SfxId.NiceTry); - } else { - ReturnToTrayAnimated(); + var pointerLocal = ScreenToLocal(e.position) + _grabOffset; + var slotPos = _slot.RectTransform.anchoredPosition; + float dist = Vector2.Distance(pointerLocal, slotPos); + + if (dist <= _cfg.PreviewRadius) + { + if (!_inPreview) { _inPreview = true; _sfx.Play(SfxId.ShapeHover); } + ApplyPreviewLerp(pointerLocal, dist); + } + else + { + _inPreview = false; + RectTransform.anchoredPosition = pointerLocal; + RectTransform.sizeDelta = _traySize; + RectTransform.localRotation = Quaternion.identity; } } -private void SnapToSlot() { - _ui.RectTransform.SetParent(_paper.PiecesParent, worldPositionStays: false); - var slot = _targetSlot.RectTransform; - _ui.RectTransform.DOAnchorPos(slot.anchoredPosition, 0.25f).SetEase(Ease.OutBack); - _ui.RectTransform.DOSizeDelta(slot.sizeDelta, 0.25f).SetEase(Ease.OutBack); - _ui.RectTransform.DOLocalRotateQuaternion(slot.localRotation, 0.25f).SetEase(Ease.OutBack); - _audio.PlayOneShot(SfxId.Snap); - _bus.Publish(new PieceSnappedSignal(_ui.PieceId)); +private void ApplyPreviewLerp(Vector2 pointerLocal, float dist) +{ + float t = Mathf.Clamp01(1f - dist / _cfg.PreviewRadius); + if (_cfg.PreviewCurve != null) t = _cfg.PreviewCurve.Evaluate(t); + var slot = _slot.RectTransform; + RectTransform.anchoredPosition = Vector2.Lerp(pointerLocal, slot.anchoredPosition, t); + RectTransform.sizeDelta = Vector2.Lerp(_traySize, slot.sizeDelta, t); + RectTransform.localRotation = Quaternion.Slerp(Quaternion.identity, slot.localRotation, t); } ``` -Three things to note: +### `OnEndDrag` — snap or return -1. **Reparent** the piece from `TrayPanel` (HUD canvas) to `ColorBookSceneRefs.PiecesParent` (PaperCanvas) so it'll be included in capture. `worldPositionStays: false` because we want the new `anchoredPosition` to be relative to the new parent, not the world. -2. **Three simultaneous tweens** — position, size, rotation. Use `DOAnchorPos`, `DOSizeDelta`, `DOLocalRotateQuaternion`. They start together so the piece visually snaps as one motion. +```csharp +public void OnEndDrag(PointerEventData e) +{ + if (_locked) return; + float dist = Vector2.Distance( + RectTransform.anchoredPosition, + _slot.RectTransform.anchoredPosition); + if (dist <= _cfg.SnapRadius) Snap(); + else ReturnToTray(); +} + +private void Snap() +{ + Lock(); // reparent + raycast off + _locked = true + var slot = _slot.RectTransform; + Tween.UIAnchoredPosition(RectTransform, slot.anchoredPosition, _cfg.SnapDuration, Ease.OutBack); + Tween.UISizeDelta (RectTransform, slot.sizeDelta, _cfg.SnapDuration, Ease.OutBack); + Tween.LocalRotation (RectTransform, slot.localRotation, _cfg.SnapDuration, Ease.OutBack); + _sfx.Play(SfxId.ShapeSnap); + _bus.Publish(new PieceSnappedSignal(_shape.Id)); +} +``` + +### Four things worth noting + +1. **Reparent on lock** — `Lock()` calls `RectTransform.SetParent(_slot.RectTransform.parent, false)`. The piece moves from the HUD-side tray to the per-drawing slot parent so it travels with the paper and gets included in the captured PNG. +2. **Three parallel PrimeTween calls** — position, size, rotation. Tweens start together so the piece visually snaps as one motion. Zero allocations per tween. 3. **`SnapRadius` is in canvas units** (from `ShapeBuilderConfig`, e.g. 80–120), not world units. Same `CanvasScaler` reference resolution across devices = same hit feel. +4. **Preview hover sound fires once per drag**, on the boundary cross into the preview radius. `_inPreview` flag resets on `OnBeginDrag`. -Controller listens for `PieceSnappedSignal`, counts against expected piece count, fires `ShapeAssembledSignal` when complete. +### Pre-snapped resume + +If the user closes the app mid-assembly (or after completing the drawing), the saved `DrawingProgress.snappedPieces` lists which pieces were locked. On resume, the controller passes `preSnapped: true` to `Setup` for those, and `ShapePiece.SnapInstantly()` puts them straight into their slots — no tween, no input. The user can keep snapping the remaining pieces. + +```csharp +private void SnapInstantly() +{ + Lock(); + var slot = _slot.RectTransform; + RectTransform.anchoredPosition = slot.anchoredPosition; + RectTransform.sizeDelta = slot.sizeDelta; + RectTransform.localRotation = slot.localRotation; +} +``` + +### Spawn loop in `ShapeBuilderController.BuildAsync` + +```csharp +var preSnappedIds = progress?.snappedPieces; +foreach (var (shape, idx) in template.Pieces.Select((s, i) => (s, i))) +{ + var go = Instantiate(_piecePrefab, _refs.TrayPanel); + var piece = go.GetComponent(); + var slot = FindSlotForShape(slots, shape); + var trayPos = _trayLayout.GetSlotPosition(idx, template.Pieces.Count); + var preSnapped = preSnappedIds != null && preSnappedIds.Contains(shape.Id); + + piece.Setup(shape, slot, _cfg, _sfx, _bus, trayPos, preSnapped); + _alive.Add(piece); +} +``` + +Controller listens for `PieceSnappedSignal`, counts against expected piece count, fires `ShapeAssembledSignal` when complete → `GameplayFlowController` captures bare-assembled thumbnail, transitions to Coloring (see §13). --- @@ -1273,19 +1478,24 @@ Toddler-mode error UI: | Class | Layer | Asmdef | |---|---|---| -| `IDrawingTemplate`, `ColorRegionDTO` | Core | `Core` | -| `ShapeSO` (ScriptableObject) | Core | `Core` | -| `ICommand`, `IUndoStack` | Core | `Core` | -| `UndoStack` | Features | `Features.History` | +| `IDrawingTemplate`, `IDrawingTemplateCatalog`, `IDrawingCatalogController` | Core | `Core` | +| `ColorRegionDTO`, `PaintCommandDTO`, `ColorPaletteSO` | Core | `Core` | +| `ShapeSO`, `ShapeBuilderConfig` (ScriptableObjects) | Core | `Core` | +| `DrawingProgress`, `DrawingPhase`, `ProgressionRootDto`, `RegionColorEntry` | Core | `Core` | +| `ICommand`, `IUndoStack`, `IProgressionSystem` | Core | `Core` | +| `UndoStack`, `HistoryButtonsView`, `HistoryButtonsPresenter` | Features | `Features.History` | | `AddressableAssetProviderService` | Services | `Services.Assets` | | `NativeGallerySaveService` | Services | `Services.Gallery` | -| `RenderTextureCaptureService` | Services | `Services.Capture` | -| `ColoringController`, `PaintRegionCommand` | Features | `Features.Coloring` | -| `ShapeBuilderController`, `ShapePieceUI` | Features | `Features.ShapeBuilder` | -| `HistoryController` | Features | `Features.History` | -| `ColorBookFlowController` | Features | `Features.ColorBookFlow` | +| `CaptureService` | Services | `Services.Capture` | +| `ColoringController`, `ColoringStateRepository`, `ColorRegionView`, `PaintRegionCommand` | Features | `Features.Coloring` | +| `ShapePiece`, `SlotMarker`, `ShapeBuilderController`, `TrayLayout` | Features | `Features.ShapeBuilder` | +| `AddressableDrawingTemplateCatalog` | Features | `Features.DrawingTemplate` | +| `DrawingCatalogController`, `DrawingCatalogPresenter`, `DrawingCatalogView`, `CatalogItemVM` | Features | `Features.DrawingCatalog` | +| `ColorbookFlowController` | Features | `Features.Colorbook` | +| `GameplayFlowController` | Features | `Features.GameplayFlow` | +| `ProgressionSystem`, `ProgressionRepository` | Features | `Features.Progression` | | `MenuMascotView`, `MenuMascotPresenter` | Features | `Features.MainMenu` | -| `ColorBookSceneRefs`, `ColorBookLifetimeScope`, `AppBoot` | App | `Darkmatter.App` | +| `RootLifetimeScope`, `MainMenuLifetimeScope`, `ColorbookLifetimeScope`, `GameplayLifetimeScope`, `GameplaySceneRefs`, `AppBoot` | App | `Darkmatter.App` | If a class's natural home doesn't match its asmdef, the architecture is bent — fix the placement, don't add a reference. @@ -1305,18 +1515,23 @@ Comprehensive index — every script (existing or planned) grouped by its module | `Core/Contracts/Services/Scenes/` | `ISceneService` | ✅ | | `Core/Contracts/Services/Capture/` | `ICaptureService` | ⚠️ | | `Core/Contracts/Services/Gallery/` | `IGalleryService` | ⚠️ | -| `Core/Contracts/Features/Drawing/` | `IDrawingTemplate`, `IDrawingTemplateCatalog` | ⚠️ | -| `Core/Contracts/Features/Coloring/` | `IColorPalette` | ⚠️ | +| `Core/Contracts/Features/DrawingCatalog/` | `IDrawingCatalogController`, `IDrawingTemplate`, `IDrawingTemplateCatalog` | ✅ | +| `Core/Contracts/Features/Coloring/` | `IColorPalette` | ✅ | | `Core/Contracts/Features/History/` | `ICommand`, `IUndoStack` | ✅ | -| `Core/Contracts/Features/Progression/` | `IProgressionService` | ⚠️ | +| `Core/Contracts/Features/Progression/` | `IProgressionSystem` | ✅ | | `Core/Data/Dynamic/Services/Audio/` | `AudioHandle`, `AudioRequest` | ✅ | | `Core/Data/Static/Services/Audio/` | `SfxCatalogSO` | ✅ | -| `Core/Data/Static/Features/Drawing/` | `DrawingTemplateSO`, `ShapeSO` | ⚠️ | -| `Core/Data/Static/Features/Coloring/` | `ColorPaletteSO` | ⚠️ | -| `Core/Data/Dynamic/Features/Drawing/` | `ColorRegionDTO` | ⚠️ | -| `Core/Data/Dynamic/Features/Coloring/` | `PaintCommandDTO` | ⚠️ | -| `Core/Data/Dynamic/Features/Signals/` | `DrawingSelectedSignal`, `ShapeAssembledSignal`, `ColorAppliedSignal`, `PieceSnappedSignal`, `PaperCapturedSignal`, `PaperSavedSignal` | ⚠️ | -| `Core/Enums/Services/Audio/` | `AudioChannel`, `AudioPlayMode`, `SfxId` | ✅ | +| `Core/Data/Static/Features/DrawingTemplate/` | `DrawingTemplateSO` | ✅ | +| `Core/Data/Static/Features/ShapeBuilder/` | `ShapeSO`, `ShapeBuilderConfig` | ✅ | +| `Core/Data/Static/Features/Coloring/` | `ColorPaletteSO` | ✅ | +| `Core/Data/Dynamic/Features/Coloring/` | `ColorRegionDTO`, `PaintCommandDTO` | ✅ | +| `Core/Data/Dynamic/Features/Progression/` | `DrawingProgress`, `ProgressionRootDto`, `RegionColorEntry` | ✅ | +| `Core/Data/Signals/Features/DrawingCatalog/` | `DrawingSelectedSignal` | ✅ | +| `Core/Data/Signals/Features/ShapeBuilder/` | `ShapeAssembledSignal`, `PieceSnappedSignal` | ✅ | +| `Core/Data/Signals/Features/Coloring/` | `ColorAppliedSignal` | ⚠️ | +| `Core/Data/Signals/Features/Capture/` | `PaperCapturedSignal`, `PaperSavedSignal` | ⚠️ | +| `Core/Enums/Features/Progression/` | `DrawingPhase` (`ShapeBuilding`, `Coloring`) | ✅ | +| `Core/Enums/Services/Audio/` | `SfxId` (`None`, `ShapeHover`, `ShapeSnap`, `ShapeNiceTry`, `ShapeReturn`) | ✅ | | `Core/Enums/Services/Camera/` | `CameraType` (add `CaptureCamera` value) | ✅ | | `Core/Enums/Services/Scenes/` | `GameScene` | ✅ | @@ -1324,8 +1539,8 @@ Comprehensive index — every script (existing or planned) grouped by its module | Module (path) | Scripts | Status | |---|---|---| -| `Libs/FSM/` | `IState`, `State`, `StateMachine` | ✅ | -| `Libs/Installers/` | `IServiceModule` | ✅ | +| `Libs/FSM/` | `IState`, `State`, `StateMachine` (abstract) | ✅ | +| `Libs/Installers/` | `IModule` | ✅ | | `Libs/Observer/` | `IEventBus`, `EventBus` | ✅ | | `Libs/PlayerPrefs/Runtime/` | `ProtectedPlayerPrefs`, `ProtectedPlayerPrefsSettings`, `PlayerPrefsKeys`, `PlayerPrefsKeyRegistry`, `LocalWriteTracker`, `PendingWriteResync` | ✅ | | `Libs/PlayerPrefs/Editor/` | `PlayerPrefsEditorWindow`, `ProtectedPlayerPrefsGettingStartedWindow`, `ProtectedPlayerPrefsSettingsUtility`, `ProtectedPlayerPrefsSetupBootstrap` | ✅ | @@ -1335,55 +1550,61 @@ Comprehensive index — every script (existing or planned) grouped by its module | Module (path) | Scripts | Status | |---|---|---| -| `Services/Analytics/Installers/` | `AnalyticsServiceModule` | ✅ | +| `Services/Analytics/Installers/` | `AnalyticsModule` | ✅ | | `Services/Analytics/Systems/` | `FirebaseAnalyticsSystem` | ✅ | | `Services/Assets/` | `AddressableAssetProviderService`, `AddressableLoadHandleTracker` | ✅ | | `Services/Audio/` | `AudioService`, `SfxPlayer` | ✅ | | `Services/Camera/Service/` | `CameraService` | ✅ | -| `Services/Camera/Installers/` | `CameraServiceModule` | ✅ | +| `Services/Camera/Installers/` | `CameraModule` | ✅ | | `Services/Inputs/Generated/` | `GameInputs` (Input System codegen) | ✅ | -| `Services/Inputs/Readers/` | `InputReaderSO` | ✅ | -| `Services/Inputs/Installers/` | `InputServiceModule` | ✅ | +| `Services/Inputs/` | (Inputs feature partial — Reader + Installer location TBD) | ⚠️ | | `Services/Scenes/` | `SceneService` | ✅ | -| `Services/Capture/` | `RenderTextureCaptureService`, `CaptureServiceModule` | ⚠️ | -| `Services/Gallery/` | `NativeGallerySaveService`, `GalleryServiceModule` | ⚠️ | +| `Services/Capture/Systems/` | `CaptureService` | ✅ (stub) | +| `Services/Capture/Installers/` | `CaptureModule` | ✅ | +| `Services/Gallery/Core/` | `GalleryService` | ✅ (stub — needs native plugin wiring) | +| `Services/Gallery/Installers/` | `GalleryModule` | ✅ | #### Features | Module (path) | Scripts | Status | |---|---|---| | `Features/History/Stack/` | `UndoStack` | ✅ | -| `Features/History/Installers/` | `HistoryServiceModule` | ✅ | -| `Features/History/UI/` | `HistoryButtonsView`, `HistoryPresenter`, `HistoryController` | ⚠️ | -| `Features/MainMenu/Installers/` | `MainMenuModule` | ⚠️ | +| `Features/History/Installers/` | `HistoryFeatureModule` | ✅ | +| `Features/History/UI/` | `HistoryButtonsView`, `HistoryButtonsPresenter` | ✅ | +| `Features/MainMenu/Installers/` | `MainMenuFeatureModule` | ⚠️ | | `Features/MainMenu/Systems/` | `MainMenuModel`, `MenuMascotPresenter` | ⚠️ | | `Features/MainMenu/UI/` | `MenuMascotView`, `IMenuMascotView` | ⚠️ | -| `Features/DrawingCatalog/Systems/` | `DrawingCatalogController` | ⚠️ | -| `Features/DrawingCatalog/UI/` | `DrawingCatalogPresenter`, `DrawingCatalogView`, `IDrawingCatalogView`, `CatalogItemVM` | ⚠️ | -| `Features/DrawingCatalog/Installers/` | `DrawingCatalogModule` | ⚠️ | -| `Features/ShapeBuilder/Systems/` | `ShapeBuilderController`, `ShapePieceFsm`, `ShapePieceFactory`, `TrayLayout` | ⚠️ | -| `Features/ShapeBuilder/UI/` | `ShapePieceUI`, `SlotMarker`, `TrayPanel` | ⚠️ | -| `Features/ShapeBuilder/Installers/` | `ShapeBuilderModule` | ⚠️ | +| `Features/DrawingCatalog/Systems/` | `DrawingCatalogController` | ✅ | +| `Features/DrawingCatalog/UI/` | `DrawingCatalogPresenter`, `DrawingCatalogView`, `DrawingCatalogButton`, `CatalogItemVM` | ✅ | +| `Features/DrawingCatalog/Installers/` | `DrawingCatalogFeatureModule` | ✅ | +| `Features/DrawingTemplate/Systems/` | `AddressableDrawingTemplateCatalog` | ✅ | +| `Features/DrawingTemplate/Installers/` | `DrawingTemplateFeatureModule` | ✅ | +| `Features/ShapeBuilder/UI/` | `ShapePiece`, `SlotMarker` | ✅ | +| `Features/ShapeBuilder/Systems/` | `ShapeBuilderController`, `TrayLayout` | ⚠️ | +| `Features/ShapeBuilder/Installers/` | `ShapeBuilderFeatureModule` | ✅ | | `Features/Coloring/Systems/` | `ColoringController`, `ColoringStateRepository`, `ColorRegionFactory` | ⚠️ | | `Features/Coloring/UI/` | `ColorRegionView`, `ColorPaletteView`, `ColorPalettePresenter` | ⚠️ | | `Features/Coloring/Commands/` | `PaintRegionCommand` | ⚠️ | -| `Features/Coloring/Installers/` | `ColoringModule` | ⚠️ | -| `Features/Capture/Systems/` | `CaptureController` | ⚠️ | +| `Features/Coloring/Installers/` | `ColoringFeatureModule` | ⚠️ | +| `Features/Capture/Systems/` | `CaptureController` (light wrapper around `ICaptureService`) | ⚠️ | | `Features/Capture/UI/` | `CaptureButtonPresenter`, `SaveToastView` | ⚠️ | | `Features/Capture/Installers/` | `CaptureFeatureModule` | ⚠️ | -| `Features/Progression/Systems/` | `ProgressionService`, `ProgressionRepository` | ⚠️ | -| `Features/Progression/Installers/` | `ProgressionModule` | ⚠️ | -| `Features/ColorBookFlow/Systems/` | `ColorBookFlowController` | ⚠️ | -| `Features/ColorBookFlow/Installers/` | `ColorBookFlowModule` | ⚠️ | +| `Features/Progression/Systems/` | `ProgressionSystem`, `ProgressionRepository` | ✅ (stubs) | +| `Features/Progression/Installers/` | `ProgressionFeatureModule` | ✅ | +| `Features/ColorbookFlow/System/` | `ColorbookFlowController` | ✅ (needs constructor injection) | +| `Features/ColorbookFlow/Installers/` | `ColorbookFlowFeatureModule` | ✅ | +| `Features/GameplayFlow/Systems/` | `GameplayFlowController` (single owner of all saves — §13) | ⚠️ | +| `Features/GameplayFlow/Installers/` | `GameplayFlowFeatureModule` | ⚠️ | #### App | Module (path) | Scripts | Status | |---|---|---| -| `App/LifetimeScopes/` | `RootLifetimeScope` | ✅ | -| `App/LifetimeScopes/` | `MainMenuLifetimeScope`, `ColorBookLifetimeScope` | ⚠️ | -| `App/Boot/` | `AppBoot` | ⚠️ | -| `App/SceneRefs/` | `ColorBookSceneRefs` | ⚠️ | +| `App/LifetimeScopes/` | `BaseLifetimeScope` (abstract), `RootLifetimeScope` | ✅ | +| `App/LifetimeScopes/` | `GameLifetimeScope` (placeholder, empty), `GameplayLifetimescope` (typo — needs rename to `GameplayLifetimeScope`) | ⚠️ | +| `App/LifetimeScopes/` | `MainMenuLifetimeScope`, `ColorbookLifetimeScope`, `GameplayLifetimeScope` (final) | ⚠️ planned | +| `App/Boot/` | `AppBoot` | ⚠️ planned | +| `App/SceneRefs/` | `GameplaySceneRefs` (PaperRoot, SlotsParent, PiecesParent, RegionsParent, TrayPanel, CaptureCamera) | ⚠️ planned | --- @@ -1728,109 +1949,124 @@ public interface IDrawingCatalogView { --- -### 32.5 Feature — `ShapeBuilder` *(planned)* +### 32.5 Feature — `ShapeBuilder` *(planned controller, MBs exist)* -#### `ShapeBuilderController` *(Systems)* -Spawns shape pieces for the selected template, tracks snap progress, fires `ShapeAssembledSignal` when complete. +The simplified post-FSM design. **No state machine per piece, no factory class.** Three roles: piece MB, slot MB, controller. Plus a tunables SO. + +#### `ShapePiece : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler` *(UI — ✅ exists)* +The single MonoBehaviour that handles drag, reactive preview lerp, snap (PrimeTween), and return-to-tray. Spawned by the controller; `Setup` binds dependencies and starting pose. ```csharp -// fields: IDrawingTemplateCatalog _catalog, ShapePieceFactory _factory, -// ColorBookSceneRefs _refs, TrayPanel _tray, IEventBus _bus, ShapeBuilderConfig _cfg -public sealed class ShapeBuilderController : IDisposable { - public IReadOnlyList Active { get; } - public UniTask BuildAsync(string templateId); // load template, spawn pieces in tray - public void Reset(); // clear, unsubscribe -} -// sub: DrawingSelectedSignal -// pub: ShapeAssembledSignal -``` -- **Internal:** counts `PieceSnappedSignal` against expected piece count. -- **Slot discovery:** after a drawing's per-drawing prefab is instantiated under `ColorBookSceneRefs.PaperRoot`, the controller queries `GetComponentsInChildren()` to discover all slots in the loaded drawing. Each slot's `_shape` field tells which `ShapeSO` it expects; matching pieces are spawned in the tray. - -#### `ShapePieceUI : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler` *(UI)* -The UI Image that the toddler drags. One prefab; the assigned `ShapeSO` determines visual identity and snap params. - -```csharp -public sealed class ShapePieceUI : MonoBehaviour, +public sealed class ShapePiece : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler { - [SerializeField] private ShapeSO _shape; // set by controller at spawn (or in inspector for testing) - [SerializeField] private Image _image; + [SerializeField] private Image image; + private ShapeSO _shape; // bound by Setup + private SlotMarker _slot; + private ShapeBuilderConfig _cfg; + private ISfxPlayer _sfx; + private IEventBus _bus; + private Vector2 _trayPos; + private Vector2 _traySize; + private bool _locked; + public ShapeSO Shape => _shape; public string PieceId => _shape != null ? _shape.Id : null; - public ShapeSO Shape => _shape; - public RectTransform RectTransform => (RectTransform)transform; - public bool IsLocked { get; private set; } - public event Action Snapped; + public bool IsLocked => _locked; + public RectTransform RectTransform { get; } - // Controller calls this at spawn time - public void Assign(ShapeSO shape) { - _shape = shape; - ApplyShape(); + public void Setup( + ShapeSO shape, SlotMarker slot, ShapeBuilderConfig cfg, + ISfxPlayer sfx, IEventBus bus, + Vector2 trayPos, bool preSnapped); +} +``` +- Drag handlers run inline in this MB — no separate FSM class. +- `Snap()` is a PrimeTween triple (`Tween.UIAnchoredPosition` / `UISizeDelta` / `LocalRotation`); `SnapInstantly()` is the resume path that puts a pre-snapped piece directly into its slot pose without animation. +- `ReturnToTray()` builds a PrimeTween `Sequence` of three parallel tweens. +- See §26 for the snap algorithm walkthrough. + +#### `SlotMarker : MonoBehaviour` *(UI — ✅ exists)* +Authored per drawing — designer places one in the per-drawing prefab at each slot location with the `RectTransform` set to the target pose and `_shape` field assigned to the matching `ShapeSO`. The `RectTransform` itself **is** the target pose. +```csharp +public sealed class SlotMarker : MonoBehaviour +{ + [SerializeField] private ShapeSO shape; + [SerializeField] private Image outline; // optional faint outline UI + + public ShapeSO Shape => shape; + public string SlotId => shape != null ? shape.Id : null; + public RectTransform RectTransform => (RectTransform)transform; + + public void SetOutlineVisible(bool visible); +} +``` +**Matching is by `ShapeSO` reference equality** — the controller pairs each `ShapePiece.Shape` with the `SlotMarker.Shape` of the same SO asset. + +#### `ShapeBuilderConfig : ScriptableObject` *(Static data — ✅ exists)* +```csharp +[CreateAssetMenu(menuName = "Darkmatter/ShapeBuilder/Config")] +public sealed class ShapeBuilderConfig : ScriptableObject +{ + public float SnapRadius; // 80–120 canvas units + public float SnapGraceMultiplier; // (currently unused — grace zone removed) + public float PreviewRadius; // ~2× SnapRadius + public float SnapDuration; // 0.25s + public float ReturnDuration; // 0.25s + public AnimationCurve PreviewCurve; // easing for the reactive lerp + + public Vector2 DragSizeDelta(ShapeSO shape); +} +``` + +#### `ShapeBuilderController` *(Systems — planned)* +Spawns pieces for the selected template, tracks snap progress, fires `ShapeAssembledSignal` when complete. **Replaces the old `ShapePieceFactory` — spawning is now a 5-line inline loop, not a separate class.** +```csharp +// fields: IDrawingTemplateCatalog _catalog, IAssetProviderService _assets, +// GameplaySceneRefs _refs, TrayLayout _trayLayout, +// ShapeBuilderConfig _cfg, ISfxPlayer _sfx, IEventBus _bus +public sealed class ShapeBuilderController : IAsyncStartable, IDisposable +{ + private readonly List _alive = new(); + private GameObject _piecePrefab; + + public async UniTask StartAsync(CancellationToken ct) { + _piecePrefab = await _assets.LoadAssetAsync( + "shapebuilder/piece", null, ct); + _pieceSnappedSub = _bus.Subscribe(OnPieceSnapped); } - private void OnValidate() => ApplyShape(); // editor inspector edits - private void Awake() => ApplyShape(); // runtime safety + public IReadOnlyList Alive => _alive; + public IReadOnlyCollection GetSnappedPieceIds(); // for save records - private void ApplyShape() { - if (_shape == null || _image == null) return; - _image.sprite = _shape.Sprite; - RectTransform.sizeDelta = _shape.DefaultSizeDelta; - } + public async UniTask BuildAsync( + IDrawingTemplate template, + IReadOnlyCollection preSnappedIds = null); + + public void Reset(); // despawns all pieces; called by GameplayFlowController on Teardown } +// sub: PieceSnappedSignal +// pub: ShapeAssembledSignal ``` -- Handlers forward to `ShapePieceFsm` (`OnDragBegin / OnDrag(localPos) / OnDragEnd`). -- `OnDrag` converts `PointerEventData.position` to canvas-local via `RectTransformUtility.ScreenPointToLocalPointInRectangle` against the piece's parent rect. -- No collider, no Physics2D anywhere. -- **Identity follows the SO** — change `_shape` in inspector and the visual + ID update on the next `OnValidate`. At runtime, `Assign(...)` is the only mutation path. +- **Slot discovery:** after the per-drawing prefab is instantiated, `GetComponentsInChildren(includeInactive: true)` finds all slots. Each slot's `_shape` tells which `ShapeSO` it expects. +- **Pre-snap on resume:** if `preSnappedIds.Contains(shape.Id)`, the spawned `ShapePiece` is initialized with `preSnapped: true` → `SnapInstantly()` lands it in the slot at scope start. +- **Snapped count:** subscribes to `PieceSnappedSignal`, counts against expected, fires `ShapeAssembledSignal` when count == `template.Pieces.Count`. -#### `ShapePieceFsm` *(Systems)* -Per-piece state machine using `Libs.FSM`. States: `InTray → Dragging → Preview → (Snapped | Returning)`. +#### `TrayLayout` *(Systems — planned)* +Tiny stateless helper. Given (`index`, `total`), returns the tray slot's `anchoredPosition`. Either uses a `HorizontalLayoutGroup`'s computed positions or a hand-rolled even spacing across the tray's width. ```csharp -// fields: ShapePieceUI _ui, SlotMarker _targetSlot, ShapeBuilderConfig _cfg, -// IAudioService _audio, IEventBus _bus -public sealed class ShapePieceFsm { - public void OnDragBegin(); - public void OnDrag(Vector2 canvasLocalPos); - public void OnDragEnd(); - public bool IsLocked { get; } +public sealed class TrayLayout +{ + [SerializeField] private RectTransform trayRect; + public Vector2 GetSlotPosition(int index, int total); } ``` -- **Preview-state update**: reactive lerp of `anchoredPosition / sizeDelta / localRotation` toward `_targetSlot`'s pose, driven by `1 - dist/PreviewRadius`. No DOTween while previewing — it's per-frame. -- **Snapped enter**: DOTween ease-out to exact slot pose (~0.2s), disable drag, fire `PieceSnappedSignal`. -- **Returning enter**: DOTween back to tray slot (`anchoredPosition` from `TrayLayout`). -#### `SlotMarker : MonoBehaviour` *(UI)* -The outline `Image` under `ColorBookSceneRefs.SlotsParent` showing where a piece should snap. Authored per drawing — designer places one in the per-drawing prefab at each slot location, with its `RectTransform` set to the target pose and `_shape` field assigned to the matching `ShapeSO`. -```csharp -public sealed class SlotMarker : MonoBehaviour { - [SerializeField] private ShapeSO _shape; // which shape fits here - [SerializeField] private Image _outline; // optional faint outline UI +#### Removed / not needed - public ShapeSO Shape => _shape; - public string SlotId => _shape != null ? _shape.Id : null; - public RectTransform RectTransform => (RectTransform)transform; -} -``` -- **Pose lives on this MB's `RectTransform`** — `anchoredPosition`, `sizeDelta`, `localRotation` directly. No pose data on the SO. -- **Matching:** `ShapePieceFsm` compares `_piece.Shape == _slot.Shape` (Unity Object reference equality). No string lookups. - -#### `TrayPanel : MonoBehaviour` *(UI)* -HUD-side panel (on `HUDCanvas`) where pieces start out. Has a `HorizontalLayoutGroup` + `ContentSizeFitter`. Provides spawn anchors via `RectTransform Slot(int index)` for the controller. - -#### `ShapePieceFactory` *(Systems)* -Pool of `ShapePieceUI` GameObjects (one prefab) + their associated FSMs. Reused across template loads. -```csharp -public sealed class ShapePieceFactory { - // Instantiates the single piece prefab under `parent`, calls Assign(shape) on it, - // and wires up its FSM with the matching SlotMarker. - public ShapePieceUI Spawn(ShapeSO shape, SlotMarker targetSlot, RectTransform parent); - public void Despawn(ShapePieceUI piece); -} -``` -- One prefab in `Content/Gameplay/Prefabs/ShapePiece.prefab` is instantiated repeatedly. Visual identity comes from the `ShapeSO` passed to `Assign`. - -#### `ShapeBuilderInputBinder` *(Systems)* -With UI handlers on the piece itself, an explicit input binder isn't strictly needed — drag events route via the EventSystem. Keep this class only if you need to listen for "any tap outside any piece" (e.g. to dismiss a preview). Otherwise skip. +- **`ShapePieceFsm`** — was a per-piece state machine. Replaced by inline drag handlers + a single `_locked` bool on `ShapePiece`. +- **`ShapePieceFactory`** — was a wrapper around `Instantiate` + FSM wiring. Replaced by a 5-line inline loop in `ShapeBuilderController.BuildAsync`. +- **Five state classes** (`InTray`, `Dragging`, `Preview`, `Snapped`, `Returning`) — gone. Their behavior maps to: `_locked = false` (idle/dragging/preview all share the same handlers), `_inPreview` flag (preview boundary detection), `Snap()` method, `ReturnToTray()` method. +- **`ShapeBuilderInputBinder`** — never needed; UI handlers on the piece are sufficient. --- @@ -1855,16 +2091,27 @@ public sealed class ColoringStateRepository { Builds and pushes `PaintRegionCommand` instances; spawns `ColorRegionView` per region. ```csharp // fields: IUndoStack _undo, ColoringStateRepository _state, ColorRegionFactory _factory, -// ColorBookSceneRefs _refs, IEventBus _bus +// GameplaySceneRefs _refs, IEventBus _bus public interface IColoringController { - UniTask SpawnRegionsAsync(IDrawingTemplate template); - void PaintRegion(ColorRegionView view); // builds command, pushes to undo stack - void Clear(); + // Spawn regions on the paper. Pass non-null savedColors to restore colors + // from a DrawingProgress record; null = use ColorRegionDTO.InitialColor. + UniTask SpawnRegionsAsync( + IDrawingTemplate template, + IReadOnlyDictionary savedColors = null); + + void PaintRegion(ColorRegionView view); // builds command, pushes to undo stack + + // Snapshot current paint state for save records (see §13). + IReadOnlyDictionary GetCurrentColors(); + + void Clear(); // despawn all regions } // sub: ShapeAssembledSignal (via flow controller, not direct) // pub: ColorAppliedSignal (via PaintRegionCommand) ``` -Spawns each region as a UI `Image` under `_paper.RegionsParent`. No `Physics2D`. +Spawns each region as a UI `Image` under `_refs.RegionsParent`. No `Physics2D`. + +**Autosave integration:** after each successful `PaintRegion`, the controller calls a debounced `GameplayFlowController.ScheduleAutosave()` so the flow can write the new color state to `IProgressionSystem` 500 ms later (no thumbnail, cheap). The flow controller cancels and resets the timer on each paint — only the last paint in a burst triggers the write. #### `ColorRegionView : MonoBehaviour, IPointerClickHandler` *(UI)* UI Image with alpha-based hit detection. Tap routes through Unity's EventSystem directly to `OnPointerClick`. @@ -2045,41 +2292,47 @@ Implemented as `MonoBehaviour` per feature/service so scopes can drag them in th |---|---|---|---| | `AppBoot` | App | Startup sequencer | assets, progression, audio, scenes | | `RootLifetimeScope` | App | Root DI | service modules | -| `ColorBookLifetimeScope` | App | Scene DI | scene refs, feature modules | | `MainMenuLifetimeScope` | App | Menu scene DI | feature modules | -| `ColorBookSceneRefs` | App | Scene-bound RectTransform / Camera holder | — | -| `MenuMascotView` | Feature | Spine mascot UI (SkeletonGraphic wrapper) | — | -| `MenuMascotPresenter` | Feature | Drives mascot animations from model events | view, model | -| `DrawingCatalogController` | Feature | Grid logic | catalog, bus | -| `DrawingCatalogPresenter` | Feature | UI bridge | view, controller, catalog | -| `ShapeSO` | Core asset | Authored shape (sprite + snap params, reusable) | — | -| `ShapeBuilderController` | Feature | Piece spawn + snap tracking | catalog, factory, refs, tray, bus, cfg | -| `ShapePieceUI` | Feature | Draggable UI piece prefab; holds `[SerializeField] ShapeSO _shape` | fsm | -| `ShapePieceFsm` | Feature | Per-piece state machine (Tray/Drag/Preview/Snapped/Returning) | ui, slot, cfg, audio, bus | -| `SlotMarker` | Feature | Slot outline UI Image at target pose; holds `_shape` | — | -| `TrayPanel` | Feature | HUD-side tray with LayoutGroup | — | -| `ColoringStateRepository` | Feature | Current color model | — | -| `ColoringController` | Feature | Region spawn + paint cmd | undo, state, factory, refs, bus | -| `ColorRegionView` | Feature | Region UI Image + IPointerClickHandler | controller | -| `PaintRegionCommand` | Feature | Undoable paint (sets Image.color) | view, bus | -| `HistoryController` | Feature | Undo/redo facade | undo stack, bus | -| `UndoStack` | Feature | Bounded undo store | — | -| `CaptureController` | Feature | Capture-then-save orchestration | capture svc, gallery svc, bus | -| `ColorBookFlowController` | Feature | Scene FSM (Catalog → Building → Coloring → Done) | bus, catalog, builder, coloring, capture, progression | -| `ProgressionService` | Feature | Completion tracking | PlayerPrefs lib | -| `EventBus` | Lib | Pub/sub | — | -| `StateMachine` | Lib | Generic FSM | — | -| `IServiceModule` | Lib | DI installer interface | — | -| `ProtectedPlayerPrefs` | Lib | Encrypted PlayerPrefs wrapper | — | -| `AddressableAssetProviderService` | Service | Addressables wrapper | — | -| `RenderTextureCaptureService` | Service | One-shot PNG render via CaptureCamera | scene refs | -| `NativeGallerySaveService` | Service | Native gallery save (thin plugin shim) | — | -| `SceneService` | Service | Async scene loads | — | -| `AudioService`, `SfxPlayer` | Service | SFX playback | assets | -| `CameraService` | Service | Camera registry (MainCamera, UICamera, CaptureCamera) | — | -| `InputReaderSO` | Service | New Input System reader | — | -| `FirebaseAnalyticsSystem` | Service | Analytics events | — | +| `ColorbookLifetimeScope` | App | Catalog scene DI | feature modules | +| `GameplayLifetimeScope` | App | Active drawing scene DI | scene refs, feature modules | +| `GameplaySceneRefs` | App | Scene-bound RectTransform + CaptureCamera holder | — | +| `MenuMascotView` | Feature.MainMenu | Spine mascot UI (`SkeletonGraphic` wrapper) | — | +| `MenuMascotPresenter` | Feature.MainMenu | Drives mascot animations from model events | view, model | +| `DrawingCatalogController` | Feature.DrawingCatalog | Visible-ID list + selection signal | catalog, progression, bus | +| `DrawingCatalogPresenter` | Feature.DrawingCatalog | UI bridge | view, controller, catalog, progression | +| `DrawingCatalogView` | Feature.DrawingCatalog | UI; renders cells | — | +| `CatalogItemVM` | Feature.DrawingCatalog | View-model per cell | — | +| `AddressableDrawingTemplateCatalog` | Feature.DrawingTemplate | Loads `DrawingTemplateSO`s, exposes `NextUnseen` | assets, progression | +| `ShapeSO` | Core asset | Authored shape (id + sprite + DefaultSizeDelta) | — | +| `ShapeBuilderConfig` | Core asset | Tunables (radii, durations, curve) | — | +| `ShapePiece` | Feature.ShapeBuilder | Draggable piece MB (drag + preview lerp + snap + return) | shape, slot, cfg, sfx, bus | +| `SlotMarker` | Feature.ShapeBuilder | Slot anchor MB; `RectTransform` == target pose | — | +| `ShapeBuilderController` | Feature.ShapeBuilder | Spawns pieces, tracks snap count | catalog, assets, refs, tray, cfg, sfx, bus | +| `TrayLayout` | Feature.ShapeBuilder | Computes piece tray positions | — | +| `ColoringStateRepository` | Feature.Coloring | Current color model | — | +| `ColoringController` | Feature.Coloring | Region spawn + paint cmd + autosave hook | undo, state, factory, refs, flow, bus | +| `ColorRegionView` | Feature.Coloring | Region UI Image + `IPointerClickHandler` | controller | +| `PaintRegionCommand` | Feature.Coloring | Undoable paint (sets `Image.color`) | view, bus | +| `HistoryController` | Feature.History | Undo/redo facade | undo stack, bus | +| `UndoStack` | Feature.History | Bounded undo store | — | +| `CaptureController` | Feature.Capture | (light wrapper) calls `ICaptureService.CaptureAsync` | capture svc | +| `ColorbookFlowController` | Feature.ColorbookFlow | Catalog scene orchestrator (init + selection→scene-load) | catalog, progression, scenes, bus | +| `GameplayFlowController` | Feature.GameplayFlow | Active drawing FSM + **single owner of all saves** (see §13) | catalog, builder, coloring, capture, gallery, progression, scenes, bus | +| `ProgressionSystem` | Feature.Progression | Per-template state + completed view | repository | +| `ProgressionRepository` | Feature.Progression | PlayerPrefs JSON + thumbnail file IO | — | +| `EventBus` | Lib.Observer | Pub/sub | — | +| `StateMachine` (abstract) + `State` | Lib.FSM | Generic FSM base (Enter/Tick/Exit, ChangeState) | — | +| `IModule` | Lib.Installers | DI installer interface | — | +| `ProtectedPlayerPrefs` | Lib.PlayerPrefs | Encrypted PlayerPrefs wrapper | — | +| `AddressableAssetProviderService` | Service.Assets | Addressables wrapper | — | +| `CaptureService` | Service.Capture | One-shot PNG render via `CaptureCamera` | refs | +| `NativeGallerySaveService` | Service.Gallery | Native gallery save (thin plugin shim) | — | +| `SceneService` | Service.Scenes | Async scene loads | — | +| `AudioService`, `SfxPlayer` | Service.Audio | SFX playback | assets | +| `CameraService` | Service.Camera | Camera registry | — | +| `InputReaderSO` | Service.Inputs | New Input System reader | — | +| `FirebaseAnalyticsSystem` | Service.Analytics | Analytics events | — | If you add a class not in this table, add it here in the same PR. This table is the cheap mental-model index — keep it honest. See §31b for the full path-by-path inventory. -> Today only these rows are real on disk: `RootLifetimeScope` (App), `AddressableAssetProviderService`, `AudioService`/`SfxPlayer`, `CameraService`, `SceneService`, `InputReaderSO`, `FirebaseAnalyticsSystem` (Services), `UndoStack` + `HistoryServiceModule` (Features.History), plus `Libs.*` entries (`EventBus`, `StateMachine`, `IServiceModule`, PlayerPrefs lib, UI toggles). Everything else is the target. +> **What's real on disk today (2026-05):** All Service classes (`AddressableAssetProviderService`, `AudioService`/`SfxPlayer`, `CameraService`, `SceneService`, `InputReaderSO`, `FirebaseAnalyticsSystem`, stub `CaptureService`, stub `GalleryService`), all Lib classes, `ShapePiece` + `SlotMarker` + `ShapeBuilderConfig`, `UndoStack` + `HistoryServiceModule`, `ProgressionSystem` + `ProgressionRepository` (stubs), `AddressableDrawingTemplateCatalog` + module, `DrawingCatalogController` + presenter + view, `ColorbookFlowController` (partial — needs constructor injection wired). Empty / planned: `MainMenu` feature, `GameplayFlow` feature, `Coloring` feature, `MainMenu`/`Colorbook`/`Gameplay` scene scopes, all scenes except `Boot.unity`.