Compare commits

...

5 Commits

Author SHA1 Message Date
Mausham
c57189de80 added confetti 2026-05-29 15:11:55 +05:45
Mausham
75b34c6ef7 Merge remote-tracking branch 'origin/savya' into work_branch
# Conflicts:
#	Assets/Darkmatter/Content/Fonts/static/Fredoka-Bold SDF Blue Outline.asset
2026-05-29 15:03:52 +05:45
Savya Bikram Shah
b78678a6d8 image save/load 2026-05-29 14:24:36 +05:45
Savya Bikram Shah
774a7159d3 Shape and coloring 2026-05-29 13:19:15 +05:45
96e69c3d1a Merge pull request 'work_branch' (#12) from work_branch into main
Reviewed-on: #12
2026-05-29 06:52:37 +02:00
145 changed files with 30349 additions and 18333 deletions

View File

@@ -13,6 +13,8 @@ MonoBehaviour:
m_Name: AddressableAssetGroupSortSettings
m_EditorClassIdentifier: Unity.Addressables.Editor::UnityEditor.AddressableAssets.Settings.GroupSchemas.AddressableAssetGroupSortSettings
sortOrder:
- 2c56f39dfa281426bbb0636a757c203b
- 01d1da4daa82a469884449cd7ea9e22e
- 86e13c2ac495848d99c739840b7d38e9
- 0e030d5498bfe4ffd8443c796618c539
- c0e2d4d32411e46a6a3dd5cdfa6dbe7e

View File

@@ -15,7 +15,7 @@ MonoBehaviour:
m_DefaultGroup: 0e030d5498bfe4ffd8443c796618c539
m_currentHash:
serializedVersion: 2
Hash: 11994545ace6358214de1d969c8c1309
Hash: ee5be5d153107dd33adea90859ed25f8
m_OptimizeCatalogSize: 0
m_BuildRemoteCatalog: 0
m_CatalogRequestsTimeout: 0
@@ -24,11 +24,11 @@ MonoBehaviour:
m_InternalBundleIdMode: 1
m_AssetLoadMode: 0
m_BundledAssetProviderType:
m_AssemblyName:
m_ClassName:
m_AssemblyName: Unity.ResourceManager, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
m_ClassName: UnityEngine.ResourceManagement.ResourceProviders.BundledAssetProvider
m_AssetBundleProviderType:
m_AssemblyName:
m_ClassName:
m_AssemblyName: Unity.ResourceManager, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
m_ClassName: UnityEngine.ResourceManagement.ResourceProviders.AssetBundleProvider
m_IgnoreUnsupportedFilesInBuild: 0
m_UniqueBundleIds: 0
m_EnableJsonCatalog: 0
@@ -61,7 +61,9 @@ MonoBehaviour:
m_BuildAddressablesWithPlayerBuild: 0
m_overridePlayerVersion: '[UnityEditor.PlayerSettings.bundleVersion]'
m_GroupAssets:
- {fileID: 11400000, guid: ec9d910e81be14a1484f351f20d32f6f, type: 2}
- {fileID: 11400000, guid: 884c7b3ae8a8543379b1b771a9b8ab47, type: 2}
- {fileID: 11400000, guid: 9fdea8257283a49d4a1a7181623bdade, type: 2}
- {fileID: 11400000, guid: fda2e763202c2462b857e04c29824b23, type: 2}
- {fileID: 11400000, guid: 9813579a74a7640e182c85c4bdeb3852, type: 2}
m_BuildSettings:
@@ -103,6 +105,7 @@ MonoBehaviour:
m_LabelTable:
m_LabelNames:
- default
- drawing
m_SchemaTemplates: []
m_GroupTemplateObjects:
- {fileID: 11400000, guid: 08cea37bc40c14d2696479a6530b6f35, type: 2}

View File

@@ -14,7 +14,17 @@ MonoBehaviour:
m_EditorClassIdentifier: Unity.Addressables.Editor::UnityEditor.AddressableAssets.Settings.AddressableAssetGroup
m_GroupName: Default Local Group
m_GUID: 0e030d5498bfe4ffd8443c796618c539
m_SerializeEntries: []
m_SerializeEntries:
- m_GUID: 319873779c4b440c3ad40798aa697460
m_Address: ColorButton
m_ReadOnly: 0
m_SerializedLabels: []
FlaggedDuringContentUpdateRestriction: 0
- m_GUID: ba3eb5e9b32d64a50bd717a07541ee18
m_Address: ShapePiece
m_ReadOnly: 0
m_SerializedLabels: []
FlaggedDuringContentUpdateRestriction: 0
m_ReadOnly: 0
m_Settings: {fileID: 11400000, guid: 4a94ef317c3674edd8270e4ed15031f6, type: 2}
m_SchemaSet:

View File

@@ -0,0 +1,29 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: bbb281ee3bf0b054c82ac2347e9e782c, type: 3}
m_Name: Drawing
m_EditorClassIdentifier: Unity.Addressables.Editor::UnityEditor.AddressableAssets.Settings.AddressableAssetGroup
m_GroupName: Drawing
m_GUID: 2c56f39dfa281426bbb0636a757c203b
m_SerializeEntries:
- m_GUID: 364f644d962504fa7ac2f382800014ea
m_Address: apple
m_ReadOnly: 0
m_SerializedLabels:
- drawing
FlaggedDuringContentUpdateRestriction: 0
m_ReadOnly: 0
m_Settings: {fileID: 11400000, guid: 4a94ef317c3674edd8270e4ed15031f6, type: 2}
m_SchemaSet:
m_Schemas:
- {fileID: 11400000, guid: c68aac65911cf47a9aa8b3355994402c, type: 2}
- {fileID: 11400000, guid: 4b166a28895af465ca9a684ed07eac42, type: 2}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 9fdea8257283a49d4a1a7181623bdade
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,28 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: bbb281ee3bf0b054c82ac2347e9e782c, type: 3}
m_Name: Palettes
m_EditorClassIdentifier: Unity.Addressables.Editor::UnityEditor.AddressableAssets.Settings.AddressableAssetGroup
m_GroupName: Palettes
m_GUID: 01d1da4daa82a469884449cd7ea9e22e
m_SerializeEntries:
- m_GUID: 00f9beb81415a4193abff0aa201ab75b
m_Address: defaultPalette
m_ReadOnly: 0
m_SerializedLabels: []
FlaggedDuringContentUpdateRestriction: 0
m_ReadOnly: 0
m_Settings: {fileID: 11400000, guid: 4a94ef317c3674edd8270e4ed15031f6, type: 2}
m_SchemaSet:
m_Schemas:
- {fileID: 11400000, guid: 5c191a09b8bef451b9f74c11840d3273, type: 2}
- {fileID: 11400000, guid: e42d0727bb3974fe596fc2f19e02b7a0, type: 2}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: ec9d910e81be14a1484f351f20d32f6f
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,48 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: e5d17a21594effb4e9591490b009e7aa, type: 3}
m_Name: Drawing_BundledAssetGroupSchema
m_EditorClassIdentifier: Unity.Addressables.Editor::UnityEditor.AddressableAssets.Settings.GroupSchemas.BundledAssetGroupSchema
m_Group: {fileID: 11400000, guid: 9fdea8257283a49d4a1a7181623bdade, type: 2}
m_InternalBundleIdMode: 1
m_Compression: 1
m_IncludeAddressInCatalog: 1
m_IncludeGUIDInCatalog: 1
m_IncludeLabelsInCatalog: 1
m_InternalIdNamingMode: 0
m_CacheClearBehavior: 0
m_IncludeInBuild: 1
m_BundledAssetProviderType:
m_AssemblyName: Unity.ResourceManager, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
m_ClassName: UnityEngine.ResourceManagement.ResourceProviders.BundledAssetProvider
m_StripDownloadOptions: 0
m_ForceUniqueProvider: 0
m_UseAssetBundleCache: 1
m_UseAssetBundleCrc: 1
m_UseAssetBundleCrcForCachedBundles: 1
m_UseUWRForLocalBundles: 0
m_Timeout: 0
m_ChunkedTransfer: 0
m_RedirectLimit: -1
m_RetryCount: 0
m_BuildPath:
m_Id: 1e7b566e879b2426f9a706a71f9612bf
m_LoadPath:
m_Id: e2253d243607142b0a072c38c39ccb14
m_BundleMode: 0
m_AssetBundleProviderType:
m_AssemblyName: Unity.ResourceManager, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
m_ClassName: UnityEngine.ResourceManagement.ResourceProviders.AssetBundleProvider
m_UseDefaultSchemaSettings: 0
m_SelectedPathPairIndex: 0
m_BundleNaming: 0
m_AssetLoadMode: 0

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: c68aac65911cf47a9aa8b3355994402c
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,16 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 5834b5087d578d24c926ce20cd31e6d6, type: 3}
m_Name: Drawing_ContentUpdateGroupSchema
m_EditorClassIdentifier: Unity.Addressables.Editor::UnityEditor.AddressableAssets.Settings.GroupSchemas.ContentUpdateGroupSchema
m_Group: {fileID: 11400000, guid: 9fdea8257283a49d4a1a7181623bdade, type: 2}
m_StaticContent: 0

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 4b166a28895af465ca9a684ed07eac42
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,48 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: e5d17a21594effb4e9591490b009e7aa, type: 3}
m_Name: Palettes_BundledAssetGroupSchema
m_EditorClassIdentifier: Unity.Addressables.Editor::UnityEditor.AddressableAssets.Settings.GroupSchemas.BundledAssetGroupSchema
m_Group: {fileID: 11400000, guid: ec9d910e81be14a1484f351f20d32f6f, type: 2}
m_InternalBundleIdMode: 1
m_Compression: 1
m_IncludeAddressInCatalog: 1
m_IncludeGUIDInCatalog: 1
m_IncludeLabelsInCatalog: 1
m_InternalIdNamingMode: 0
m_CacheClearBehavior: 0
m_IncludeInBuild: 1
m_BundledAssetProviderType:
m_AssemblyName: Unity.ResourceManager, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
m_ClassName: UnityEngine.ResourceManagement.ResourceProviders.BundledAssetProvider
m_StripDownloadOptions: 0
m_ForceUniqueProvider: 0
m_UseAssetBundleCache: 1
m_UseAssetBundleCrc: 1
m_UseAssetBundleCrcForCachedBundles: 1
m_UseUWRForLocalBundles: 0
m_Timeout: 0
m_ChunkedTransfer: 0
m_RedirectLimit: -1
m_RetryCount: 0
m_BuildPath:
m_Id: 1e7b566e879b2426f9a706a71f9612bf
m_LoadPath:
m_Id: e2253d243607142b0a072c38c39ccb14
m_BundleMode: 0
m_AssetBundleProviderType:
m_AssemblyName: Unity.ResourceManager, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
m_ClassName: UnityEngine.ResourceManagement.ResourceProviders.AssetBundleProvider
m_UseDefaultSchemaSettings: 0
m_SelectedPathPairIndex: 0
m_BundleNaming: 0
m_AssetLoadMode: 0

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 5c191a09b8bef451b9f74c11840d3273
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,16 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 5834b5087d578d24c926ce20cd31e6d6, type: 3}
m_Name: Palettes_ContentUpdateGroupSchema
m_EditorClassIdentifier: Unity.Addressables.Editor::UnityEditor.AddressableAssets.Settings.GroupSchemas.ContentUpdateGroupSchema
m_Group: {fileID: 11400000, guid: ec9d910e81be14a1484f351f20d32f6f, type: 2}
m_StaticContent: 0

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: e42d0727bb3974fe596fc2f19e02b7a0
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -8,7 +8,7 @@ Material:
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: confetti4x4
m_Shader: {fileID: 203, guid: 0000000000000000f000000000000000, type: 0}
m_Shader: {fileID: 10721, guid: 0000000000000000f000000000000000, type: 0}
m_Parent: {fileID: 0}
m_ModifiedSerializedProperties: 0
m_ValidKeywords: []

View File

@@ -8,7 +8,7 @@ Material:
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: confettiblurred4x4
m_Shader: {fileID: 203, guid: 0000000000000000f000000000000000, type: 0}
m_Shader: {fileID: 10721, guid: 0000000000000000f000000000000000, type: 0}
m_Parent: {fileID: 0}
m_ModifiedSerializedProperties: 0
m_ValidKeywords: []

View File

@@ -8,7 +8,7 @@ Material:
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: trail
m_Shader: {fileID: 203, guid: 0000000000000000f000000000000000, type: 0}
m_Shader: {fileID: 10721, guid: 0000000000000000f000000000000000, type: 0}
m_Parent: {fileID: 0}
m_ModifiedSerializedProperties: 0
m_ValidKeywords: []

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 46449f63247f4179976c276c22d17393
timeCreated: 1780040939

View File

@@ -0,0 +1,9 @@
using System.Threading;
using Cysharp.Threading.Tasks;
namespace Darkmatter.Core.Contracts.Features.Capture;
public interface ICaptureFeature
{
UniTask<byte[]> CapturePngAsync(bool saveToGallery = false, CancellationToken ct = default);
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: ccf092b5e4744b9ca769205f0bc49368
timeCreated: 1780040946

View File

@@ -1,12 +1,13 @@
using System.Threading;
using Cysharp.Threading.Tasks;
namespace Darkmatter.Core.Contracts.Features.GameplayFlow
{
public interface IGameplayFlowController
{
UniTask BackAsync();
UniTask SaveAsync();
UniTask NextAsync();
UniTask BackAsync(CancellationToken cancellationToken);
UniTask SaveAsync(CancellationToken cancellationToken);
UniTask NextAsync(CancellationToken cancellationToken);
void OnApplicationPaused();
}
}

View File

@@ -13,5 +13,6 @@ public interface IShapeBuilderController
IReadOnlyCollection<string> preSnappedIds, CancellationToken ct);
IReadOnlyCollection<string> GetSnappedPieceIds();
void DespawnDrawing();
void Clear();
}

View File

@@ -6,7 +6,7 @@ namespace Darkmatter.Core.Contracts.Services.Capture
{
public interface ICaptureService
{
UniTask<Sprite> CapturePngAsync(GameObject captureObject, float captureSize,
UniTask<byte[]> CapturePngAsync(GameObject captureObject, float scale,
CancellationToken cancellationToken = default);
}
}

View File

@@ -1,3 +1,4 @@
using System;
using System.Collections.Generic;
using Darkmatter.Core.Contracts.Features.DrawingCatalog;
using Darkmatter.Core.Data.Dynamic.Features.Coloring;
@@ -9,13 +10,47 @@ namespace Darkmatter.Core.Data.Static.Features.DrawingTemplate
[CreateAssetMenu(menuName = "Darkmatter/Drawing/New Drawing Template")]
public class DrawingTemplateSO : ScriptableObject, IDrawingTemplate
{
[field: SerializeField] public string Id { get; private set; }
[field: SerializeField] public string DisplayName { get; private set; }
[field: SerializeField] public Sprite DefaultThumbnail { get; private set; }
[field: SerializeField] public GameObject DrawingPrefab { get; private set; }
[field: SerializeField] public GameObject ColoringPrefab { get; private set; }
[field: SerializeField] public IReadOnlyList<ShapeSO> Pieces { get; private set; }
[field: SerializeField] public IReadOnlyList<ColorRegionDTO> Regions { get; private set; }
[field: SerializeField] public string ColorPaletteId { get; private set; } = "defaultPalette";
[SerializeField] private string id;
[SerializeField] private string displayName;
[SerializeField] private Sprite defaultThumbnail;
[SerializeField] private GameObject drawingPrefab;
[SerializeField] private GameObject coloringPrefab;
[SerializeField] private List<ShapeSO> pieces = new();
[SerializeField] private List<RegionAuthoring> regions = new();
[SerializeField] private string colorPaletteId = "defaultPalette";
public string Id => id;
public string DisplayName => displayName;
public Sprite DefaultThumbnail => defaultThumbnail;
public GameObject DrawingPrefab => drawingPrefab;
public GameObject ColoringPrefab => coloringPrefab;
public IReadOnlyList<ShapeSO> Pieces => pieces;
public IReadOnlyList<ColorRegionDTO> Regions => Array.Empty<ColorRegionDTO>();
public string ColorPaletteId => colorPaletteId;
public IReadOnlyList<RegionAuthoring> AuthoredRegions => regions;
#if UNITY_EDITOR
public void EditorSet(string newId, string newDisplayName, Sprite thumbnail,
GameObject drawing, GameObject coloring, List<ShapeSO> newPieces,
List<RegionAuthoring> newRegions, string paletteId)
{
id = newId;
displayName = newDisplayName;
defaultThumbnail = thumbnail;
drawingPrefab = drawing;
coloringPrefab = coloring;
pieces = newPieces ?? new List<ShapeSO>();
regions = newRegions ?? new List<RegionAuthoring>();
colorPaletteId = paletteId;
}
#endif
}
[Serializable]
public struct RegionAuthoring
{
public string RegionId;
public Color InitialColor;
}
}

View File

@@ -17,16 +17,21 @@ namespace Darkmatter.Features.AppBoot.Flow
private readonly AppBootSceneRefs _sceneRefs;
private readonly ISceneService _sceneService;
private readonly IEventBus _eventBus;
private readonly IProgressionSystem _progression;
public AppBootFlow(AppBootSceneRefs sceneRefs, ISceneService sceneService, IEventBus eventBus)
public AppBootFlow(AppBootSceneRefs sceneRefs, ISceneService sceneService, IEventBus eventBus,
IProgressionSystem progression)
{
_sceneRefs = sceneRefs;
_sceneService = sceneService;
_eventBus = eventBus;
_progression = progression;
}
public async UniTask StartAsync(CancellationToken cancellation = default)
{
await _progression.LoadAsync();
var tcs = new UniTaskCompletionSource();
var player = _sceneRefs.IntroVideoPlayer;

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: d54fa8b2c22014496a84c508d897dcdd
guid: eeefc3c8ab31d4ac983deab507c76b1f
folderAsset: yes
DefaultImporter:
externalObjects: {}

View File

@@ -1,11 +1,11 @@
{
"name": "Services.Inputs",
"rootNamespace": "Darkmatter.Services.Inputs",
"name": "Features.Capture",
"rootNamespace": "Darkmatter.Features.Capture",
"references": [
"GUID:6a0a834eb41764f12ba55c3fb04a40cb",
"GUID:c1c03c0e5b2f4412b9f2be1c20d6a9b1",
"GUID:75469ad4d38634e559750d17036d5f7c",
"GUID:b0214a6008ed146ff8f122a6a9c2f6cc"
"GUID:b0214a6008ed146ff8f122a6a9c2f6cc",
"GUID:f51ebe6a0ceec4240a699833d6309b23"
],
"includePlatforms": [],
"excludePlatforms": [],

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 68042734671ce4660bff89e042777454
guid: 80056ede5198b460198933cb79d694ff
AssemblyDefinitionImporter:
externalObjects: {}
userData:

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 88abeaac3da9d499288f8b5a1830cebc
guid: 338d273a95ef0403ca2dd1aca67f97f5
folderAsset: yes
DefaultImporter:
externalObjects: {}

View File

@@ -0,0 +1,24 @@
using Darkmatter.Core.Contracts.Features.Capture;
using Darkmatter.Features.Capture.UI;
using Darkmatter.Libs.Installers;
using UnityEngine;
using VContainer;
using VContainer.Unity;
namespace Darkmatter.Features.Capture
{
public class CaptureFeatureModule : MonoBehaviour, IModule
{
[SerializeField, Range(0.1f, 2f)] private float captureScale = 1f;
[SerializeField] private CaptureButtonView captureButtonView;
public void Register(IContainerBuilder builder)
{
builder.RegisterInstance(new CaptureConfig(captureScale));
builder.Register<ICaptureFeature, CaptureSystem>(Lifetime.Singleton);
if (captureButtonView != null)
builder.RegisterEntryPoint<CaptureButtonPresenter>().WithParameter(captureButtonView);
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 9b7df1c2a732341d3b123b5e7ae5d7b7

View File

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

View File

@@ -0,0 +1,15 @@
using System;
namespace Darkmatter.Features.Capture
{
[Serializable]
public struct CaptureConfig
{
public float CaptureScale { get; }
public CaptureConfig(float captureScale)
{
CaptureScale = captureScale;
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 6f12070b2d795429a9b7f6cc0e4ae894

View File

@@ -0,0 +1,50 @@
using System;
using System.Threading;
using Cysharp.Threading.Tasks;
using Darkmatter.Core.Contracts.Features.Capture;
using Darkmatter.Core.Contracts.Features.GameplayFlow;
using Darkmatter.Core.Contracts.Services.Capture;
using Darkmatter.Core.Contracts.Services.Gallery;
using UnityEngine;
namespace Darkmatter.Features.Capture
{
public class CaptureSystem : ICaptureFeature
{
private readonly ICaptureService _captureService;
private readonly IGalleryService _galleryService;
private readonly IGameplaySceneRefs _refs;
private readonly CaptureConfig _config;
public CaptureSystem(
ICaptureService captureService,
IGalleryService galleryService,
IGameplaySceneRefs refs,
CaptureConfig config)
{
_captureService = captureService;
_galleryService = galleryService;
_refs = refs;
_config = config;
}
public async UniTask<byte[]> CapturePngAsync(bool saveToGallery = false, CancellationToken ct = default)
{
var png = await _captureService.CapturePngAsync(_refs.PaperRoot.gameObject, _config.CaptureScale, ct);
if (!saveToGallery || png == null || png.Length == 0) return png;
var tex = new Texture2D(2, 2, TextureFormat.RGBA32, mipChain: false);
try
{
if (tex.LoadImage(png))
await _galleryService.SaveImageAsync(tex,
$"colorbook_{DateTime.UtcNow:yyyyMMdd_HHmmss}.png", ct);
}
finally
{
UnityEngine.Object.Destroy(tex);
}
return png;
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 76bbd68f070e24d6a86130ec07c237b8

View File

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

View File

@@ -0,0 +1,44 @@
using System;
using Cysharp.Threading.Tasks;
using Darkmatter.Core.Contracts.Features.Capture;
using VContainer.Unity;
namespace Darkmatter.Features.Capture.UI
{
public class CaptureButtonPresenter : IStartable, IDisposable
{
private readonly CaptureButtonView _view;
private readonly ICaptureFeature _capture;
public CaptureButtonPresenter(CaptureButtonView view, ICaptureFeature capture)
{
_view = view;
_capture = capture;
}
public void Start()
{
_view.OnCaptureClicked += HandleCaptureClicked;
}
private void HandleCaptureClicked() => CaptureAsync().Forget();
private async UniTaskVoid CaptureAsync()
{
_view.SetInteractable(false);
try
{
await _capture.CapturePngAsync(saveToGallery: true);
}
finally
{
_view.SetInteractable(true);
}
}
public void Dispose()
{
_view.OnCaptureClicked -= HandleCaptureClicked;
}
}
}

View File

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

View File

@@ -0,0 +1,29 @@
using System;
using UnityEngine;
using UnityEngine.UI;
namespace Darkmatter.Features.Capture.UI
{
public class CaptureButtonView : MonoBehaviour
{
[SerializeField] private Button captureButton;
public event Action OnCaptureClicked;
private void Start()
{
if (captureButton != null)
captureButton.onClick.AddListener(() => OnCaptureClicked?.Invoke());
}
public void SetInteractable(bool value)
{
if (captureButton != null) captureButton.interactable = value;
}
private void OnDestroy()
{
if (captureButton != null) captureButton.onClick.RemoveAllListeners();
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 4f0946b153da9431eb6c66bda432901f

View File

@@ -70,8 +70,13 @@ public class ColorbookFlowController : IAsyncStartable, IDisposable
private async UniTaskVoid HandleSelectionAsync(string templateId)
{
_loadingScreen.Show();
var progress = new Progress<float>(p => _loadingScreen.SetProgress(p * 0.5f));
var mappedProgress = new Progress<float>(p => _loadingScreen.SetProgress(0.5f + p * 0.25f));
await _progression.SetLastOpenedAsync(templateId);
await _scenes.LoadSceneAsync(GameScene.Gameplay, progress: null, cancellationToken: default);
await _scenes.LoadSceneAsync(nameof(GameScene.Gameplay), progress: progress, cancellationToken: default);
await _scenes.UnloadSceneAsync(nameof(GameScene.Colorbook), progress: mappedProgress,
cancellationToken: default);
}
public void Dispose()

View File

@@ -19,7 +19,7 @@ namespace Darkmatter.Features.Coloring.Systems;
public class ColoringController : IColoringController, IDisposable
{
private const string ColorButtonPrefabKey = "colorButton";
private const string ColorButtonPrefabKey = "ColorButton";
private readonly ColoringStateRepository _repository;
private readonly IColorButtonFactory _buttonFactory;
@@ -27,6 +27,7 @@ public class ColoringController : IColoringController, IDisposable
private readonly IAssetProviderService _assetProviderService;
private readonly IUndoStack _history;
private readonly IGameplaySceneRefs _refs;
private readonly ColorPaletteHolderView _paletteHolder;
private GameObject _colorInstance;
private GameObject _colorButtonPrefab;
@@ -39,7 +40,8 @@ public class ColoringController : IColoringController, IDisposable
IEventBus bus,
IAssetProviderService assetProviderService,
IUndoStack history,
IGameplaySceneRefs refs)
IGameplaySceneRefs refs,
ColorPaletteHolderView paletteHolder)
{
_repository = repository;
_buttonFactory = buttonFactory;
@@ -47,12 +49,14 @@ public class ColoringController : IColoringController, IDisposable
_assetProviderService = assetProviderService;
_history = history;
_refs = refs;
_paletteHolder = paletteHolder;
}
public async UniTask InitializeRegionsAsync(IDrawingTemplate template,
IReadOnlyDictionary<string, Color> savedColors, CancellationToken ct)
{
Clear();
_paletteHolder.Show();
await TryLoadColorButtonPrefabAsync(ct);
ct.ThrowIfCancellationRequested();
await TryLoadColorPaletteAsync(template, ct);
@@ -67,6 +71,7 @@ public class ColoringController : IColoringController, IDisposable
if (region == null) return;
var from = region.Color;
if (from != color)
_history.Push(new ColorRegionCommand(region, from, color));
_bus.Publish(new ColorAppliedSignal(regionId, color));
}
@@ -84,7 +89,8 @@ public class ColoringController : IColoringController, IDisposable
_history.Drop();
foreach (var button in _buttons)
if (button != null) UnityEngine.Object.Destroy(button.gameObject);
if (button != null)
UnityEngine.Object.Destroy(button.gameObject);
_buttons.Clear();
_regions.Clear();

View File

@@ -9,8 +9,9 @@ namespace Darkmatter.Features.Coloring.UI
[RequireComponent(typeof(Button))]
public class ColorButton : MonoBehaviour
{
[SerializeField] private Image swatch;
[SerializeField] private GameObject selectedUI;
[SerializeField] private Image[] swatches;
[SerializeField] private GameObject activeUI;
[SerializeField] private GameObject inactiveUI;
private Button _button;
private Color _color;
private ColoringStateRepository _repository;
@@ -26,7 +27,11 @@ namespace Darkmatter.Features.Coloring.UI
_color = color;
_repository = repository;
_sfx = sfx;
if (_button == null) _button = GetComponent<Button>();
foreach (var swatch in swatches)
{
swatch.color = color;
}
_button.onClick.AddListener(OnClick);
_repository.SelectedIndexChanged += UpdateSelectedUI;
@@ -41,8 +46,10 @@ namespace Darkmatter.Features.Coloring.UI
private void UpdateSelectedUI()
{
if (selectedUI != null)
selectedUI.SetActive(_repository.SelectedColor == _color);
if (activeUI != null)
activeUI.SetActive(_repository.SelectedColor == _color);
if (inactiveUI != null)
inactiveUI.SetActive(_repository.SelectedColor != _color);
}
private void OnDestroy()

View File

@@ -15,18 +15,24 @@ namespace Darkmatter.Features.Coloring.UI
private CanvasGroup _canvasGroup;
private Vector2 _shownAnchoredPos;
private Sequence _activeSequence;
private bool _refsReady;
public RectTransform SpawnRoot => spawnRoot;
private void Awake()
private void Awake() => EnsureRefs();
private void EnsureRefs()
{
_canvasGroup = GetComponent<CanvasGroup>();
if (_refsReady) return;
if (_canvasGroup == null) _canvasGroup = GetComponent<CanvasGroup>();
if (animatedRoot == null) animatedRoot = (RectTransform)transform;
_shownAnchoredPos = animatedRoot.anchoredPosition;
_refsReady = true;
}
public Sequence Show()
{
EnsureRefs();
KillActive();
gameObject.SetActive(true);
_canvasGroup.interactable = true;
@@ -40,6 +46,7 @@ namespace Darkmatter.Features.Coloring.UI
public Sequence Hide()
{
EnsureRefs();
KillActive();
_canvasGroup.interactable = false;
_canvasGroup.blocksRaycasts = false;
@@ -54,6 +61,7 @@ namespace Darkmatter.Features.Coloring.UI
public void HideInstant()
{
EnsureRefs();
KillActive();
animatedRoot.anchoredPosition = _shownAnchoredPos + hiddenOffset;
_canvasGroup.alpha = 0f;

View File

@@ -14,6 +14,7 @@ namespace Darkmatter.Features.Coloring.UI
private Image _image;
private event Action OnRegionClicked;
private void Awake()
{
_image = GetComponent<Image>();
@@ -33,6 +34,7 @@ namespace Darkmatter.Features.Coloring.UI
public void OnPointerClick(PointerEventData eventData)
{
Debug.Log($"[ColorRegion] clicked '{RegionId}' on '{gameObject.name}'");
OnRegionClicked?.Invoke();
}

View File

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

View File

@@ -0,0 +1,917 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Darkmatter.Core.Data.Static.Features.Coloring;
using Darkmatter.Core.Data.Static.Features.DrawingTemplate;
using Darkmatter.Core.Data.Static.Features.ShapeBuilder;
using Darkmatter.Features.Coloring.UI;
using Darkmatter.Features.ShapeBuilder.UI;
using UnityEditor;
using UnityEditor.AddressableAssets;
using UnityEditor.AddressableAssets.Settings;
using UnityEngine;
namespace Darkmatter.Features.DrawingTemplates.Editor
{
public sealed class DrawingTemplateEditorWindow : EditorWindow
{
private const string AddressableLabel = "drawing";
private const string DrawingsGroupName = "Drawing";
private const string PalettesGroupName = "Palettes";
private const string DefaultTemplateFolder = "Assets/Darkmatter/Data/Drawings/Templates";
private const string DefaultShapeFolder = "Assets/Darkmatter/Data/Drawings/Shapes";
private const string DefaultPaletteFolder = "Assets/Darkmatter/Data/Drawings/Palettes";
private enum Tab { Templates, Shapes, Palettes }
private Tab _tab;
private Vector2 _leftScroll;
private Vector2 _rightScroll;
private string _search = string.Empty;
private readonly List<DrawingTemplateSO> _templates = new();
private readonly List<ShapeSO> _shapes = new();
private readonly List<ColorPaletteSO> _palettes = new();
private DrawingTemplateSO _selectedTemplate;
private ShapeSO _selectedShape;
private ColorPaletteSO _selectedPalette;
private readonly List<string> _validation = new();
private string _lastScanReport;
private DefaultAsset _batchShapeFolder;
private bool _autoAssignRegionIds = true;
private bool _mergeRegions = false;
[MenuItem("Tools/Darkmatter/Drawing Template Editor", priority = 10)]
public static void Open()
{
var win = GetWindow<DrawingTemplateEditorWindow>("Drawing Editor");
win.minSize = new Vector2(900, 540);
win.Refresh();
}
public static void OpenAndSelect(DrawingTemplateSO template)
{
var win = GetWindow<DrawingTemplateEditorWindow>("Drawing Editor");
win.minSize = new Vector2(900, 540);
win.Refresh();
win._tab = Tab.Templates;
win.Select(template);
}
private void OnEnable() => Refresh();
private void Refresh()
{
_templates.Clear();
_shapes.Clear();
_palettes.Clear();
_templates.AddRange(FindAllOfType<DrawingTemplateSO>());
_shapes.AddRange(FindAllOfType<ShapeSO>());
_palettes.AddRange(FindAllOfType<ColorPaletteSO>());
}
private static IEnumerable<T> FindAllOfType<T>() where T : ScriptableObject
{
var guids = AssetDatabase.FindAssets("t:" + typeof(T).Name);
foreach (var g in guids)
{
var path = AssetDatabase.GUIDToAssetPath(g);
var a = AssetDatabase.LoadAssetAtPath<T>(path);
if (a != null) yield return a;
}
}
private void OnGUI()
{
DrawToolbar();
EditorGUILayout.Space(2);
switch (_tab)
{
case Tab.Templates: DrawTemplatesTab(); break;
case Tab.Shapes: DrawShapesTab(); break;
case Tab.Palettes: DrawPalettesTab(); break;
}
}
// ─── Toolbar ──────────────────────────────────────────────────────────────
private void DrawToolbar()
{
using (new EditorGUILayout.HorizontalScope(EditorStyles.toolbar))
{
if (TabButton("Templates", _tab == Tab.Templates)) _tab = Tab.Templates;
if (TabButton("Shapes", _tab == Tab.Shapes)) _tab = Tab.Shapes;
if (TabButton("Palettes", _tab == Tab.Palettes)) _tab = Tab.Palettes;
GUILayout.FlexibleSpace();
_search = GUILayout.TextField(_search, EditorStyles.toolbarSearchField, GUILayout.Width(220));
if (GUILayout.Button("Refresh", EditorStyles.toolbarButton, GUILayout.Width(60)))
Refresh();
}
}
private static bool TabButton(string label, bool active)
{
var bg = GUI.backgroundColor;
if (active) GUI.backgroundColor = new Color(0.6f, 0.8f, 1f);
var click = GUILayout.Button(label, EditorStyles.toolbarButton, GUILayout.Width(90));
GUI.backgroundColor = bg;
return click;
}
// ─── Templates Tab ────────────────────────────────────────────────────────
private void DrawTemplatesTab()
{
using (new EditorGUILayout.HorizontalScope())
{
DrawTemplateList();
DrawSeparator();
DrawTemplateDetail();
}
}
private void DrawTemplateList()
{
using (new EditorGUILayout.VerticalScope(GUILayout.Width(260)))
{
if (GUILayout.Button("+ New Drawing Template", GUILayout.Height(26)))
CreateNewTemplate();
EditorGUILayout.LabelField($"Templates ({_templates.Count})", EditorStyles.boldLabel);
using (var scroll = new EditorGUILayout.ScrollViewScope(_leftScroll))
{
_leftScroll = scroll.scrollPosition;
foreach (var t in _templates)
{
if (t == null) continue;
if (!string.IsNullOrEmpty(_search) &&
(t.name == null || t.name.IndexOf(_search, StringComparison.OrdinalIgnoreCase) < 0) &&
(t.Id == null || t.Id.IndexOf(_search, StringComparison.OrdinalIgnoreCase) < 0))
continue;
DrawTemplateRow(t);
}
}
}
}
private void DrawTemplateRow(DrawingTemplateSO t)
{
var active = _selectedTemplate == t;
var bg = GUI.backgroundColor;
if (active) GUI.backgroundColor = new Color(0.55f, 0.8f, 1f);
using (new EditorGUILayout.HorizontalScope("box"))
{
if (t.DefaultThumbnail != null)
GUILayout.Label(AssetPreview.GetAssetPreview(t.DefaultThumbnail), GUILayout.Width(36), GUILayout.Height(36));
else
GUILayout.Label(GUIContent.none, GUILayout.Width(36), GUILayout.Height(36));
using (new EditorGUILayout.VerticalScope())
{
GUILayout.Label(string.IsNullOrEmpty(t.DisplayName) ? t.name : t.DisplayName, EditorStyles.boldLabel);
GUILayout.Label("id: " + (string.IsNullOrEmpty(t.Id) ? "<unset>" : t.Id), EditorStyles.miniLabel);
}
if (GUILayout.Button("Select", GUILayout.Width(54)))
Select(t);
}
GUI.backgroundColor = bg;
}
private void Select(DrawingTemplateSO t)
{
_selectedTemplate = t;
_lastScanReport = null;
Validate();
Repaint();
}
private void DrawTemplateDetail()
{
using (var scroll = new EditorGUILayout.ScrollViewScope(_rightScroll))
{
_rightScroll = scroll.scrollPosition;
if (_selectedTemplate == null)
{
EditorGUILayout.HelpBox("Select a template from the left list, or click '+ New Drawing Template'.", MessageType.Info);
return;
}
var t = _selectedTemplate;
var so = new SerializedObject(t);
so.Update();
EditorGUILayout.LabelField(AssetDatabase.GetAssetPath(t), EditorStyles.miniLabel);
EditorGUILayout.Space(4);
// Basic fields
EditorGUILayout.LabelField("Basics", EditorStyles.boldLabel);
EditorGUILayout.PropertyField(so.FindProperty("id"), new GUIContent("Id (Addressable Key)"));
EditorGUILayout.PropertyField(so.FindProperty("displayName"));
EditorGUILayout.PropertyField(so.FindProperty("defaultThumbnail"));
EditorGUILayout.Space(6);
EditorGUILayout.LabelField("Prefabs", EditorStyles.boldLabel);
EditorGUILayout.PropertyField(so.FindProperty("drawingPrefab"), new GUIContent("Drawing Prefab (SlotMarkers)"));
EditorGUILayout.PropertyField(so.FindProperty("coloringPrefab"), new GUIContent("Coloring Prefab (ColorRegionViews)"));
EditorGUILayout.Space(6);
EditorGUILayout.LabelField("Palette", EditorStyles.boldLabel);
DrawPaletteIdField(so.FindProperty("colorPaletteId"));
EditorGUILayout.Space(8);
EditorGUILayout.LabelField("Pieces", EditorStyles.boldLabel);
using (new EditorGUILayout.HorizontalScope())
{
if (GUILayout.Button("Scan Drawing Prefab", GUILayout.Height(22)))
{
ScanDrawingPrefab(t);
so.Update();
}
if (GUILayout.Button("Clear", GUILayout.Width(60)))
{
Undo.RecordObject(t, "Clear Pieces");
var emptyPieces = new List<ShapeSO>();
t.EditorSet(t.Id, t.DisplayName, t.DefaultThumbnail, t.DrawingPrefab, t.ColoringPrefab,
emptyPieces, t.AuthoredRegions.ToList(), t.ColorPaletteId);
EditorUtility.SetDirty(t);
so.Update();
}
}
EditorGUILayout.PropertyField(so.FindProperty("pieces"), includeChildren: true);
EditorGUILayout.Space(8);
EditorGUILayout.LabelField("Regions", EditorStyles.boldLabel);
using (new EditorGUILayout.HorizontalScope())
{
_autoAssignRegionIds = GUILayout.Toggle(_autoAssignRegionIds,
new GUIContent("Auto-assign blank Ids from GameObject name (writes back to prefab)"),
GUILayout.ExpandWidth(false));
}
using (new EditorGUILayout.HorizontalScope())
{
_mergeRegions = GUILayout.Toggle(_mergeRegions,
new GUIContent("Merge mode (keep existing entries' colors)"),
GUILayout.ExpandWidth(false));
}
using (new EditorGUILayout.HorizontalScope())
{
if (GUILayout.Button("Scan Coloring Prefab", GUILayout.Height(22)))
{
ScanColoringPrefab(t);
so.Update();
}
if (GUILayout.Button("Clear", GUILayout.Width(60)))
{
Undo.RecordObject(t, "Clear Regions");
t.EditorSet(t.Id, t.DisplayName, t.DefaultThumbnail, t.DrawingPrefab, t.ColoringPrefab,
t.Pieces.ToList(), new List<RegionAuthoring>(), t.ColorPaletteId);
EditorUtility.SetDirty(t);
so.Update();
}
}
EditorGUILayout.PropertyField(so.FindProperty("regions"), includeChildren: true);
so.ApplyModifiedProperties();
EditorGUILayout.Space(10);
DrawValidationBox();
EditorGUILayout.Space(4);
if (!string.IsNullOrEmpty(_lastScanReport))
EditorGUILayout.HelpBox(_lastScanReport, MessageType.Info);
EditorGUILayout.Space(8);
using (new EditorGUILayout.HorizontalScope())
{
if (GUILayout.Button("Validate", GUILayout.Height(28)))
Validate();
if (GUILayout.Button("Mark Addressable ('drawing')", GUILayout.Height(28)))
TryMakeAddressable(t);
if (GUILayout.Button("Ping Asset", GUILayout.Width(120), GUILayout.Height(28)))
EditorGUIUtility.PingObject(t);
}
}
}
private void DrawPaletteIdField(SerializedProperty prop)
{
using (new EditorGUILayout.HorizontalScope())
{
EditorGUILayout.PropertyField(prop, new GUIContent("Palette Id"));
var ids = _palettes.Where(p => p != null).Select(p => p.Id).Where(s => !string.IsNullOrEmpty(s)).Distinct().ToList();
if (ids.Count == 0)
{
GUILayout.Label("(no palettes)", EditorStyles.miniLabel, GUILayout.Width(90));
return;
}
var current = ids.IndexOf(prop.stringValue);
var newIndex = EditorGUILayout.Popup(current, ids.ToArray(), GUILayout.Width(150));
if (newIndex >= 0 && newIndex != current)
prop.stringValue = ids[newIndex];
}
}
// ─── Scans ────────────────────────────────────────────────────────────────
private void ScanDrawingPrefab(DrawingTemplateSO t)
{
if (t.DrawingPrefab == null)
{
_lastScanReport = "No Drawing Prefab assigned.";
return;
}
var path = AssetDatabase.GetAssetPath(t.DrawingPrefab);
var root = PrefabUtility.LoadPrefabContents(path);
try
{
var markers = root.GetComponentsInChildren<SlotMarker>(includeInactive: true);
var pieces = new List<ShapeSO>();
var missing = 0;
foreach (var m in markers)
{
if (m.Shape == null) { missing++; continue; }
if (!pieces.Contains(m.Shape)) pieces.Add(m.Shape);
}
Undo.RecordObject(t, "Scan Drawing Prefab");
t.EditorSet(t.Id, t.DisplayName, t.DefaultThumbnail, t.DrawingPrefab, t.ColoringPrefab,
pieces, t.AuthoredRegions.ToList(), t.ColorPaletteId);
EditorUtility.SetDirty(t);
_lastScanReport = $"Found {markers.Length} SlotMarker(s), {pieces.Count} unique ShapeSO. {missing} marker(s) had no ShapeSO assigned.";
Validate();
}
finally
{
PrefabUtility.UnloadPrefabContents(root);
}
}
private void ScanColoringPrefab(DrawingTemplateSO t)
{
if (t.ColoringPrefab == null)
{
_lastScanReport = "No Coloring Prefab assigned.";
return;
}
var path = AssetDatabase.GetAssetPath(t.ColoringPrefab);
var root = PrefabUtility.LoadPrefabContents(path);
var existingColors = _mergeRegions
? t.AuthoredRegions.ToDictionary(r => r.RegionId, r => r.InitialColor)
: new Dictionary<string, Color>();
try
{
var views = root.GetComponentsInChildren<ColorRegionView>(includeInactive: true);
var regions = new List<RegionAuthoring>();
var seen = new HashSet<string>();
var assigned = new List<string>();
var duplicates = new List<string>();
var blanks = new List<string>();
var prefabDirty = false;
foreach (var v in views)
{
var id = v.RegionId;
var goPath = GetHierarchyPath(v.transform, root.transform);
if (string.IsNullOrEmpty(id))
{
if (_autoAssignRegionIds)
{
var baseId = SanitizeId(v.gameObject.name);
id = MakeUniqueId(baseId, seen);
if (TrySetRegionId(v, id))
{
prefabDirty = true;
assigned.Add($"{goPath} → '{id}'");
}
else
{
blanks.Add($"{goPath} (could not set Id; backing field not found)");
continue;
}
}
else
{
blanks.Add(goPath);
continue;
}
}
if (!seen.Add(id))
{
duplicates.Add($"{goPath} (id='{id}')");
continue;
}
var img = v.GetComponent<UnityEngine.UI.Image>();
var col = existingColors.TryGetValue(id, out var keepCol)
? keepCol
: (img != null ? img.color : Color.white);
regions.Add(new RegionAuthoring { RegionId = id, InitialColor = col });
}
if (prefabDirty)
PrefabUtility.SaveAsPrefabAsset(root, path);
Undo.RecordObject(t, "Scan Coloring Prefab");
t.EditorSet(t.Id, t.DisplayName, t.DefaultThumbnail, t.DrawingPrefab, t.ColoringPrefab,
t.Pieces.ToList(), regions, t.ColorPaletteId);
EditorUtility.SetDirty(t);
var report = new System.Text.StringBuilder();
report.AppendLine($"Found {views.Length} ColorRegionView(s). Stored {regions.Count}. Merge mode: {_mergeRegions}.");
if (assigned.Count > 0)
{
report.AppendLine($"Auto-assigned {assigned.Count} blank Id(s) and wrote back to prefab:");
foreach (var a in assigned) report.AppendLine(" • " + a);
}
if (blanks.Count > 0)
{
report.AppendLine($"Skipped {blanks.Count} blank Id(s) (enable auto-assign to fix):");
foreach (var b in blanks) report.AppendLine(" • " + b);
}
if (duplicates.Count > 0)
{
report.AppendLine($"Skipped {duplicates.Count} duplicate Id(s):");
foreach (var d in duplicates) report.AppendLine(" • " + d);
}
_lastScanReport = report.ToString().TrimEnd();
Validate();
}
finally
{
PrefabUtility.UnloadPrefabContents(root);
}
}
private static bool TrySetRegionId(ColorRegionView v, string id)
{
var vso = new SerializedObject(v);
var prop = FindAutoProp(vso, "RegionId");
if (prop == null) return false;
prop.stringValue = id;
vso.ApplyModifiedPropertiesWithoutUndo();
EditorUtility.SetDirty(v);
return true;
}
// Robust lookup for [field: SerializeField] backing fields across Unity versions.
// Tries '<Name>k__BackingField', 'Name', 'name', 'm_Name', then iterates visible properties matching by name.
private static SerializedProperty FindAutoProp(SerializedObject so, string propertyName)
{
var prop = so.FindProperty("<" + propertyName + ">k__BackingField");
if (prop != null) return prop;
prop = so.FindProperty(propertyName);
if (prop != null) return prop;
var camel = char.ToLowerInvariant(propertyName[0]) + propertyName.Substring(1);
prop = so.FindProperty(camel);
if (prop != null) return prop;
prop = so.FindProperty("m_" + propertyName);
if (prop != null) return prop;
var iter = so.GetIterator();
if (!iter.NextVisible(true)) return null;
do
{
if (iter.name.IndexOf(propertyName, StringComparison.OrdinalIgnoreCase) >= 0)
return iter.Copy();
} while (iter.NextVisible(false));
return null;
}
private static string MakeUniqueId(string baseId, HashSet<string> taken)
{
if (!taken.Contains(baseId)) return baseId;
for (int i = 2; i < 10000; i++)
{
var candidate = baseId + "_" + i;
if (!taken.Contains(candidate)) return candidate;
}
return baseId + "_" + System.Guid.NewGuid().ToString("N").Substring(0, 6);
}
private static string GetHierarchyPath(Transform node, Transform root)
{
if (node == root) return node.name;
var parts = new List<string> { node.name };
var cur = node.parent;
while (cur != null && cur != root)
{
parts.Add(cur.name);
cur = cur.parent;
}
parts.Reverse();
return string.Join("/", parts);
}
// ─── Validation ───────────────────────────────────────────────────────────
private void Validate()
{
_validation.Clear();
var t = _selectedTemplate;
if (t == null) return;
if (string.IsNullOrWhiteSpace(t.Id)) _validation.Add("Id is empty.");
if (string.IsNullOrWhiteSpace(t.DisplayName)) _validation.Add("DisplayName is empty.");
if (t.DefaultThumbnail == null) _validation.Add("DefaultThumbnail is missing.");
if (t.DrawingPrefab == null) _validation.Add("DrawingPrefab is missing.");
if (t.ColoringPrefab == null) _validation.Add("ColoringPrefab is missing.");
if (string.IsNullOrWhiteSpace(t.ColorPaletteId)) _validation.Add("ColorPaletteId is empty.");
else if (!_palettes.Any(p => p != null && p.Id == t.ColorPaletteId))
_validation.Add($"No ColorPaletteSO with Id '{t.ColorPaletteId}' found in project.");
if (t.Pieces == null || t.Pieces.Count == 0)
_validation.Add("No Pieces assigned (use 'Scan Drawing Prefab').");
else
{
var dup = t.Pieces.GroupBy(p => p != null ? p.Id : null).Where(g => g.Count() > 1).Select(g => g.Key).ToList();
foreach (var d in dup) _validation.Add($"Duplicate piece Id '{d}'.");
if (t.Pieces.Any(p => p == null)) _validation.Add("A Piece slot is null.");
if (t.Pieces.Any(p => p != null && string.IsNullOrEmpty(p.Id))) _validation.Add("A Piece has empty Id.");
}
var ridDup = t.AuthoredRegions.GroupBy(r => r.RegionId).Where(g => g.Count() > 1).Select(g => g.Key).ToList();
foreach (var d in ridDup) _validation.Add($"Duplicate region Id '{d}'.");
// Cross-check: piece count vs slot count in DrawingPrefab
if (t.DrawingPrefab != null && t.Pieces != null)
{
var path = AssetDatabase.GetAssetPath(t.DrawingPrefab);
var root = PrefabUtility.LoadPrefabContents(path);
try
{
var markerCount = root.GetComponentsInChildren<SlotMarker>(true).Length;
if (markerCount != t.Pieces.Count)
_validation.Add($"Pieces count ({t.Pieces.Count}) does not match SlotMarker count in prefab ({markerCount}).");
}
finally { PrefabUtility.UnloadPrefabContents(root); }
}
}
private void DrawValidationBox()
{
if (_validation.Count == 0)
{
EditorGUILayout.HelpBox("Looks good.", MessageType.Info);
return;
}
EditorGUILayout.HelpBox(string.Join("\n", _validation.Select(v => "• " + v)), MessageType.Warning);
}
// ─── Addressables ─────────────────────────────────────────────────────────
private void TryMakeAddressable(UnityEngine.Object asset)
{
try
{
var settings = AddressableAssetSettingsDefaultObject.Settings;
if (settings == null)
{
EditorUtility.DisplayDialog("Addressables", "Addressables settings not found. Open Window > Asset Management > Addressables > Groups and click 'Create Addressables Settings' first.", "OK");
return;
}
var group = EnsureGroup(settings, DrawingsGroupName);
var path = AssetDatabase.GetAssetPath(asset);
var guid = AssetDatabase.AssetPathToGUID(path);
var entry = settings.CreateOrMoveEntry(guid, group);
var t = asset as DrawingTemplateSO;
if (t != null && !string.IsNullOrEmpty(t.Id))
entry.address = t.Id;
if (!settings.GetLabels().Contains(AddressableLabel))
settings.AddLabel(AddressableLabel);
entry.SetLabel(AddressableLabel, true, true, false);
settings.SetDirty(AddressableAssetSettings.ModificationEvent.EntryModified, entry, true);
_lastScanReport = $"Marked '{asset.name}' addressable in group '{group.Name}'. Address='{entry.address}', label='{AddressableLabel}'.";
}
catch (Exception e)
{
EditorUtility.DisplayDialog("Addressables", "Failed: " + e.Message, "OK");
}
}
private static AddressableAssetGroup EnsureGroup(AddressableAssetSettings settings, string groupName)
{
var group = settings.FindGroup(groupName);
if (group != null) return group;
System.Type[] schemaTypes;
if (settings.DefaultGroup != null && settings.DefaultGroup.Schemas.Count > 0)
schemaTypes = settings.DefaultGroup.Schemas.Select(s => s.GetType()).ToArray();
else
schemaTypes = new[] { typeof(UnityEditor.AddressableAssets.Settings.GroupSchemas.BundledAssetGroupSchema) };
return settings.CreateGroup(groupName, false, false, true, null, schemaTypes);
}
// ─── New Template ─────────────────────────────────────────────────────────
private void CreateNewTemplate()
{
if (!AssetDatabase.IsValidFolder(DefaultTemplateFolder))
EnsureFolder(DefaultTemplateFolder);
var path = EditorUtility.SaveFilePanelInProject(
"New Drawing Template", "NewDrawing", "asset",
"Choose where to save the drawing template asset.",
DefaultTemplateFolder);
if (string.IsNullOrEmpty(path)) return;
var t = CreateInstance<DrawingTemplateSO>();
var name = Path.GetFileNameWithoutExtension(path);
t.EditorSet(name, name, null, null, null, new List<ShapeSO>(), new List<RegionAuthoring>(), "defaultPalette");
AssetDatabase.CreateAsset(t, path);
AssetDatabase.SaveAssets();
Refresh();
Select(t);
}
// ─── Shapes Tab ───────────────────────────────────────────────────────────
private void DrawShapesTab()
{
using (new EditorGUILayout.HorizontalScope())
{
using (new EditorGUILayout.VerticalScope(GUILayout.Width(280)))
{
if (GUILayout.Button("+ New Shape from Sprite", GUILayout.Height(24)))
CreateShapePicker();
EditorGUILayout.LabelField("Batch import from folder:", EditorStyles.miniBoldLabel);
_batchShapeFolder = (DefaultAsset)EditorGUILayout.ObjectField(_batchShapeFolder, typeof(DefaultAsset), false);
using (new EditorGUI.DisabledScope(_batchShapeFolder == null))
{
if (GUILayout.Button("Batch Create From Folder"))
BatchCreateShapesFromFolder(_batchShapeFolder);
}
EditorGUILayout.Space(4);
EditorGUILayout.LabelField($"Shapes ({_shapes.Count})", EditorStyles.boldLabel);
using (var s = new EditorGUILayout.ScrollViewScope(_leftScroll))
{
_leftScroll = s.scrollPosition;
foreach (var sh in _shapes)
{
if (sh == null) continue;
if (!string.IsNullOrEmpty(_search) &&
sh.name.IndexOf(_search, StringComparison.OrdinalIgnoreCase) < 0 &&
(sh.Id == null || sh.Id.IndexOf(_search, StringComparison.OrdinalIgnoreCase) < 0)) continue;
DrawShapeRow(sh);
}
}
}
DrawSeparator();
DrawShapeDetail();
}
}
private void DrawShapeRow(ShapeSO sh)
{
using (new EditorGUILayout.HorizontalScope("box"))
{
var preview = sh.Sprite != null ? AssetPreview.GetAssetPreview(sh.Sprite) : null;
GUILayout.Label(preview, GUILayout.Width(36), GUILayout.Height(36));
using (new EditorGUILayout.VerticalScope())
{
GUILayout.Label(sh.name, EditorStyles.boldLabel);
GUILayout.Label("id: " + (string.IsNullOrEmpty(sh.Id) ? "<unset>" : sh.Id), EditorStyles.miniLabel);
}
if (GUILayout.Button("Edit", GUILayout.Width(48)))
{
_selectedShape = sh;
Repaint();
}
}
}
private void DrawShapeDetail()
{
using (var s = new EditorGUILayout.ScrollViewScope(_rightScroll))
{
_rightScroll = s.scrollPosition;
if (_selectedShape == null)
{
EditorGUILayout.HelpBox("Select a shape on the left, or create a new one.", MessageType.Info);
return;
}
var so = new SerializedObject(_selectedShape);
so.Update();
EditorGUILayout.LabelField(AssetDatabase.GetAssetPath(_selectedShape), EditorStyles.miniLabel);
EditorGUILayout.PropertyField(FindAutoProp(so, "Id"), new GUIContent("Id"));
EditorGUILayout.PropertyField(FindAutoProp(so, "Sprite"), new GUIContent("Sprite"));
EditorGUILayout.PropertyField(FindAutoProp(so, "DefaultSizeDelta"), new GUIContent("Default Size Delta"));
so.ApplyModifiedProperties();
EditorGUILayout.Space(8);
if (_selectedShape.Sprite != null)
{
var preview = AssetPreview.GetAssetPreview(_selectedShape.Sprite);
if (preview != null)
GUILayout.Label(preview, GUILayout.Width(160), GUILayout.Height(160));
}
EditorGUILayout.Space(8);
if (GUILayout.Button("Ping Asset", GUILayout.Width(120)))
EditorGUIUtility.PingObject(_selectedShape);
}
}
private void CreateShapePicker()
{
var path = EditorUtility.OpenFilePanelWithFilters(
"Pick sprite", Application.dataPath,
new[] { "Sprites", "png,jpg,jpeg,psd,asset" });
if (string.IsNullOrEmpty(path)) return;
if (!path.StartsWith(Application.dataPath))
{
EditorUtility.DisplayDialog("Pick sprite", "Sprite must be inside the project's Assets folder.", "OK");
return;
}
var relative = "Assets" + path.Substring(Application.dataPath.Length);
var sprite = AssetDatabase.LoadAssetAtPath<Sprite>(relative);
if (sprite == null)
{
EditorUtility.DisplayDialog("Pick sprite", "Selected file is not a Sprite asset.", "OK");
return;
}
CreateShape(sprite);
}
private void BatchCreateShapesFromFolder(DefaultAsset folder)
{
var folderPath = AssetDatabase.GetAssetPath(folder);
if (!AssetDatabase.IsValidFolder(folderPath))
{
EditorUtility.DisplayDialog("Batch import", "Selection is not a folder.", "OK");
return;
}
var guids = AssetDatabase.FindAssets("t:Sprite", new[] { folderPath });
int created = 0;
foreach (var g in guids)
{
var p = AssetDatabase.GUIDToAssetPath(g);
var spr = AssetDatabase.LoadAssetAtPath<Sprite>(p);
if (spr == null) continue;
CreateShape(spr, batch: true);
created++;
}
AssetDatabase.SaveAssets();
Refresh();
_lastScanReport = $"Batch created {created} ShapeSO from '{folderPath}'.";
}
private ShapeSO CreateShape(Sprite sprite, bool batch = false)
{
EnsureFolder(DefaultShapeFolder);
var idGuess = SanitizeId(sprite.name);
var path = $"{DefaultShapeFolder}/{idGuess}.asset";
path = AssetDatabase.GenerateUniqueAssetPath(path);
var shape = CreateInstance<ShapeSO>();
var so = new SerializedObject(shape);
FindAutoProp(so, "Id").stringValue = idGuess;
FindAutoProp(so, "Sprite").objectReferenceValue = sprite;
FindAutoProp(so, "DefaultSizeDelta").vector2Value = new Vector2(256, 256);
so.ApplyModifiedProperties();
AssetDatabase.CreateAsset(shape, path);
if (!batch)
{
AssetDatabase.SaveAssets();
Refresh();
_selectedShape = shape;
EditorGUIUtility.PingObject(shape);
}
return shape;
}
// ─── Palettes Tab ─────────────────────────────────────────────────────────
private void DrawPalettesTab()
{
using (new EditorGUILayout.HorizontalScope())
{
using (new EditorGUILayout.VerticalScope(GUILayout.Width(260)))
{
if (GUILayout.Button("+ New Color Palette", GUILayout.Height(24)))
CreatePalette();
EditorGUILayout.LabelField($"Palettes ({_palettes.Count})", EditorStyles.boldLabel);
using (var s = new EditorGUILayout.ScrollViewScope(_leftScroll))
{
_leftScroll = s.scrollPosition;
foreach (var p in _palettes)
{
if (p == null) continue;
using (new EditorGUILayout.HorizontalScope("box"))
{
using (new EditorGUILayout.VerticalScope())
{
GUILayout.Label(p.name, EditorStyles.boldLabel);
GUILayout.Label("id: " + (string.IsNullOrEmpty(p.Id) ? "<unset>" : p.Id), EditorStyles.miniLabel);
DrawPaletteSwatches(p);
}
if (GUILayout.Button("Edit", GUILayout.Width(48)))
{
_selectedPalette = p;
Repaint();
}
}
}
}
}
DrawSeparator();
using (var s = new EditorGUILayout.ScrollViewScope(_rightScroll))
{
_rightScroll = s.scrollPosition;
if (_selectedPalette == null)
{
EditorGUILayout.HelpBox("Select a palette on the left, or create a new one.", MessageType.Info);
return;
}
var so = new SerializedObject(_selectedPalette);
so.Update();
EditorGUILayout.LabelField(AssetDatabase.GetAssetPath(_selectedPalette), EditorStyles.miniLabel);
EditorGUILayout.PropertyField(FindAutoProp(so, "Id"), new GUIContent("Id"));
EditorGUILayout.PropertyField(FindAutoProp(so, "Colors"), new GUIContent("Colors"), includeChildren: true);
so.ApplyModifiedProperties();
EditorGUILayout.Space(6);
if (GUILayout.Button("Mark Addressable (key=Id)", GUILayout.Height(24)))
TryMakeAddressablePalette(_selectedPalette);
}
}
}
private void TryMakeAddressablePalette(ColorPaletteSO p)
{
try
{
var settings = AddressableAssetSettingsDefaultObject.Settings;
if (settings == null)
{
EditorUtility.DisplayDialog("Addressables", "Addressables settings not found. Open Window > Asset Management > Addressables > Groups and click 'Create Addressables Settings' first.", "OK");
return;
}
var group = EnsureGroup(settings, PalettesGroupName);
var path = AssetDatabase.GetAssetPath(p);
var guid = AssetDatabase.AssetPathToGUID(path);
var entry = settings.CreateOrMoveEntry(guid, group);
if (!string.IsNullOrEmpty(p.Id)) entry.address = p.Id;
settings.SetDirty(AddressableAssetSettings.ModificationEvent.EntryModified, entry, true);
_lastScanReport = $"Marked palette '{p.name}' addressable in group '{group.Name}'. Address='{entry.address}'.";
}
catch (Exception e)
{
EditorUtility.DisplayDialog("Addressables", "Failed: " + e.Message, "OK");
}
}
private static void DrawPaletteSwatches(ColorPaletteSO p)
{
if (p.Colors == null) return;
const int swatch = 14;
using (new EditorGUILayout.HorizontalScope())
{
foreach (var c in p.Colors)
{
var r = GUILayoutUtility.GetRect(swatch, swatch, GUILayout.Width(swatch), GUILayout.Height(swatch));
EditorGUI.DrawRect(r, c);
}
}
}
private void CreatePalette()
{
EnsureFolder(DefaultPaletteFolder);
var path = EditorUtility.SaveFilePanelInProject(
"New Color Palette", "NewPalette", "asset",
"Choose where to save the palette asset.",
DefaultPaletteFolder);
if (string.IsNullOrEmpty(path)) return;
var p = CreateInstance<ColorPaletteSO>();
var so = new SerializedObject(p);
FindAutoProp(so, "Id").stringValue = Path.GetFileNameWithoutExtension(path);
so.ApplyModifiedProperties();
AssetDatabase.CreateAsset(p, path);
AssetDatabase.SaveAssets();
Refresh();
_selectedPalette = p;
}
// ─── Helpers ──────────────────────────────────────────────────────────────
private static void DrawSeparator()
{
var r = GUILayoutUtility.GetRect(2, 0, GUILayout.Width(2), GUILayout.ExpandHeight(true));
EditorGUI.DrawRect(r, new Color(0, 0, 0, 0.25f));
}
private static void EnsureFolder(string assetPath)
{
if (AssetDatabase.IsValidFolder(assetPath)) return;
var parts = assetPath.Split('/');
var current = parts[0];
for (int i = 1; i < parts.Length; i++)
{
var next = current + "/" + parts[i];
if (!AssetDatabase.IsValidFolder(next))
AssetDatabase.CreateFolder(current, parts[i]);
current = next;
}
}
private static string SanitizeId(string raw)
{
if (string.IsNullOrEmpty(raw)) return "shape";
var chars = raw.Select(c => char.IsLetterOrDigit(c) || c == '_' ? c : '_').ToArray();
var s = new string(chars).Trim('_');
return string.IsNullOrEmpty(s) ? "shape" : s;
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 64a89f3acbab9486288ef3ff452a39c7

View File

@@ -0,0 +1,26 @@
using Darkmatter.Core.Data.Static.Features.DrawingTemplate;
using UnityEditor;
using UnityEngine;
namespace Darkmatter.Features.DrawingTemplates.Editor
{
[CustomEditor(typeof(DrawingTemplateSO))]
public sealed class DrawingTemplateInspector : UnityEditor.Editor
{
public override void OnInspectorGUI()
{
var t = (DrawingTemplateSO)target;
using (new EditorGUILayout.HorizontalScope())
{
if (GUILayout.Button("Open in Drawing Editor", GUILayout.Height(28)))
DrawingTemplateEditorWindow.OpenAndSelect(t);
if (GUILayout.Button("Ping", GUILayout.Width(60), GUILayout.Height(28)))
EditorGUIUtility.PingObject(t);
}
EditorGUILayout.Space(4);
DrawDefaultInspector();
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 7ac1d35307f6a427082cca127e61ab71

View File

@@ -0,0 +1,23 @@
{
"name": "Features.DrawingTemplates.Editor",
"rootNamespace": "Darkmatter.Features.DrawingTemplates.Editor",
"references": [
"GUID:6a005d98aed1c4439bc4689802fa2e3b",
"GUID:6a0a834eb41764f12ba55c3fb04a40cb",
"GUID:4cede189a43c349069c614e305683720",
"GUID:2ca8c3a66565544118d3d52d3922933b",
"GUID:9e24947de15b9834991c9d8411ea37cf",
"GUID:69448af7b92c7f342b298e06a37122aa"
],
"includePlatforms": [
"Editor"
],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 32c91add8e49f4e1fb2121cac770862f
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -52,11 +52,18 @@ namespace Darkmatter.Features.DrawingTemplates.Systems
_initialized = true;
}
public UniTask<Sprite> GetThumbnailAsync(string id)
public async UniTask<Sprite> GetThumbnailAsync(string id)
{
if (!_byId.TryGetValue(id, out var t))
throw new KeyNotFoundException($"Template '{id}' not in catalog. Did InitializeAsync run?");
return UniTask.FromResult(t.DefaultThumbnail);
var savedTex = await _progression.GetCachedThumbnailAsync(id);
if (savedTex != null)
{
var rect = new Rect(0, 0, savedTex.width, savedTex.height);
return Sprite.Create(savedTex, rect, new Vector2(0.5f, 0.5f));
}
return t.DefaultThumbnail;
}
public UniTask<IDrawingTemplate> LoadAsync(string id)

View File

@@ -2,11 +2,14 @@ using System;
using System.Collections.Generic;
using System.Threading;
using Cysharp.Threading.Tasks;
using Darkmatter.Core.Contracts.Features.Capture;
using Darkmatter.Core.Contracts.Features.Coloring;
using Darkmatter.Core.Contracts.Features.DrawingCatalog;
using Darkmatter.Core.Contracts.Features.GameplayFlow;
using Darkmatter.Core.Contracts.Features.Loading;
using Darkmatter.Core.Contracts.Features.Progression;
using Darkmatter.Core.Contracts.Features.ShapeBuilder;
using Darkmatter.Core.Contracts.Services.Gallery;
using Darkmatter.Core.Contracts.Services.Scenes;
using Darkmatter.Core.Data.Dynamic.Features.Progression;
using Darkmatter.Core.Data.Signals.Features.Coloring;
@@ -28,6 +31,8 @@ namespace Darkmatter.Features.GameplayFlow.Systems
private readonly IShapeBuilderController _shapeBuilder;
private readonly IColoringController _coloring;
private readonly ISceneService _scenes;
private readonly ICaptureFeature _capture;
private readonly ILoadingScreen _loadingScreen;
private readonly IEventBus _bus;
private IDrawingTemplate _template;
@@ -45,6 +50,8 @@ namespace Darkmatter.Features.GameplayFlow.Systems
IShapeBuilderController shapeBuilder,
IColoringController coloring,
ISceneService scenes,
ICaptureFeature capture,
ILoadingScreen loadingScreen,
IEventBus bus)
{
_progression = progression;
@@ -52,6 +59,8 @@ namespace Darkmatter.Features.GameplayFlow.Systems
_shapeBuilder = shapeBuilder;
_coloring = coloring;
_scenes = scenes;
_capture = capture;
_loadingScreen = loadingScreen;
_bus = bus;
}
@@ -62,7 +71,8 @@ namespace Darkmatter.Features.GameplayFlow.Systems
_templateId = _progression.LastOpenedTemplateId;
if (string.IsNullOrEmpty(_templateId))
throw new Exception("[GameplayFlow] No LastOpenedTemplateId set. ColorbookFlow must call _progression.SetLastOpenedAsync(id) before loading Gameplay.");
throw new Exception(
"[GameplayFlow] No LastOpenedTemplateId set. ColorbookFlow must call _progression.SetLastOpenedAsync(id) before loading Gameplay.");
_template = await _catalog.LoadAsync(_templateId);
ct.ThrowIfCancellationRequested();
@@ -76,38 +86,40 @@ namespace Darkmatter.Features.GameplayFlow.Systems
_assembledSub = _bus.Subscribe<ShapeAssembledSignal>(OnShapeAssembled);
_colorAppliedSub = _bus.Subscribe<ColorAppliedSignal>(OnColorApplied);
Application.quitting += OnAppQuitting;
Application.focusChanged += OnAppFocusChanged;
_loadingScreen.SetProgress(1f);
if (_phase == DrawingPhase.Coloring)
{
// Resume direct into coloring: pre-snap every piece. ShapeBuilder
// emits ShapeAssembledSignal once counter hits expected; that path
// also triggers InitializeColoring with savedColors.
var allIds = CollectAllPieceIds(_template);
await _shapeBuilder.BuildAsync(_template, allIds, ct);
var savedColors = ToColorDict(progress?.regionColors);
await _coloring.InitializeRegionsAsync(_template, savedColors, ct);
}
else
{
await _shapeBuilder.BuildAsync(_template, progress?.snappedPieces, ct);
}
_loadingScreen.Hide();
}
public async UniTask BackAsync()
public async UniTask BackAsync(CancellationToken ct)
{
await SaveCurrentAsync(captureThumbnail: _phase == DrawingPhase.Coloring);
await SaveCurrentAsync(CancellationToken.None);
_shapeBuilder.Clear();
_coloring.Clear();
await _scenes.LoadSceneAsync(GameScene.Colorbook, progress: null, cancellationToken: default);
await _scenes.LoadSceneAsync(GameScene.Colorbook, progress: null, cancellationToken: ct);
}
public async UniTask SaveAsync()
public async UniTask SaveAsync(CancellationToken ct)
{
// Explicit user-pressed save — capture thumbnail + (planned) native gallery export.
await SaveCurrentAsync(captureThumbnail: true);
// TODO: route through ICaptureService + IGalleryService once those exist.
await SaveCurrentAsync(ct);
await _capture.CapturePngAsync(saveToGallery: true, ct);
}
public async UniTask NextAsync()
public async UniTask NextAsync(CancellationToken ct)
{
await SaveCurrentAsync(captureThumbnail: true);
await SaveCurrentAsync(ct);
_progression.MarkCompleted(_templateId);
var nextId = _catalog.GetNextTemplate(_templateId);
@@ -126,26 +138,32 @@ namespace Darkmatter.Features.GameplayFlow.Systems
public void OnApplicationPaused()
{
// Fire-and-forget — pause window is small; PlayerPrefs write is sync under the hood.
SaveCurrentAsync(captureThumbnail: false).Forget();
SaveCurrentAsync(CancellationToken.None).Forget();
}
private void OnAppQuitting() => OnApplicationPaused();
private void OnAppFocusChanged(bool focused)
{
if (!focused) OnApplicationPaused();
}
private void OnShapeAssembled(ShapeAssembledSignal signal)
{
if (signal.TemplateId != _templateId) return;
EnterColoringAsync().Forget();
EnterColoringAsync(CancellationToken.None).Forget();
}
private async UniTask EnterColoringAsync()
private async UniTask EnterColoringAsync(CancellationToken ct)
{
_phase = DrawingPhase.Coloring;
var progress = _progression.GetProgress(_templateId);
var savedColors = ToColorDict(progress?.regionColors);
await _coloring.InitializeRegionsAsync(_template, savedColors, _scopeCts.Token);
_shapeBuilder.DespawnDrawing();
// Bare-assembled snapshot — catalog should show the puzzle outline even if
// the child never paints (per readme §12b save matrix).
await SaveCurrentAsync(captureThumbnail: true);
await SaveCurrentAsync(ct);
}
private void OnColorApplied(ColorAppliedSignal _)
@@ -162,12 +180,15 @@ namespace Darkmatter.Features.GameplayFlow.Systems
try
{
await UniTask.Delay(AutosaveDebounceMs, cancellationToken: ct);
await SaveCurrentAsync(captureThumbnail: false);
await SaveCurrentAsync(ct);
}
catch (OperationCanceledException)
{
/* superseded by next paint or scope end */
}
catch (OperationCanceledException) { /* superseded by next paint or scope end */ }
}
private async UniTask SaveCurrentAsync(bool captureThumbnail)
private async UniTask SaveCurrentAsync(CancellationToken ct)
{
if (string.IsNullOrEmpty(_templateId)) return;
@@ -183,30 +204,18 @@ namespace Darkmatter.Features.GameplayFlow.Systems
phase = _phase,
snappedPieces = snappedIds,
regionColors = regionEntries,
hasThumbnail = captureThumbnail || (existing?.hasThumbnail ?? false),
hasThumbnail = true,
hasBeenCompleted = existing?.hasBeenCompleted ?? false,
completionCount = existing?.completionCount ?? 0,
UpdatedUtc = DateTime.UtcNow,
FirstCompletedUtc = existing?.FirstCompletedUtc,
};
byte[] thumbnailPng = null;
if (captureThumbnail)
{
// TODO: replace with ICaptureService.CaptureAsync() once available.
// For now we record hasThumbnail=true but write no PNG.
}
var thumbnailPng = await _capture.CapturePngAsync(saveToGallery: false, ct);
await _progression.SaveProgressAsync(progress, thumbnailPng);
}
private static IReadOnlyCollection<string> CollectAllPieceIds(IDrawingTemplate template)
{
var ids = new List<string>(template.Pieces.Count);
foreach (var p in template.Pieces) ids.Add(p.Id);
return ids;
}
private static IReadOnlyDictionary<string, Color> ToColorDict(List<RegionColorEntry> entries)
{
var dict = new Dictionary<string, Color>();
@@ -219,6 +228,9 @@ namespace Darkmatter.Features.GameplayFlow.Systems
public void Dispose()
{
Application.quitting -= OnAppQuitting;
Application.focusChanged -= OnAppFocusChanged;
_assembledSub?.Dispose();
_colorAppliedSub?.Dispose();
_autosaveCts?.Cancel();

View File

@@ -43,7 +43,7 @@ namespace Darkmatter.Features.History
{
_view.SetUndoInteractable(_undoStack.CanUndo);
_view.SetRedoInteractable(_undoStack.CanRedo);
_view.SetClearInteractable(_undoStack.CanUndo || _undoStack.CanRedo);
_view.SetClearInteractable(_undoStack.CanUndo);
}
public void Dispose()

View File

@@ -1,4 +1,3 @@
using System;
using UnityEngine;
using UnityEngine.UI;
@@ -16,20 +15,31 @@ namespace Darkmatter.Features.History
void Start()
{
undoButton.onClick.AddListener(() => OnUndoClicked?.Invoke());
redoButton.onClick.AddListener(() => OnRedoClicked?.Invoke());
clearButton.onClick.AddListener(() => OnClearClicked?.Invoke());
if (undoButton != null) undoButton.onClick.AddListener(() => OnUndoClicked?.Invoke());
if (redoButton != null) redoButton.onClick.AddListener(() => OnRedoClicked?.Invoke());
if (clearButton != null) clearButton.onClick.AddListener(() => OnClearClicked?.Invoke());
}
public void SetUndoInteractable(bool value) => undoButton.interactable = value;
public void SetRedoInteractable(bool value) => redoButton.interactable = value;
public void SetClearInteractable(bool value) => clearButton.interactable = value;
public void SetUndoInteractable(bool value)
{
if (undoButton != null) undoButton.interactable = value;
}
public void SetRedoInteractable(bool value)
{
if (redoButton != null) redoButton.interactable = value;
}
public void SetClearInteractable(bool value)
{
if (clearButton != null) clearButton.interactable = value;
}
private void OnDestroy()
{
undoButton.onClick.RemoveListener(() => OnUndoClicked?.Invoke());
redoButton.onClick.RemoveListener(() => OnRedoClicked?.Invoke());
clearButton.onClick.RemoveListener(() => OnClearClicked?.Invoke());
if (undoButton != null) undoButton.onClick.RemoveAllListeners();
if (redoButton != null) redoButton.onClick.RemoveAllListeners();
if (clearButton != null) clearButton.onClick.RemoveAllListeners();
}
}
}

View File

@@ -11,20 +11,20 @@ namespace Darkmatter.Features.ShapeBuilder.Commands
private readonly Vector2 _prevSize;
private readonly Quaternion _prevRot;
private readonly Transform _prevParent;
private readonly int _prevSiblingIndex;
public SnapPieceCommand(ShapePiece piece)
{
_piece = piece;
var rt = piece.RectTransform;
_prevPos = rt.anchoredPosition;
_prevSize = rt.sizeDelta;
_prevRot = rt.localRotation;
_prevParent = rt.parent;
_prevParent = piece.HomeParent;
_prevSiblingIndex = piece.HomeSiblingIndex;
_prevPos = piece.TrayPosition;
_prevSize = piece.TraySize;
_prevRot = Quaternion.identity;
}
public void Execute() => _piece.SnapInternal();
public void Undo() => _piece.UnsnapInternal(_prevParent, _prevPos, _prevSize, _prevRot);
public void Undo() => _piece.UnsnapInternal(_prevParent, _prevSiblingIndex, _prevPos, _prevSize, _prevRot);
}
}

View File

@@ -20,7 +20,7 @@ namespace Darkmatter.Features.ShapeBuilder.Systems
{
public class ShapeBuilderController : IShapeBuilderController, IDisposable
{
private const string PiecePrefabKey = "ShapeBuilder/Piece";
private const string PiecePrefabKey = "ShapePiece";
private string _currentTemplateId;
private int _expected;
@@ -173,6 +173,16 @@ namespace Darkmatter.Features.ShapeBuilder.Systems
return _snappedPieceIds;
}
public void DespawnDrawing()
{
foreach (var piece in _pieces)
if (piece != null) Object.Destroy(piece.gameObject);
_pieces.Clear();
if (_drawingInstance != null) Object.Destroy(_drawingInstance);
_drawingInstance = null;
}
public void Clear()
{
_undo.Drop();

View File

@@ -1,3 +1,4 @@
using Darkmatter.Core.Contracts.Features.GameplayFlow;
using Darkmatter.Core.Contracts.Features.History;
using Darkmatter.Core.Contracts.Services.Audio;
using Darkmatter.Core.Data.Static.Features.ShapeBuilder;
@@ -14,19 +15,22 @@ namespace Darkmatter.Features.ShapeBuilder.Systems
private readonly ISfxPlayer _sfx;
private readonly IEventBus _bus;
private readonly IUndoStack _undo;
private readonly IGameplaySceneRefs _refs;
public ShapePieceFactory(
ShapeHolderView holder,
ShapeBuilderConfig cfg,
ISfxPlayer sfx,
IEventBus bus,
IUndoStack undo)
IUndoStack undo,
IGameplaySceneRefs refs)
{
_holder = holder;
_cfg = cfg;
_sfx = sfx;
_bus = bus;
_undo = undo;
_refs = refs;
}
public ShapePiece Create(GameObject prefab, ShapeSO shape, SlotMarker slot, Vector2 trayPos)
@@ -35,7 +39,7 @@ namespace Darkmatter.Features.ShapeBuilder.Systems
go.name = $"Piece_{shape.Id}";
var piece = go.GetComponent<ShapePiece>();
piece.Setup(shape, slot, _cfg, _sfx, _bus, _undo, trayPos);
piece.Setup(shape, slot, _cfg, _sfx, _bus, _undo, trayPos, _refs.PaperRoot);
return piece;
}
}

View File

@@ -27,12 +27,19 @@ namespace Darkmatter.Features.ShapeBuilder.UI
private IUndoStack _undo;
private Vector2 _trayPos;
private Vector2 _traySize;
private RectTransform _dragRoot;
private Transform _homeParent;
private int _homeSiblingIndex;
// Per-drag state
private RectTransform _rt;
private RectTransform _parentRect;
private Camera _eventCam;
private Vector2 _grabOffset;
private Vector2 _trayPosInDragRoot;
private Vector2 _dragSizeDelta;
private Vector3 _dragLocalScale;
private Sequence _previewSeq;
private bool _locked;
private bool _inPreview;
@@ -40,6 +47,10 @@ namespace Darkmatter.Features.ShapeBuilder.UI
public string PieceId => _shape != null ? _shape.Id : null;
public bool IsLocked => _locked;
public RectTransform RectTransform => _rt != null ? _rt : (_rt = (RectTransform)transform);
public Transform HomeParent => _homeParent;
public int HomeSiblingIndex => _homeSiblingIndex;
public Vector2 TrayPosition => _trayPos;
public Vector2 TraySize => _traySize;
public void Setup(
ShapeSO shape,
@@ -48,7 +59,8 @@ namespace Darkmatter.Features.ShapeBuilder.UI
ISfxPlayer sfx,
IEventBus bus,
IUndoStack undo,
Vector2 trayPos)
Vector2 trayPos,
RectTransform dragRoot)
{
_shape = shape;
_slot = slot;
@@ -58,6 +70,10 @@ namespace Darkmatter.Features.ShapeBuilder.UI
_undo = undo;
_trayPos = trayPos;
_traySize = shape.DefaultSizeDelta;
_dragRoot = dragRoot;
_homeParent = RectTransform.parent;
_homeSiblingIndex = RectTransform.GetSiblingIndex();
image.sprite = shape.Sprite;
ApplyTrayPose();
@@ -66,8 +82,18 @@ namespace Darkmatter.Features.ShapeBuilder.UI
public void OnBeginDrag(PointerEventData e)
{
if (_locked) return;
if (_dragRoot != null && RectTransform.parent != _dragRoot)
{
RectTransform.SetParent(_dragRoot, worldPositionStays: true);
RectTransform.SetAsLastSibling();
}
_parentRect = (RectTransform)RectTransform.parent;
_eventCam = e.pressEventCamera;
_trayPosInDragRoot = RectTransform.anchoredPosition;
_dragSizeDelta = RectTransform.sizeDelta;
_dragLocalScale = RectTransform.localScale;
_grabOffset = RectTransform.anchoredPosition - ScreenToLocal(e.position);
_inPreview = false;
}
@@ -77,75 +103,122 @@ namespace Darkmatter.Features.ShapeBuilder.UI
if (_locked) return;
var pointerLocal = ScreenToLocal(e.position) + _grabOffset;
var slotPos = _slot.RectTransform.anchoredPosition;
float dist = Vector2.Distance(pointerLocal, slotPos);
bool insidePreview = IsOverSlot(e.position);
if (dist <= _cfg.PreviewRadius)
{
if (!_inPreview)
if (insidePreview && !_inPreview)
{
_inPreview = true;
_sfx.Play(SfxId.ShapeHover);
AnimatePreviewPose(toSlot: true);
}
ApplyPreviewLerp(pointerLocal, dist);
}
else
else if (!insidePreview && _inPreview)
{
_inPreview = false;
RectTransform.anchoredPosition = pointerLocal;
RectTransform.sizeDelta = _traySize;
RectTransform.localRotation = Quaternion.identity;
AnimatePreviewPose(toSlot: false);
}
if (!_inPreview)
RectTransform.anchoredPosition = pointerLocal;
}
public void OnEndDrag(PointerEventData e)
{
if (_locked) return;
float dist = Vector2.Distance(
RectTransform.anchoredPosition,
_slot.RectTransform.anchoredPosition);
if (dist <= _cfg.SnapRadius)
if (IsOverSlot(e.position))
_undo.Push(new SnapPieceCommand(this));
else
ReturnToTray();
}
private void ApplyPreviewLerp(Vector2 pointerLocal, float dist)
private bool IsOverSlot(Vector2 screenPos)
{
float t = Mathf.Clamp01(1f - dist / _cfg.PreviewRadius);
if (_cfg.PreviewCurve != null) t = _cfg.PreviewCurve.Evaluate(t);
return RectTransformUtility.RectangleContainsScreenPoint(
_slot.RectTransform, screenPos, _eventCam);
}
private void AnimatePreviewPose(bool toSlot)
{
if (_previewSeq.isAlive) _previewSeq.Stop();
if (toSlot)
{
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);
_previewSeq = Sequence.Create()
.Group(Tween.UIAnchoredPosition(RectTransform, SlotPosInDragSpace(), _cfg.SnapDuration, Ease.OutQuad))
.Group(Tween.LocalScale(RectTransform, SlotScaleInDragSpace(), _cfg.SnapDuration, Ease.OutQuad))
.Group(Tween.LocalRotation(RectTransform, SlotRotInDragSpace(), _cfg.SnapDuration, Ease.OutQuad))
.Group(Tween.UISizeDelta(RectTransform, slot.sizeDelta, _cfg.SnapDuration, Ease.OutQuad));
}
else
{
_previewSeq = Sequence.Create()
.Group(Tween.LocalScale(RectTransform, _dragLocalScale, _cfg.SnapDuration, Ease.OutQuad))
.Group(Tween.LocalRotation(RectTransform, Quaternion.identity, _cfg.SnapDuration, Ease.OutQuad))
.Group(Tween.UISizeDelta(RectTransform, _dragSizeDelta, _cfg.SnapDuration, Ease.OutQuad));
}
}
private Vector2 SlotPosInDragSpace()
{
Vector3 worldPos = _slot.RectTransform.position;
Vector3 local = _parentRect.InverseTransformPoint(worldPos);
Vector2 parentSize = _parentRect.rect.size;
Vector2 anchorRef = (RectTransform.anchorMin - _parentRect.pivot) * parentSize;
return new Vector2(local.x - anchorRef.x, local.y - anchorRef.y);
}
private void StopPreviewTweens()
{
if (_previewSeq.isAlive) _previewSeq.Stop();
_previewSeq = default;
_inPreview = false;
}
private Quaternion SlotRotInDragSpace()
{
return Quaternion.Inverse(_parentRect.rotation) * _slot.RectTransform.rotation;
}
private Vector3 SlotScaleInDragSpace()
{
Vector3 parentLossy = _parentRect.lossyScale;
Vector3 slotLossy = _slot.RectTransform.lossyScale;
return new Vector3(
slotLossy.x / Mathf.Max(0.0001f, parentLossy.x),
slotLossy.y / Mathf.Max(0.0001f, parentLossy.y),
slotLossy.z / Mathf.Max(0.0001f, parentLossy.z));
}
internal void SnapInternal()
{
StopPreviewTweens();
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);
Tween.Position(RectTransform, slot.position, _cfg.SnapDuration, Ease.OutBack);
Tween.Rotation(RectTransform, slot.rotation, _cfg.SnapDuration, Ease.OutBack);
Tween.LocalScale(RectTransform, slot.localScale, _cfg.SnapDuration, Ease.OutBack);
Tween.UISizeDelta(RectTransform, slot.sizeDelta, _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)
internal void UnsnapInternal(Transform parent, int siblingIndex, Vector2 pos, Vector2 size, Quaternion rot)
{
_locked = false;
image.raycastTarget = true;
RectTransform.SetParent(parent, worldPositionStays: false);
Tween.StopAll(onTarget: RectTransform);
Tween.UIAnchoredPosition(RectTransform, pos, _cfg.ReturnDuration, Ease.OutQuad);
Tween.UISizeDelta (RectTransform, size, _cfg.ReturnDuration, Ease.OutQuad);
Tween.LocalRotation (RectTransform, rot, _cfg.ReturnDuration, Ease.OutQuad);
RectTransform.SetParent(parent, worldPositionStays: false);
if (siblingIndex >= 0) RectTransform.SetSiblingIndex(siblingIndex);
RectTransform.anchoredPosition = pos;
RectTransform.sizeDelta = size;
RectTransform.localRotation = rot;
RectTransform.localScale = Vector3.one;
_sfx.Play(SfxId.ShapeReturn);
_bus.Publish(new PieceUnsnappedSignal(_shape.Id));
@@ -155,25 +228,37 @@ namespace Darkmatter.Features.ShapeBuilder.UI
{
Lock();
var slot = _slot.RectTransform;
RectTransform.anchoredPosition = slot.anchoredPosition;
RectTransform.position = slot.position;
RectTransform.rotation = slot.rotation;
RectTransform.localScale = slot.localScale;
RectTransform.sizeDelta = slot.sizeDelta;
RectTransform.localRotation = slot.localRotation;
}
private void ReturnToTray()
{
StopPreviewTweens();
_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));
.Group(Tween.UIAnchoredPosition(RectTransform, _trayPosInDragRoot, _cfg.ReturnDuration, Ease.OutQuad))
.Group(Tween.LocalScale(RectTransform, _dragLocalScale, _cfg.ReturnDuration, Ease.OutQuad))
.Group(Tween.LocalRotation(RectTransform, Quaternion.identity, _cfg.ReturnDuration, Ease.OutQuad))
.Group(Tween.UISizeDelta(RectTransform, _dragSizeDelta, _cfg.ReturnDuration, Ease.OutQuad))
.ChainCallback(RestoreToHomeParent);
}
private void RestoreToHomeParent()
{
if (this == null || RectTransform == null || _homeParent == null) return;
RectTransform.SetParent(_homeParent, worldPositionStays: false);
RectTransform.SetSiblingIndex(_homeSiblingIndex);
ApplyTrayPose();
}
private void Lock()
{
_locked = true;
image.raycastTarget = false;
RectTransform.SetParent(_slot.RectTransform.parent, worldPositionStays: false);
RectTransform.SetParent(_slot.RectTransform.parent, worldPositionStays: true);
}
private void ApplyTrayPose()

View File

@@ -1,52 +1,88 @@
using System.Threading;
using Cysharp.Threading.Tasks;
using Darkmatter.Core.Contracts.Services.Camera;
using Darkmatter.Core.Contracts.Services.Capture;
using UnityEngine;
using CameraType = Darkmatter.Core.Enums.Services.Camera.CameraType;
namespace Darkmatter.Services.Capture
{
public class CaptureService : ICaptureService
{
private readonly ICameraService _cameraService;
public CaptureService(ICameraService cameraService)
{
_cameraService = cameraService;
}
public async UniTask<Sprite> CapturePngAsync(GameObject captureObject, float captureSize,
public async UniTask<byte[]> CapturePngAsync(GameObject captureObject, float scale,
CancellationToken cancellationToken = default)
{
var captureCamera = _cameraService.GetCamera(CameraType.CaptureCamera);
await UniTask.WaitForEndOfFrame(cancellationToken);
await UniTask.Yield(PlayerLoopTiming.Update, cancellationToken);
var fullScreen = ScreenCapture.CaptureScreenshotAsTexture();
try
{
Rect crop = ComputeCropRect(captureObject, fullScreen.width, fullScreen.height);
int cropW = Mathf.Max(1, (int)crop.width);
int cropH = Mathf.Max(1, (int)crop.height);
int size = Mathf.RoundToInt(captureSize);
var renderTexture = RenderTexture.GetTemporary(size, size, 24);
var previousTarget = captureCamera.targetTexture;
var previousActive = RenderTexture.active;
var cropped = new Texture2D(cropW, cropH, TextureFormat.RGBA32, mipChain: false);
try
{
cropped.SetPixels(fullScreen.GetPixels((int)crop.x, (int)crop.y, cropW, cropH));
cropped.Apply();
int targetW = Mathf.Max(1, Mathf.RoundToInt(cropW * scale));
int targetH = Mathf.Max(1, Mathf.RoundToInt(cropH * scale));
Texture2D output = cropped;
if (output.width != targetW || output.height != targetH)
output = Resize(cropped, targetW, targetH);
try
{
captureCamera.targetTexture = renderTexture;
captureCamera.Render();
RenderTexture.active = renderTexture;
var texture = new Texture2D(size, size, TextureFormat.RGBA32, false);
texture.ReadPixels(new Rect(0, 0, size, size), 0, 0);
texture.Apply();
return Sprite.Create(texture, new Rect(0, 0, size, size), new Vector2(0.5f, 0.5f));
return output.EncodeToPNG();
}
finally
{
captureCamera.targetTexture = previousTarget;
RenderTexture.active = previousActive;
RenderTexture.ReleaseTemporary(renderTexture);
if (output != cropped) Object.Destroy(output);
}
}
finally
{
Object.Destroy(cropped);
}
}
finally
{
Object.Destroy(fullScreen);
}
}
private static Rect ComputeCropRect(GameObject target, int screenW, int screenH)
{
if (target == null || target.transform is not RectTransform rt)
return new Rect(0, 0, screenW, screenH);
var corners = new Vector3[4];
rt.GetWorldCorners(corners);
// ScreenSpaceOverlay canvas: world corners are already in screen pixels.
float minX = Mathf.Clamp(corners[0].x, 0, screenW);
float minY = Mathf.Clamp(corners[0].y, 0, screenH);
float maxX = Mathf.Clamp(corners[2].x, 0, screenW);
float maxY = Mathf.Clamp(corners[2].y, 0, screenH);
return Rect.MinMaxRect(minX, minY, maxX, maxY);
}
private static Texture2D Resize(Texture2D src, int width, int height)
{
var rt = RenderTexture.GetTemporary(width, height);
var prev = RenderTexture.active;
try
{
Graphics.Blit(src, rt);
RenderTexture.active = rt;
var dst = new Texture2D(width, height, TextureFormat.RGBA32, mipChain: false);
dst.ReadPixels(new Rect(0, 0, width, height), 0, 0);
dst.Apply();
return dst;
}
finally
{
RenderTexture.active = prev;
RenderTexture.ReleaseTemporary(rt);
}
}
}

View File

@@ -119,6 +119,19 @@ TextureImporter:
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 4
buildTarget: iOS
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites: []

View File

@@ -3,7 +3,7 @@ guid: 1a8737cfb07a94a4e9840c2181ebca6e
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 12
serializedVersion: 13
mipmaps:
mipMapMode: 0
enableMipMap: 0
@@ -67,7 +67,7 @@ TextureImporter:
swizzle: 50462976
cookieLightType: 0
platformSettings:
- serializedVersion: 3
- serializedVersion: 4
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
@@ -80,7 +80,7 @@ TextureImporter:
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
- serializedVersion: 4
buildTarget: WebGL
maxTextureSize: 256
resizeAlgorithm: 0
@@ -93,7 +93,7 @@ TextureImporter:
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
- serializedVersion: 4
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
@@ -106,7 +106,7 @@ TextureImporter:
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
- serializedVersion: 4
buildTarget: Server
maxTextureSize: 2048
resizeAlgorithm: 0
@@ -119,8 +119,8 @@ TextureImporter:
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: iPhone
- serializedVersion: 4
buildTarget: iOS
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
@@ -132,7 +132,7 @@ TextureImporter:
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
- serializedVersion: 4
buildTarget: Android
maxTextureSize: 2048
resizeAlgorithm: 0
@@ -145,8 +145,8 @@ TextureImporter:
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Windows Store Apps
- serializedVersion: 4
buildTarget: WindowsStoreApps
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
@@ -162,6 +162,7 @@ TextureImporter:
serializedVersion: 2
sprites: []
outline: []
customData:
physicsShape: []
bones: []
spriteID: 5e97eb03825dee720800000000000000
@@ -171,6 +172,8 @@ TextureImporter:
edges: []
weights: []
secondaryTextures: []
spriteCustomMetadata:
entries: []
nameFileIdTable: {}
mipmapLimitGroupName:
pSDRemoveMatte: 0

View File

@@ -109,6 +109,32 @@ TextureImporter:
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 4
buildTarget: WebGL
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 4
buildTarget: iOS
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites:

Binary file not shown.

After

Width:  |  Height:  |  Size: 146 KiB

View File

@@ -0,0 +1,182 @@
fileFormatVersion: 2
guid: b67ad040e6b7d4ed4ad289d72b2206cf
TextureImporter:
internalIDToNameTable:
- first:
213: -2204038546871774018
second: colorbookref_0
externalObjects: {}
serializedVersion: 13
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
flipGreenChannel: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
vTOnly: 0
ignoreMipmapLimit: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: 1
aniso: 1
mipBias: 0
wrapU: 1
wrapV: 1
wrapW: 1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 1
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 8
textureShape: 1
singleChannelComponent: 0
flipbookRows: 1
flipbookColumns: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
ignorePngGamma: 0
applyGammaDecoding: 0
swizzle: 50462976
cookieLightType: 0
platformSettings:
- serializedVersion: 4
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 4
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 4
buildTarget: Android
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 4
buildTarget: WebGL
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 4
buildTarget: iOS
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites:
- serializedVersion: 2
name: colorbookref_0
rect:
serializedVersion: 2
x: 0
y: 0
width: 710
height: 399
alignment: 0
pivot: {x: 0, y: 0}
border: {x: 0, y: 0, z: 0, w: 0}
customData:
outline: []
physicsShape: []
tessellationDetail: -1
bones: []
spriteID: eb4907e7e9ea961e0800000000000000
internalID: -2204038546871774018
vertices: []
indices:
edges: []
weights: []
outline: []
customData:
physicsShape: []
bones: []
spriteID: 5e97eb03825dee720800000000000000
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
spriteCustomMetadata:
entries: []
nameFileIdTable:
colorbookref_0: -2204038546871774018
mipmapLimitGroupName:
pSDRemoveMatte: 0
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View File

@@ -7,7 +7,7 @@ TextureImporter:
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 1
sRGBTexture: 0
linearTexture: 0
fadeOut: 0
borderMipMap: 0
@@ -134,7 +134,51 @@ TextureImporter:
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites: []
sprites:
- serializedVersion: 2
name: Car1_Reference(1)_0
rect:
serializedVersion: 2
x: 226
y: 329
width: 218
height: 213
alignment: 0
pivot: {x: 0, y: 0}
border: {x: 0, y: 0, z: 0, w: 0}
customData:
outline: []
physicsShape: []
tessellationDetail: 0
bones: []
spriteID: 2f976fcdaa1f340788955aad311c79d6
internalID: -1669840421
vertices: []
indices:
edges: []
weights: []
- serializedVersion: 2
name: Car1_Reference(1)_1
rect:
serializedVersion: 2
x: 432
y: 79
width: 457
height: 463
alignment: 0
pivot: {x: 0, y: 0}
border: {x: 0, y: 0, z: 0, w: 0}
customData:
outline: []
physicsShape: []
tessellationDetail: 0
bones: []
spriteID: bc3bcf0c16643491da2d92cfdffedc9c
internalID: -702197950
vertices: []
indices:
edges: []
weights: []
outline: []
customData:
physicsShape: []
@@ -148,7 +192,9 @@ TextureImporter:
secondaryTextures: []
spriteCustomMetadata:
entries: []
nameFileIdTable: {}
nameFileIdTable:
Car1_Reference(1)_0: -1669840421
Car1_Reference(1)_1: -702197950
mipmapLimitGroupName:
pSDRemoveMatte: 0
userData:

View File

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

View File

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

@@ -67,7 +67,7 @@ TextureImporter:
swizzle: 50462976
cookieLightType: 0
platformSettings:
- serializedVersion: 3
- serializedVersion: 4
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
@@ -80,7 +80,7 @@ TextureImporter:
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
- serializedVersion: 4
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
@@ -93,8 +93,8 @@ TextureImporter:
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: iPhone
- serializedVersion: 4
buildTarget: iOS
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
@@ -106,7 +106,7 @@ TextureImporter:
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
- serializedVersion: 4
buildTarget: WebGL
maxTextureSize: 2048
resizeAlgorithm: 0
@@ -119,7 +119,7 @@ TextureImporter:
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
- serializedVersion: 4
buildTarget: Android
maxTextureSize: 2048
resizeAlgorithm: 0
@@ -136,6 +136,7 @@ TextureImporter:
serializedVersion: 2
sprites: []
outline: []
customData:
physicsShape: []
bones: []
spriteID: 5e97eb03825dee720800000000000000
@@ -145,6 +146,8 @@ TextureImporter:
edges: []
weights: []
secondaryTextures: []
spriteCustomMetadata:
entries: []
nameFileIdTable: {}
mipmapLimitGroupName:
pSDRemoveMatte: 0

View File

@@ -67,7 +67,7 @@ TextureImporter:
swizzle: 50462976
cookieLightType: 0
platformSettings:
- serializedVersion: 3
- serializedVersion: 4
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
@@ -80,7 +80,7 @@ TextureImporter:
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
- serializedVersion: 4
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
@@ -93,7 +93,7 @@ TextureImporter:
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
- serializedVersion: 4
buildTarget: WebGL
maxTextureSize: 2048
resizeAlgorithm: 0
@@ -106,7 +106,7 @@ TextureImporter:
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
- serializedVersion: 4
buildTarget: Android
maxTextureSize: 2048
resizeAlgorithm: 0
@@ -119,10 +119,24 @@ TextureImporter:
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 4
buildTarget: iOS
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
customData:
physicsShape: []
bones: []
spriteID: 5e97eb03825dee720800000000000000
@@ -132,6 +146,8 @@ TextureImporter:
edges: []
weights: []
secondaryTextures: []
spriteCustomMetadata:
entries: []
nameFileIdTable: {}
mipmapLimitGroupName:
pSDRemoveMatte: 0

View File

@@ -67,7 +67,7 @@ TextureImporter:
swizzle: 50462976
cookieLightType: 0
platformSettings:
- serializedVersion: 3
- serializedVersion: 4
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
@@ -80,7 +80,7 @@ TextureImporter:
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
- serializedVersion: 4
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
@@ -93,7 +93,7 @@ TextureImporter:
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
- serializedVersion: 4
buildTarget: WebGL
maxTextureSize: 2048
resizeAlgorithm: 0
@@ -106,7 +106,7 @@ TextureImporter:
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
- serializedVersion: 4
buildTarget: Android
maxTextureSize: 2048
resizeAlgorithm: 0
@@ -119,10 +119,24 @@ TextureImporter:
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 4
buildTarget: iOS
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
customData:
physicsShape: []
bones: []
spriteID: 5e97eb03825dee720800000000000000
@@ -132,6 +146,8 @@ TextureImporter:
edges: []
weights: []
secondaryTextures: []
spriteCustomMetadata:
entries: []
nameFileIdTable: {}
mipmapLimitGroupName:
pSDRemoveMatte: 0

View File

@@ -67,7 +67,7 @@ TextureImporter:
swizzle: 50462976
cookieLightType: 0
platformSettings:
- serializedVersion: 3
- serializedVersion: 4
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
@@ -80,7 +80,7 @@ TextureImporter:
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
- serializedVersion: 4
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
@@ -93,7 +93,7 @@ TextureImporter:
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
- serializedVersion: 4
buildTarget: WebGL
maxTextureSize: 2048
resizeAlgorithm: 0
@@ -106,7 +106,7 @@ TextureImporter:
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
- serializedVersion: 4
buildTarget: Android
maxTextureSize: 2048
resizeAlgorithm: 0
@@ -119,10 +119,24 @@ TextureImporter:
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 4
buildTarget: iOS
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
customData:
physicsShape: []
bones: []
spriteID: 5e97eb03825dee720800000000000000
@@ -132,6 +146,8 @@ TextureImporter:
edges: []
weights: []
secondaryTextures: []
spriteCustomMetadata:
entries: []
nameFileIdTable: {}
mipmapLimitGroupName:
pSDRemoveMatte: 0

View File

@@ -67,7 +67,7 @@ TextureImporter:
swizzle: 50462976
cookieLightType: 0
platformSettings:
- serializedVersion: 3
- serializedVersion: 4
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
@@ -80,7 +80,7 @@ TextureImporter:
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
- serializedVersion: 4
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
@@ -93,7 +93,7 @@ TextureImporter:
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
- serializedVersion: 4
buildTarget: WebGL
maxTextureSize: 2048
resizeAlgorithm: 0
@@ -106,7 +106,7 @@ TextureImporter:
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
- serializedVersion: 4
buildTarget: Android
maxTextureSize: 2048
resizeAlgorithm: 0
@@ -119,10 +119,24 @@ TextureImporter:
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 4
buildTarget: iOS
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
customData:
physicsShape: []
bones: []
spriteID: 5e97eb03825dee720800000000000000
@@ -132,6 +146,8 @@ TextureImporter:
edges: []
weights: []
secondaryTextures: []
spriteCustomMetadata:
entries: []
nameFileIdTable: {}
mipmapLimitGroupName:
pSDRemoveMatte: 0

View File

@@ -67,7 +67,7 @@ TextureImporter:
swizzle: 50462976
cookieLightType: 0
platformSettings:
- serializedVersion: 3
- serializedVersion: 4
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
@@ -80,7 +80,7 @@ TextureImporter:
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
- serializedVersion: 4
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
@@ -93,7 +93,7 @@ TextureImporter:
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
- serializedVersion: 4
buildTarget: WebGL
maxTextureSize: 2048
resizeAlgorithm: 0
@@ -106,7 +106,7 @@ TextureImporter:
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
- serializedVersion: 4
buildTarget: Android
maxTextureSize: 2048
resizeAlgorithm: 0
@@ -119,10 +119,24 @@ TextureImporter:
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 4
buildTarget: iOS
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
customData:
physicsShape: []
bones: []
spriteID: 5e97eb03825dee720800000000000000
@@ -132,6 +146,8 @@ TextureImporter:
edges: []
weights: []
secondaryTextures: []
spriteCustomMetadata:
entries: []
nameFileIdTable: {}
mipmapLimitGroupName:
pSDRemoveMatte: 0

View File

@@ -67,7 +67,7 @@ TextureImporter:
swizzle: 50462976
cookieLightType: 0
platformSettings:
- serializedVersion: 3
- serializedVersion: 4
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
@@ -80,7 +80,7 @@ TextureImporter:
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
- serializedVersion: 4
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
@@ -93,7 +93,7 @@ TextureImporter:
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
- serializedVersion: 4
buildTarget: WebGL
maxTextureSize: 2048
resizeAlgorithm: 0
@@ -106,7 +106,7 @@ TextureImporter:
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
- serializedVersion: 4
buildTarget: Android
maxTextureSize: 2048
resizeAlgorithm: 0
@@ -119,10 +119,24 @@ TextureImporter:
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 4
buildTarget: iOS
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
customData:
physicsShape: []
bones: []
spriteID: 5e97eb03825dee720800000000000000
@@ -132,6 +146,8 @@ TextureImporter:
edges: []
weights: []
secondaryTextures: []
spriteCustomMetadata:
entries: []
nameFileIdTable: {}
mipmapLimitGroupName:
pSDRemoveMatte: 0

View File

Before

Width:  |  Height:  |  Size: 69 KiB

After

Width:  |  Height:  |  Size: 69 KiB

View File

@@ -67,7 +67,7 @@ TextureImporter:
swizzle: 50462976
cookieLightType: 0
platformSettings:
- serializedVersion: 3
- serializedVersion: 4
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
@@ -80,7 +80,7 @@ TextureImporter:
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
- serializedVersion: 4
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
@@ -93,7 +93,7 @@ TextureImporter:
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
- serializedVersion: 4
buildTarget: WebGL
maxTextureSize: 2048
resizeAlgorithm: 0
@@ -106,7 +106,7 @@ TextureImporter:
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
- serializedVersion: 4
buildTarget: Android
maxTextureSize: 2048
resizeAlgorithm: 0
@@ -119,10 +119,24 @@ TextureImporter:
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 4
buildTarget: iOS
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
customData:
physicsShape: []
bones: []
spriteID: 5e97eb03825dee720800000000000000
@@ -132,6 +146,8 @@ TextureImporter:
edges: []
weights: []
secondaryTextures: []
spriteCustomMetadata:
entries: []
nameFileIdTable: {}
mipmapLimitGroupName:
pSDRemoveMatte: 0

View File

@@ -67,7 +67,7 @@ TextureImporter:
swizzle: 50462976
cookieLightType: 0
platformSettings:
- serializedVersion: 3
- serializedVersion: 4
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
@@ -80,7 +80,7 @@ TextureImporter:
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
- serializedVersion: 4
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
@@ -93,7 +93,7 @@ TextureImporter:
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
- serializedVersion: 4
buildTarget: WebGL
maxTextureSize: 2048
resizeAlgorithm: 0
@@ -106,7 +106,7 @@ TextureImporter:
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
- serializedVersion: 4
buildTarget: Android
maxTextureSize: 2048
resizeAlgorithm: 0
@@ -119,10 +119,24 @@ TextureImporter:
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 4
buildTarget: iOS
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
customData:
physicsShape: []
bones: []
spriteID: 5e97eb03825dee720800000000000000
@@ -132,6 +146,8 @@ TextureImporter:
edges: []
weights: []
secondaryTextures: []
spriteCustomMetadata:
entries: []
nameFileIdTable: {}
mipmapLimitGroupName:
pSDRemoveMatte: 0

View File

@@ -67,7 +67,7 @@ TextureImporter:
swizzle: 50462976
cookieLightType: 0
platformSettings:
- serializedVersion: 3
- serializedVersion: 4
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
@@ -80,7 +80,7 @@ TextureImporter:
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
- serializedVersion: 4
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
@@ -93,7 +93,7 @@ TextureImporter:
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
- serializedVersion: 4
buildTarget: WebGL
maxTextureSize: 2048
resizeAlgorithm: 0
@@ -106,7 +106,7 @@ TextureImporter:
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
- serializedVersion: 4
buildTarget: Android
maxTextureSize: 2048
resizeAlgorithm: 0
@@ -119,10 +119,24 @@ TextureImporter:
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 4
buildTarget: iOS
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
customData:
physicsShape: []
bones: []
spriteID: 5e97eb03825dee720800000000000000
@@ -132,6 +146,8 @@ TextureImporter:
edges: []
weights: []
secondaryTextures: []
spriteCustomMetadata:
entries: []
nameFileIdTable: {}
mipmapLimitGroupName:
pSDRemoveMatte: 0

View File

@@ -67,7 +67,7 @@ TextureImporter:
swizzle: 50462976
cookieLightType: 0
platformSettings:
- serializedVersion: 3
- serializedVersion: 4
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
@@ -80,7 +80,7 @@ TextureImporter:
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
- serializedVersion: 4
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
@@ -93,7 +93,7 @@ TextureImporter:
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
- serializedVersion: 4
buildTarget: WebGL
maxTextureSize: 2048
resizeAlgorithm: 0
@@ -106,7 +106,7 @@ TextureImporter:
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
- serializedVersion: 4
buildTarget: Android
maxTextureSize: 2048
resizeAlgorithm: 0
@@ -119,10 +119,24 @@ TextureImporter:
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 4
buildTarget: iOS
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
customData:
physicsShape: []
bones: []
spriteID: 5e97eb03825dee720800000000000000
@@ -132,6 +146,8 @@ TextureImporter:
edges: []
weights: []
secondaryTextures: []
spriteCustomMetadata:
entries: []
nameFileIdTable: {}
mipmapLimitGroupName:
pSDRemoveMatte: 0

View File

Before

Width:  |  Height:  |  Size: 69 KiB

After

Width:  |  Height:  |  Size: 69 KiB

View File

@@ -67,7 +67,7 @@ TextureImporter:
swizzle: 50462976
cookieLightType: 0
platformSettings:
- serializedVersion: 3
- serializedVersion: 4
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
@@ -80,7 +80,7 @@ TextureImporter:
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
- serializedVersion: 4
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
@@ -93,7 +93,7 @@ TextureImporter:
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
- serializedVersion: 4
buildTarget: WebGL
maxTextureSize: 2048
resizeAlgorithm: 0
@@ -106,7 +106,7 @@ TextureImporter:
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
- serializedVersion: 4
buildTarget: Android
maxTextureSize: 2048
resizeAlgorithm: 0
@@ -119,10 +119,24 @@ TextureImporter:
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 4
buildTarget: iOS
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
customData:
physicsShape: []
bones: []
spriteID: 5e97eb03825dee720800000000000000
@@ -132,6 +146,8 @@ TextureImporter:
edges: []
weights: []
secondaryTextures: []
spriteCustomMetadata:
entries: []
nameFileIdTable: {}
mipmapLimitGroupName:
pSDRemoveMatte: 0

View File

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

View File

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

View File

@@ -0,0 +1,395 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1 &50587740288594971
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 140255021915712345}
- component: {fileID: 1883818561078558899}
- component: {fileID: 704928915224039838}
- component: {fileID: 3501346190407548150}
m_Layer: 5
m_Name: Stem
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &140255021915712345
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 50587740288594971}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 3.5, y: 3.5, z: 3.5}
m_ConstrainProportionsScale: 1
m_Children: []
m_Father: {fileID: 6464301421508797729}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 1}
m_AnchorMax: {x: 0.5, y: 1}
m_AnchoredPosition: {x: 54, y: -326}
m_SizeDelta: {x: 31, y: 69}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &1883818561078558899
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 50587740288594971}
m_CullTransparentMesh: 1
--- !u!114 &704928915224039838
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 50587740288594971}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
m_Name:
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.Image
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_Sprite: {fileID: 21300000, guid: e5caa2ff8c16b5c44bc9f06ffd2e830b, type: 3}
m_Type: 0
m_PreserveAspect: 1
m_FillCenter: 1
m_FillMethod: 4
m_FillAmount: 1
m_FillClockwise: 1
m_FillOrigin: 0
m_UseSpriteMesh: 0
m_PixelsPerUnitMultiplier: 1
--- !u!114 &3501346190407548150
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 50587740288594971}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 7667901d8aea645d28b5125a2ed546ce, type: 3}
m_Name:
m_EditorClassIdentifier: Features.Coloring::Darkmatter.Features.Coloring.UI.ColorRegionView
<RegionId>k__BackingField: Stem
alphaHitThreshold: 0.5
--- !u!1 &1735931098048087757
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 6464301421508797729}
- component: {fileID: 2018123450027732598}
m_Layer: 5
m_Name: AppleColoringPrefab
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &6464301421508797729
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1735931098048087757}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 2435532055949234065}
- {fileID: 140255021915712345}
- {fileID: 4751863057281583490}
- {fileID: 3538580236428514699}
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 1, y: 1}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 0}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &2018123450027732598
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1735931098048087757}
m_CullTransparentMesh: 1
--- !u!1 &2374753269266990102
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 2435532055949234065}
- component: {fileID: 4544345163211921881}
- component: {fileID: 1366380858875779886}
- component: {fileID: 6919807059513103890}
m_Layer: 5
m_Name: Body
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &2435532055949234065
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2374753269266990102}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 3.5, y: 3.5, z: 3.5}
m_ConstrainProportionsScale: 1
m_Children: []
m_Father: {fileID: 6464301421508797729}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0.5}
m_AnchorMax: {x: 0.5, y: 0.5}
m_AnchoredPosition: {x: 0, y: -139}
m_SizeDelta: {x: 298, y: 239}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &4544345163211921881
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2374753269266990102}
m_CullTransparentMesh: 1
--- !u!114 &1366380858875779886
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2374753269266990102}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
m_Name:
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.Image
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_Sprite: {fileID: 21300000, guid: 64e1042b9ae9b0c409d479a470953438, type: 3}
m_Type: 0
m_PreserveAspect: 1
m_FillCenter: 1
m_FillMethod: 4
m_FillAmount: 1
m_FillClockwise: 1
m_FillOrigin: 0
m_UseSpriteMesh: 0
m_PixelsPerUnitMultiplier: 1
--- !u!114 &6919807059513103890
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2374753269266990102}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 7667901d8aea645d28b5125a2ed546ce, type: 3}
m_Name:
m_EditorClassIdentifier: Features.Coloring::Darkmatter.Features.Coloring.UI.ColorRegionView
<RegionId>k__BackingField: Body
alphaHitThreshold: 0.5
--- !u!1 &5786905061811789401
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 3538580236428514699}
- component: {fileID: 4059753188331664390}
- component: {fileID: 562267067691760084}
m_Layer: 5
m_Name: Outline
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &3538580236428514699
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5786905061811789401}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 3.5, y: 3.5, z: 3.5}
m_ConstrainProportionsScale: 1
m_Children: []
m_Father: {fileID: 6464301421508797729}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0.5}
m_AnchorMax: {x: 0.5, y: 0.5}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 306, y: 321}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &4059753188331664390
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5786905061811789401}
m_CullTransparentMesh: 1
--- !u!114 &562267067691760084
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5786905061811789401}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
m_Name:
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.Image
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_RaycastTarget: 0
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_Sprite: {fileID: 21300000, guid: f6db270b00fab4f4b9c4f2002451b690, type: 3}
m_Type: 0
m_PreserveAspect: 1
m_FillCenter: 1
m_FillMethod: 4
m_FillAmount: 1
m_FillClockwise: 1
m_FillOrigin: 0
m_UseSpriteMesh: 0
m_PixelsPerUnitMultiplier: 1
--- !u!1 &6927301726631464396
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 4751863057281583490}
- component: {fileID: 6558630183505278502}
- component: {fileID: 5606251243252857327}
- component: {fileID: 1129874825894614399}
m_Layer: 5
m_Name: Leaf
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &4751863057281583490
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6927301726631464396}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 3.5, y: 3.5, z: 3.5}
m_ConstrainProportionsScale: 1
m_Children: []
m_Father: {fileID: 6464301421508797729}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0.5}
m_AnchorMax: {x: 0.5, y: 0.5}
m_AnchoredPosition: {x: -173, y: 415}
m_SizeDelta: {x: 102, y: 70}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &6558630183505278502
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6927301726631464396}
m_CullTransparentMesh: 1
--- !u!114 &5606251243252857327
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6927301726631464396}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
m_Name:
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.Image
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_Sprite: {fileID: 21300000, guid: d17674c618588734bba10d4faaab248e, type: 3}
m_Type: 0
m_PreserveAspect: 1
m_FillCenter: 1
m_FillMethod: 4
m_FillAmount: 1
m_FillClockwise: 1
m_FillOrigin: 0
m_UseSpriteMesh: 0
m_PixelsPerUnitMultiplier: 1
--- !u!114 &1129874825894614399
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6927301726631464396}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 7667901d8aea645d28b5125a2ed546ce, type: 3}
m_Name:
m_EditorClassIdentifier: Features.Coloring::Darkmatter.Features.Coloring.UI.ColorRegionView
<RegionId>k__BackingField: Leaf
alphaHitThreshold: 0.5

Some files were not shown because too many files have changed in this diff Show More