First pass over MPV for the cement-statue-sticker minigame (#63)

Co-authored-by: Michal Pikulski <michal.a.pikulski@gmail.com>
Co-authored-by: Michal Pikulski <michal@foolhardyhorizons.com>
Reviewed-on: #63
This commit is contained in:
2025-11-24 14:55:45 +00:00
parent e33de5da3d
commit 86c1df55f2
66 changed files with 4455 additions and 413 deletions

View File

@@ -20,6 +20,11 @@ MonoBehaviour:
m_ReadOnly: 0 m_ReadOnly: 0
m_SerializedLabels: [] m_SerializedLabels: []
FlaggedDuringContentUpdateRestriction: 0 FlaggedDuringContentUpdateRestriction: 0
- m_GUID: 359004e51663d6442b7d2b960d12b459
m_Address: Settings/StatueDressupSettings
m_ReadOnly: 0
m_SerializedLabels: []
FlaggedDuringContentUpdateRestriction: 0
- m_GUID: 35bfcff00faa72c4eb272a9e8288f965 - m_GUID: 35bfcff00faa72c4eb272a9e8288f965
m_Address: Settings/PlayerFollowerSettings m_Address: Settings/PlayerFollowerSettings
m_ReadOnly: 0 m_ReadOnly: 0

View File

@@ -122,6 +122,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: WindowsStoreApps
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:
@@ -129,10 +155,10 @@ TextureImporter:
name: AEblerup_Map_Statue_0 name: AEblerup_Map_Statue_0
rect: rect:
serializedVersion: 2 serializedVersion: 2
x: 59 x: 0
y: 48 y: 0
width: 405 width: 555
height: 567 height: 676
alignment: 9 alignment: 9
pivot: {x: 0.5, y: 0.25} pivot: {x: 0.5, y: 0.25}
border: {x: 0, y: 0, z: 0, w: 0} border: {x: 0, y: 0, z: 0, w: 0}

View File

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

View File

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

View File

@@ -0,0 +1,19 @@
%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: 74c6ae9aa803480c8fb918dd58cfb809, type: 3}
m_Name: TestDecorationData 1
m_EditorClassIdentifier: AppleHillsScripts::Minigames.StatueDressup.Data.DecorationData
decorationId: Shoe
decorationName: Shoe
decorationSprite: {fileID: -792204027, guid: f1b529408513adc409a57c9ba7131823, type: 3}
authoredSize: {x: 300, y: 300}
isUnlocked: 1

View File

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

View File

@@ -0,0 +1,19 @@
%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: 74c6ae9aa803480c8fb918dd58cfb809, type: 3}
m_Name: TestDecorationData 2
m_EditorClassIdentifier: AppleHillsScripts::Minigames.StatueDressup.Data.DecorationData
decorationId: axe
decorationName: axe
decorationSprite: {fileID: 6674386295937086461, guid: 3bd1c178a78fcd144965cd1731dc309b, type: 3}
authoredSize: {x: 300, y: 300}
isUnlocked: 1

View File

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

View File

@@ -0,0 +1,19 @@
%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: 74c6ae9aa803480c8fb918dd58cfb809, type: 3}
m_Name: TestDecorationData 3
m_EditorClassIdentifier: AppleHillsScripts::Minigames.StatueDressup.Data.DecorationData
decorationId: can
decorationName: can
decorationSprite: {fileID: 792078976, guid: f1b529408513adc409a57c9ba7131823, type: 3}
authoredSize: {x: 300, y: 300}
isUnlocked: 1

View File

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

View File

@@ -0,0 +1,19 @@
%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: 74c6ae9aa803480c8fb918dd58cfb809, type: 3}
m_Name: TestDecorationData 4
m_EditorClassIdentifier: AppleHillsScripts::Minigames.StatueDressup.Data.DecorationData
decorationId: i_feel_the_magic_between_you_and_i
decorationName: I feel the magic between you and I
decorationSprite: {fileID: 1623587888, guid: 1630961e1f25e4243ad74e4e3b0c7e54, type: 3}
authoredSize: {x: 300, y: 300}
isUnlocked: 1

View File

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

View File

@@ -0,0 +1,19 @@
%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: 74c6ae9aa803480c8fb918dd58cfb809, type: 3}
m_Name: TestDecorationData 5
m_EditorClassIdentifier: AppleHillsScripts::Minigames.StatueDressup.Data.DecorationData
decorationId: the_people's_sticker
decorationName: the people's sticker
decorationSprite: {fileID: 3452003437791708593, guid: 4c13556eeb918624c9dd3d7e4086242e, type: 3}
authoredSize: {x: 300, y: 300}
isUnlocked: 1

View File

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

View File

@@ -0,0 +1,19 @@
%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: 74c6ae9aa803480c8fb918dd58cfb809, type: 3}
m_Name: TestDecorationData 6
m_EditorClassIdentifier: AppleHillsScripts::Minigames.StatueDressup.Data.DecorationData
decorationId: cardalbum
decorationName: CardAlbum
decorationSprite: {fileID: -4354454609415314374, guid: 1ba1f8cf73f79214190f1432fe1e3bc6, type: 3}
authoredSize: {x: 300, y: 300}
isUnlocked: 1

View File

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

View File

@@ -0,0 +1,19 @@
%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: 74c6ae9aa803480c8fb918dd58cfb809, type: 3}
m_Name: TestDecorationData 7
m_EditorClassIdentifier: AppleHillsScripts::Minigames.StatueDressup.Data.DecorationData
decorationId: chocolate
decorationName: chocolate
decorationSprite: {fileID: -509776585262497855, guid: c648336c825f7d7479582bbe4d95d0bc, type: 3}
authoredSize: {x: 300, y: 300}
isUnlocked: 1

View File

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

View File

@@ -0,0 +1,19 @@
%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: 74c6ae9aa803480c8fb918dd58cfb809, type: 3}
m_Name: TestDecorationData 8
m_EditorClassIdentifier: AppleHillsScripts::Minigames.StatueDressup.Data.DecorationData
decorationId: tennis_ball
decorationName: tennis ball
decorationSprite: {fileID: -8897872742393391051, guid: 44a64b7a80921694790236bab7765357, type: 3}
authoredSize: {x: 300, y: 300}
isUnlocked: 1

View File

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

View File

@@ -0,0 +1,19 @@
%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: 74c6ae9aa803480c8fb918dd58cfb809, type: 3}
m_Name: TestDecorationData 9
m_EditorClassIdentifier: AppleHillsScripts::Minigames.StatueDressup.Data.DecorationData
decorationId: bird_poop
decorationName: bird poop
decorationSprite: {fileID: 6130942287420046110, guid: 9ef635f111f888a4386a7f0290117264, type: 3}
authoredSize: {x: 300, y: 300}
isUnlocked: 1

View File

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

View File

@@ -0,0 +1,19 @@
%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: 74c6ae9aa803480c8fb918dd58cfb809, type: 3}
m_Name: TestDecorationData
m_EditorClassIdentifier: AppleHillsScripts::Minigames.StatueDressup.Data.DecorationData
decorationId: backpack
decorationName: backpack
decorationSprite: {fileID: -6415490079858998490, guid: b9d1a045f7c163a4d9e2d38071913885, type: 3}
authoredSize: {x: 300, y: 300}
isUnlocked: 1

View File

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

View File

@@ -19,7 +19,9 @@ MonoBehaviour:
requiredOrientation: 1 requiredOrientation: 1
- sceneName: DivingForPictures - sceneName: DivingForPictures
requiredOrientation: 0 requiredOrientation: 0
- sceneName: BirdB - sceneName: BirdPoop
requiredOrientation: 1 requiredOrientation: 1
- sceneName: CardQualityControl - sceneName: CardQualityControl
requiredOrientation: 1 requiredOrientation: 1
- sceneName: StatueDecoration
requiredOrientation: 1

View File

@@ -2,7 +2,6 @@
using UnityEditor; using UnityEditor;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.IO;
using Core.Settings; using Core.Settings;
namespace AppleHills.Core.Settings.Editor namespace AppleHills.Core.Settings.Editor
@@ -11,7 +10,7 @@ namespace AppleHills.Core.Settings.Editor
{ {
private Vector2 scrollPosition; private Vector2 scrollPosition;
private List<BaseSettings> allSettings = new List<BaseSettings>(); private List<BaseSettings> allSettings = new List<BaseSettings>();
private string[] tabNames = new string[] { "Player & Follower", "Interaction & Items", "Diving Minigame", "Card System", "Card Sorting", "Bird Pooper" }; private string[] tabNames = new string[] { "Player & Follower", "Interaction & Items", "Diving Minigame", "Card System", "Card Sorting", "Bird Pooper", "Statue Dressup" };
private int selectedTab = 0; private int selectedTab = 0;
private Dictionary<string, SerializedObject> serializedSettingsObjects = new Dictionary<string, SerializedObject>(); private Dictionary<string, SerializedObject> serializedSettingsObjects = new Dictionary<string, SerializedObject>();
private GUIStyle headerStyle; private GUIStyle headerStyle;
@@ -52,6 +51,7 @@ namespace AppleHills.Core.Settings.Editor
CreateSettingsIfMissing<CardSystemSettings>("CardSystemSettings"); CreateSettingsIfMissing<CardSystemSettings>("CardSystemSettings");
CreateSettingsIfMissing<CardSortingSettings>("CardSortingSettings"); CreateSettingsIfMissing<CardSortingSettings>("CardSortingSettings");
CreateSettingsIfMissing<BirdPooperSettings>("BirdPooperSettings"); CreateSettingsIfMissing<BirdPooperSettings>("BirdPooperSettings");
CreateSettingsIfMissing<StatueDressupSettings>("StatueDressupSettings");
} }
private void CreateSettingsIfMissing<T>(string fileName) where T : BaseSettings private void CreateSettingsIfMissing<T>(string fileName) where T : BaseSettings
@@ -127,6 +127,9 @@ namespace AppleHills.Core.Settings.Editor
case 5: // Bird Pooper case 5: // Bird Pooper
DrawSettingsEditor<BirdPooperSettings>(); DrawSettingsEditor<BirdPooperSettings>();
break; break;
case 6: // Statue Dressup
DrawSettingsEditor<StatueDressupSettings>();
break;
} }
EditorGUILayout.EndScrollView(); EditorGUILayout.EndScrollView();

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

@@ -0,0 +1,195 @@
fileFormatVersion: 2
guid: 77b22fe548c7b264a8c6d243bd1d62ad
TextureImporter:
internalIDToNameTable:
- first:
213: -6300450527438492720
second: camera_icon_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: 2
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: 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
- 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: 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: 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: WindowsStoreApps
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: camera_icon_0
rect:
serializedVersion: 2
x: 19
y: 68
width: 474
height: 377
alignment: 0
pivot: {x: 0, y: 0}
border: {x: 0, y: 0, z: 0, w: 0}
customData:
outline: []
physicsShape: []
tessellationDetail: -1
bones: []
spriteID: 0db2b1360ad4098a0800000000000000
internalID: -6300450527438492720
vertices: []
indices:
edges: []
weights: []
outline: []
customData:
physicsShape: []
bones: []
spriteID:
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
spriteCustomMetadata:
entries: []
nameFileIdTable:
camera_icon_0: -6300450527438492720
mipmapLimitGroupName:
pSDRemoveMatte: 0
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

View File

@@ -0,0 +1,195 @@
fileFormatVersion: 2
guid: 338c4323de4ff7f4c99e4c10a744e914
TextureImporter:
internalIDToNameTable:
- first:
213: -7424888634701936452
second: statue_outline_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: 2
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: 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
- 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: 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: 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: WindowsStoreApps
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: statue_outline_0
rect:
serializedVersion: 2
x: 0
y: 0
width: 555
height: 676
alignment: 0
pivot: {x: 0.5, y: 0.5}
border: {x: 0, y: 0, z: 0, w: 0}
customData:
outline: []
physicsShape: []
tessellationDetail: -1
bones: []
spriteID: cb881cf102f75f890800000000000000
internalID: -7424888634701936452
vertices: []
indices:
edges: []
weights: []
outline: []
customData:
physicsShape: []
bones: []
spriteID: a4e62b13d7f4aeb42a7c302cf33555e9
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
spriteCustomMetadata:
entries: []
nameFileIdTable:
statue_outline_0: -7424888634701936452
mipmapLimitGroupName:
pSDRemoveMatte: 0
userData:
assetBundleName:
assetBundleVariant:

View File

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

View File

@@ -0,0 +1,105 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1 &769974252937479200
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 7351787172634191403}
- component: {fileID: 7495592582591578536}
- component: {fileID: 597267714783345863}
- component: {fileID: 3617977973382190563}
- component: {fileID: 8998709565229564215}
m_Layer: 5
m_Name: DecorationDraggableInstance
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &7351787172634191403
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 769974252937479200}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 0}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &7495592582591578536
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 769974252937479200}
m_CullTransparentMesh: 1
--- !u!114 &597267714783345863
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 769974252937479200}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
m_Name:
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.Image
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_Sprite: {fileID: 0}
m_Type: 0
m_PreserveAspect: 0
m_FillCenter: 1
m_FillMethod: 4
m_FillAmount: 1
m_FillClockwise: 1
m_FillOrigin: 0
m_UseSpriteMesh: 0
m_PixelsPerUnitMultiplier: 1
--- !u!225 &3617977973382190563
CanvasGroup:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 769974252937479200}
m_Enabled: 1
m_Alpha: 1
m_Interactable: 1
m_BlocksRaycasts: 1
m_IgnoreParentGroups: 0
--- !u!114 &8998709565229564215
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 769974252937479200}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: e4659fd035c74a79af0311de9e17f44a, type: 3}
m_Name:
m_EditorClassIdentifier: AppleHillsScripts::Minigames.StatueDressup.DragDrop.DecorationDraggableInstance
decorationImage: {fileID: 597267714783345863}
canvasGroup: {fileID: 0}

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 064cd4d021ea13e47860a59bbe8224aa
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,105 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1 &769974252937479200
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 7351787172634191403}
- component: {fileID: 7495592582591578536}
- component: {fileID: 597267714783345863}
- component: {fileID: 3617977973382190563}
- component: {fileID: 2222137027263565689}
m_Layer: 5
m_Name: DecorationGridIcon
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &7351787172634191403
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 769974252937479200}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 0}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &7495592582591578536
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 769974252937479200}
m_CullTransparentMesh: 1
--- !u!114 &597267714783345863
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 769974252937479200}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
m_Name:
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.Image
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_Sprite: {fileID: 0}
m_Type: 0
m_PreserveAspect: 0
m_FillCenter: 1
m_FillMethod: 4
m_FillAmount: 1
m_FillClockwise: 1
m_FillOrigin: 0
m_UseSpriteMesh: 0
m_PixelsPerUnitMultiplier: 1
--- !u!225 &3617977973382190563
CanvasGroup:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 769974252937479200}
m_Enabled: 1
m_Alpha: 1
m_Interactable: 1
m_BlocksRaycasts: 1
m_IgnoreParentGroups: 0
--- !u!114 &2222137027263565689
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 769974252937479200}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 9c806d80a321498c9f33f13d7a31065c, type: 3}
m_Name:
m_EditorClassIdentifier: AppleHillsScripts::Minigames.StatueDressup.DragDrop.DecorationGridIcon
iconImage: {fileID: 597267714783345863}
decorationData: {fileID: 0}

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: a461d4cb94a8ab1429388c90bbd543b6
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@@ -172,6 +172,7 @@ namespace Core
var cardSystemSettings = SettingsProvider.Instance.LoadSettingsSynchronous<CardSystemSettings>(); var cardSystemSettings = SettingsProvider.Instance.LoadSettingsSynchronous<CardSystemSettings>();
var sortingGameSettings = SettingsProvider.Instance.LoadSettingsSynchronous<CardSortingSettings>(); var sortingGameSettings = SettingsProvider.Instance.LoadSettingsSynchronous<CardSortingSettings>();
var birdPooperSettings = SettingsProvider.Instance.LoadSettingsSynchronous<BirdPooperSettings>(); var birdPooperSettings = SettingsProvider.Instance.LoadSettingsSynchronous<BirdPooperSettings>();
var statueDressupSettings = SettingsProvider.Instance.LoadSettingsSynchronous<StatueDressupSettings>();
// Register settings with service locator // Register settings with service locator
if (playerSettings != null) if (playerSettings != null)
@@ -233,9 +234,20 @@ namespace Core
{ {
Debug.LogError("Failed to load BirdPooperSettings"); Debug.LogError("Failed to load BirdPooperSettings");
} }
if (statueDressupSettings != null)
{
ServiceLocator.Register<IStatueDressupSettings>(statueDressupSettings);
Logging.Debug("StatueDressupSettings registered successfully");
}
else
{
Debug.LogError("Failed to load StatueDressupSettings");
}
// Log success // Log success
_settingsLoaded = playerSettings != null && interactionSettings != null && minigameSettings != null && cardSystemSettings != null && birdPooperSettings != null; _settingsLoaded = playerSettings != null && interactionSettings != null && minigameSettings != null
&& cardSystemSettings != null && birdPooperSettings != null && statueDressupSettings != null;
if (_settingsLoaded) if (_settingsLoaded)
{ {
Logging.Debug("All settings loaded and registered with ServiceLocator"); Logging.Debug("All settings loaded and registered with ServiceLocator");

View File

@@ -1,5 +1,6 @@
using UnityEngine; using UnityEngine;
using System.Collections.Generic; using System.Collections.Generic;
using Minigames.StatueDressup.Data;
namespace AppleHills.Core.Settings namespace AppleHills.Core.Settings
{ {
@@ -160,4 +161,45 @@ namespace AppleHills.Core.Settings
// General Animation // General Animation
float DefaultAnimationDuration { get; } float DefaultAnimationDuration { get; }
} }
/// <summary>
/// Interface for statue dressup minigame settings
/// </summary>
public interface IStatueDressupSettings
{
// Decoration Display
Vector2 DefaultAuthoredSize { get; }
// Decoration Content
List<DecorationData> AllDecorations { get; }
// Menu Configuration
int ItemsPerPage { get; }
int GridColumns { get; }
Vector2 GridSpacing { get; }
// Drag and Drop
float DragScaleTransitionDuration { get; }
float ReturnToMenuDuration { get; }
float MinOverlapPercentage { get; }
// Animation
float HoverScaleMultiplier { get; }
float HoverAnimationDuration { get; }
float PlacementAnimationDuration { get; }
// Photo Settings
string PhotoSaveKey { get; }
int PhotoQuality { get; }
bool CaptureFullScreen { get; }
// Rewards
int CardsRewardCount { get; }
bool AutoCompleteOnPhoto { get; }
// State Persistence
bool EnableStatePersistence { get; }
string StateSaveKey { get; }
int MaxSavedDecorations { get; }
}
} }

View File

@@ -0,0 +1,149 @@
using System.Collections.Generic;
using AppleHills.Core.Settings;
using Minigames.StatueDressup.Data;
using UnityEngine;
namespace Core.Settings
{
/// <summary>
/// Settings for the Mr. Cement Statue Decoration minigame
/// </summary>
[CreateAssetMenu(fileName = "StatueDressupSettings", menuName = "AppleHills/Settings/Statue Dressup", order = 7)]
public class StatueDressupSettings : BaseSettings, IStatueDressupSettings
{
[Header("Decoration Display")]
[Tooltip("Default full size for decorations when placed on statue")]
[SerializeField] private Vector2 defaultAuthoredSize = new Vector2(128f, 128f);
[Header("Decoration Content")]
[Tooltip("List of all available decoration data assets")]
[SerializeField] private List<DecorationData> allDecorations = new List<DecorationData>();
[Header("Menu Configuration")]
[Tooltip("Number of decoration items to display per page (2 columns x 5 rows = 10)")]
[SerializeField] private int itemsPerPage = 10;
[Tooltip("Number of columns in the decoration grid")]
[SerializeField] private int gridColumns = 2;
[Tooltip("Spacing between grid items")]
[SerializeField] private Vector2 gridSpacing = new Vector2(10f, 10f);
[Header("Drag and Drop")]
[Tooltip("Duration for icon to full size transition when dragging starts")]
[SerializeField] private float dragScaleTransitionDuration = 0.2f;
[Tooltip("Duration for return to menu animation")]
[SerializeField] private float returnToMenuDuration = 0.3f;
[Tooltip("Minimum overlap percentage required to place on statue (0-1)")]
[SerializeField] private float minOverlapPercentage = 0.1f;
[Header("Animation")]
[Tooltip("Scale multiplier for hover effect (1.0 = no change, 1.1 = 10% larger)")]
[SerializeField] private float hoverScaleMultiplier = 1.05f;
[Tooltip("Duration of hover animation")]
[SerializeField] private float hoverAnimationDuration = 0.2f;
[Tooltip("Duration for placement animation")]
[SerializeField] private float placementAnimationDuration = 0.15f;
[Header("Photo Settings")]
[Tooltip("PlayerPrefs key for saving the statue photo")]
[SerializeField] private string photoSaveKey = "MrCementStatuePhoto";
[Tooltip("Quality of the captured photo (1-100)")]
[SerializeField] private int photoQuality = 85;
[Tooltip("Whether to capture full screen or just statue area")]
[SerializeField] private bool captureFullScreen;
[Header("Rewards")]
[Tooltip("Number of Blokkemon cards awarded on completion")]
[SerializeField] private int cardsRewardCount = 3;
[Tooltip("Whether completion is automatic or requires confirmation")]
[SerializeField] private bool autoCompleteOnPhoto = true;
[Header("State Persistence")]
[Tooltip("Whether to save decoration positions between sessions")]
[SerializeField] private bool enableStatePersistence = true;
[Tooltip("PlayerPrefs key for saving decoration state")]
[SerializeField] private string stateSaveKey = "StatueDecorationState";
[Tooltip("Maximum number of decorations to save")]
[SerializeField] private int maxSavedDecorations = 50;
// IStatueDressupSettings implementation - Decoration Display
public Vector2 DefaultAuthoredSize => defaultAuthoredSize;
// IStatueDressupSettings implementation - Decoration Content
public List<DecorationData> AllDecorations => allDecorations;
// IStatueDressupSettings implementation - Menu Configuration
public int ItemsPerPage => itemsPerPage;
public int GridColumns => gridColumns;
public Vector2 GridSpacing => gridSpacing;
// IStatueDressupSettings implementation - Drag and Drop
public float DragScaleTransitionDuration => dragScaleTransitionDuration;
public float ReturnToMenuDuration => returnToMenuDuration;
public float MinOverlapPercentage => minOverlapPercentage;
// IStatueDressupSettings implementation - Animation
public float HoverScaleMultiplier => hoverScaleMultiplier;
public float HoverAnimationDuration => hoverAnimationDuration;
public float PlacementAnimationDuration => placementAnimationDuration;
// IStatueDressupSettings implementation - Photo Settings
public string PhotoSaveKey => photoSaveKey;
public int PhotoQuality => photoQuality;
public bool CaptureFullScreen => captureFullScreen;
// IStatueDressupSettings implementation - Rewards
public int CardsRewardCount => cardsRewardCount;
public bool AutoCompleteOnPhoto => autoCompleteOnPhoto;
// IStatueDressupSettings implementation - State Persistence
public bool EnableStatePersistence => enableStatePersistence;
public string StateSaveKey => stateSaveKey;
public int MaxSavedDecorations => maxSavedDecorations;
public override void OnValidate()
{
base.OnValidate();
// Validate decoration display
defaultAuthoredSize.x = Mathf.Max(32f, defaultAuthoredSize.x);
defaultAuthoredSize.y = Mathf.Max(32f, defaultAuthoredSize.y);
// Validate menu configuration
itemsPerPage = Mathf.Max(1, itemsPerPage);
gridColumns = Mathf.Max(1, gridColumns);
gridSpacing.x = Mathf.Max(0f, gridSpacing.x);
gridSpacing.y = Mathf.Max(0f, gridSpacing.y);
// Validate drag and drop
dragScaleTransitionDuration = Mathf.Max(0.01f, dragScaleTransitionDuration);
returnToMenuDuration = Mathf.Max(0.01f, returnToMenuDuration);
minOverlapPercentage = Mathf.Clamp01(minOverlapPercentage);
// Validate animation
hoverScaleMultiplier = Mathf.Max(1f, hoverScaleMultiplier);
hoverAnimationDuration = Mathf.Max(0.01f, hoverAnimationDuration);
placementAnimationDuration = Mathf.Max(0.01f, placementAnimationDuration);
// Validate photo settings
photoQuality = Mathf.Clamp(photoQuality, 1, 100);
// Validate rewards
cardsRewardCount = Mathf.Max(0, cardsRewardCount);
// Validate state persistence
maxSavedDecorations = Mathf.Max(1, maxSavedDecorations);
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 4fcf232a64e34f489b874519cc96339e
timeCreated: 1763984221

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 5596931aef9448a3b369f7917af07797
timeCreated: 1763745490

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 34525368248b48e0b271537891123818
timeCreated: 1763745579

View File

@@ -0,0 +1,333 @@
using System.Collections.Generic;
using Core;
using Core.Lifecycle;
using Minigames.StatueDressup.Data;
using Minigames.StatueDressup.DragDrop;
using UnityEngine;
using UnityEngine.UI;
namespace Minigames.StatueDressup.Controllers
{
/// <summary>
/// Manages the side menu with decoration items and pagination
/// </summary>
public class DecorationMenuController : ManagedBehaviour
{
[Header("References")]
[SerializeField] private DecorationGridIcon iconPrefab;
[SerializeField] private DecorationDraggableInstance draggablePrefab;
[SerializeField] private Transform itemsContainer;
[SerializeField] private Transform draggableContainer; // Parent for spawned draggables
[SerializeField] private Button nextPageButton;
[SerializeField] private Button previousPageButton;
[SerializeField] private StatueDecorationController statueController; // Controller for registration
[SerializeField] private Image statueOutline; // Outline image shown during drag to indicate valid drop area
[Header("Layout")]
[SerializeField] private GridLayoutGroup gridLayout;
private int _currentPage;
private int _totalPages;
private List<DecorationGridIcon> _spawnedIcons = new List<DecorationGridIcon>();
private AppleHills.Core.Settings.IStatueDressupSettings _settings;
// Properties
public int CurrentPage => _currentPage;
public int TotalPages => _totalPages;
/// <summary>
/// Early initialization - get settings reference
/// </summary>
internal override void OnManagedAwake()
{
base.OnManagedAwake();
// Get settings early
_settings = GameManager.GetSettingsObject<AppleHills.Core.Settings.IStatueDressupSettings>();
if (_settings == null)
{
Logging.Error("[DecorationMenuController] Failed to load StatueDressupSettings!");
}
}
/// <summary>
/// Main initialization after all managers are ready
/// </summary>
internal override void OnManagedStart()
{
base.OnManagedStart();
if (_settings == null)
{
Logging.Error("[DecorationMenuController] Cannot initialize without settings!");
return;
}
// Ensure outline starts hidden
if (statueOutline != null)
{
statueOutline.gameObject.SetActive(false);
}
var allDecorations = _settings.AllDecorations;
int itemsPerPage = _settings.ItemsPerPage;
Logging.Debug($"[DecorationMenuController] Initializing with {allDecorations?.Count ?? 0} decorations");
// Calculate total pages
if (allDecorations != null && allDecorations.Count > 0)
{
_totalPages = Mathf.CeilToInt((float)allDecorations.Count / itemsPerPage);
Logging.Debug($"[DecorationMenuController] Total pages: {_totalPages}");
}
else
{
Logging.Warning("[DecorationMenuController] No decorations found in settings!");
_totalPages = 0;
}
// Setup buttons
if (nextPageButton != null)
{
nextPageButton.onClick.AddListener(OnNextPage);
}
if (previousPageButton != null)
{
previousPageButton.onClick.AddListener(OnPreviousPage);
}
// Subscribe to drag events for all items
// (will be handled per-item when spawned)
// Populate first page
PopulateCurrentPage();
}
/// <summary>
/// Populate the current page with decoration icons
/// </summary>
private void PopulateCurrentPage()
{
if (_settings == null) return;
var allDecorations = _settings.AllDecorations;
int itemsPerPage = _settings.ItemsPerPage;
if (allDecorations == null || allDecorations.Count == 0)
{
Logging.Warning("[DecorationMenuController] No decorations to populate");
return;
}
Logging.Debug($"[DecorationMenuController] Populating page {_currentPage + 1}/{_totalPages}");
// Clear existing icons
ClearIcons();
// Calculate range for current page
int startIndex = _currentPage * itemsPerPage;
int endIndex = Mathf.Min(startIndex + itemsPerPage, allDecorations.Count);
Logging.Debug($"[DecorationMenuController] Spawning icons {startIndex} to {endIndex - 1}");
// Spawn icons for this page
for (int i = startIndex; i < endIndex; i++)
{
SpawnGridIcon(allDecorations[i]);
}
// Update button states
UpdateNavigationButtons();
}
/// <summary>
/// Spawn a grid icon in the menu
/// </summary>
private void SpawnGridIcon(DecorationData data)
{
if (iconPrefab == null || itemsContainer == null)
{
Logging.Warning("[DecorationMenuController] Missing icon prefab or container");
return;
}
DecorationGridIcon icon = Instantiate(iconPrefab, itemsContainer);
icon.Initialize(data, this);
_spawnedIcons.Add(icon);
Logging.Debug($"[DecorationMenuController] Spawned icon: {data.DecorationName}");
}
/// <summary>
/// Factory method: Spawn a draggable instance at cursor position
/// Called by DecorationGridIcon when drag starts
/// </summary>
public DecorationDraggableInstance SpawnDraggableInstance(DecorationData data, Vector3 screenPosition)
{
if (draggablePrefab == null || statueController == null)
{
Logging.Warning("[DecorationMenuController] Missing draggable prefab or statue controller");
return null;
}
// Show statue outline
ShowStatueOutline();
// Determine parent - use draggableContainer if set, otherwise itemsContainer's parent
Transform parent = draggableContainer != null ? draggableContainer : itemsContainer.parent;
// Spawn draggable instance
DecorationDraggableInstance instance = Instantiate(draggablePrefab, parent);
// Get outline RectTransform for overlap detection
RectTransform outlineRect = statueOutline != null ? statueOutline.rectTransform : null;
// Initialize with references
instance.Initialize(
data,
outlineRect,
statueController.StatueParent,
statueController,
_settings,
OnDraggableFinished
);
// Position at cursor (in local space)
Canvas canvas = GetComponentInParent<Canvas>();
if (canvas != null)
{
RectTransformUtility.ScreenPointToLocalPointInRectangle(
canvas.transform as RectTransform,
screenPosition,
canvas.worldCamera,
out Vector2 localPoint);
RectTransform instanceRect = instance.GetComponent<RectTransform>();
if (instanceRect != null)
{
instanceRect.localPosition = localPoint;
}
}
Logging.Debug($"[DecorationMenuController] Spawned draggable instance: {data.DecorationName}");
return instance;
}
/// <summary>
/// Show the statue outline to indicate valid drop area
/// </summary>
private void ShowStatueOutline()
{
if (statueOutline != null)
{
statueOutline.gameObject.SetActive(true);
Logging.Debug("[DecorationMenuController] Statue outline shown");
}
}
/// <summary>
/// Hide the statue outline after drag ends
/// </summary>
private void HideStatueOutline()
{
if (statueOutline != null)
{
statueOutline.gameObject.SetActive(false);
Logging.Debug("[DecorationMenuController] Statue outline hidden");
}
}
/// <summary>
/// Callback from DecorationDraggableInstance when drag finishes
/// </summary>
private void OnDraggableFinished()
{
HideStatueOutline();
}
/// <summary>
/// Clear all spawned icons
/// </summary>
private void ClearIcons()
{
foreach (var icon in _spawnedIcons)
{
if (icon != null)
{
Destroy(icon.gameObject);
}
}
_spawnedIcons.Clear();
}
/// <summary>
/// Navigate to next page
/// </summary>
private void OnNextPage()
{
if (_currentPage < _totalPages - 1)
{
_currentPage++;
PopulateCurrentPage();
Logging.Debug($"[DecorationMenuController] Next page: {_currentPage + 1}/{_totalPages}");
}
}
/// <summary>
/// Navigate to previous page
/// </summary>
private void OnPreviousPage()
{
if (_currentPage > 0)
{
_currentPage--;
PopulateCurrentPage();
Logging.Debug($"[DecorationMenuController] Previous page: {_currentPage + 1}/{_totalPages}");
}
}
/// <summary>
/// Update navigation button interactability
/// </summary>
private void UpdateNavigationButtons()
{
if (previousPageButton != null)
{
previousPageButton.interactable = _currentPage > 0;
}
if (nextPageButton != null)
{
nextPageButton.interactable = _currentPage < _totalPages - 1;
}
}
/// <summary>
/// Cleanup when menu controller is destroyed
/// </summary>
internal override void OnManagedDestroy()
{
base.OnManagedDestroy();
// Cleanup button listeners
if (nextPageButton != null)
{
nextPageButton.onClick.RemoveListener(OnNextPage);
}
if (previousPageButton != null)
{
previousPageButton.onClick.RemoveListener(OnPreviousPage);
}
// Cleanup icons
ClearIcons();
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: acbd542762b44e719326dff6c3a69e6e
timeCreated: 1763745579

View File

@@ -0,0 +1,307 @@
using System.Collections.Generic;
using Core;
using Core.Lifecycle;
using Minigames.StatueDressup.DragDrop;
using UnityEngine;
using UnityEngine.UI;
namespace Minigames.StatueDressup.Controllers
{
/// <summary>
/// Main controller for the Mr. Cement statue decoration minigame
/// Uses overlap-based placement instead of slots
/// </summary>
public class StatueDecorationController : ManagedBehaviour
{
[Header("References")]
[SerializeField] private RectTransform statueArea; // Statue area for overlap detection
[SerializeField] private Transform statueParent; // Parent for placed decorations
[SerializeField] private DecorationMenuController menuController;
[SerializeField] private Button takePhotoButton;
[SerializeField] private GameObject statue;
[Header("UI Elements to Hide for Photo")]
[SerializeField] private GameObject[] uiElementsToHideForPhoto;
[Header("Photo Settings")]
[SerializeField] private RectTransform photoArea; // Area to capture
[SerializeField] private string photoSaveKey = "MrCementStatuePhoto";
private List<DecorationDraggableInstance> _placedDecorations = new List<DecorationDraggableInstance>();
private bool _minigameCompleted;
private AppleHills.Core.Settings.IStatueDressupSettings _settings;
// Public property for menu controller
public Transform StatueParent => statueParent;
/// <summary>
/// Early initialization - get settings reference
/// </summary>
internal override void OnManagedAwake()
{
base.OnManagedAwake();
// Get settings early
_settings = GameManager.GetSettingsObject<AppleHills.Core.Settings.IStatueDressupSettings>();
}
/// <summary>
/// Main initialization after all managers are ready
/// </summary>
internal override void OnManagedStart()
{
base.OnManagedStart();
Logging.Debug("[StatueDecorationController] Initializing minigame");
// Setup photo button
if (takePhotoButton != null)
{
takePhotoButton.onClick.AddListener(OnTakePhoto);
}
// Subscribe to menu controller for tracking placed items
// Items will manage their own placement via overlap detection
if (menuController != null)
{
// Menu controller will handle spawning replacements
Logging.Debug("[StatueDecorationController] Menu controller connected");
}
// Load saved state if exists
LoadStatueState();
}
/// <summary>
/// Register a decoration as placed on statue
/// </summary>
public void RegisterDecoration(DecorationDraggableInstance decoration)
{
if (decoration != null && !_placedDecorations.Contains(decoration))
{
_placedDecorations.Add(decoration);
Logging.Debug($"[StatueDecorationController] Decoration placed: {decoration.Data?.DecorationName}");
// Auto-save state
SaveStatueState();
}
}
/// <summary>
/// Unregister a decoration (when removed)
/// </summary>
public void UnregisterDecoration(DecorationDraggableInstance decoration)
{
if (decoration != null && _placedDecorations.Contains(decoration))
{
_placedDecorations.Remove(decoration);
Logging.Debug($"[StatueDecorationController] Decoration removed: {decoration.Data?.DecorationName}");
// Auto-save state
SaveStatueState();
}
}
/// <summary>
/// Take photo of decorated statue
/// </summary>
private void OnTakePhoto()
{
if (_minigameCompleted)
{
Logging.Debug("[StatueDecorationController] Minigame already completed");
return;
}
Logging.Debug("[StatueDecorationController] Taking photo of statue");
// Hide UI elements
HideUIForPhoto(true);
// Wait a frame for UI to hide, then capture
StartCoroutine(CapturePhotoCoroutine());
}
/// <summary>
/// Capture photo after UI is hidden
/// </summary>
private System.Collections.IEnumerator CapturePhotoCoroutine()
{
yield return new WaitForEndOfFrame();
// Capture the photo area
Texture2D photo = CaptureScreenshotArea();
if (photo != null)
{
// Save photo to album
SavePhotoToAlbum(photo);
// Award cards
AwardCards();
// Update town icon
UpdateTownIcon(photo);
// Show completion feedback
ShowCompletionFeedback();
_minigameCompleted = true;
}
// Restore UI
HideUIForPhoto(false);
}
/// <summary>
/// Capture screenshot of specific area
/// </summary>
private Texture2D CaptureScreenshotArea()
{
if (photoArea == null)
{
Logging.Warning("[StatueDecorationController] No photo area specified, capturing full screen");
// Capture full screen
Texture2D screenshot = new Texture2D(Screen.width, Screen.height, TextureFormat.RGB24, false);
screenshot.ReadPixels(new Rect(0, 0, Screen.width, Screen.height), 0, 0);
screenshot.Apply();
return screenshot;
}
// Get world corners of the rect
Vector3[] corners = new Vector3[4];
photoArea.GetWorldCorners(corners);
// Convert to screen space
Vector2 min = RectTransformUtility.WorldToScreenPoint(Camera.main, corners[0]);
Vector2 max = RectTransformUtility.WorldToScreenPoint(Camera.main, corners[2]);
int width = (int)(max.x - min.x);
int height = (int)(max.y - min.y);
Logging.Debug($"[StatueDecorationController] Capturing area: {width}x{height} at ({min.x}, {min.y})");
// Capture the specified area
Texture2D areaScreenshot = new Texture2D(width, height, TextureFormat.RGB24, false);
areaScreenshot.ReadPixels(new Rect(min.x, min.y, width, height), 0, 0);
areaScreenshot.Apply();
return areaScreenshot;
}
/// <summary>
/// Save photo to card album
/// </summary>
private void SavePhotoToAlbum(Texture2D photo)
{
// TODO: Integrate with existing album save system
// For now, save to PlayerPrefs as base64
byte[] bytes = photo.EncodeToPNG();
string base64 = System.Convert.ToBase64String(bytes);
string saveKey = _settings?.PhotoSaveKey ?? photoSaveKey;
PlayerPrefs.SetString(saveKey, base64);
PlayerPrefs.Save();
Logging.Debug("[StatueDecorationController] Photo saved to album");
}
/// <summary>
/// Award Blokkemon cards to player
/// </summary>
private void AwardCards()
{
// TODO: Integrate with MinigameBoosterGiver
// MinigameBoosterGiver.GiveBooster();
Logging.Debug("[StatueDecorationController] Cards awarded (TODO: implement)");
}
/// <summary>
/// Update town menu icon with decorated statue
/// </summary>
private void UpdateTownIcon(Texture2D photo)
{
// TODO: Integrate with town system
// TownIconUpdater.SetStatueIcon(photo);
Logging.Debug("[StatueDecorationController] Town icon updated (TODO: implement)");
}
/// <summary>
/// Show completion feedback to player
/// </summary>
private void ShowCompletionFeedback()
{
// TODO: Show success message/animation
DebugUIMessage.Show("Photo captured! Mr. Cement looks amazing!", Color.green);
Logging.Debug("[StatueDecorationController] Minigame completed!");
}
/// <summary>
/// Hide/show UI elements for photo
/// </summary>
private void HideUIForPhoto(bool hide)
{
foreach (var element in uiElementsToHideForPhoto)
{
if (element != null)
{
element.SetActive(!hide);
}
}
}
/// <summary>
/// Save current statue decoration state
/// </summary>
private void SaveStatueState()
{
// Check if persistence is enabled
if (_settings == null || !_settings.EnableStatePersistence)
{
Logging.Debug("[StatueDecorationController] State persistence disabled");
return;
}
// TODO: Implement save system
// Save decoration ID + position + rotation for each placed item
// Respect MaxSavedDecorations limit
Logging.Debug($"[StatueDecorationController] State saved to {_settings.StateSaveKey} (TODO: implement persistence)");
}
/// <summary>
/// Load saved statue decoration state
/// </summary>
private void LoadStatueState()
{
// Check if persistence is enabled
if (_settings == null || !_settings.EnableStatePersistence)
{
Logging.Debug("[StatueDecorationController] State persistence disabled");
return;
}
// TODO: Implement load system
// Restore decorations from saved state
Logging.Debug($"[StatueDecorationController] State loaded from {_settings.StateSaveKey} (TODO: implement persistence)");
}
/// <summary>
/// Cleanup when controller is destroyed
/// </summary>
internal override void OnManagedDestroy()
{
base.OnManagedDestroy();
// Cleanup button listener
if (takePhotoButton != null)
{
takePhotoButton.onClick.RemoveListener(OnTakePhoto);
}
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 19e312ceaffa40ae90ac87b8209319cb
timeCreated: 1763745610

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: a6e7dfb0a39c441fb8ac888a5e58a91e
timeCreated: 1763745500

View File

@@ -0,0 +1,42 @@
using UnityEngine;
namespace Minigames.StatueDressup.Data
{
/// <summary>
/// ScriptableObject data definition for statue decorations
/// </summary>
[CreateAssetMenu(fileName = "DecorationData", menuName = "AppleHills/Minigames/Decoration Data", order = 1)]
public class DecorationData : ScriptableObject
{
[Header("Identity")]
[SerializeField] private string decorationId;
[SerializeField] private string decorationName;
[Header("Visual")]
[SerializeField] private Sprite decorationSprite;
[Header("Size Configuration")]
[Tooltip("Full size when placed on statue (actual sprite size)")]
[SerializeField] private Vector2 authoredSize = new Vector2(128f, 128f);
[Header("Progression (Optional)")]
[SerializeField] private bool isUnlocked = true;
// Properties
public string DecorationId => decorationId;
public string DecorationName => decorationName;
public Sprite DecorationSprite => decorationSprite;
public Vector2 AuthoredSize => authoredSize;
public bool IsUnlocked => isUnlocked;
private void OnValidate()
{
// Auto-generate ID from name if empty
if (string.IsNullOrEmpty(decorationId) && !string.IsNullOrEmpty(decorationName))
{
decorationId = decorationName.Replace(" ", "_").ToLower();
}
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 74c6ae9aa803480c8fb918dd58cfb809
timeCreated: 1763745511

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 4c3389a935534b7b86800516ffa42acb
timeCreated: 1763745531

View File

@@ -0,0 +1,242 @@
using Core;
using Minigames.StatueDressup.Controllers;
using Minigames.StatueDressup.Data;
using Minigames.StatueDressup.Utils;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
namespace Minigames.StatueDressup.DragDrop
{
/// <summary>
/// Draggable instance of a decoration that can be placed on the statue.
/// Created dynamically when dragging from menu or picking up from statue.
/// Destroyed if dropped outside statue area.
/// </summary>
public class DecorationDraggableInstance : MonoBehaviour
{
[Header("References")]
[SerializeField] private Image decorationImage;
[SerializeField] private CanvasGroup canvasGroup;
private DecorationData _decorationData;
private RectTransform _rectTransform;
private Canvas _canvas;
private RectTransform _statueOutline;
private Transform _statueParent;
private StatueDecorationController _controller;
private AppleHills.Core.Settings.IStatueDressupSettings _settings;
private System.Action _onFinishedCallback;
private bool _isDragging;
private bool _isPlacedOnStatue;
private Vector3 _dragOffset;
// Properties
public DecorationData Data => _decorationData;
public bool IsPlacedOnStatue => _isPlacedOnStatue;
private void Awake()
{
_rectTransform = GetComponent<RectTransform>();
_canvas = GetComponentInParent<Canvas>();
if (canvasGroup == null)
{
canvasGroup = gameObject.AddComponent<CanvasGroup>();
}
}
/// <summary>
/// Initialize the draggable instance
/// </summary>
public void Initialize(DecorationData data, RectTransform statueOutline, Transform statueParent,
StatueDecorationController controller, AppleHills.Core.Settings.IStatueDressupSettings settings,
System.Action onFinishedCallback)
{
_decorationData = data;
_statueOutline = statueOutline;
_statueParent = statueParent;
_controller = controller;
_settings = settings;
_onFinishedCallback = onFinishedCallback;
// Set sprite
if (decorationImage != null && data != null && data.DecorationSprite != null)
{
decorationImage.sprite = data.DecorationSprite;
}
// Set authored size
if (_rectTransform != null && data != null)
{
_rectTransform.sizeDelta = data.AuthoredSize;
}
Logging.Debug($"[DecorationDraggableInstance] Initialized: {data?.DecorationName}");
}
/// <summary>
/// Start dragging from icon
/// </summary>
public void StartDragFromIcon(PointerEventData eventData)
{
_isDragging = true;
// Calculate offset from cursor to object center
RectTransformUtility.ScreenPointToLocalPointInRectangle(
_canvas.transform as RectTransform,
eventData.position,
eventData.pressEventCamera,
out Vector2 localPoint);
_dragOffset = _rectTransform.localPosition - (Vector3)localPoint;
Logging.Debug($"[DecorationDraggableInstance] Started drag from icon: {_decorationData?.DecorationName}");
}
/// <summary>
/// Continue dragging
/// </summary>
public void ContinueDrag(PointerEventData eventData)
{
if (!_isDragging) return;
// Update position to follow cursor
RectTransformUtility.ScreenPointToLocalPointInRectangle(
_canvas.transform as RectTransform,
eventData.position,
eventData.pressEventCamera,
out Vector2 localPoint);
_rectTransform.localPosition = localPoint + (Vector2)_dragOffset;
}
/// <summary>
/// End drag - check placement
/// </summary>
public void EndDrag(PointerEventData eventData)
{
_isDragging = false;
Logging.Debug($"[DecorationDraggableInstance] Drag ended: {_decorationData?.DecorationName}");
// Check if overlapping with statue
if (IsOverlappingStatue())
{
PlaceOnStatue();
}
else
{
PlayPopOutAndDestroy();
}
}
/// <summary>
/// Check if item overlaps with statue outline
/// </summary>
private bool IsOverlappingStatue()
{
if (_statueOutline == null || _rectTransform == null)
{
Logging.Warning($"[DecorationDraggableInstance] Cannot check overlap - statueOutline or RectTransform is null");
return false;
}
// Get bounds of this item in world space
Rect itemRect = GetWorldRect(_rectTransform);
Rect outlineRect = GetWorldRect(_statueOutline);
// Check for any overlap
bool overlaps = itemRect.Overlaps(outlineRect);
Logging.Debug($"[DecorationDraggableInstance] Overlap check: {_decorationData?.DecorationName}, overlaps={overlaps}");
return overlaps;
}
/// <summary>
/// Get world space rect for a RectTransform
/// </summary>
private Rect GetWorldRect(RectTransform rectTransform)
{
Vector3[] corners = new Vector3[4];
rectTransform.GetWorldCorners(corners);
Vector3 bottomLeft = corners[0];
Vector3 topRight = corners[2];
return new Rect(bottomLeft.x, bottomLeft.y, topRight.x - bottomLeft.x, topRight.y - bottomLeft.y);
}
/// <summary>
/// Place item on statue at current position
/// </summary>
private void PlaceOnStatue()
{
Logging.Debug($"[DecorationDraggableInstance] Placing on statue: {_decorationData?.DecorationName}");
_isPlacedOnStatue = true;
// Move to statue parent if specified
if (_statueParent != null && transform.parent != _statueParent)
{
transform.SetParent(_statueParent, true); // Keep world position
}
// Register with controller
if (_controller != null)
{
_controller.RegisterDecoration(this);
}
// Notify menu controller to hide outline
_onFinishedCallback?.Invoke();
}
/// <summary>
/// Play pop-out animation and destroy
/// </summary>
private void PlayPopOutAndDestroy()
{
Logging.Debug($"[DecorationDraggableInstance] Pop-out and destroy: {_decorationData?.DecorationName}");
// Notify menu controller to hide outline immediately
_onFinishedCallback?.Invoke();
float duration = _settings?.PlacementAnimationDuration ?? 0.3f;
// Play pop-out with fade animation
TweenAnimationUtility.PopOutWithFade(transform, canvasGroup, duration, () =>
{
Destroy(gameObject);
});
}
/// <summary>
/// Allow picking up from statue for repositioning
/// </summary>
public void StartDragFromStatue(Vector3 pointerPosition)
{
if (_controller != null)
{
_controller.UnregisterDecoration(this);
}
_isPlacedOnStatue = false;
_isDragging = true;
// Calculate offset
RectTransformUtility.ScreenPointToLocalPointInRectangle(
_canvas.transform as RectTransform,
pointerPosition,
null,
out Vector2 localPoint);
_dragOffset = _rectTransform.localPosition - (Vector3)localPoint;
Logging.Debug($"[DecorationDraggableInstance] Started drag from statue: {_decorationData?.DecorationName}");
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: e4659fd035c74a79af0311de9e17f44a
timeCreated: 1763991638

View File

@@ -0,0 +1,100 @@
using Core;
using Minigames.StatueDressup.Data;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
namespace Minigames.StatueDressup.DragDrop
{
/// <summary>
/// Static grid icon for decorations in the menu.
/// Handles tap and drag initiation, but doesn't move itself.
/// Spawns a draggable instance when drag starts.
/// </summary>
public class DecorationGridIcon : MonoBehaviour, IPointerClickHandler, IBeginDragHandler, IDragHandler, IEndDragHandler
{
[Header("References")]
[SerializeField] private Image iconImage;
[SerializeField] private DecorationData decorationData;
private Controllers.DecorationMenuController _menuController;
private DecorationDraggableInstance _activeDraggableInstance;
// Properties
public DecorationData Data => decorationData;
/// <summary>
/// Initialize the icon with decoration data
/// </summary>
public void Initialize(DecorationData data, Controllers.DecorationMenuController controller)
{
decorationData = data;
_menuController = controller;
if (iconImage != null && data != null && data.DecorationSprite != null)
{
iconImage.sprite = data.DecorationSprite;
}
}
/// <summary>
/// Handle tap/click on icon
/// </summary>
public void OnPointerClick(PointerEventData eventData)
{
// Only process clicks if we're not dragging
if (_activeDraggableInstance == null)
{
Logging.Debug($"[DecorationGridIcon] Item tapped: {decorationData?.DecorationName}");
// Future: Open detail view, preview, etc.
}
}
/// <summary>
/// Handle drag start - spawn draggable instance
/// </summary>
public void OnBeginDrag(PointerEventData eventData)
{
if (_menuController == null || decorationData == null)
{
Logging.Warning("[DecorationGridIcon] Cannot start drag - missing controller or data");
return;
}
Logging.Debug($"[DecorationGridIcon] Starting drag for: {decorationData.DecorationName}");
// Spawn draggable instance at cursor position
_activeDraggableInstance = _menuController.SpawnDraggableInstance(decorationData, eventData.position);
// Start the drag on the spawned instance
if (_activeDraggableInstance != null)
{
_activeDraggableInstance.StartDragFromIcon(eventData);
}
}
/// <summary>
/// Forward drag events to the active draggable instance
/// </summary>
public void OnDrag(PointerEventData eventData)
{
if (_activeDraggableInstance != null)
{
_activeDraggableInstance.ContinueDrag(eventData);
}
}
/// <summary>
/// Forward drag end to the active draggable instance
/// </summary>
public void OnEndDrag(PointerEventData eventData)
{
if (_activeDraggableInstance != null)
{
_activeDraggableInstance.EndDrag(eventData);
_activeDraggableInstance = null;
}
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 9c806d80a321498c9f33f13d7a31065c
timeCreated: 1763991611

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: fe03648f638e4872abafaf49234a3f55
timeCreated: 1763745490

View File

@@ -0,0 +1,171 @@
using Pixelplacement;
using Pixelplacement.TweenSystem;
using UnityEngine;
using System;
namespace Minigames.StatueDressup.Utils
{
/// <summary>
/// Common animation utilities extracted from CardAnimator pattern.
/// Provides reusable tween animations for UI elements.
/// </summary>
public static class TweenAnimationUtility
{
#region Scale Animations
/// <summary>
/// Animate scale to target value with ease in-out
/// </summary>
public static TweenBase AnimateScale(Transform transform, Vector3 targetScale, float duration, Action onComplete = null)
{
return Tween.LocalScale(transform, targetScale, duration, 0f, Tween.EaseInOut, completeCallback: onComplete);
}
/// <summary>
/// Pulse scale animation (scale up then back to original)
/// </summary>
public static void PulseScale(Transform transform, float pulseAmount = 1.1f, float duration = 0.2f, Action onComplete = null)
{
Vector3 originalScale = transform.localScale;
Vector3 pulseScale = originalScale * pulseAmount;
Tween.LocalScale(transform, pulseScale, duration, 0f, Tween.EaseOutBack,
completeCallback: () =>
{
Tween.LocalScale(transform, originalScale, duration, 0f, Tween.EaseInBack, completeCallback: onComplete);
});
}
/// <summary>
/// Pop-in animation (scale from 0 to target with overshoot)
/// </summary>
public static TweenBase PopIn(Transform transform, Vector3 targetScale, float duration = 0.5f, Action onComplete = null)
{
transform.localScale = Vector3.zero;
return Tween.LocalScale(transform, targetScale, duration, 0f, Tween.EaseOutBack, completeCallback: onComplete);
}
/// <summary>
/// Pop-out animation (scale from current to 0)
/// </summary>
public static TweenBase PopOut(Transform transform, float duration = 0.3f, Action onComplete = null)
{
return Tween.LocalScale(transform, Vector3.zero, duration, 0f, Tween.EaseInBack, completeCallback: onComplete);
}
/// <summary>
/// Smooth scale transition with bounce
/// </summary>
public static TweenBase ScaleWithBounce(Transform transform, Vector3 targetScale, float duration, Action onComplete = null)
{
return Tween.LocalScale(transform, targetScale, duration, 0f, Tween.EaseOutBack, completeCallback: onComplete);
}
#endregion
#region Position Animations
/// <summary>
/// Animate anchored position (for RectTransform UI elements)
/// </summary>
public static TweenBase AnimateAnchoredPosition(RectTransform rectTransform, Vector2 targetPosition, float duration, Action onComplete = null)
{
return Tween.AnchoredPosition(rectTransform, targetPosition, duration, 0f, Tween.EaseInOut, completeCallback: onComplete);
}
/// <summary>
/// Animate local position (for regular transforms)
/// </summary>
public static TweenBase AnimateLocalPosition(Transform transform, Vector3 targetPosition, float duration, Action onComplete = null)
{
return Tween.LocalPosition(transform, targetPosition, duration, 0f, Tween.EaseInOut, completeCallback: onComplete);
}
/// <summary>
/// Move with bounce effect
/// </summary>
public static TweenBase MoveWithBounce(RectTransform rectTransform, Vector2 targetPosition, float duration, Action onComplete = null)
{
return Tween.AnchoredPosition(rectTransform, targetPosition, duration, 0f, Tween.EaseOutBack, completeCallback: onComplete);
}
#endregion
#region Combined Hover Animations
/// <summary>
/// Hover enter animation (lift and scale) for RectTransform
/// </summary>
public static void HoverEnter(RectTransform rectTransform, Vector2 originalPosition, float liftAmount = 20f,
float scaleMultiplier = 1.05f, float duration = 0.2f, Action onComplete = null)
{
Vector2 targetPos = originalPosition + Vector2.up * liftAmount;
Tween.AnchoredPosition(rectTransform, targetPos, duration, 0f, Tween.EaseOutBack);
Tween.LocalScale(rectTransform, Vector3.one * scaleMultiplier, duration, 0f, Tween.EaseOutBack, completeCallback: onComplete);
}
/// <summary>
/// Hover exit animation (return to original position and scale) for RectTransform
/// </summary>
public static void HoverExit(RectTransform rectTransform, Vector2 originalPosition, float duration = 0.2f, Action onComplete = null)
{
Tween.AnchoredPosition(rectTransform, originalPosition, duration, 0f, Tween.EaseInBack);
Tween.LocalScale(rectTransform, Vector3.one, duration, 0f, Tween.EaseInBack, completeCallback: onComplete);
}
/// <summary>
/// Glow pulse effect (scale up/down repeatedly)
/// </summary>
public static TweenBase StartGlowPulse(Transform transform, float pulseAmount = 1.1f, float duration = 0.8f)
{
Vector3 originalScale = transform.localScale;
Vector3 pulseScale = originalScale * pulseAmount;
return Tween.LocalScale(transform, pulseScale, duration, 0f, Tween.EaseIn, Tween.LoopType.PingPong);
}
/// <summary>
/// Stop any active tweens on transform
/// </summary>
public static void StopTweens(Transform transform)
{
Tween.Cancel(transform.GetInstanceID());
}
#endregion
#region Fade Animations
/// <summary>
/// Fade CanvasGroup alpha
/// </summary>
public static TweenBase FadeCanvasGroup(CanvasGroup canvasGroup, float targetAlpha, float duration, Action onComplete = null)
{
return Tween.CanvasGroupAlpha(canvasGroup, targetAlpha, duration, 0f, Tween.EaseInOut, completeCallback: onComplete);
}
/// <summary>
/// Pop-out with fade - scale to 0 and fade out simultaneously
/// </summary>
public static void PopOutWithFade(Transform transform, CanvasGroup canvasGroup, float duration, Action onComplete = null)
{
// Scale to 0
Tween.LocalScale(transform, Vector3.zero, duration, 0f, Tween.EaseInBack);
// Fade out simultaneously
if (canvasGroup != null)
{
Tween.CanvasGroupAlpha(canvasGroup, 0f, duration, 0f, Tween.EaseInOut, completeCallback: onComplete);
}
else
{
// If no canvas group, just call complete after scale
Tween.LocalScale(transform, Vector3.zero, duration, 0f, Tween.EaseInBack, completeCallback: onComplete);
}
}
#endregion
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: abd48147eff149508890fe2fa87b8421
timeCreated: 1763745490

View File

@@ -235,7 +235,7 @@ namespace UI
case "Quarry": case "Quarry":
currentUIMode = UIMode.Puzzle; currentUIMode = UIMode.Puzzle;
break; break;
case "DivingForPictures" or "CardQualityControl" or "BirdPoop": case "DivingForPictures" or "CardQualityControl" or "BirdPoop" or "StatueDecoration":
currentUIMode = UIMode.Minigame; currentUIMode = UIMode.Minigame;
break; break;
} }

View File

@@ -27,3 +27,5 @@ MonoBehaviour:
obstacleMaxSpawnY: 3 obstacleMaxSpawnY: 3
poopFallSpeed: 10 poopFallSpeed: 10
poopDestroyYPosition: -20 poopDestroyYPosition: -20
targetMoveSpeed: 4
targetSpawnInterval: 3

View File

@@ -35,19 +35,24 @@ MonoBehaviour:
allowedItems: allowedItems:
- {fileID: 11400000, guid: ecae2d83a5ab2a047a2733ebff607380, type: 2} - {fileID: 11400000, guid: ecae2d83a5ab2a047a2733ebff607380, type: 2}
forbiddenItems: [] forbiddenItems: []
requiredItemCount: 0
- slotItem: {fileID: 11400000, guid: f97b9e24d6dceb145b56426c1152ebeb, type: 2} - slotItem: {fileID: 11400000, guid: f97b9e24d6dceb145b56426c1152ebeb, type: 2}
allowedItems: allowedItems:
- {fileID: 11400000, guid: ff4bbba87722023468a0f6395d1f96c7, type: 2} - {fileID: 11400000, guid: ff4bbba87722023468a0f6395d1f96c7, type: 2}
forbiddenItems: [] forbiddenItems: []
requiredItemCount: 0
- slotItem: {fileID: 11400000, guid: d28f5774afad9d14f823601707150700, type: 2} - slotItem: {fileID: 11400000, guid: d28f5774afad9d14f823601707150700, type: 2}
allowedItems: allowedItems:
- {fileID: 11400000, guid: 6934dcb56c610c44da228f7f24ca13c9, type: 2} - {fileID: 11400000, guid: 6934dcb56c610c44da228f7f24ca13c9, type: 2}
forbiddenItems: [] forbiddenItems: []
requiredItemCount: 0
- slotItem: {fileID: 11400000, guid: aaf36cd26cf74334e9c7db6c1b03b3fb, type: 2} - slotItem: {fileID: 11400000, guid: aaf36cd26cf74334e9c7db6c1b03b3fb, type: 2}
allowedItems: allowedItems:
- {fileID: 11400000, guid: c50330645a2b9d549aae3639bdfcea19, type: 2} - {fileID: 11400000, guid: c50330645a2b9d549aae3639bdfcea19, type: 2}
forbiddenItems: [] forbiddenItems: []
requiredItemCount: 0
- slotItem: {fileID: 11400000, guid: c68dea945fecbf44094359769db04f31, type: 2} - slotItem: {fileID: 11400000, guid: c68dea945fecbf44094359769db04f31, type: 2}
allowedItems: allowedItems:
- {fileID: 11400000, guid: ab57c8237aac144439a18d69f56d36c6, type: 2} - {fileID: 11400000, guid: ab57c8237aac144439a18d69f56d36c6, type: 2}
forbiddenItems: [] forbiddenItems: []
requiredItemCount: 0

View File

@@ -0,0 +1,44 @@
%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: 4fcf232a64e34f489b874519cc96339e, type: 3}
m_Name: StatueDressupSettings
m_EditorClassIdentifier: AppleHillsScripts::Core.Settings.StatueDressupSettings
defaultIconSize: {x: 64, y: 64}
defaultAuthoredSize: {x: 128, y: 128}
allDecorations:
- {fileID: 11400000, guid: 2ea75de9ff6dbfb4b8c246a654868479, type: 2}
- {fileID: 11400000, guid: ca949a6208ce5b5488e90ea3e2eed6df, type: 2}
- {fileID: 11400000, guid: 5efa934e009bc234e920904b05db3c2f, type: 2}
- {fileID: 11400000, guid: 8819ec8b1f4910a4494755cf043636d1, type: 2}
- {fileID: 11400000, guid: b09b79db8ef15144bb2138ec59f26a9c, type: 2}
- {fileID: 11400000, guid: 8838477f768600848813a215ab6a46fe, type: 2}
- {fileID: 11400000, guid: f0df83df3cff9d84ba9fd4895e5d1b58, type: 2}
- {fileID: 11400000, guid: 4101d48e428899d409df02f24c83571f, type: 2}
- {fileID: 11400000, guid: b01ee8334ee052b4784225337e9a5ece, type: 2}
- {fileID: 11400000, guid: a5d493c2c7c9cf74cab038023b401273, type: 2}
itemsPerPage: 8
gridColumns: 2
gridSpacing: {x: 10, y: 10}
dragScaleTransitionDuration: 0.2
returnToMenuDuration: 0.3
minOverlapPercentage: 0.1
hoverScaleMultiplier: 1.05
hoverAnimationDuration: 0.2
placementAnimationDuration: 0.15
photoSaveKey: MrCementStatuePhoto
photoQuality: 85
captureFullScreen: 0
cardsRewardCount: 3
autoCompleteOnPhoto: 1
enableStatePersistence: 1
stateSaveKey: StatueDecorationState
maxSavedDecorations: 50

View File

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