This commit is contained in:
Savya Bikram Shah
2026-05-29 16:17:55 +05:45
parent 6c14eaaacf
commit 44bdb3286c
12 changed files with 401 additions and 60 deletions

View File

@@ -14,5 +14,7 @@ public interface IColoringController
void PaintRegion(string regionId, Color color); void PaintRegion(string regionId, Color color);
IReadOnlyDictionary<string, Color> GetCurrentColors(); IReadOnlyDictionary<string, Color> GetCurrentColors();
UniTask PlayCompletionAnimationAsync(CancellationToken ct); UniTask PlayCompletionAnimationAsync(CancellationToken ct);
bool HasNonAuthoredColors { get; }
void ResetAll();
void Clear(); void Clear();
} }

View File

@@ -12,6 +12,7 @@ namespace Darkmatter.Core.Contracts.Features.DrawingCatalog
Sprite DefaultThumbnail { get; } Sprite DefaultThumbnail { get; }
GameObject DrawingPrefab { get; } GameObject DrawingPrefab { get; }
GameObject ColoringPrefab { get; } GameObject ColoringPrefab { get; }
GameObject CompletionAnimationPrefab { get; }
IReadOnlyList<ShapeSO> Pieces { get; } IReadOnlyList<ShapeSO> Pieces { get; }
IReadOnlyList<ColorRegionDTO> Regions { get; } IReadOnlyList<ColorRegionDTO> Regions { get; }
string ColorPaletteId { get; } string ColorPaletteId { get; }

View File

@@ -0,0 +1,4 @@
namespace Darkmatter.Core.Data.Signals.Features.Coloring
{
public record struct RegionsInitializedSignal;
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 2fa8b37ac847d4387b9289a4da8a07f4

View File

@@ -15,6 +15,7 @@ namespace Darkmatter.Core.Data.Static.Features.DrawingTemplate
[SerializeField] private Sprite defaultThumbnail; [SerializeField] private Sprite defaultThumbnail;
[SerializeField] private GameObject drawingPrefab; [SerializeField] private GameObject drawingPrefab;
[SerializeField] private GameObject coloringPrefab; [SerializeField] private GameObject coloringPrefab;
[SerializeField] private GameObject completionAnimationPrefab;
[SerializeField] private List<ShapeSO> pieces = new(); [SerializeField] private List<ShapeSO> pieces = new();
[SerializeField] private List<RegionAuthoring> regions = new(); [SerializeField] private List<RegionAuthoring> regions = new();
[SerializeField] private string colorPaletteId = "defaultPalette"; [SerializeField] private string colorPaletteId = "defaultPalette";
@@ -24,6 +25,7 @@ namespace Darkmatter.Core.Data.Static.Features.DrawingTemplate
public Sprite DefaultThumbnail => defaultThumbnail; public Sprite DefaultThumbnail => defaultThumbnail;
public GameObject DrawingPrefab => drawingPrefab; public GameObject DrawingPrefab => drawingPrefab;
public GameObject ColoringPrefab => coloringPrefab; public GameObject ColoringPrefab => coloringPrefab;
public GameObject CompletionAnimationPrefab => completionAnimationPrefab;
public IReadOnlyList<ShapeSO> Pieces => pieces; public IReadOnlyList<ShapeSO> Pieces => pieces;
public IReadOnlyList<ColorRegionDTO> Regions => Array.Empty<ColorRegionDTO>(); public IReadOnlyList<ColorRegionDTO> Regions => Array.Empty<ColorRegionDTO>();
public string ColorPaletteId => colorPaletteId; public string ColorPaletteId => colorPaletteId;
@@ -32,7 +34,8 @@ namespace Darkmatter.Core.Data.Static.Features.DrawingTemplate
#if UNITY_EDITOR #if UNITY_EDITOR
public void EditorSet(string newId, string newDisplayName, Sprite thumbnail, public void EditorSet(string newId, string newDisplayName, Sprite thumbnail,
GameObject drawing, GameObject coloring, List<ShapeSO> newPieces, GameObject drawing, GameObject coloring, GameObject completionAnimation,
List<ShapeSO> newPieces,
List<RegionAuthoring> newRegions, string paletteId) List<RegionAuthoring> newRegions, string paletteId)
{ {
id = newId; id = newId;
@@ -40,6 +43,7 @@ namespace Darkmatter.Core.Data.Static.Features.DrawingTemplate
defaultThumbnail = thumbnail; defaultThumbnail = thumbnail;
drawingPrefab = drawing; drawingPrefab = drawing;
coloringPrefab = coloring; coloringPrefab = coloring;
completionAnimationPrefab = completionAnimation;
pieces = newPieces ?? new List<ShapeSO>(); pieces = newPieces ?? new List<ShapeSO>();
regions = newRegions ?? new List<RegionAuthoring>(); regions = newRegions ?? new List<RegionAuthoring>();
colorPaletteId = paletteId; colorPaletteId = paletteId;

View File

@@ -31,8 +31,10 @@ public class ColoringController : IColoringController, IDisposable
private GameObject _colorInstance; private GameObject _colorInstance;
private GameObject _colorButtonPrefab; private GameObject _colorButtonPrefab;
private GameObject _completionAnimationPrefab;
private readonly List<ColorRegionView> _regions = new(); private readonly List<ColorRegionView> _regions = new();
private readonly List<ColorButton> _buttons = new(); private readonly List<ColorButton> _buttons = new();
private readonly Dictionary<string, Color> _authoredColors = new();
public ColoringController( public ColoringController(
ColoringStateRepository repository, ColoringStateRepository repository,
@@ -63,6 +65,7 @@ public class ColoringController : IColoringController, IDisposable
ct.ThrowIfCancellationRequested(); ct.ThrowIfCancellationRequested();
CreateColorButtonInstances(); CreateColorButtonInstances();
InitializeColorRegions(template, savedColors); InitializeColorRegions(template, savedColors);
_bus.Publish(new RegionsInitializedSignal());
} }
public void PaintRegion(string regionId, Color color) public void PaintRegion(string regionId, Color color)
@@ -86,15 +89,44 @@ public class ColoringController : IColoringController, IDisposable
public async UniTask PlayCompletionAnimationAsync(CancellationToken ct) public async UniTask PlayCompletionAnimationAsync(CancellationToken ct)
{ {
if (_colorInstance == null) return; if (_completionAnimationPrefab == null) return;
var animator = _colorInstance.GetComponentInChildren<Animator>(includeInactive: true); var instance = UnityEngine.Object.Instantiate(_completionAnimationPrefab, _refs.PaperRoot);
if (animator == null || animator.runtimeAnimatorController == null) return; try
{
var view = instance.GetComponentInChildren<CompletionAnimationView>();
if (view == null) return;
await view.PlayAsync(ct);
}
finally
{
if (instance != null) UnityEngine.Object.Destroy(instance);
}
}
animator.Play(0, 0, 0f); public bool HasNonAuthoredColors
animator.Update(0f); {
var length = animator.GetCurrentAnimatorStateInfo(0).length; get
if (length <= 0f) return; {
await UniTask.Delay(TimeSpan.FromSeconds(length), cancellationToken: ct); foreach (var region in _regions)
{
if (region == null) continue;
if (_authoredColors.TryGetValue(region.RegionId, out var authored) && region.Color != authored)
return true;
}
return false;
}
}
public void ResetAll()
{
if (_regions.Count == 0) return;
foreach (var region in _regions)
{
if (region == null) continue;
if (_authoredColors.TryGetValue(region.RegionId, out var authored))
region.SetColor(authored);
}
_history.Drop();
} }
public void Clear() public void Clear()
@@ -107,6 +139,8 @@ public class ColoringController : IColoringController, IDisposable
_buttons.Clear(); _buttons.Clear();
_regions.Clear(); _regions.Clear();
_authoredColors.Clear();
_completionAnimationPrefab = null;
if (_colorInstance != null) if (_colorInstance != null)
{ {
@@ -120,12 +154,14 @@ public class ColoringController : IColoringController, IDisposable
private void InitializeColorRegions(IDrawingTemplate template, IReadOnlyDictionary<string, Color> savedColors) private void InitializeColorRegions(IDrawingTemplate template, IReadOnlyDictionary<string, Color> savedColors)
{ {
_colorInstance = UnityEngine.Object.Instantiate(template.ColoringPrefab, _refs.PaperRoot); _colorInstance = UnityEngine.Object.Instantiate(template.ColoringPrefab, _refs.PaperRoot);
_completionAnimationPrefab = template.CompletionAnimationPrefab;
var views = _colorInstance.GetComponentsInChildren<ColorRegionView>(includeInactive: true); var views = _colorInstance.GetComponentsInChildren<ColorRegionView>(includeInactive: true);
foreach (var region in views) foreach (var region in views)
{ {
var id = region.RegionId; var id = region.RegionId;
var authoredColor = region.Color; var authoredColor = region.Color;
_authoredColors[id] = authoredColor;
var resumeColor = savedColors != null && savedColors.TryGetValue(id, out var saved) var resumeColor = savedColors != null && savedColors.TryGetValue(id, out var saved)
? saved ? saved
: authoredColor; : authoredColor;

View File

@@ -0,0 +1,30 @@
using System.Threading;
using Cysharp.Threading.Tasks;
using PrimeTween;
using UnityEngine;
namespace Darkmatter.Features.Coloring.UI
{
public class CompletionAnimationView : MonoBehaviour
{
[SerializeField] private RectTransform target;
[SerializeField] private float duration = 0.6f;
[SerializeField] private Vector3 startScale = Vector3.zero;
[SerializeField] private Vector3 endScale = Vector3.one;
[SerializeField] private Ease ease = Ease.OutBack;
public async UniTask PlayAsync(CancellationToken ct)
{
var rt = target != null ? target : transform as RectTransform;
if (rt == null) return;
rt.localScale = startScale;
await Tween.Scale(rt, endScale, duration, ease).ToUniTask(cancellationToken: ct);
}
private void OnDestroy()
{
var rt = target != null ? target : transform as RectTransform;
if (rt != null) Tween.StopAll(onTarget: rt);
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 01fc8d24088db42b3a76d40120f81a9c

View File

@@ -212,6 +212,7 @@ namespace Darkmatter.Features.DrawingTemplates.Editor
EditorGUILayout.LabelField("Prefabs", EditorStyles.boldLabel); EditorGUILayout.LabelField("Prefabs", EditorStyles.boldLabel);
EditorGUILayout.PropertyField(so.FindProperty("drawingPrefab"), new GUIContent("Drawing Prefab (SlotMarkers)")); EditorGUILayout.PropertyField(so.FindProperty("drawingPrefab"), new GUIContent("Drawing Prefab (SlotMarkers)"));
EditorGUILayout.PropertyField(so.FindProperty("coloringPrefab"), new GUIContent("Coloring Prefab (ColorRegionViews)")); EditorGUILayout.PropertyField(so.FindProperty("coloringPrefab"), new GUIContent("Coloring Prefab (ColorRegionViews)"));
EditorGUILayout.PropertyField(so.FindProperty("completionAnimationPrefab"), new GUIContent("Completion Animation Prefab"));
EditorGUILayout.Space(6); EditorGUILayout.Space(6);
EditorGUILayout.LabelField("Palette", EditorStyles.boldLabel); EditorGUILayout.LabelField("Palette", EditorStyles.boldLabel);
@@ -231,7 +232,7 @@ namespace Darkmatter.Features.DrawingTemplates.Editor
Undo.RecordObject(t, "Clear Pieces"); Undo.RecordObject(t, "Clear Pieces");
var emptyPieces = new List<ShapeSO>(); var emptyPieces = new List<ShapeSO>();
t.EditorSet(t.Id, t.DisplayName, t.DefaultThumbnail, t.DrawingPrefab, t.ColoringPrefab, t.EditorSet(t.Id, t.DisplayName, t.DefaultThumbnail, t.DrawingPrefab, t.ColoringPrefab,
emptyPieces, t.AuthoredRegions.ToList(), t.ColorPaletteId); t.CompletionAnimationPrefab, emptyPieces, t.AuthoredRegions.ToList(), t.ColorPaletteId);
EditorUtility.SetDirty(t); EditorUtility.SetDirty(t);
so.Update(); so.Update();
} }
@@ -263,7 +264,7 @@ namespace Darkmatter.Features.DrawingTemplates.Editor
{ {
Undo.RecordObject(t, "Clear Regions"); Undo.RecordObject(t, "Clear Regions");
t.EditorSet(t.Id, t.DisplayName, t.DefaultThumbnail, t.DrawingPrefab, t.ColoringPrefab, t.EditorSet(t.Id, t.DisplayName, t.DefaultThumbnail, t.DrawingPrefab, t.ColoringPrefab,
t.Pieces.ToList(), new List<RegionAuthoring>(), t.ColorPaletteId); t.CompletionAnimationPrefab, t.Pieces.ToList(), new List<RegionAuthoring>(), t.ColorPaletteId);
EditorUtility.SetDirty(t); EditorUtility.SetDirty(t);
so.Update(); so.Update();
} }
@@ -331,7 +332,7 @@ namespace Darkmatter.Features.DrawingTemplates.Editor
} }
Undo.RecordObject(t, "Scan Drawing Prefab"); Undo.RecordObject(t, "Scan Drawing Prefab");
t.EditorSet(t.Id, t.DisplayName, t.DefaultThumbnail, t.DrawingPrefab, t.ColoringPrefab, t.EditorSet(t.Id, t.DisplayName, t.DefaultThumbnail, t.DrawingPrefab, t.ColoringPrefab,
pieces, t.AuthoredRegions.ToList(), t.ColorPaletteId); t.CompletionAnimationPrefab, pieces, t.AuthoredRegions.ToList(), t.ColorPaletteId);
EditorUtility.SetDirty(t); EditorUtility.SetDirty(t);
_lastScanReport = $"Found {markers.Length} SlotMarker(s), {pieces.Count} unique ShapeSO. {missing} marker(s) had no ShapeSO assigned."; _lastScanReport = $"Found {markers.Length} SlotMarker(s), {pieces.Count} unique ShapeSO. {missing} marker(s) had no ShapeSO assigned.";
Validate(); Validate();
@@ -411,7 +412,7 @@ namespace Darkmatter.Features.DrawingTemplates.Editor
Undo.RecordObject(t, "Scan Coloring Prefab"); Undo.RecordObject(t, "Scan Coloring Prefab");
t.EditorSet(t.Id, t.DisplayName, t.DefaultThumbnail, t.DrawingPrefab, t.ColoringPrefab, t.EditorSet(t.Id, t.DisplayName, t.DefaultThumbnail, t.DrawingPrefab, t.ColoringPrefab,
t.Pieces.ToList(), regions, t.ColorPaletteId); t.CompletionAnimationPrefab, t.Pieces.ToList(), regions, t.ColorPaletteId);
EditorUtility.SetDirty(t); EditorUtility.SetDirty(t);
var report = new System.Text.StringBuilder(); var report = new System.Text.StringBuilder();
@@ -611,7 +612,7 @@ namespace Darkmatter.Features.DrawingTemplates.Editor
if (string.IsNullOrEmpty(path)) return; if (string.IsNullOrEmpty(path)) return;
var t = CreateInstance<DrawingTemplateSO>(); var t = CreateInstance<DrawingTemplateSO>();
var name = Path.GetFileNameWithoutExtension(path); var name = Path.GetFileNameWithoutExtension(path);
t.EditorSet(name, name, null, null, null, new List<ShapeSO>(), new List<RegionAuthoring>(), "defaultPalette"); t.EditorSet(name, name, null, null, null, null, new List<ShapeSO>(), new List<RegionAuthoring>(), "defaultPalette");
AssetDatabase.CreateAsset(t, path); AssetDatabase.CreateAsset(t, path);
AssetDatabase.SaveAssets(); AssetDatabase.SaveAssets();
Refresh(); Refresh();

View File

@@ -4,7 +4,8 @@
"references": [ "references": [
"GUID:6a0a834eb41764f12ba55c3fb04a40cb", "GUID:6a0a834eb41764f12ba55c3fb04a40cb",
"GUID:b0214a6008ed146ff8f122a6a9c2f6cc", "GUID:b0214a6008ed146ff8f122a6a9c2f6cc",
"GUID:c1c03c0e5b2f4412b9f2be1c20d6a9b1" "GUID:c1c03c0e5b2f4412b9f2be1c20d6a9b1",
"GUID:b4c9f7fbf1e144933a1797dc208ece5f"
], ],
"includePlatforms": [], "includePlatforms": [],
"excludePlatforms": [], "excludePlatforms": [],

View File

@@ -1,5 +1,8 @@
using System; using System;
using Darkmatter.Core.Contracts.Features.Coloring;
using Darkmatter.Core.Contracts.Features.History; using Darkmatter.Core.Contracts.Features.History;
using Darkmatter.Core.Data.Signals.Features.Coloring;
using Darkmatter.Libs.Observer;
using VContainer.Unity; using VContainer.Unity;
namespace Darkmatter.Features.History namespace Darkmatter.Features.History
@@ -8,11 +11,18 @@ namespace Darkmatter.Features.History
{ {
private readonly HistoryButtonsView _view; private readonly HistoryButtonsView _view;
private readonly IUndoStack _undoStack; private readonly IUndoStack _undoStack;
private readonly IColoringController _coloring;
private readonly IEventBus _bus;
private IDisposable _initSub;
private IDisposable _colorAppliedSub;
public HistoryButtonsPresenter(IUndoStack undoStack, HistoryButtonsView view) public HistoryButtonsPresenter(IUndoStack undoStack, HistoryButtonsView view, IColoringController coloring,
IEventBus bus)
{ {
_undoStack = undoStack; _undoStack = undoStack;
_view = view; _view = view;
_coloring = coloring;
_bus = bus;
} }
public void Start() public void Start()
@@ -22,11 +32,14 @@ namespace Darkmatter.Features.History
_view.OnClearClicked += HandleClearClicked; _view.OnClearClicked += HandleClearClicked;
UpdateButtonUI(); UpdateButtonUI();
_undoStack.OnStackChanged += UpdateButtonUI; _undoStack.OnStackChanged += UpdateButtonUI;
_initSub = _bus.Subscribe<RegionsInitializedSignal>(_ => UpdateButtonUI());
_colorAppliedSub = _bus.Subscribe<ColorAppliedSignal>(_ => UpdateButtonUI());
} }
private void HandleClearClicked() private void HandleClearClicked()
{ {
_undoStack.Clear(); _undoStack.Clear();
_coloring.ResetAll();
} }
private void HandleRedoClicked() private void HandleRedoClicked()
@@ -43,7 +56,7 @@ namespace Darkmatter.Features.History
{ {
_view.SetUndoInteractable(_undoStack.CanUndo); _view.SetUndoInteractable(_undoStack.CanUndo);
_view.SetRedoInteractable(_undoStack.CanRedo); _view.SetRedoInteractable(_undoStack.CanRedo);
_view.SetClearInteractable(_undoStack.CanUndo); _view.SetClearInteractable(_undoStack.CanUndo || _coloring.HasNonAuthoredColors);
} }
public void Dispose() public void Dispose()
@@ -52,6 +65,8 @@ namespace Darkmatter.Features.History
_view.OnRedoClicked -= HandleRedoClicked; _view.OnRedoClicked -= HandleRedoClicked;
_view.OnClearClicked -= HandleClearClicked; _view.OnClearClicked -= HandleClearClicked;
_undoStack.OnStackChanged -= UpdateButtonUI; _undoStack.OnStackChanged -= UpdateButtonUI;
_initSub?.Dispose();
_colorAppliedSub?.Dispose();
} }
} }
} }

File diff suppressed because one or more lines are too long