Compare commits

...

4 Commits

Author SHA1 Message Date
Savya Bikram Shah
b4d10f62cb Shape added 2026-05-29 15:02:24 +05:45
Savya Bikram Shah
7a4bd29b57 Merge remote-tracking branch 'origin/main' into savya
# Conflicts:
#	Assets/Darkmatter/Content/Fonts/static/Fredoka-Bold SDF Blue Outline.asset
2026-05-29 14:26:23 +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
162 changed files with 31106 additions and 18335 deletions

View File

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

View File

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

View File

@@ -14,7 +14,17 @@ MonoBehaviour:
m_EditorClassIdentifier: Unity.Addressables.Editor::UnityEditor.AddressableAssets.Settings.AddressableAssetGroup m_EditorClassIdentifier: Unity.Addressables.Editor::UnityEditor.AddressableAssets.Settings.AddressableAssetGroup
m_GroupName: Default Local Group m_GroupName: Default Local Group
m_GUID: 0e030d5498bfe4ffd8443c796618c539 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_ReadOnly: 0
m_Settings: {fileID: 11400000, guid: 4a94ef317c3674edd8270e4ed15031f6, type: 2} m_Settings: {fileID: 11400000, guid: 4a94ef317c3674edd8270e4ed15031f6, type: 2}
m_SchemaSet: 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

@@ -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

@@ -13,5 +13,6 @@ public interface IColoringController
void PaintRegion(string regionId, Color color); void PaintRegion(string regionId, Color color);
IReadOnlyDictionary<string, Color> GetCurrentColors(); IReadOnlyDictionary<string, Color> GetCurrentColors();
UniTask PlayCompletionAnimationAsync(CancellationToken ct);
void Clear(); void Clear();
} }

View File

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

View File

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

View File

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

View File

@@ -1,3 +1,4 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using Darkmatter.Core.Contracts.Features.DrawingCatalog; using Darkmatter.Core.Contracts.Features.DrawingCatalog;
using Darkmatter.Core.Data.Dynamic.Features.Coloring; 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")] [CreateAssetMenu(menuName = "Darkmatter/Drawing/New Drawing Template")]
public class DrawingTemplateSO : ScriptableObject, IDrawingTemplate public class DrawingTemplateSO : ScriptableObject, IDrawingTemplate
{ {
[field: SerializeField] public string Id { get; private set; } [SerializeField] private string id;
[field: SerializeField] public string DisplayName { get; private set; } [SerializeField] private string displayName;
[field: SerializeField] public Sprite DefaultThumbnail { get; private set; } [SerializeField] private Sprite defaultThumbnail;
[field: SerializeField] public GameObject DrawingPrefab { get; private set; } [SerializeField] private GameObject drawingPrefab;
[field: SerializeField] public GameObject ColoringPrefab { get; private set; } [SerializeField] private GameObject coloringPrefab;
[field: SerializeField] public IReadOnlyList<ShapeSO> Pieces { get; private set; } [SerializeField] private List<ShapeSO> pieces = new();
[field: SerializeField] public IReadOnlyList<ColorRegionDTO> Regions { get; private set; } [SerializeField] private List<RegionAuthoring> regions = new();
[field: SerializeField] public string ColorPaletteId { get; private set; } = "defaultPalette"; [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 AppBootSceneRefs _sceneRefs;
private readonly ISceneService _sceneService; private readonly ISceneService _sceneService;
private readonly IEventBus _eventBus; 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; _sceneRefs = sceneRefs;
_sceneService = sceneService; _sceneService = sceneService;
_eventBus = eventBus; _eventBus = eventBus;
_progression = progression;
} }
public async UniTask StartAsync(CancellationToken cancellation = default) public async UniTask StartAsync(CancellationToken cancellation = default)
{ {
await _progression.LoadAsync();
var tcs = new UniTaskCompletionSource(); var tcs = new UniTaskCompletionSource();
var player = _sceneRefs.IntroVideoPlayer; var player = _sceneRefs.IntroVideoPlayer;

View File

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

View File

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

View File

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

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: 88abeaac3da9d499288f8b5a1830cebc guid: 338d273a95ef0403ca2dd1aca67f97f5
folderAsset: yes folderAsset: yes
DefaultImporter: DefaultImporter:
externalObjects: {} 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) 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 _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() public void Dispose()

View File

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

View File

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

View File

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

View File

@@ -14,6 +14,7 @@ namespace Darkmatter.Features.Coloring.UI
private Image _image; private Image _image;
private event Action OnRegionClicked; private event Action OnRegionClicked;
private void Awake() private void Awake()
{ {
_image = GetComponent<Image>(); _image = GetComponent<Image>();
@@ -33,6 +34,7 @@ namespace Darkmatter.Features.Coloring.UI
public void OnPointerClick(PointerEventData eventData) public void OnPointerClick(PointerEventData eventData)
{ {
Debug.Log($"[ColorRegion] clicked '{RegionId}' on '{gameObject.name}'");
OnRegionClicked?.Invoke(); 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; _initialized = true;
} }
public UniTask<Sprite> GetThumbnailAsync(string id) public async UniTask<Sprite> GetThumbnailAsync(string id)
{ {
if (!_byId.TryGetValue(id, out var t)) if (!_byId.TryGetValue(id, out var t))
throw new KeyNotFoundException($"Template '{id}' not in catalog. Did InitializeAsync run?"); 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) public UniTask<IDrawingTemplate> LoadAsync(string id)

View File

@@ -1,6 +1,7 @@
using Darkmatter.Core.Contracts.Features.GameplayFlow; using Darkmatter.Core.Contracts.Features.GameplayFlow;
using Darkmatter.Features.GameplayFlow.SceneRefs; using Darkmatter.Features.GameplayFlow.SceneRefs;
using Darkmatter.Features.GameplayFlow.Systems; using Darkmatter.Features.GameplayFlow.Systems;
using Darkmatter.Features.GameplayFlow.UI;
using Darkmatter.Libs.Installers; using Darkmatter.Libs.Installers;
using UnityEngine; using UnityEngine;
using VContainer; using VContainer;
@@ -11,6 +12,8 @@ namespace Darkmatter.Features.GameplayFlow
public class GameplayFlowFeatureModule : MonoBehaviour, IModule public class GameplayFlowFeatureModule : MonoBehaviour, IModule
{ {
[SerializeField] private GameplaySceneRefs sceneRefs; [SerializeField] private GameplaySceneRefs sceneRefs;
[SerializeField] private NextButtonView nextButtonView;
[SerializeField] private BackButtonView backButtonView;
public void Register(IContainerBuilder builder) public void Register(IContainerBuilder builder)
{ {
@@ -20,6 +23,12 @@ namespace Darkmatter.Features.GameplayFlow
builder.Register<GameplayFlowController>(Lifetime.Singleton) builder.Register<GameplayFlowController>(Lifetime.Singleton)
.As<IGameplayFlowController>() .As<IGameplayFlowController>()
.As<IAsyncStartable>(); .As<IAsyncStartable>();
if (nextButtonView != null)
builder.RegisterEntryPoint<NextButtonPresenter>().WithParameter(nextButtonView);
if (backButtonView != null)
builder.RegisterEntryPoint<BackButtonPresenter>().WithParameter(backButtonView);
} }
} }
} }

View File

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

View File

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

View File

@@ -0,0 +1,44 @@
using System;
using Cysharp.Threading.Tasks;
using Darkmatter.Core.Contracts.Features.GameplayFlow;
using VContainer.Unity;
namespace Darkmatter.Features.GameplayFlow.UI
{
public class BackButtonPresenter : IStartable, IDisposable
{
private readonly BackButtonView _view;
private readonly IGameplayFlowController _flow;
public BackButtonPresenter(BackButtonView view, IGameplayFlowController flow)
{
_view = view;
_flow = flow;
}
public void Start()
{
_view.OnBackClicked += HandleBackClicked;
}
private void HandleBackClicked() => BackAsync().Forget();
private async UniTaskVoid BackAsync()
{
_view.SetInteractable(false);
try
{
await _flow.BackAsync(default);
}
finally
{
_view.SetInteractable(true);
}
}
public void Dispose()
{
_view.OnBackClicked -= HandleBackClicked;
}
}
}

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,52 @@
using System;
using Cysharp.Threading.Tasks;
using Darkmatter.Core.Contracts.Features.GameplayFlow;
using Darkmatter.Core.Data.Signals.Features.Coloring;
using Darkmatter.Libs.Observer;
using VContainer.Unity;
namespace Darkmatter.Features.GameplayFlow.UI
{
public class NextButtonPresenter : IStartable, IDisposable
{
private readonly NextButtonView _view;
private readonly IGameplayFlowController _flow;
private readonly IEventBus _bus;
private IDisposable _colorSub;
public NextButtonPresenter(NextButtonView view, IGameplayFlowController flow, IEventBus bus)
{
_view = view;
_flow = flow;
_bus = bus;
}
public void Start()
{
_view.Hide();
_view.OnNextClicked += HandleNextClicked;
_colorSub = _bus.Subscribe<ColorAppliedSignal>(_ => _view.Show());
}
private void HandleNextClicked() => NextAsync().Forget();
private async UniTaskVoid NextAsync()
{
_view.SetInteractable(false);
try
{
await _flow.NextAsync(default);
}
finally
{
_view.SetInteractable(true);
}
}
public void Dispose()
{
_view.OnNextClicked -= HandleNextClicked;
_colorSub?.Dispose();
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 06e4d4a98bf0e45de98a7960005542a0

View File

@@ -0,0 +1,32 @@
using System;
using UnityEngine;
using UnityEngine.UI;
namespace Darkmatter.Features.GameplayFlow.UI
{
public class NextButtonView : MonoBehaviour
{
[SerializeField] private Button nextButton;
public event Action OnNextClicked;
private void Awake()
{
if (nextButton != null)
nextButton.onClick.AddListener(() => OnNextClicked?.Invoke());
}
public void Show() => gameObject.SetActive(true);
public void Hide() => gameObject.SetActive(false);
public void SetInteractable(bool value)
{
if (nextButton != null) nextButton.interactable = value;
}
private void OnDestroy()
{
if (nextButton != null) nextButton.onClick.RemoveAllListeners();
}
}
}

View File

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

View File

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

View File

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

View File

@@ -11,20 +11,20 @@ namespace Darkmatter.Features.ShapeBuilder.Commands
private readonly Vector2 _prevSize; private readonly Vector2 _prevSize;
private readonly Quaternion _prevRot; private readonly Quaternion _prevRot;
private readonly Transform _prevParent; private readonly Transform _prevParent;
private readonly int _prevSiblingIndex;
public SnapPieceCommand(ShapePiece piece) public SnapPieceCommand(ShapePiece piece)
{ {
_piece = piece; _piece = piece;
_prevParent = piece.HomeParent;
var rt = piece.RectTransform; _prevSiblingIndex = piece.HomeSiblingIndex;
_prevPos = rt.anchoredPosition; _prevPos = piece.TrayPosition;
_prevSize = rt.sizeDelta; _prevSize = piece.TraySize;
_prevRot = rt.localRotation; _prevRot = Quaternion.identity;
_prevParent = rt.parent;
} }
public void Execute() => _piece.SnapInternal(); 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 public class ShapeBuilderController : IShapeBuilderController, IDisposable
{ {
private const string PiecePrefabKey = "ShapeBuilder/Piece"; private const string PiecePrefabKey = "ShapePiece";
private string _currentTemplateId; private string _currentTemplateId;
private int _expected; private int _expected;
@@ -173,6 +173,16 @@ namespace Darkmatter.Features.ShapeBuilder.Systems
return _snappedPieceIds; 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() public void Clear()
{ {
_undo.Drop(); _undo.Drop();

View File

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

View File

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

View File

@@ -1,52 +1,88 @@
using System.Threading; using System.Threading;
using Cysharp.Threading.Tasks; using Cysharp.Threading.Tasks;
using Darkmatter.Core.Contracts.Services.Camera;
using Darkmatter.Core.Contracts.Services.Capture; using Darkmatter.Core.Contracts.Services.Capture;
using UnityEngine; using UnityEngine;
using CameraType = Darkmatter.Core.Enums.Services.Camera.CameraType;
namespace Darkmatter.Services.Capture namespace Darkmatter.Services.Capture
{ {
public class CaptureService : ICaptureService public class CaptureService : ICaptureService
{ {
private readonly ICameraService _cameraService; public async UniTask<byte[]> CapturePngAsync(GameObject captureObject, float scale,
public CaptureService(ICameraService cameraService)
{
_cameraService = cameraService;
}
public async UniTask<Sprite> CapturePngAsync(GameObject captureObject, float captureSize,
CancellationToken cancellationToken = default) 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 cropped = new Texture2D(cropW, cropH, TextureFormat.RGBA32, mipChain: false);
var renderTexture = RenderTexture.GetTemporary(size, size, 24); try
var previousTarget = captureCamera.targetTexture; {
var previousActive = RenderTexture.active; 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 try
{ {
captureCamera.targetTexture = renderTexture; return output.EncodeToPNG();
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));
} }
finally finally
{ {
captureCamera.targetTexture = previousTarget; if (output != cropped) Object.Destroy(output);
RenderTexture.active = previousActive; }
RenderTexture.ReleaseTemporary(renderTexture); }
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 ignorePlatformSupport: 0
androidETC2FallbackOverride: 0 androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 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: spriteSheet:
serializedVersion: 2 serializedVersion: 2
sprites: [] sprites: []

View File

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

View File

@@ -109,6 +109,32 @@ TextureImporter:
ignorePlatformSupport: 0 ignorePlatformSupport: 0
androidETC2FallbackOverride: 0 androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 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: spriteSheet:
serializedVersion: 2 serializedVersion: 2
sprites: 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: mipmaps:
mipMapMode: 0 mipMapMode: 0
enableMipMap: 0 enableMipMap: 0
sRGBTexture: 1 sRGBTexture: 0
linearTexture: 0 linearTexture: 0
fadeOut: 0 fadeOut: 0
borderMipMap: 0 borderMipMap: 0
@@ -134,7 +134,51 @@ TextureImporter:
forceMaximumCompressionQuality_BC6H_BC7: 0 forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet: spriteSheet:
serializedVersion: 2 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: [] outline: []
customData: customData:
physicsShape: [] physicsShape: []
@@ -148,7 +192,9 @@ TextureImporter:
secondaryTextures: [] secondaryTextures: []
spriteCustomMetadata: spriteCustomMetadata:
entries: [] entries: []
nameFileIdTable: {} nameFileIdTable:
Car1_Reference(1)_0: -1669840421
Car1_Reference(1)_1: -702197950
mipmapLimitGroupName: mipmapLimitGroupName:
pSDRemoveMatte: 0 pSDRemoveMatte: 0
userData: 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 swizzle: 50462976
cookieLightType: 0 cookieLightType: 0
platformSettings: platformSettings:
- serializedVersion: 3 - serializedVersion: 4
buildTarget: DefaultTexturePlatform buildTarget: DefaultTexturePlatform
maxTextureSize: 2048 maxTextureSize: 2048
resizeAlgorithm: 0 resizeAlgorithm: 0
@@ -80,7 +80,7 @@ TextureImporter:
ignorePlatformSupport: 0 ignorePlatformSupport: 0
androidETC2FallbackOverride: 0 androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0 forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3 - serializedVersion: 4
buildTarget: Standalone buildTarget: Standalone
maxTextureSize: 2048 maxTextureSize: 2048
resizeAlgorithm: 0 resizeAlgorithm: 0
@@ -93,8 +93,8 @@ TextureImporter:
ignorePlatformSupport: 0 ignorePlatformSupport: 0
androidETC2FallbackOverride: 0 androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0 forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3 - serializedVersion: 4
buildTarget: iPhone buildTarget: iOS
maxTextureSize: 2048 maxTextureSize: 2048
resizeAlgorithm: 0 resizeAlgorithm: 0
textureFormat: -1 textureFormat: -1
@@ -106,7 +106,7 @@ TextureImporter:
ignorePlatformSupport: 0 ignorePlatformSupport: 0
androidETC2FallbackOverride: 0 androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0 forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3 - serializedVersion: 4
buildTarget: WebGL buildTarget: WebGL
maxTextureSize: 2048 maxTextureSize: 2048
resizeAlgorithm: 0 resizeAlgorithm: 0
@@ -119,7 +119,7 @@ TextureImporter:
ignorePlatformSupport: 0 ignorePlatformSupport: 0
androidETC2FallbackOverride: 0 androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0 forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3 - serializedVersion: 4
buildTarget: Android buildTarget: Android
maxTextureSize: 2048 maxTextureSize: 2048
resizeAlgorithm: 0 resizeAlgorithm: 0
@@ -136,6 +136,7 @@ TextureImporter:
serializedVersion: 2 serializedVersion: 2
sprites: [] sprites: []
outline: [] outline: []
customData:
physicsShape: [] physicsShape: []
bones: [] bones: []
spriteID: 5e97eb03825dee720800000000000000 spriteID: 5e97eb03825dee720800000000000000
@@ -145,6 +146,8 @@ TextureImporter:
edges: [] edges: []
weights: [] weights: []
secondaryTextures: [] secondaryTextures: []
spriteCustomMetadata:
entries: []
nameFileIdTable: {} nameFileIdTable: {}
mipmapLimitGroupName: mipmapLimitGroupName:
pSDRemoveMatte: 0 pSDRemoveMatte: 0

View File

@@ -67,7 +67,7 @@ TextureImporter:
swizzle: 50462976 swizzle: 50462976
cookieLightType: 0 cookieLightType: 0
platformSettings: platformSettings:
- serializedVersion: 3 - serializedVersion: 4
buildTarget: DefaultTexturePlatform buildTarget: DefaultTexturePlatform
maxTextureSize: 2048 maxTextureSize: 2048
resizeAlgorithm: 0 resizeAlgorithm: 0
@@ -80,7 +80,7 @@ TextureImporter:
ignorePlatformSupport: 0 ignorePlatformSupport: 0
androidETC2FallbackOverride: 0 androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0 forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3 - serializedVersion: 4
buildTarget: Standalone buildTarget: Standalone
maxTextureSize: 2048 maxTextureSize: 2048
resizeAlgorithm: 0 resizeAlgorithm: 0
@@ -93,7 +93,7 @@ TextureImporter:
ignorePlatformSupport: 0 ignorePlatformSupport: 0
androidETC2FallbackOverride: 0 androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0 forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3 - serializedVersion: 4
buildTarget: WebGL buildTarget: WebGL
maxTextureSize: 2048 maxTextureSize: 2048
resizeAlgorithm: 0 resizeAlgorithm: 0
@@ -106,7 +106,7 @@ TextureImporter:
ignorePlatformSupport: 0 ignorePlatformSupport: 0
androidETC2FallbackOverride: 0 androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0 forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3 - serializedVersion: 4
buildTarget: Android buildTarget: Android
maxTextureSize: 2048 maxTextureSize: 2048
resizeAlgorithm: 0 resizeAlgorithm: 0
@@ -119,10 +119,24 @@ TextureImporter:
ignorePlatformSupport: 0 ignorePlatformSupport: 0
androidETC2FallbackOverride: 0 androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 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: spriteSheet:
serializedVersion: 2 serializedVersion: 2
sprites: [] sprites: []
outline: [] outline: []
customData:
physicsShape: [] physicsShape: []
bones: [] bones: []
spriteID: 5e97eb03825dee720800000000000000 spriteID: 5e97eb03825dee720800000000000000
@@ -132,6 +146,8 @@ TextureImporter:
edges: [] edges: []
weights: [] weights: []
secondaryTextures: [] secondaryTextures: []
spriteCustomMetadata:
entries: []
nameFileIdTable: {} nameFileIdTable: {}
mipmapLimitGroupName: mipmapLimitGroupName:
pSDRemoveMatte: 0 pSDRemoveMatte: 0

View File

@@ -67,7 +67,7 @@ TextureImporter:
swizzle: 50462976 swizzle: 50462976
cookieLightType: 0 cookieLightType: 0
platformSettings: platformSettings:
- serializedVersion: 3 - serializedVersion: 4
buildTarget: DefaultTexturePlatform buildTarget: DefaultTexturePlatform
maxTextureSize: 2048 maxTextureSize: 2048
resizeAlgorithm: 0 resizeAlgorithm: 0
@@ -80,7 +80,7 @@ TextureImporter:
ignorePlatformSupport: 0 ignorePlatformSupport: 0
androidETC2FallbackOverride: 0 androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0 forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3 - serializedVersion: 4
buildTarget: Standalone buildTarget: Standalone
maxTextureSize: 2048 maxTextureSize: 2048
resizeAlgorithm: 0 resizeAlgorithm: 0
@@ -93,7 +93,7 @@ TextureImporter:
ignorePlatformSupport: 0 ignorePlatformSupport: 0
androidETC2FallbackOverride: 0 androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0 forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3 - serializedVersion: 4
buildTarget: WebGL buildTarget: WebGL
maxTextureSize: 2048 maxTextureSize: 2048
resizeAlgorithm: 0 resizeAlgorithm: 0
@@ -106,7 +106,7 @@ TextureImporter:
ignorePlatformSupport: 0 ignorePlatformSupport: 0
androidETC2FallbackOverride: 0 androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0 forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3 - serializedVersion: 4
buildTarget: Android buildTarget: Android
maxTextureSize: 2048 maxTextureSize: 2048
resizeAlgorithm: 0 resizeAlgorithm: 0
@@ -119,10 +119,24 @@ TextureImporter:
ignorePlatformSupport: 0 ignorePlatformSupport: 0
androidETC2FallbackOverride: 0 androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 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: spriteSheet:
serializedVersion: 2 serializedVersion: 2
sprites: [] sprites: []
outline: [] outline: []
customData:
physicsShape: [] physicsShape: []
bones: [] bones: []
spriteID: 5e97eb03825dee720800000000000000 spriteID: 5e97eb03825dee720800000000000000
@@ -132,6 +146,8 @@ TextureImporter:
edges: [] edges: []
weights: [] weights: []
secondaryTextures: [] secondaryTextures: []
spriteCustomMetadata:
entries: []
nameFileIdTable: {} nameFileIdTable: {}
mipmapLimitGroupName: mipmapLimitGroupName:
pSDRemoveMatte: 0 pSDRemoveMatte: 0

View File

@@ -67,7 +67,7 @@ TextureImporter:
swizzle: 50462976 swizzle: 50462976
cookieLightType: 0 cookieLightType: 0
platformSettings: platformSettings:
- serializedVersion: 3 - serializedVersion: 4
buildTarget: DefaultTexturePlatform buildTarget: DefaultTexturePlatform
maxTextureSize: 2048 maxTextureSize: 2048
resizeAlgorithm: 0 resizeAlgorithm: 0
@@ -80,7 +80,7 @@ TextureImporter:
ignorePlatformSupport: 0 ignorePlatformSupport: 0
androidETC2FallbackOverride: 0 androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0 forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3 - serializedVersion: 4
buildTarget: Standalone buildTarget: Standalone
maxTextureSize: 2048 maxTextureSize: 2048
resizeAlgorithm: 0 resizeAlgorithm: 0
@@ -93,7 +93,7 @@ TextureImporter:
ignorePlatformSupport: 0 ignorePlatformSupport: 0
androidETC2FallbackOverride: 0 androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0 forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3 - serializedVersion: 4
buildTarget: WebGL buildTarget: WebGL
maxTextureSize: 2048 maxTextureSize: 2048
resizeAlgorithm: 0 resizeAlgorithm: 0
@@ -106,7 +106,7 @@ TextureImporter:
ignorePlatformSupport: 0 ignorePlatformSupport: 0
androidETC2FallbackOverride: 0 androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0 forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3 - serializedVersion: 4
buildTarget: Android buildTarget: Android
maxTextureSize: 2048 maxTextureSize: 2048
resizeAlgorithm: 0 resizeAlgorithm: 0
@@ -119,10 +119,24 @@ TextureImporter:
ignorePlatformSupport: 0 ignorePlatformSupport: 0
androidETC2FallbackOverride: 0 androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 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: spriteSheet:
serializedVersion: 2 serializedVersion: 2
sprites: [] sprites: []
outline: [] outline: []
customData:
physicsShape: [] physicsShape: []
bones: [] bones: []
spriteID: 5e97eb03825dee720800000000000000 spriteID: 5e97eb03825dee720800000000000000
@@ -132,6 +146,8 @@ TextureImporter:
edges: [] edges: []
weights: [] weights: []
secondaryTextures: [] secondaryTextures: []
spriteCustomMetadata:
entries: []
nameFileIdTable: {} nameFileIdTable: {}
mipmapLimitGroupName: mipmapLimitGroupName:
pSDRemoveMatte: 0 pSDRemoveMatte: 0

View File

@@ -67,7 +67,7 @@ TextureImporter:
swizzle: 50462976 swizzle: 50462976
cookieLightType: 0 cookieLightType: 0
platformSettings: platformSettings:
- serializedVersion: 3 - serializedVersion: 4
buildTarget: DefaultTexturePlatform buildTarget: DefaultTexturePlatform
maxTextureSize: 2048 maxTextureSize: 2048
resizeAlgorithm: 0 resizeAlgorithm: 0
@@ -80,7 +80,7 @@ TextureImporter:
ignorePlatformSupport: 0 ignorePlatformSupport: 0
androidETC2FallbackOverride: 0 androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0 forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3 - serializedVersion: 4
buildTarget: Standalone buildTarget: Standalone
maxTextureSize: 2048 maxTextureSize: 2048
resizeAlgorithm: 0 resizeAlgorithm: 0
@@ -93,7 +93,7 @@ TextureImporter:
ignorePlatformSupport: 0 ignorePlatformSupport: 0
androidETC2FallbackOverride: 0 androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0 forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3 - serializedVersion: 4
buildTarget: WebGL buildTarget: WebGL
maxTextureSize: 2048 maxTextureSize: 2048
resizeAlgorithm: 0 resizeAlgorithm: 0
@@ -106,7 +106,7 @@ TextureImporter:
ignorePlatformSupport: 0 ignorePlatformSupport: 0
androidETC2FallbackOverride: 0 androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0 forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3 - serializedVersion: 4
buildTarget: Android buildTarget: Android
maxTextureSize: 2048 maxTextureSize: 2048
resizeAlgorithm: 0 resizeAlgorithm: 0
@@ -119,10 +119,24 @@ TextureImporter:
ignorePlatformSupport: 0 ignorePlatformSupport: 0
androidETC2FallbackOverride: 0 androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 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: spriteSheet:
serializedVersion: 2 serializedVersion: 2
sprites: [] sprites: []
outline: [] outline: []
customData:
physicsShape: [] physicsShape: []
bones: [] bones: []
spriteID: 5e97eb03825dee720800000000000000 spriteID: 5e97eb03825dee720800000000000000
@@ -132,6 +146,8 @@ TextureImporter:
edges: [] edges: []
weights: [] weights: []
secondaryTextures: [] secondaryTextures: []
spriteCustomMetadata:
entries: []
nameFileIdTable: {} nameFileIdTable: {}
mipmapLimitGroupName: mipmapLimitGroupName:
pSDRemoveMatte: 0 pSDRemoveMatte: 0

View File

@@ -67,7 +67,7 @@ TextureImporter:
swizzle: 50462976 swizzle: 50462976
cookieLightType: 0 cookieLightType: 0
platformSettings: platformSettings:
- serializedVersion: 3 - serializedVersion: 4
buildTarget: DefaultTexturePlatform buildTarget: DefaultTexturePlatform
maxTextureSize: 2048 maxTextureSize: 2048
resizeAlgorithm: 0 resizeAlgorithm: 0
@@ -80,7 +80,7 @@ TextureImporter:
ignorePlatformSupport: 0 ignorePlatformSupport: 0
androidETC2FallbackOverride: 0 androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0 forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3 - serializedVersion: 4
buildTarget: Standalone buildTarget: Standalone
maxTextureSize: 2048 maxTextureSize: 2048
resizeAlgorithm: 0 resizeAlgorithm: 0
@@ -93,7 +93,7 @@ TextureImporter:
ignorePlatformSupport: 0 ignorePlatformSupport: 0
androidETC2FallbackOverride: 0 androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0 forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3 - serializedVersion: 4
buildTarget: WebGL buildTarget: WebGL
maxTextureSize: 2048 maxTextureSize: 2048
resizeAlgorithm: 0 resizeAlgorithm: 0
@@ -106,7 +106,7 @@ TextureImporter:
ignorePlatformSupport: 0 ignorePlatformSupport: 0
androidETC2FallbackOverride: 0 androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0 forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3 - serializedVersion: 4
buildTarget: Android buildTarget: Android
maxTextureSize: 2048 maxTextureSize: 2048
resizeAlgorithm: 0 resizeAlgorithm: 0
@@ -119,10 +119,24 @@ TextureImporter:
ignorePlatformSupport: 0 ignorePlatformSupport: 0
androidETC2FallbackOverride: 0 androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 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: spriteSheet:
serializedVersion: 2 serializedVersion: 2
sprites: [] sprites: []
outline: [] outline: []
customData:
physicsShape: [] physicsShape: []
bones: [] bones: []
spriteID: 5e97eb03825dee720800000000000000 spriteID: 5e97eb03825dee720800000000000000
@@ -132,6 +146,8 @@ TextureImporter:
edges: [] edges: []
weights: [] weights: []
secondaryTextures: [] secondaryTextures: []
spriteCustomMetadata:
entries: []
nameFileIdTable: {} nameFileIdTable: {}
mipmapLimitGroupName: mipmapLimitGroupName:
pSDRemoveMatte: 0 pSDRemoveMatte: 0

View File

@@ -67,7 +67,7 @@ TextureImporter:
swizzle: 50462976 swizzle: 50462976
cookieLightType: 0 cookieLightType: 0
platformSettings: platformSettings:
- serializedVersion: 3 - serializedVersion: 4
buildTarget: DefaultTexturePlatform buildTarget: DefaultTexturePlatform
maxTextureSize: 2048 maxTextureSize: 2048
resizeAlgorithm: 0 resizeAlgorithm: 0
@@ -80,7 +80,7 @@ TextureImporter:
ignorePlatformSupport: 0 ignorePlatformSupport: 0
androidETC2FallbackOverride: 0 androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0 forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3 - serializedVersion: 4
buildTarget: Standalone buildTarget: Standalone
maxTextureSize: 2048 maxTextureSize: 2048
resizeAlgorithm: 0 resizeAlgorithm: 0
@@ -93,7 +93,7 @@ TextureImporter:
ignorePlatformSupport: 0 ignorePlatformSupport: 0
androidETC2FallbackOverride: 0 androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0 forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3 - serializedVersion: 4
buildTarget: WebGL buildTarget: WebGL
maxTextureSize: 2048 maxTextureSize: 2048
resizeAlgorithm: 0 resizeAlgorithm: 0
@@ -106,7 +106,7 @@ TextureImporter:
ignorePlatformSupport: 0 ignorePlatformSupport: 0
androidETC2FallbackOverride: 0 androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0 forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3 - serializedVersion: 4
buildTarget: Android buildTarget: Android
maxTextureSize: 2048 maxTextureSize: 2048
resizeAlgorithm: 0 resizeAlgorithm: 0
@@ -119,10 +119,24 @@ TextureImporter:
ignorePlatformSupport: 0 ignorePlatformSupport: 0
androidETC2FallbackOverride: 0 androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 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: spriteSheet:
serializedVersion: 2 serializedVersion: 2
sprites: [] sprites: []
outline: [] outline: []
customData:
physicsShape: [] physicsShape: []
bones: [] bones: []
spriteID: 5e97eb03825dee720800000000000000 spriteID: 5e97eb03825dee720800000000000000
@@ -132,6 +146,8 @@ TextureImporter:
edges: [] edges: []
weights: [] weights: []
secondaryTextures: [] secondaryTextures: []
spriteCustomMetadata:
entries: []
nameFileIdTable: {} nameFileIdTable: {}
mipmapLimitGroupName: mipmapLimitGroupName:
pSDRemoveMatte: 0 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 swizzle: 50462976
cookieLightType: 0 cookieLightType: 0
platformSettings: platformSettings:
- serializedVersion: 3 - serializedVersion: 4
buildTarget: DefaultTexturePlatform buildTarget: DefaultTexturePlatform
maxTextureSize: 2048 maxTextureSize: 2048
resizeAlgorithm: 0 resizeAlgorithm: 0
@@ -80,7 +80,7 @@ TextureImporter:
ignorePlatformSupport: 0 ignorePlatformSupport: 0
androidETC2FallbackOverride: 0 androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0 forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3 - serializedVersion: 4
buildTarget: Standalone buildTarget: Standalone
maxTextureSize: 2048 maxTextureSize: 2048
resizeAlgorithm: 0 resizeAlgorithm: 0
@@ -93,7 +93,7 @@ TextureImporter:
ignorePlatformSupport: 0 ignorePlatformSupport: 0
androidETC2FallbackOverride: 0 androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0 forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3 - serializedVersion: 4
buildTarget: WebGL buildTarget: WebGL
maxTextureSize: 2048 maxTextureSize: 2048
resizeAlgorithm: 0 resizeAlgorithm: 0
@@ -106,7 +106,7 @@ TextureImporter:
ignorePlatformSupport: 0 ignorePlatformSupport: 0
androidETC2FallbackOverride: 0 androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0 forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3 - serializedVersion: 4
buildTarget: Android buildTarget: Android
maxTextureSize: 2048 maxTextureSize: 2048
resizeAlgorithm: 0 resizeAlgorithm: 0
@@ -119,10 +119,24 @@ TextureImporter:
ignorePlatformSupport: 0 ignorePlatformSupport: 0
androidETC2FallbackOverride: 0 androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 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: spriteSheet:
serializedVersion: 2 serializedVersion: 2
sprites: [] sprites: []
outline: [] outline: []
customData:
physicsShape: [] physicsShape: []
bones: [] bones: []
spriteID: 5e97eb03825dee720800000000000000 spriteID: 5e97eb03825dee720800000000000000
@@ -132,6 +146,8 @@ TextureImporter:
edges: [] edges: []
weights: [] weights: []
secondaryTextures: [] secondaryTextures: []
spriteCustomMetadata:
entries: []
nameFileIdTable: {} nameFileIdTable: {}
mipmapLimitGroupName: mipmapLimitGroupName:
pSDRemoveMatte: 0 pSDRemoveMatte: 0

View File

@@ -67,7 +67,7 @@ TextureImporter:
swizzle: 50462976 swizzle: 50462976
cookieLightType: 0 cookieLightType: 0
platformSettings: platformSettings:
- serializedVersion: 3 - serializedVersion: 4
buildTarget: DefaultTexturePlatform buildTarget: DefaultTexturePlatform
maxTextureSize: 2048 maxTextureSize: 2048
resizeAlgorithm: 0 resizeAlgorithm: 0
@@ -80,7 +80,7 @@ TextureImporter:
ignorePlatformSupport: 0 ignorePlatformSupport: 0
androidETC2FallbackOverride: 0 androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0 forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3 - serializedVersion: 4
buildTarget: Standalone buildTarget: Standalone
maxTextureSize: 2048 maxTextureSize: 2048
resizeAlgorithm: 0 resizeAlgorithm: 0
@@ -93,7 +93,7 @@ TextureImporter:
ignorePlatformSupport: 0 ignorePlatformSupport: 0
androidETC2FallbackOverride: 0 androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0 forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3 - serializedVersion: 4
buildTarget: WebGL buildTarget: WebGL
maxTextureSize: 2048 maxTextureSize: 2048
resizeAlgorithm: 0 resizeAlgorithm: 0
@@ -106,7 +106,7 @@ TextureImporter:
ignorePlatformSupport: 0 ignorePlatformSupport: 0
androidETC2FallbackOverride: 0 androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0 forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3 - serializedVersion: 4
buildTarget: Android buildTarget: Android
maxTextureSize: 2048 maxTextureSize: 2048
resizeAlgorithm: 0 resizeAlgorithm: 0
@@ -119,10 +119,24 @@ TextureImporter:
ignorePlatformSupport: 0 ignorePlatformSupport: 0
androidETC2FallbackOverride: 0 androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 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: spriteSheet:
serializedVersion: 2 serializedVersion: 2
sprites: [] sprites: []
outline: [] outline: []
customData:
physicsShape: [] physicsShape: []
bones: [] bones: []
spriteID: 5e97eb03825dee720800000000000000 spriteID: 5e97eb03825dee720800000000000000
@@ -132,6 +146,8 @@ TextureImporter:
edges: [] edges: []
weights: [] weights: []
secondaryTextures: [] secondaryTextures: []
spriteCustomMetadata:
entries: []
nameFileIdTable: {} nameFileIdTable: {}
mipmapLimitGroupName: mipmapLimitGroupName:
pSDRemoveMatte: 0 pSDRemoveMatte: 0

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