diff --git a/Assets/Art/Sprites/Cards.meta b/Assets/Art/Sprites/Cards.meta new file mode 100644 index 00000000..1e5ca1c1 --- /dev/null +++ b/Assets/Art/Sprites/Cards.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2d6e815822cccaf40b10ce3951beed36 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Art/Sprites/Cards/basic_background.png b/Assets/Art/Sprites/Cards/basic_background.png new file mode 100644 index 00000000..37f1dffa Binary files /dev/null and b/Assets/Art/Sprites/Cards/basic_background.png differ diff --git a/Assets/Art/Sprites/Cards/basic_background.png.meta b/Assets/Art/Sprites/Cards/basic_background.png.meta new file mode 100644 index 00000000..f3fda3d6 --- /dev/null +++ b/Assets/Art/Sprites/Cards/basic_background.png.meta @@ -0,0 +1,195 @@ +fileFormatVersion: 2 +guid: 6dd6a8569dd5cef408d97594bb5e9d49 +TextureImporter: + internalIDToNameTable: + - first: + 213: -3713692513169282065 + second: basic_background_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: basic_background_0 + rect: + serializedVersion: 2 + x: 0 + y: 0 + width: 662 + height: 876 + alignment: 0 + pivot: {x: 0.5, y: 0.5} + border: {x: 120, y: 120, z: 120, w: 120} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: feb6483d550567cc0800000000000000 + internalID: -3713692513169282065 + vertices: [] + indices: + edges: [] + weights: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: 11dbb82cfbe469a478659c7ea91b560e + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: [] + nameFileIdTable: + basic_background_0: -3713692513169282065 + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Art/Sprites/Cards/basic_frame.png b/Assets/Art/Sprites/Cards/basic_frame.png new file mode 100644 index 00000000..ebe3d729 Binary files /dev/null and b/Assets/Art/Sprites/Cards/basic_frame.png differ diff --git a/Assets/Art/Sprites/Cards/basic_frame.png.meta b/Assets/Art/Sprites/Cards/basic_frame.png.meta new file mode 100644 index 00000000..a286d141 --- /dev/null +++ b/Assets/Art/Sprites/Cards/basic_frame.png.meta @@ -0,0 +1,195 @@ +fileFormatVersion: 2 +guid: bd7528147fbfb4e40b0c06c68e99e217 +TextureImporter: + internalIDToNameTable: + - first: + 213: 855352274089539417 + second: basic_frame_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: basic_frame_0 + rect: + serializedVersion: 2 + x: 0 + y: 0 + width: 662 + height: 876 + alignment: 0 + pivot: {x: 0.5, y: 0.5} + border: {x: 111, y: 143, z: 113, w: 131} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: 957fde68c52dedb00800000000000000 + internalID: 855352274089539417 + vertices: [] + indices: + edges: [] + weights: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: 39ae7a6c6a40db644a51724672b938e1 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: [] + nameFileIdTable: + basic_frame_0: 855352274089539417 + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Art/Sprites/Cards/basic_shapes.png b/Assets/Art/Sprites/Cards/basic_shapes.png new file mode 100644 index 00000000..f8b9175c Binary files /dev/null and b/Assets/Art/Sprites/Cards/basic_shapes.png differ diff --git a/Assets/Art/Sprites/Cards/basic_shapes.png.meta b/Assets/Art/Sprites/Cards/basic_shapes.png.meta new file mode 100644 index 00000000..a759cbb7 --- /dev/null +++ b/Assets/Art/Sprites/Cards/basic_shapes.png.meta @@ -0,0 +1,247 @@ +fileFormatVersion: 2 +guid: 84a9632f9bdc1ee4bab91cf4b764b5f7 +TextureImporter: + internalIDToNameTable: + - first: + 213: 8542402908941169558 + second: basic_shapes_0 + - first: + 213: -1529071355430692878 + second: basic_shapes_1 + - first: + 213: 1152548570994208632 + second: basic_shapes_2 + 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: basic_shapes_0 + rect: + serializedVersion: 2 + x: 89 + y: 212 + width: 253 + height: 220 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: 693b3b3af26bc8670800000000000000 + internalID: 8542402908941169558 + vertices: [] + indices: + edges: [] + weights: [] + - serializedVersion: 2 + name: basic_shapes_1 + rect: + serializedVersion: 2 + x: 0 + y: 0 + width: 200 + height: 201 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: 2f7145f14b5a7cae0800000000000000 + internalID: -1529071355430692878 + vertices: [] + indices: + edges: [] + weights: [] + - serializedVersion: 2 + name: basic_shapes_2 + rect: + serializedVersion: 2 + x: 216 + y: 0 + width: 201 + height: 201 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: 87f6e70a1dcaeff00800000000000000 + internalID: 1152548570994208632 + vertices: [] + indices: + edges: [] + weights: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: [] + nameFileIdTable: + basic_shapes_0: 8542402908941169558 + basic_shapes_1: -1529071355430692878 + basic_shapes_2: 1152548570994208632 + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Art/Sprites/Cards/name_plaque.png b/Assets/Art/Sprites/Cards/name_plaque.png new file mode 100644 index 00000000..a78f37e2 Binary files /dev/null and b/Assets/Art/Sprites/Cards/name_plaque.png differ diff --git a/Assets/Art/Sprites/Cards/name_plaque.png.meta b/Assets/Art/Sprites/Cards/name_plaque.png.meta new file mode 100644 index 00000000..49198822 --- /dev/null +++ b/Assets/Art/Sprites/Cards/name_plaque.png.meta @@ -0,0 +1,195 @@ +fileFormatVersion: 2 +guid: bf14f631f4b34e74d83c20a1dd671422 +TextureImporter: + internalIDToNameTable: + - first: + 213: -3310850967021205615 + second: name_plaque_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: name_plaque_0 + rect: + serializedVersion: 2 + x: 0 + y: 0 + width: 521 + height: 161 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: 197417e469e7d02d0800000000000000 + internalID: -3310850967021205615 + vertices: [] + indices: + edges: [] + weights: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: [] + nameFileIdTable: + name_plaque_0: -3310850967021205615 + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Art/Sprites/UI.meta b/Assets/Art/Sprites/UI.meta new file mode 100644 index 00000000..06d39237 --- /dev/null +++ b/Assets/Art/Sprites/UI.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 162c13cb471747a40b1fc47e6c0ae164 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Art/Sprites/UI/CameraCrosshair.png b/Assets/Art/Sprites/UI/CameraCrosshair.png new file mode 100644 index 00000000..65004ec7 Binary files /dev/null and b/Assets/Art/Sprites/UI/CameraCrosshair.png differ diff --git a/Assets/Art/Sprites/UI/CameraCrosshair.png.meta b/Assets/Art/Sprites/UI/CameraCrosshair.png.meta new file mode 100644 index 00000000..0692d66c --- /dev/null +++ b/Assets/Art/Sprites/UI/CameraCrosshair.png.meta @@ -0,0 +1,195 @@ +fileFormatVersion: 2 +guid: c9d2fdec6416f7840a7eb9f6542b3c01 +TextureImporter: + internalIDToNameTable: + - first: + 213: -4229316332011032055 + second: CameraCrosshair_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: CameraCrosshair_0 + rect: + serializedVersion: 2 + x: 6 + y: 6 + width: 245 + height: 245 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: 90279b334337e45c0800000000000000 + internalID: -4229316332011032055 + vertices: [] + indices: + edges: [] + weights: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: [] + nameFileIdTable: + CameraCrosshair_0: -4229316332011032055 + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Art/Sprites/UI/CameraGrid.png b/Assets/Art/Sprites/UI/CameraGrid.png new file mode 100644 index 00000000..5db239dc Binary files /dev/null and b/Assets/Art/Sprites/UI/CameraGrid.png differ diff --git a/Assets/Art/Sprites/UI/CameraGrid.png.meta b/Assets/Art/Sprites/UI/CameraGrid.png.meta new file mode 100644 index 00000000..10a61850 --- /dev/null +++ b/Assets/Art/Sprites/UI/CameraGrid.png.meta @@ -0,0 +1,207 @@ +fileFormatVersion: 2 +guid: 0db492dd1eea9514db54af61f1a4d79e +TextureImporter: + internalIDToNameTable: + - first: + 213: -2291430160556362638 + second: CameraGrid_0 + - first: + 213: -7433212772583906915 + second: CameraGrid_1 + - first: + 213: -6331681754600744794 + second: CameraGrid_2 + - first: + 213: 9186846772083346892 + second: CameraGrid_3 + 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: CameraGrid_0 + rect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1080 + height: 1080 + alignment: 0 + pivot: {x: 0.5, y: 0.5} + border: {x: 319, y: 319, z: 321, w: 321} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: 274fb64d8643330e0800000000000000 + internalID: -2291430160556362638 + vertices: [] + indices: + edges: [] + weights: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: 621374f63d453a746b2a05f897083f21 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: [] + nameFileIdTable: + CameraGrid_0: -2291430160556362638 + CameraGrid_1: -7433212772583906915 + CameraGrid_2: -6331681754600744794 + CameraGrid_3: 9186846772083346892 + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Art/Sprites/UI/DashedCircle.png b/Assets/Art/Sprites/UI/DashedCircle.png new file mode 100644 index 00000000..92f0f12d Binary files /dev/null and b/Assets/Art/Sprites/UI/DashedCircle.png differ diff --git a/Assets/Art/Sprites/UI/DashedCircle.png.meta b/Assets/Art/Sprites/UI/DashedCircle.png.meta new file mode 100644 index 00000000..f6f0b0e4 --- /dev/null +++ b/Assets/Art/Sprites/UI/DashedCircle.png.meta @@ -0,0 +1,410 @@ +fileFormatVersion: 2 +guid: 0bbb26ed6c3670b4293fca36266cacd6 +TextureImporter: + internalIDToNameTable: + - first: + 213: -1042073035024568290 + second: DashedCircle_0 + - first: + 213: 1198012375559701613 + second: DashedCircle_1 + - first: + 213: 3575682463495918587 + second: DashedCircle_2 + - first: + 213: -3720864688460320768 + second: DashedCircle_3 + - first: + 213: 680239502275791533 + second: DashedCircle_4 + - first: + 213: 1736819210918236808 + second: DashedCircle_5 + - first: + 213: 1056949738484492957 + second: DashedCircle_6 + - first: + 213: 1431131774511067332 + second: DashedCircle_7 + - first: + 213: -167254740965665211 + second: DashedCircle_8 + - first: + 213: -3910096327737939745 + second: DashedCircle_9 + - first: + 213: -5302975873317320706 + second: DashedCircle_10 + - first: + 213: -2109135628057173682 + second: DashedCircle_11 + - first: + 213: 5466542998642919973 + second: DashedCircle_12 + - first: + 213: 6092693048300773932 + second: DashedCircle_13 + - first: + 213: -2965461848591405491 + second: DashedCircle_14 + - first: + 213: 4512459140711343436 + second: DashedCircle_15 + - first: + 213: 2881723598896683060 + second: DashedCircle_16 + - first: + 213: 193170154187064169 + second: DashedCircle_17 + - first: + 213: 4443682387266619127 + second: DashedCircle_18 + - first: + 213: -7897697084676391889 + second: DashedCircle_19 + - first: + 213: -288567154801312313 + second: DashedCircle_20 + - first: + 213: 2797897369853195603 + second: DashedCircle_21 + - first: + 213: -6690315256748342625 + second: DashedCircle_22 + - first: + 213: -8562532787892489207 + second: DashedCircle_23 + - first: + 213: 4014038365856674002 + second: DashedCircle_24 + - first: + 213: -4786183874250423663 + second: DashedCircle_25 + - first: + 213: -3632435244273727750 + second: DashedCircle_26 + - first: + 213: -24000256950301646 + second: DashedCircle_27 + - first: + 213: 6429170275310342203 + second: DashedCircle_28 + - first: + 213: -6573703860567998153 + second: DashedCircle_29 + - first: + 213: -220249821621487743 + second: DashedCircle_30 + - first: + 213: 5662653624411841387 + second: DashedCircle_31 + - first: + 213: 1649369697970804789 + second: DashedCircle_32 + - first: + 213: 8579455917647979248 + second: DashedCircle_33 + - first: + 213: 7924434688719549588 + second: DashedCircle_34 + - first: + 213: 3792837440245620024 + second: DashedCircle_35 + - first: + 213: 4679242095454240323 + second: DashedCircle_36 + - first: + 213: -9046064784838744603 + second: DashedCircle_37 + - first: + 213: -2100802971890440573 + second: DashedCircle_38 + - first: + 213: 4433386870443865299 + second: DashedCircle_39 + - first: + 213: 291372625661053975 + second: DashedCircle_40 + - first: + 213: 6163558657729589689 + second: DashedCircle_41 + - first: + 213: -6167089269325768898 + second: DashedCircle_42 + - first: + 213: -7374075482581896232 + second: DashedCircle_43 + - first: + 213: -2574481143699225037 + second: DashedCircle_44 + - first: + 213: -4400616549326023814 + second: DashedCircle_45 + - first: + 213: -2565976320392877806 + second: DashedCircle_46 + - first: + 213: 6967808848227107928 + second: DashedCircle_47 + - first: + 213: -7092969014401834029 + second: DashedCircle_48 + - first: + 213: -5549159261358251902 + second: DashedCircle_49 + - first: + 213: -3057923684788338049 + second: DashedCircle_50 + - first: + 213: -2042200000063096557 + second: DashedCircle_51 + - first: + 213: -2986097484319979018 + second: DashedCircle_52 + - first: + 213: 8796018875121672966 + second: DashedCircle_53 + - first: + 213: -6161271026730342519 + second: DashedCircle_54 + - first: + 213: -5183153657707916280 + second: DashedCircle_55 + - first: + 213: -2285831903291485180 + second: DashedCircle_56 + - first: + 213: 6120294655806491703 + second: DashedCircle_57 + - first: + 213: 3169255490993108987 + second: DashedCircle_58 + - first: + 213: -4382947593213467410 + second: DashedCircle_59 + - first: + 213: 82460703863433667 + second: DashedCircle_60 + - first: + 213: -2682841992920941999 + second: DashedCircle_61 + - first: + 213: 8495901985148463557 + second: DashedCircle_62 + - first: + 213: 3839875421836278576 + second: DashedCircle_63 + - first: + 213: -5509755570484174961 + second: DashedCircle_64 + - first: + 213: 5627319682533994315 + second: DashedCircle_65 + - first: + 213: -1379420503456066803 + second: DashedCircle_66 + - first: + 213: -6958861691495982227 + second: DashedCircle_67 + - first: + 213: 4704030842322679582 + second: DashedCircle_68 + - first: + 213: 8201440963701657049 + second: DashedCircle_69 + - first: + 213: 6193005162756480905 + second: DashedCircle_70 + - first: + 213: -4075948179454758634 + second: DashedCircle_71 + 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: DashedCircle_0 + rect: + serializedVersion: 2 + x: 757 + y: 749 + width: 4497 + height: 4492 + 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: e10f8558810d981f0800000000000000 + internalID: -1042073035024568290 + vertices: [] + indices: + edges: [] + weights: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: 77146c70d8538a841854591dc0ba1184 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: + - key: SpriteEditor.SliceSettings + value: '{"sliceOnImport":false,"gridCellCount":{"x":1.0,"y":1.0},"gridSpriteSize":{"x":6000.0,"y":6000.0},"gridSpriteOffset":{"x":0.0,"y":0.0},"gridSpritePadding":{"x":0.0,"y":0.0},"pivot":{"x":0.5,"y":0.5},"pivotPixels":{"x":0.0,"y":0.0},"autoSlicingMethod":0,"spriteAlignment":0,"pivotUnitMode":0,"slicingType":2,"keepEmptyRects":false,"isAlternate":false}' + nameFileIdTable: + DashedCircle_0: -1042073035024568290 + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Data/Cards.meta b/Assets/Data/Cards.meta new file mode 100644 index 00000000..cf5d8cc1 --- /dev/null +++ b/Assets/Data/Cards.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 9ff52efcb2e505f498abb98b6c6ee31d +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Data/Cards/CardVisualConfig.asset b/Assets/Data/Cards/CardVisualConfig.asset new file mode 100644 index 00000000..81ff7c03 --- /dev/null +++ b/Assets/Data/Cards/CardVisualConfig.asset @@ -0,0 +1,41 @@ +%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: a82f88f485b4410e9eb7c383b44557cf, type: 3} + m_Name: CardVisualConfig + m_EditorClassIdentifier: AppleHillsScripts::AppleHills.Data.CardSystem.CardVisualConfig + rarityColors: + - rarity: 0 + color: {r: 0.7132075, g: 0.4388013, b: 0, a: 1} + - rarity: 1 + color: {r: 0, g: 0.6603774, b: 0.10775841, a: 1} + - rarity: 2 + color: {r: 0, g: 0.19755316, b: 1, a: 1} + - rarity: 3 + color: {r: 0.5849056, g: 0, b: 0.4619053, a: 1} + - rarity: 4 + color: {r: 0.96563864, g: 1, b: 0.0056602955, a: 1} + zoneVisuals: + - zone: 0 + color: {r: 0.8, g: 0.9, b: 0.8, a: 1} + backgroundShape: {fileID: 8542402908941169558, guid: 84a9632f9bdc1ee4bab91cf4b764b5f7, type: 3} + - zone: 1 + color: {r: 0.85, g: 0.8, b: 0.7, a: 1} + backgroundShape: {fileID: -1529071355430692878, guid: 84a9632f9bdc1ee4bab91cf4b764b5f7, type: 3} + - zone: 2 + color: {r: 0.6, g: 0.8, b: 0.6, a: 1} + backgroundShape: {fileID: 1152548570994208632, guid: 84a9632f9bdc1ee4bab91cf4b764b5f7, type: 3} + - zone: 3 + color: {r: 0.7, g: 0.7, b: 0.9, a: 1} + backgroundShape: {fileID: 8542402908941169558, guid: 84a9632f9bdc1ee4bab91cf4b764b5f7, type: 3} + - zone: 4 + color: {r: 0.9, g: 0.85, b: 0.7, a: 1} + backgroundShape: {fileID: -1529071355430692878, guid: 84a9632f9bdc1ee4bab91cf4b764b5f7, type: 3} diff --git a/Assets/Data/Cards/CardVisualConfig.asset.meta b/Assets/Data/Cards/CardVisualConfig.asset.meta new file mode 100644 index 00000000..d2fac6db --- /dev/null +++ b/Assets/Data/Cards/CardVisualConfig.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 473a9bc98f6f6684e8023126fc557a88 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Data/Cards/Card_New Card 1.asset b/Assets/Data/Cards/Card_New Card 1.asset new file mode 100644 index 00000000..7a0ff941 --- /dev/null +++ b/Assets/Data/Cards/Card_New Card 1.asset @@ -0,0 +1,21 @@ +%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: 2a80cc88c9884512b8b633110d838780, type: 3} + m_Name: Card_New Card 1 + m_EditorClassIdentifier: AppleHillsScripts::AppleHills.Data.CardSystem.CardDefinition + Id: f3faeebd-41fd-4a5c-b021-366ed5170f0c + Name: New awesome card + Description: Description goes here + Rarity: 4 + Zone: 2 + CardImage: {fileID: -4209461767521648114, guid: 95abe5ab485a1c64b977f3dd2aff5256, type: 3} + CollectionIndex: 6 diff --git a/Assets/Data/Cards/Card_New Card 1.asset.meta b/Assets/Data/Cards/Card_New Card 1.asset.meta new file mode 100644 index 00000000..b3b1dc4e --- /dev/null +++ b/Assets/Data/Cards/Card_New Card 1.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5d8121cdf52bfe9488b40ed22d649209 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Data/Cards/Card_New Card.asset b/Assets/Data/Cards/Card_New Card.asset new file mode 100644 index 00000000..db7489a9 --- /dev/null +++ b/Assets/Data/Cards/Card_New Card.asset @@ -0,0 +1,21 @@ +%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: 2a80cc88c9884512b8b633110d838780, type: 3} + m_Name: Card_New Card + m_EditorClassIdentifier: AppleHillsScripts::AppleHills.Data.CardSystem.CardDefinition + Id: c392baeb-f816-4482-8b9c-2e2b81e36527 + Name: Test example card + Description: Some example description + Rarity: 4 + Zone: 4 + CardImage: {fileID: 2204075899874250563, guid: 0f7eeae107549d943b762c87ab0dc144, type: 3} + CollectionIndex: 0 diff --git a/Assets/Data/Cards/Card_New Card.asset.meta b/Assets/Data/Cards/Card_New Card.asset.meta new file mode 100644 index 00000000..adf20b77 --- /dev/null +++ b/Assets/Data/Cards/Card_New Card.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 91031de62f795884e8e2ccbaebeebf9b +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Data/Cards/Card_Test example card (Copy) 1.asset b/Assets/Data/Cards/Card_Test example card (Copy) 1.asset new file mode 100644 index 00000000..aa26d282 --- /dev/null +++ b/Assets/Data/Cards/Card_Test example card (Copy) 1.asset @@ -0,0 +1,21 @@ +%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: 2a80cc88c9884512b8b633110d838780, type: 3} + m_Name: Card_Test example card (Copy) 1 + m_EditorClassIdentifier: AppleHillsScripts::AppleHills.Data.CardSystem.CardDefinition + Id: 629423af-af60-495b-8c89-36709e063acd + Name: Test example card (Copy) + Description: Some example description + Rarity: 0 + Zone: 0 + CardImage: {fileID: 2204075899874250563, guid: 0f7eeae107549d943b762c87ab0dc144, type: 3} + CollectionIndex: 0 diff --git a/Assets/Data/Cards/Card_Test example card (Copy) 1.asset.meta b/Assets/Data/Cards/Card_Test example card (Copy) 1.asset.meta new file mode 100644 index 00000000..24ec7332 --- /dev/null +++ b/Assets/Data/Cards/Card_Test example card (Copy) 1.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8fdeae7881d130f408e0f31c101ab41f +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Data/Cards/Card_Test example card (Copy).asset b/Assets/Data/Cards/Card_Test example card (Copy).asset new file mode 100644 index 00000000..a998a949 --- /dev/null +++ b/Assets/Data/Cards/Card_Test example card (Copy).asset @@ -0,0 +1,21 @@ +%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: 2a80cc88c9884512b8b633110d838780, type: 3} + m_Name: Card_Test example card (Copy) + m_EditorClassIdentifier: AppleHillsScripts::AppleHills.Data.CardSystem.CardDefinition + Id: 6aa0d454-47f5-4617-ae30-50614fd2fa94 + Name: Test example card 2 + Description: Some example description + Rarity: 1 + Zone: 0 + CardImage: {fileID: -765527507412255412, guid: f70246e6148769846aaea223ec0c2a55, type: 3} + CollectionIndex: 0 diff --git a/Assets/Data/Cards/Card_Test example card (Copy).asset.meta b/Assets/Data/Cards/Card_Test example card (Copy).asset.meta new file mode 100644 index 00000000..11307de5 --- /dev/null +++ b/Assets/Data/Cards/Card_Test example card (Copy).asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8f02c3699de87014bac8c03b96772a4b +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Data/Cards/Card_Test example card 2 (Copy) 1.asset b/Assets/Data/Cards/Card_Test example card 2 (Copy) 1.asset new file mode 100644 index 00000000..2428db58 --- /dev/null +++ b/Assets/Data/Cards/Card_Test example card 2 (Copy) 1.asset @@ -0,0 +1,21 @@ +%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: 2a80cc88c9884512b8b633110d838780, type: 3} + m_Name: Card_Test example card 2 (Copy) 1 + m_EditorClassIdentifier: AppleHillsScripts::AppleHills.Data.CardSystem.CardDefinition + Id: ee76a6fc-d86d-469f-9b0f-c19286228357 + Name: Test example card 2 (Copy) + Description: Some example description + Rarity: 1 + Zone: 3 + CardImage: {fileID: -765527507412255412, guid: f70246e6148769846aaea223ec0c2a55, type: 3} + CollectionIndex: 0 diff --git a/Assets/Data/Cards/Card_Test example card 2 (Copy) 1.asset.meta b/Assets/Data/Cards/Card_Test example card 2 (Copy) 1.asset.meta new file mode 100644 index 00000000..72e531a5 --- /dev/null +++ b/Assets/Data/Cards/Card_Test example card 2 (Copy) 1.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: dec49537f6ae6d241acf8275eaa6c653 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Data/Cards/Card_Test example card 2 (Copy).asset b/Assets/Data/Cards/Card_Test example card 2 (Copy).asset new file mode 100644 index 00000000..ca74c2f0 --- /dev/null +++ b/Assets/Data/Cards/Card_Test example card 2 (Copy).asset @@ -0,0 +1,21 @@ +%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: 2a80cc88c9884512b8b633110d838780, type: 3} + m_Name: Card_Test example card 2 (Copy) + m_EditorClassIdentifier: AppleHillsScripts::AppleHills.Data.CardSystem.CardDefinition + Id: ee1e2aec-bdb6-4c68-8d7a-061c7f5e8583 + Name: Test example card 3 + Description: Some example description + Rarity: 2 + Zone: 0 + CardImage: {fileID: -9213056636207805707, guid: 00354ded9d8f8d643acc14837a229544, type: 3} + CollectionIndex: 0 diff --git a/Assets/Data/Cards/Card_Test example card 2 (Copy).asset.meta b/Assets/Data/Cards/Card_Test example card 2 (Copy).asset.meta new file mode 100644 index 00000000..e21a013b --- /dev/null +++ b/Assets/Data/Cards/Card_Test example card 2 (Copy).asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 28dbfbd7a6b2cd84b8274bd1126b220b +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Data/Cards/Card_Test example card 3 (Copy).asset b/Assets/Data/Cards/Card_Test example card 3 (Copy).asset new file mode 100644 index 00000000..319e0230 --- /dev/null +++ b/Assets/Data/Cards/Card_Test example card 3 (Copy).asset @@ -0,0 +1,21 @@ +%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: 2a80cc88c9884512b8b633110d838780, type: 3} + m_Name: Card_Test example card 3 (Copy) + m_EditorClassIdentifier: AppleHillsScripts::AppleHills.Data.CardSystem.CardDefinition + Id: 1afdfea7-ca85-45ae-bd2c-3814729e628d + Name: Test example card 3 (Copy) + Description: Some example description + Rarity: 2 + Zone: 4 + CardImage: {fileID: -9213056636207805707, guid: 00354ded9d8f8d643acc14837a229544, type: 3} + CollectionIndex: 0 diff --git a/Assets/Data/Cards/Card_Test example card 3 (Copy).asset.meta b/Assets/Data/Cards/Card_Test example card 3 (Copy).asset.meta new file mode 100644 index 00000000..c76502a1 --- /dev/null +++ b/Assets/Data/Cards/Card_Test example card 3 (Copy).asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6afed7a67f64404418f905e7808bf5cb +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Editor/CardSystem.meta b/Assets/Editor/CardSystem.meta new file mode 100644 index 00000000..08ed7af1 --- /dev/null +++ b/Assets/Editor/CardSystem.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 51dfa0a923ad4d0f8aa89ac702a57530 +timeCreated: 1759925706 \ No newline at end of file diff --git a/Assets/Editor/CardSystem/CardEditorWindow.cs b/Assets/Editor/CardSystem/CardEditorWindow.cs new file mode 100644 index 00000000..d94fc5d9 --- /dev/null +++ b/Assets/Editor/CardSystem/CardEditorWindow.cs @@ -0,0 +1,1093 @@ +using System.Collections.Generic; +using System.IO; +using System.Linq; +using AppleHills.Data.CardSystem; +using AppleHills.UI.CardSystem; +using UnityEditor; +using UnityEngine; +using UnityEngine.UI; + +namespace AppleHills.Editor.CardSystem +{ + /// + /// Editor utility for managing card definitions without directly editing scriptable objects. + /// Provides a searchable list and visual preview of cards. + /// + public class CardEditorWindow : EditorWindow + { + // Paths + private const string CardDefinitionsPath = "Assets/Data/Cards"; + private const string MenuPath = "AppleHills/Card Editor"; + private const string CardUIPrefabPath = "Assets/Prefabs/UI/Cards/CardUI.prefab"; + private const string CardVisualConfigPath = CardDefinitionsPath + "/CardVisualConfig.asset"; + + // Editor state + private List _cards = new List(); + private CardDefinition _selectedCard; + private CardDefinition _editingCard; // Clone of selected card for editing + private Vector2 _cardListScrollPosition; + private Vector2 _cardEditScrollPosition; + private string _searchQuery = ""; + private bool _showPreview = true; + private bool _isDirty = false; + + // UI state for card preview + private GameObject _previewCardObject; + private CardUIElement _previewCardElement; + private CardData _previewCardData; + private Rect _previewRect; + private GameObject _cardUIPrefab; + private CardVisualConfig _cardVisualConfig; + private UnityEditor.Editor _cardPreviewEditor; + private Texture2D _staticPreviewTexture; + private bool _previewNeedsUpdate = true; + + // Preview settings + private float _previewZoom = 1.0f; + private Vector2 _previewOffset = Vector2.zero; + private bool _debugMode = false; + private float _zoomMultiplier = 1.5f; // Default multiplier (no zoom) + private const float DEFAULT_ZOOM = 1.5f; // Store default zoom as a constant + private const float BASE_ORTHO_SIZE = 400.0f; // Increased from 0.8f to 8.0f for a much wider view + + // PreviewRenderUtility for rendering the card in a hidden scene + private PreviewRenderUtility _previewUtility; + private float _orbitRotation = 0f; + private float _autoRotateSpeed = 0f; + private bool _autoRotate = false; + private GameObject _previewInstance; + + [MenuItem(MenuPath)] + public static void ShowWindow() + { + var window = GetWindow("Card Editor"); + window.minSize = new Vector2(800, 600); + window.Show(); + } + + private void OnEnable() + { + // Load all card definitions + LoadCardDefinitions(); + + // Initialize preview + InitializePreview(); + + // Register for undo/redo + Undo.undoRedoPerformed += OnUndoRedo; + + // Set up a repaint on script compilation + EditorApplication.update += OnEditorUpdate; + EditorApplication.playModeStateChanged += OnPlayModeStateChanged; + } + + private void OnDisable() + { + // Clean up preview + CleanupPreview(); + + // Unregister from undo/redo + Undo.undoRedoPerformed -= OnUndoRedo; + + // Unregister from update + EditorApplication.update -= OnEditorUpdate; + EditorApplication.playModeStateChanged -= OnPlayModeStateChanged; + } + + private void OnEditorUpdate() + { + if (_showPreview && _previewNeedsUpdate) + { + Repaint(); + } + + // Auto-rotate the preview if enabled + if (_autoRotate && _previewUtility != null) + { + _orbitRotation += _autoRotateSpeed * Time.deltaTime; + Repaint(); + } + } + + private void OnUndoRedo() + { + // Reload card definitions and refresh + LoadCardDefinitions(); + Repaint(); + } + + private void OnPlayModeStateChanged(PlayModeStateChange stateChange) + { + if (stateChange == PlayModeStateChange.EnteredEditMode) + { + LoadCardDefinitions(); + InitializePreview(); + } + else if (stateChange == PlayModeStateChange.ExitingEditMode) + { + CleanupPreview(); + } + } + + private void LoadCardDefinitions() + { + _cards.Clear(); + + // Create the directory structure if it doesn't exist + string dataDirectory = Path.GetDirectoryName(CardDefinitionsPath); // Gets the "Assets/Data" part + if (!Directory.Exists(dataDirectory)) + { + Directory.CreateDirectory(dataDirectory); + } + + if (!Directory.Exists(CardDefinitionsPath)) + { + Directory.CreateDirectory(CardDefinitionsPath); + AssetDatabase.Refresh(); + } + + // Find all card definition assets + string[] guids = AssetDatabase.FindAssets("t:CardDefinition", new[] { CardDefinitionsPath }); + foreach (string guid in guids) + { + string path = AssetDatabase.GUIDToAssetPath(guid); + CardDefinition card = AssetDatabase.LoadAssetAtPath(path); + if (card != null) + { + _cards.Add(card); + } + } + + // Sort by name + _cards = _cards.OrderBy(c => c.Name).ToList(); + + // If we had a selected card, try to find it again + if (_selectedCard != null) + { + _selectedCard = _cards.FirstOrDefault(c => c.Id == _selectedCard.Id); + if (_selectedCard != null) + { + _editingCard = CloneCard(_selectedCard); + UpdatePreview(); + } + } + } + + private void InitializePreview() + { + // Initialize PreviewRenderUtility for 3D preview + if (_previewUtility == null) + { + _previewUtility = new PreviewRenderUtility(); + + // Configure camera for 2D UI rendering + var cam = _previewUtility.camera; + cam.clearFlags = CameraClearFlags.Color; + cam.backgroundColor = Color.gray; // Background color when nothing is rendered + cam.orthographic = true; // Orthographic is better for 2D UI + cam.orthographicSize = 1f; + cam.nearClipPlane = 0.01f; + cam.farClipPlane = 100f; + cam.cullingMask = ~0; // Render everything + cam.transform.position = new Vector3(0, 0, -6); + cam.transform.rotation = Quaternion.identity; + + // Configure lights for better UI visibility + // Key light + _previewUtility.lights[0].intensity = 1.2f; + _previewUtility.lights[0].color = Color.white; + _previewUtility.lights[0].transform.rotation = Quaternion.Euler(30f, 30f, 0f); + + // Fill light + _previewUtility.lights[1].intensity = 0.7f; + _previewUtility.lights[1].color = new Color(0.7f, 0.7f, 0.8f); + _previewUtility.lights[1].transform.rotation = Quaternion.Euler(-30f, -30f, 0f); + } + + // Load the prefab + _cardUIPrefab = AssetDatabase.LoadAssetAtPath(CardUIPrefabPath); + if (_cardUIPrefab == null) + { + Debug.LogError($"[CardEditorWindow] Could not find card UI prefab at {CardUIPrefabPath}"); + return; + } + + // Try to load the visual config + _cardVisualConfig = AssetDatabase.LoadAssetAtPath(CardVisualConfigPath); + if (_cardVisualConfig == null) + { + Debug.LogWarning($"[CardEditorWindow] Could not find card visual config at {CardVisualConfigPath}"); + } + + // Create preview card object + CreatePreviewCardObject(); + } + + private void CreatePreviewCardObject() + { + // Clean up any existing preview objects + CleanupPreviewInstance(); + + if (_cardUIPrefab == null) + { + Debug.LogError("[CardEditorWindow] Card UI prefab not loaded"); + return; + } + + try + { + // Create the preview instance in the PreviewRenderUtility's scene + if (_previewUtility != null) + { + // 1. First create a root GameObject in the preview scene + _previewInstance = new GameObject("PreviewRoot"); + _previewInstance.hideFlags = HideFlags.HideAndDontSave; + + // 2. Create a Canvas to hold our card UI + GameObject canvasGO = new GameObject("PreviewCanvas"); + canvasGO.transform.SetParent(_previewInstance.transform, false); + + // 3. Add Canvas component and configure it + Canvas canvas = canvasGO.AddComponent(); + canvas.renderMode = RenderMode.WorldSpace; // Changed from ScreenSpaceCamera to WorldSpace + canvas.worldCamera = _previewUtility.camera; + + // Set fixed world space size for the canvas + RectTransform canvasRect = canvasGO.GetComponent(); + canvasRect.sizeDelta = new Vector2(30f, 30f * (9f/16f)); // Increased from 10f to 30f for better sizing with larger ortho + canvasRect.localPosition = Vector3.zero; // Center position + canvasRect.localScale = Vector3.one * 0.8f; // Slightly scaled down for better proportions + + // 4. Add CanvasScaler but configure it for constant physical size instead of responsive scaling + CanvasScaler scaler = canvasGO.AddComponent(); + scaler.uiScaleMode = CanvasScaler.ScaleMode.ConstantPixelSize; // Use constant pixel size instead of screen-based scaling + scaler.scaleFactor = 1f; // Base scale factor + + // 5. Add GraphicRaycaster (required for UI) + canvasGO.AddComponent(); + + // 6. Instantiate the card prefab as a child of the canvas + GameObject cardInstance = GameObject.Instantiate(_cardUIPrefab, canvasGO.transform, false); + + // 7. Position the card in the center of the canvas and set a fixed size + RectTransform cardRect = cardInstance.GetComponent(); + if (cardRect != null) + { + cardRect.anchorMin = new Vector2(0.5f, 0.5f); + cardRect.anchorMax = new Vector2(0.5f, 0.5f); + cardRect.pivot = new Vector2(0.5f, 0.5f); + cardRect.anchoredPosition = Vector2.zero; + // Use the original size of the card prefab + // No automatic scaling will occur in world space mode + } + + // 8. Get the CardUIElement component + _previewCardElement = cardInstance.GetComponent(); + if (_previewCardElement == null) + { + _previewCardElement = cardInstance.GetComponentInChildren(); + } + + // 9. Add the root to the preview scene + _previewUtility.AddSingleGO(_previewInstance); + + // 10. Set the visual config + if (_cardVisualConfig != null && _previewCardElement != null) + { + var serializedObject = new SerializedObject(_previewCardElement); + var visualConfigProperty = serializedObject.FindProperty("visualConfig"); + if (visualConfigProperty != null) + { + visualConfigProperty.objectReferenceValue = _cardVisualConfig; + serializedObject.ApplyModifiedProperties(); + } + } + + // 11. Update the preview with card data if available + if (_previewCardData != null && _previewCardElement != null) + { + _previewCardElement.SetupCard(_previewCardData); + } + + // Set up the camera to frame the canvas properly + SetupPreviewCamera(); + + Debug.Log($"[CardEditorWindow] Successfully created preview card with UI canvas in PreviewRenderUtility"); + } + else + { + // Fallback to the original method for creating the preview object + _previewCardObject = Instantiate(_cardUIPrefab); + _previewCardObject.hideFlags = _debugMode ? HideFlags.DontSave : HideFlags.HideAndDontSave; + + foreach (var renderer in _previewCardObject.GetComponentsInChildren()) + { + renderer.enabled = false; + } + + _previewCardElement = _previewCardObject.GetComponent(); + if (_previewCardElement == null) + { + _previewCardElement = _previewCardObject.GetComponentInChildren(); + } + + // Create an Editor for the preview object to generate previews + if (_cardPreviewEditor != null) + { + DestroyImmediate(_cardPreviewEditor); + } + _cardPreviewEditor = UnityEditor.Editor.CreateEditor(_previewCardObject); + } + + _previewNeedsUpdate = true; + } + catch (System.Exception e) + { + Debug.LogError($"[CardEditorWindow] Error creating preview card: {e.Message}\n{e.StackTrace}"); + } + } + + private void SetupPreviewCamera() + { + if (_previewUtility == null) + return; + + // Configure camera for UI rendering + Camera cam = _previewUtility.camera; + cam.clearFlags = CameraClearFlags.SolidColor; + cam.backgroundColor = new Color(0.2f, 0.2f, 0.2f); // Dark gray background + + // Apply the base orthographic size with the current zoom multiplier + cam.orthographicSize = BASE_ORTHO_SIZE / _zoomMultiplier; + + // Position the camera to look at the origin + cam.transform.position = new Vector3(0, 0, -5); + cam.transform.rotation = Quaternion.identity; + + if (_debugMode) + { + Debug.Log($"[CardEditorWindow] Setup preview camera at position: {cam.transform.position}, orthographicSize: {cam.orthographicSize}"); + } + } + + private void CleanupPreviewInstance() + { + if (_previewInstance != null) + { + DestroyImmediate(_previewInstance); + _previewInstance = null; + } + + _previewCardElement = null; + } + + private void CleanupPreview() + { + CleanupPreviewInstance(); + + if (_previewCardObject != null) + { + DestroyImmediate(_previewCardObject); + _previewCardObject = null; + } + + if (_cardPreviewEditor != null) + { + DestroyImmediate(_cardPreviewEditor); + _cardPreviewEditor = null; + } + + if (_staticPreviewTexture != null) + { + DestroyImmediate(_staticPreviewTexture); + _staticPreviewTexture = null; + } + + if (_previewUtility != null) + { + _previewUtility.Cleanup(); + _previewUtility = null; + } + } + + private void UpdatePreview() + { + if (_editingCard == null || !_showPreview) + return; + + try + { + // Update the preview card UI element + if (_previewCardElement != null) + { + // First set the cardDefinition field via reflection or SerializedObject + // (since it's a serialized field we don't have direct access) + var serializedObject = new SerializedObject(_previewCardElement); + var cardDefinitionProperty = serializedObject.FindProperty("cardDefinition"); + if (cardDefinitionProperty != null) + { + cardDefinitionProperty.objectReferenceValue = _editingCard; + serializedObject.ApplyModifiedProperties(); + } + + // Now directly call CreateFromDefinition which will create the card data and update visuals + var createFromDefMethod = typeof(CardUIElement).GetMethod("CreateFromDefinition", + System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public | + System.Reflection.BindingFlags.NonPublic); + + if (createFromDefMethod != null) + { + createFromDefMethod.Invoke(_previewCardElement, null); + + // Store a reference to the card data for other uses if needed + var cardDataField = typeof(CardUIElement).GetField("cardData", + System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic); + if (cardDataField != null) + { + _previewCardData = (CardData)cardDataField.GetValue(_previewCardElement); + } + + _previewNeedsUpdate = true; + } + else + { + Debug.LogError("[CardEditorWindow] Could not find CreateFromDefinition method in CardUIElement"); + } + + // Auto-frame the card in the preview by calculating its bounds + if (_previewInstance != null) + { + AutoFramePreviewObject(); + } + + if (_debugMode) + { + Debug.Log($"[CardEditorWindow] Updated preview card data via CreateFromDefinition: {_editingCard.Name}"); + } + } + } + catch (System.Exception ex) + { + Debug.LogError($"[CardEditorWindow] Error updating preview: {ex.Message}\n{ex.StackTrace}"); + } + } + + private void AutoFramePreviewObject() + { + if (_previewInstance == null || _previewUtility == null) + return; + + // Find all visible elements to calculate bounds + Bounds bounds = new Bounds(); + bool boundsInitialized = false; + + // Calculate bounds from RectTransforms properly by using their corners in world space + foreach (var rectTransform in _previewInstance.GetComponentsInChildren()) + { + // Get the corners of the RectTransform in world space + Vector3[] corners = new Vector3[4]; + rectTransform.GetWorldCorners(corners); + + // Initialize or expand bounds based on corners + if (!boundsInitialized) + { + bounds = new Bounds(corners[0], Vector3.zero); + boundsInitialized = true; + + // Expand initial bounds to include all corners + for (int i = 1; i < 4; i++) + { + bounds.Encapsulate(corners[i]); + } + } + else + { + // Encapsulate all corners for existing bounds + foreach (Vector3 corner in corners) + { + bounds.Encapsulate(corner); + } + } + } + + // Also check regular Renderers (if any) + foreach (var renderer in _previewInstance.GetComponentsInChildren()) + { + if (!boundsInitialized) + { + bounds = renderer.bounds; + boundsInitialized = true; + } + else + { + bounds.Encapsulate(renderer.bounds); + } + } + + // Keep using the existing camera settings, only update the orthographic size based on zoom + Camera cam = _previewUtility.camera; + cam.orthographicSize = BASE_ORTHO_SIZE / _zoomMultiplier; + + if (_debugMode) + { + Debug.Log($"[CardEditorWindow] Updated zoom: orthoSize={cam.orthographicSize}, zoomMultiplier={_zoomMultiplier}, position={cam.transform.position}"); + } + } + + private void RenderCardPreview(Rect rect) + { + if (_editingCard == null) + { + DrawSimplePreview(rect); + return; + } + + // Use PreviewRenderUtility if available + if (_previewUtility != null && _previewInstance != null) + { + try + { + // Store the current orthographic size before rendering (to restore it if changed) + float currentOrthoSize = _previewUtility.camera.orthographicSize; + + // Start the preview rendering - using a fixed size to maintain consistency + _previewUtility.BeginPreview(rect, GUIStyle.none); + + // Ensure the camera's orthographic size is correct before rendering + _previewUtility.camera.orthographicSize = BASE_ORTHO_SIZE / _zoomMultiplier; + + // Apply rotation based on orbit angle + if (_previewInstance != null) + { + _previewInstance.transform.rotation = Quaternion.Euler(0, _orbitRotation, 0); + } + + // Render the preview scene + _previewUtility.camera.Render(); + + // Get the rendered texture and draw it + Texture rendered = _previewUtility.EndPreview(); + + // Keep a constant aspect ratio when drawing + float textureAspect = (float)rendered.width / rendered.height; + float rectAspect = rect.width / rect.height; + + Rect drawRect = rect; + + // Adjust the drawing rectangle to maintain aspect ratio + if (textureAspect > rectAspect) // Texture is wider than rect + { + float newHeight = rect.width / textureAspect; + drawRect.y += (rect.height - newHeight) * 0.5f; + drawRect.height = newHeight; + } + else // Texture is taller than rect + { + float newWidth = rect.height * textureAspect; + drawRect.x += (rect.width - newWidth) * 0.5f; + drawRect.width = newWidth; + } + + // Draw with fixed aspect ratio + GUI.DrawTexture(drawRect, rendered, ScaleMode.StretchToFill); + + // Draw overlay info + GUI.Label(new Rect(rect.x + 10, rect.y + 10, rect.width - 20, 20), + $"Preview: {_editingCard.Name}", EditorStyles.boldLabel); + + if (_debugMode) + { + // Show size debugging info + GUI.Label(new Rect(rect.x + 10, rect.y + rect.height - 40, rect.width - 20, 20), + $"Texture: {rendered.width}x{rendered.height}, Rect: {rect.width}x{rect.height}", + EditorStyles.miniLabel); + } + + return; + } + catch (System.Exception ex) + { + Debug.LogError($"[CardEditorWindow] Error rendering with PreviewRenderUtility: {ex.Message}"); + // Fall through to backup rendering method + } + } + + // Fallback to the original preview method if PreviewRenderUtility failed + if (_cardPreviewEditor != null) + { + try + { + // Use the editor's OnInteractivePreviewGUI to render our card preview + _cardPreviewEditor.OnPreviewGUI(rect, EditorStyles.helpBox); + + // Draw overlay information + GUI.Label(new Rect(rect.x + 10, rect.y + 10, rect.width - 20, 20), + $"Preview: {_editingCard.Name}", EditorStyles.boldLabel); + return; + } + catch (System.Exception ex) + { + Debug.LogError($"[CardEditorWindow] Error rendering with Editor preview: {ex.Message}"); + } + } + + // Ultimate fallback if all else fails + DrawSimplePreview(rect); + } + + private void OnGUI() + { + GUILayout.BeginHorizontal(); + + // Card list panel (left) + DrawCardListPanel(); + + // Add padding between sections + GUILayout.Space(10); + + // Card editor panel (middle) + DrawCardEditPanel(); + + // Add padding between sections + GUILayout.Space(10); + + // Card preview panel (right) + DrawCardPreviewPanel(); + + GUILayout.EndHorizontal(); + } + + private void DrawCardListPanel() + { + GUILayout.BeginVertical(GUILayout.Width(250)); + + // Header + GUILayout.Label("Cards", EditorStyles.boldLabel); + + // Search bar + EditorGUI.BeginChangeCheck(); + _searchQuery = EditorGUILayout.TextField("Search", _searchQuery, GUILayout.ExpandWidth(true)); + if (EditorGUI.EndChangeCheck()) + { + Repaint(); + } + + // Create new card button + if (GUILayout.Button("Create New Card")) + { + CreateNewCard(); + } + + // Card list + _cardListScrollPosition = EditorGUILayout.BeginScrollView(_cardListScrollPosition); + + // Filter by search query if any + List filteredCards = _cards; + if (!string.IsNullOrWhiteSpace(_searchQuery)) + { + string search = _searchQuery.ToLowerInvariant(); + filteredCards = _cards.Where(c => + c.Name.ToLowerInvariant().Contains(search) || + c.Description.ToLowerInvariant().Contains(search) || + c.Zone.ToString().ToLowerInvariant().Contains(search) || + c.Rarity.ToString().ToLowerInvariant().Contains(search) + ).ToList(); + } + + // Display cards + foreach (var card in filteredCards) + { + bool isSelected = _selectedCard != null && _selectedCard.Id == card.Id; + + GUIStyle style = isSelected ? EditorStyles.selectionRect : EditorStyles.label; + + EditorGUILayout.BeginHorizontal(style); + + if (GUILayout.Button(card.Name, EditorStyles.label, GUILayout.ExpandWidth(true))) + { + SelectCard(card); + } + + GUILayout.Label(card.Rarity.ToString(), GUILayout.Width(70)); + + EditorGUILayout.EndHorizontal(); + } + + EditorGUILayout.EndScrollView(); + + GUILayout.EndVertical(); + } + + private void DrawCardEditPanel() + { + GUILayout.BeginVertical(GUILayout.ExpandWidth(true)); + + if (_editingCard != null) + { + // Header + GUILayout.Label("Edit Card", EditorStyles.boldLabel); + + _cardEditScrollPosition = EditorGUILayout.BeginScrollView(_cardEditScrollPosition); + + // Basic info + EditorGUI.BeginChangeCheck(); + + _editingCard.Name = EditorGUILayout.TextField("Name", _editingCard.Name); + _editingCard.Description = EditorGUILayout.TextArea(_editingCard.Description, GUILayout.Height(100)); + _editingCard.Rarity = (CardRarity)EditorGUILayout.EnumPopup("Rarity", _editingCard.Rarity); + _editingCard.Zone = (CardZone)EditorGUILayout.EnumPopup("Zone", _editingCard.Zone); + + // Visual elements + EditorGUILayout.Space(); + GUILayout.Label("Visual Elements", EditorStyles.boldLabel); + + _editingCard.CardImage = (Sprite)EditorGUILayout.ObjectField("Card Image", _editingCard.CardImage, typeof(Sprite), false); + + // Display derived properties (for information only) + GUI.enabled = false; + EditorGUILayout.ColorField("Background Color (from Zone)", _editingCard.GetBackgroundColor()); + EditorGUILayout.TextField("Frame Shape (from Rarity)", $"Frame_{_editingCard.Rarity}"); + GUI.enabled = true; + + // Collection info + EditorGUILayout.Space(); + GUILayout.Label("Collection Info", EditorStyles.boldLabel); + + _editingCard.CollectionIndex = EditorGUILayout.IntField("Collection Index", _editingCard.CollectionIndex); + + if (EditorGUI.EndChangeCheck()) + { + _isDirty = true; + UpdatePreview(); + } + + GUILayout.FlexibleSpace(); + + // Action buttons + GUILayout.BeginHorizontal(); + + if (GUILayout.Button("Apply Changes", GUILayout.Height(30))) + { + ApplyChanges(); + } + + if (GUILayout.Button("Duplicate", GUILayout.Height(30))) + { + DuplicateSelectedCard(); + } + + if (GUILayout.Button("Delete", GUILayout.Height(30))) + { + if (EditorUtility.DisplayDialog("Delete Card", + $"Are you sure you want to delete '{_selectedCard.Name}'?", + "Delete", "Cancel")) + { + DeleteSelectedCard(); + } + } + + GUILayout.EndHorizontal(); + + // Warning if dirty + if (_isDirty) + { + EditorGUILayout.HelpBox("You have unsaved changes.", MessageType.Info); + } + + EditorGUILayout.EndScrollView(); + } + else + { + GUILayout.Label("Select a card to edit", EditorStyles.centeredGreyMiniLabel); + } + + GUILayout.EndVertical(); + } + + private void DrawCardPreviewPanel() + { + GUILayout.BeginVertical(GUILayout.Width(300)); + + // Header with toggle + GUILayout.BeginHorizontal(); + GUILayout.Label("Preview", EditorStyles.boldLabel); + + EditorGUI.BeginChangeCheck(); + _showPreview = EditorGUILayout.Toggle("Show Preview", _showPreview); + if (EditorGUI.EndChangeCheck()) + { + if (_showPreview) + { + // Recreate the preview when toggling it on + CreatePreviewCardObject(); + UpdatePreview(); + } + } + GUILayout.EndHorizontal(); + + if (_showPreview && _editingCard != null) + { + // Preview area + _previewRect = GUILayoutUtility.GetRect(300, 400); + + // Render the preview + RenderCardPreview(_previewRect); + + // Preview controls + GUILayout.BeginHorizontal(); + + // Refresh button + if (GUILayout.Button("Refresh Preview")) + { + CreatePreviewCardObject(); + UpdatePreview(); + } + + // Auto-rotate toggle + EditorGUI.BeginChangeCheck(); + _autoRotate = GUILayout.Toggle(_autoRotate, "Auto-Rotate"); + if (EditorGUI.EndChangeCheck() && _autoRotate) + { + _autoRotateSpeed = 20f; // Degrees per second + } + + // Debug toggle + EditorGUI.BeginChangeCheck(); + _debugMode = GUILayout.Toggle(_debugMode, "Debug Mode"); + if (EditorGUI.EndChangeCheck()) + { + // If entering debug mode, make objects visible in hierarchy + if (_previewCardObject != null) + { + _previewCardObject.hideFlags = _debugMode ? + HideFlags.DontSave : HideFlags.HideAndDontSave; + } + } + + GUILayout.EndHorizontal(); + + // Manual rotation slider + if (!_autoRotate) + { + EditorGUI.BeginChangeCheck(); + _orbitRotation = EditorGUILayout.Slider("Rotation", _orbitRotation, 0f, 360f); + if (EditorGUI.EndChangeCheck()) + { + Repaint(); + } + } + + // Zoom control + EditorGUI.BeginChangeCheck(); + _zoomMultiplier = EditorGUILayout.Slider("Zoom", _zoomMultiplier, 0.0f, 4.0f); + if (EditorGUI.EndChangeCheck()) + { + if (_previewUtility != null) + { + // Adjust the orthographic size of the camera based on zoom level + _previewUtility.camera.orthographicSize = BASE_ORTHO_SIZE / _zoomMultiplier; + if (_debugMode) + { + Debug.Log($"[CardEditorWindow] Adjusted camera orthographic size for zoom. Zoom: {_zoomMultiplier}, Ortho: {_previewUtility.camera.orthographicSize}"); + } + } + } + + // Debug info + if (_debugMode) + { + EditorGUILayout.LabelField($"Card: {_editingCard.Name}"); + EditorGUILayout.LabelField($"Rarity: {_editingCard.Rarity}"); + EditorGUILayout.LabelField($"Zone: {_editingCard.Zone}"); + EditorGUILayout.LabelField($"Preview Method: {(_previewUtility != null ? "PreviewRenderUtility" : "Editor Preview")}"); + EditorGUILayout.LabelField($"UI Component: {(_previewCardElement != null ? "Found" : "Missing")}"); + + if (_previewUtility != null && _previewInstance != null) + { + EditorGUILayout.LabelField($"Camera Position: {_previewUtility.camera.transform.position}"); + EditorGUILayout.LabelField($"Card Rotation: {_previewInstance.transform.rotation.eulerAngles}"); + } + } + + EditorGUILayout.HelpBox( + "This preview uses PreviewRenderUtility to render the card prefab in a hidden scene. " + + "You can rotate the card to see it from different angles.", MessageType.Info); + } + + GUILayout.EndVertical(); + } + + + private void DrawSimplePreview(Rect rect) + { + // This is the original simple preview code as a fallback + + // Draw a colored background to represent the card + EditorGUI.DrawRect(rect, _editingCard.GetBackgroundColor()); + + // Draw a border + Rect borderRect = new Rect(rect.x + 2, rect.y + 2, rect.width - 4, rect.height - 4); + EditorGUI.DrawRect(borderRect, Color.white); + + // Draw card name + Rect nameRect = new Rect(rect.x + 20, rect.y + 20, rect.width - 40, 30); + EditorGUI.LabelField(nameRect, _editingCard.Name, EditorStyles.whiteLargeLabel); + + // Draw card image if available + if (_editingCard.CardImage != null) + { + Rect imageRect = new Rect(rect.x + 50, rect.y + 60, rect.width - 100, 200); + GUI.DrawTexture(imageRect, AssetPreview.GetAssetPreview(_editingCard.CardImage) ?? _editingCard.CardImage.texture); + } + + // Draw card description + Rect descRect = new Rect(rect.x + 20, rect.y + 270, rect.width - 40, 100); + EditorGUI.LabelField(descRect, _editingCard.Description, EditorStyles.wordWrappedLabel); + + // Draw rarity at the bottom + Rect rarityRect = new Rect(rect.x + 20, rect.y + rect.height - 40, rect.width - 40, 30); + EditorGUI.LabelField(rarityRect, $"Rarity: {_editingCard.Rarity}", EditorStyles.boldLabel); + } + + private Color GetRarityColor(CardRarity rarity) + { + switch (rarity) + { + case CardRarity.Common: + return Color.gray; + case CardRarity.Uncommon: + return Color.green; + case CardRarity.Rare: + return Color.blue; + case CardRarity.Epic: + return new Color(0.5f, 0f, 0.5f); // Purple + case CardRarity.Legendary: + return Color.yellow; + default: + return Color.white; + } + } + + private void SelectCard(CardDefinition card) + { + // Check for unsaved changes + if (_isDirty && _selectedCard != null) + { + if (EditorUtility.DisplayDialog("Unsaved Changes", + "You have unsaved changes. Do you want to apply them before switching cards?", + "Apply Changes", "Discard Changes")) + { + ApplyChanges(); + } + } + + _selectedCard = card; + _editingCard = CloneCard(card); + _isDirty = false; + + // Force a complete recreation of the preview when selecting a new card + if (_showPreview) + { + // Clean up previous preview objects to ensure a fresh start + CleanupPreviewInstance(); + // Create a new preview instance with the selected card + CreatePreviewCardObject(); + // Update preview with the new card data + UpdatePreview(); + } + } + + private void CreateNewCard() + { + // Create a new card definition + CardDefinition newCard = CreateInstance(); + + // Set default values + newCard.Id = System.Guid.NewGuid().ToString(); + newCard.Name = "New Card"; + newCard.Description = "Description goes here"; + newCard.Rarity = CardRarity.Common; + newCard.Zone = CardZone.AppleHills; + // Note: No longer setting BackgroundColor since it's derived from Zone + newCard.CollectionIndex = _cards.Count; + + // Save the asset + string path = $"{CardDefinitionsPath}/Card_{newCard.Name}.asset"; + path = AssetDatabase.GenerateUniqueAssetPath(path); + AssetDatabase.CreateAsset(newCard, path); + AssetDatabase.SaveAssets(); + AssetDatabase.Refresh(); + + // Reload cards and select the new one + LoadCardDefinitions(); + SelectCard(newCard); + } + + private void DuplicateSelectedCard() + { + if (_selectedCard == null) + return; + + // Create a new card definition + CardDefinition newCard = CloneCard(_editingCard); + + // Give it a new ID + newCard.Id = System.Guid.NewGuid().ToString(); + newCard.Name += " (Copy)"; + + // Save the asset + string path = $"{CardDefinitionsPath}/Card_{newCard.Name}.asset"; + path = AssetDatabase.GenerateUniqueAssetPath(path); + AssetDatabase.CreateAsset(newCard, path); + AssetDatabase.SaveAssets(); + AssetDatabase.Refresh(); + + // Reload cards and select the new one + LoadCardDefinitions(); + SelectCard(newCard); + } + + private void DeleteSelectedCard() + { + if (_selectedCard == null) + return; + + // Get the path of the selected card + string path = AssetDatabase.GetAssetPath(_selectedCard); + + // Delete the asset + AssetDatabase.DeleteAsset(path); + AssetDatabase.SaveAssets(); + AssetDatabase.Refresh(); + + // Clear selection and reload + _selectedCard = null; + _editingCard = null; + _isDirty = false; + LoadCardDefinitions(); + } + + private void ApplyChanges() + { + if (_selectedCard == null || _editingCard == null) + return; + + // Apply changes to the selected card + EditorUtility.CopySerialized(_editingCard, _selectedCard); + + // Mark as dirty and save + EditorUtility.SetDirty(_selectedCard); + AssetDatabase.SaveAssets(); + + // Clear dirty flag + _isDirty = false; + } + + private CardDefinition CloneCard(CardDefinition original) + { + CardDefinition clone = CreateInstance(); + EditorUtility.CopySerialized(original, clone); + return clone; + } + } +} diff --git a/Assets/Editor/CardSystem/CardEditorWindow.cs.meta b/Assets/Editor/CardSystem/CardEditorWindow.cs.meta new file mode 100644 index 00000000..87ccb730 --- /dev/null +++ b/Assets/Editor/CardSystem/CardEditorWindow.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 8055c7b5c1c541cbb3ee9e55bf65b376 +timeCreated: 1759925706 \ No newline at end of file diff --git a/Assets/External/TextMesh Pro/Resources/Fonts & Materials/LiberationSans SDF.asset b/Assets/External/TextMesh Pro/Resources/Fonts & Materials/LiberationSans SDF.asset index 54327370..d39ee081 100644 --- a/Assets/External/TextMesh Pro/Resources/Fonts & Materials/LiberationSans SDF.asset +++ b/Assets/External/TextMesh Pro/Resources/Fonts & Materials/LiberationSans SDF.asset @@ -37,7 +37,7 @@ Material: - _MaskSoftnessX: 0 - _MaskSoftnessY: 0 - _OutlineSoftness: 0 - - _OutlineWidth: 0.045 + - _OutlineWidth: 0.2 - _PerspectiveFilter: 0.875 - _ScaleRatioA: 0.9 - _ScaleRatioB: 1 diff --git a/Assets/Prefabs/Minigames/DivingForPictures/QuarryMonster.prefab b/Assets/Prefabs/Minigames/DivingForPictures/QuarryMonster.prefab index 4245050c..225b76bf 100644 --- a/Assets/Prefabs/Minigames/DivingForPictures/QuarryMonster.prefab +++ b/Assets/Prefabs/Minigames/DivingForPictures/QuarryMonster.prefab @@ -12,6 +12,7 @@ GameObject: - component: {fileID: 8447572436637192077} - component: {fileID: 4998672042618199381} - component: {fileID: 3714732064953161914} + - component: {fileID: 8725474797166928194} m_Layer: 12 m_Name: QuarryMonster m_TagString: Untagged @@ -19,21 +20,26 @@ GameObject: m_NavMeshLayer: 0 m_StaticEditorFlags: 0 m_IsActive: 1 ---- !u!4 &6779310478082390115 -Transform: +--- !u!224 &6779310478082390115 +RectTransform: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 2015720985618639356} - serializedVersion: 2 m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 2.46, y: -1.79, z: 0} + m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 0.5, y: 0.5, z: 0.5} m_ConstrainProportionsScale: 0 - m_Children: [] + m_Children: + - {fileID: 2948264547315403581} m_Father: {fileID: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 2.46, y: 3.45} + m_Pivot: {x: 0.5, y: 0.5} --- !u!212 &8447572436637192077 SpriteRenderer: m_ObjectHideFlags: 0 @@ -54,6 +60,8 @@ SpriteRenderer: m_RayTracingAccelStructBuildFlagsOverride: 0 m_RayTracingAccelStructBuildFlags: 1 m_SmallMeshCulling: 1 + m_ForceMeshLod: -1 + m_MeshLodSelectionBias: 0 m_RenderingLayerMask: 1 m_RendererPriority: 0 m_Materials: @@ -75,6 +83,7 @@ SpriteRenderer: m_AutoUVMaxDistance: 0.5 m_AutoUVMaxAngle: 89 m_LightmapParameters: {fileID: 0} + m_GlobalIlluminationMeshLod: 0 m_SortingLayerID: 0 m_SortingLayer: 0 m_SortingOrder: 0 @@ -124,7 +133,7 @@ CircleCollider2D: m_CompositeOperation: 0 m_CompositeOrder: 0 m_Offset: {x: 0, y: 0} - m_Radius: 3 + m_Radius: 4.8 --- !u!114 &3714732064953161914 MonoBehaviour: m_ObjectHideFlags: 0 @@ -138,3 +147,114 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: detectionCollider: {fileID: 4998672042618199381} +--- !u!222 &8725474797166928194 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2015720985618639356} + m_CullTransparentMesh: 1 +--- !u!1 &5329236367077024222 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2948264547315403581} + - component: {fileID: 3497342652431039817} + - component: {fileID: 1007575356016584257} + m_Layer: 12 + m_Name: ProximityIndicator + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &2948264547315403581 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5329236367077024222} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0.19, y: 0.19, z: 0.19} + m_ConstrainProportionsScale: 1 + m_Children: [] + m_Father: {fileID: 6779310478082390115} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 20, y: 20} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &3497342652431039817 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5329236367077024222} + m_CullTransparentMesh: 1 +--- !u!212 &1007575356016584257 +SpriteRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5329236367077024222} + m_Enabled: 1 + m_CastShadows: 0 + m_ReceiveShadows: 0 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 0 + m_RayTraceProcedural: 0 + m_RayTracingAccelStructBuildFlagsOverride: 0 + m_RayTracingAccelStructBuildFlags: 1 + m_SmallMeshCulling: 1 + m_ForceMeshLod: -1 + m_MeshLodSelectionBias: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: a97c105638bdf8b4a8650670310a4cd3, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 0 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_GlobalIlluminationMeshLod: 0 + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_Sprite: {fileID: -1042073035024568290, guid: 0bbb26ed6c3670b4293fca36266cacd6, type: 3} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_FlipX: 0 + m_FlipY: 0 + m_DrawMode: 0 + m_Size: {x: 44.97, y: 44.920002} + m_AdaptiveModeThreshold: 0.5 + m_SpriteTileMode: 0 + m_WasSpriteAssigned: 1 + m_MaskInteraction: 0 + m_SpriteSortPoint: 0 diff --git a/Assets/Prefabs/UI/CameraCrosshair.prefab b/Assets/Prefabs/UI/CameraCrosshair.prefab new file mode 100644 index 00000000..0bd74e27 --- /dev/null +++ b/Assets/Prefabs/UI/CameraCrosshair.prefab @@ -0,0 +1,343 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &3191012273289593430 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5112036956614418003} + - component: {fileID: 1661625883045147498} + - component: {fileID: 3982494409369176681} + - component: {fileID: 644215793910550285} + - component: {fileID: 3473674839339771682} + m_Layer: 5 + m_Name: CameraCrosshair + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &5112036956614418003 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3191012273289593430} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 7977007561442923662} + - {fileID: 2458922740234910074} + - {fileID: 5102142052451200951} + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 1080, y: 1080} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1661625883045147498 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3191012273289593430} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 306cc8c2b49d7114eaa3623786fc2126, type: 3} + m_Name: + m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.LayoutElement + m_IgnoreLayout: 0 + m_MinWidth: -1 + m_MinHeight: -1 + m_PreferredWidth: -1 + m_PreferredHeight: 1080 + m_FlexibleWidth: -1 + m_FlexibleHeight: -1 + m_LayoutPriority: 1 +--- !u!114 &3982494409369176681 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3191012273289593430} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4b4b818dd8cb454abe85b8edcaece1db, type: 3} + m_Name: + m_EditorClassIdentifier: AppleHillsScripts::Minigames.DivingForPictures.PictureCamera.Viewfinder + viewfinderImages: + - {fileID: 6238430743545047181} + - {fileID: 1454823446688413410} + - {fileID: 4320080458651963543} +--- !u!222 &644215793910550285 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3191012273289593430} + m_CullTransparentMesh: 1 +--- !u!114 &3473674839339771682 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3191012273289593430} + 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: 0} + 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!1 &4595905309701925297 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2458922740234910074} + - component: {fileID: 5615879403855295613} + - component: {fileID: 1454823446688413410} + m_Layer: 5 + m_Name: FrameInner + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &2458922740234910074 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4595905309701925297} + 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: 5112036956614418003} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: -100, y: -100} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &5615879403855295613 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4595905309701925297} + m_CullTransparentMesh: 1 +--- !u!114 &1454823446688413410 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4595905309701925297} + 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: -2291430160556362638, guid: 0db492dd1eea9514db54af61f1a4d79e, type: 3} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 2.09 +--- !u!1 &5728489349197067000 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5102142052451200951} + - component: {fileID: 2870967395300042642} + - component: {fileID: 4320080458651963543} + m_Layer: 5 + m_Name: Crosshair + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &5102142052451200951 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5728489349197067000} + 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: 5112036956614418003} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 100, y: 100} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &2870967395300042642 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5728489349197067000} + m_CullTransparentMesh: 1 +--- !u!114 &4320080458651963543 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5728489349197067000} + 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: -4229316332011032055, guid: c9d2fdec6416f7840a7eb9f6542b3c01, type: 3} + 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!1 &6361514160153350252 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 7977007561442923662} + - component: {fileID: 7721310424969853524} + - component: {fileID: 6238430743545047181} + m_Layer: 5 + m_Name: FrameOuter + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &7977007561442923662 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6361514160153350252} + 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: 5112036956614418003} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &7721310424969853524 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6361514160153350252} + m_CullTransparentMesh: 1 +--- !u!114 &6238430743545047181 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6361514160153350252} + 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: -2291430160556362638, guid: 0db492dd1eea9514db54af61f1a4d79e, type: 3} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 2.09 diff --git a/Assets/Prefabs/UI/CameraCrosshair.prefab.meta b/Assets/Prefabs/UI/CameraCrosshair.prefab.meta new file mode 100644 index 00000000..1265ce8a --- /dev/null +++ b/Assets/Prefabs/UI/CameraCrosshair.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 99666bddf27a652479c2a3e0007a94dc +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Prefabs/UI/Cards.meta b/Assets/Prefabs/UI/Cards.meta new file mode 100644 index 00000000..0360a0d9 --- /dev/null +++ b/Assets/Prefabs/UI/Cards.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 320a6ca9a05e02f4aa97badfd140d9f1 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Prefabs/UI/Cards/CardUI.prefab b/Assets/Prefabs/UI/Cards/CardUI.prefab new file mode 100644 index 00000000..c3e1892c --- /dev/null +++ b/Assets/Prefabs/UI/Cards/CardUI.prefab @@ -0,0 +1,619 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &1674595570562273386 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 8321041088571283042} + - component: {fileID: 8657710833814654092} + - component: {fileID: 3062587662617271504} + m_Layer: 5 + m_Name: Background + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &8321041088571283042 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1674595570562273386} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 7987423280633120294} + - {fileID: 6467154550771149323} + - {fileID: 5853287755371765300} + - {fileID: 1376284209458560831} + m_Father: {fileID: 2699789555794789249} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &8657710833814654092 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1674595570562273386} + m_CullTransparentMesh: 1 +--- !u!114 &3062587662617271504 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1674595570562273386} + 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: 0.8, g: 0.9, b: 0.8, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 0 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: -3713692513169282065, guid: 6dd6a8569dd5cef408d97594bb5e9d49, type: 3} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 2.5 +--- !u!1 &2060536854119323360 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 8124520331884430719} + - component: {fileID: 2165315952716078155} + - component: {fileID: 2550939788652313610} + m_Layer: 0 + m_Name: NameText + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &8124520331884430719 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2060536854119323360} + m_LocalRotation: {x: -0, y: -0, z: 0.15619579, w: 0.9877261} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 7987423280633120294} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 17.972} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: -2.9004517, y: 8.941284} + m_SizeDelta: {x: 200, y: 50} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &2165315952716078155 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2060536854119323360} + m_CullTransparentMesh: 1 +--- !u!114 &2550939788652313610 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2060536854119323360} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} + m_Name: + m_EditorClassIdentifier: Unity.TextMeshPro::TMPro.TextMeshProUGUI + 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_text: Test example card 3 + m_isRightToLeft: 0 + m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_fontSharedMaterials: [] + m_fontMaterial: {fileID: 0} + m_fontMaterials: [] + m_fontColor32: + serializedVersion: 2 + rgba: 4294967295 + m_fontColor: {r: 1, g: 1, b: 1, a: 1} + m_enableVertexGradient: 0 + m_colorMode: 3 + m_fontColorGradient: + topLeft: {r: 1, g: 1, b: 1, a: 1} + topRight: {r: 1, g: 1, b: 1, a: 1} + bottomLeft: {r: 1, g: 1, b: 1, a: 1} + bottomRight: {r: 1, g: 1, b: 1, a: 1} + m_fontColorGradientPreset: {fileID: 0} + m_spriteAsset: {fileID: 0} + m_tintAllSprites: 0 + m_StyleSheet: {fileID: 0} + m_TextStyleHashCode: -1183493901 + m_overrideHtmlColors: 0 + m_faceColor: + serializedVersion: 2 + rgba: 4294967295 + m_fontSize: 15 + m_fontSizeBase: 15 + m_fontWeight: 400 + m_enableAutoSizing: 0 + m_fontSizeMin: 18 + m_fontSizeMax: 72 + m_fontStyle: 0 + m_HorizontalAlignment: 2 + m_VerticalAlignment: 512 + m_textAlignment: 65535 + m_characterSpacing: 0 + m_wordSpacing: 0 + m_lineSpacing: 0 + m_lineSpacingMax: 0 + m_paragraphSpacing: 0 + m_charWidthMaxAdj: 0 + m_TextWrappingMode: 1 + m_wordWrappingRatios: 0.4 + m_overflowMode: 0 + m_linkedTextComponent: {fileID: 0} + parentLinkedComponent: {fileID: 0} + m_enableKerning: 0 + m_ActiveFontFeatures: 6e72656b + m_enableExtraPadding: 0 + checkPaddingRequired: 0 + m_isRichText: 1 + m_EmojiFallbackSupport: 1 + m_parseCtrlCharacters: 1 + m_isOrthographic: 1 + m_isCullingEnabled: 0 + m_horizontalMapping: 0 + m_verticalMapping: 0 + m_uvLineOffset: 0 + m_geometrySortingOrder: 0 + m_IsTextObjectScaleStatic: 0 + m_VertexBufferAutoSizeReduction: 0 + m_useMaxVisibleDescender: 1 + m_pageToDisplay: 1 + m_margin: {x: 0, y: 0, z: 0, w: 0} + m_isUsingLegacyAnimationComponent: 0 + m_isVolumetricText: 0 + m_hasFontAssetChanged: 0 + m_baseMaterial: {fileID: 0} + m_maskOffset: {x: 0, y: 0, z: 0, w: 0} +--- !u!1 &2421709636016798578 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 7987423280633120294} + - component: {fileID: 8745186166470585342} + - component: {fileID: 353314911414134125} + m_Layer: 0 + m_Name: NameBackground + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &7987423280633120294 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2421709636016798578} + 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: 1 + m_Children: + - {fileID: 8124520331884430719} + m_Father: {fileID: 8321041088571283042} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0} + m_AnchorMax: {x: 0.5, y: 0} + m_AnchoredPosition: {x: 0, y: 54.599976} + m_SizeDelta: {x: 250, y: 77.5} + m_Pivot: {x: 0.5, y: 0} +--- !u!222 &8745186166470585342 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2421709636016798578} + m_CullTransparentMesh: 1 +--- !u!114 &353314911414134125 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2421709636016798578} + 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: -3310850967021205615, guid: bf14f631f4b34e74d83c20a1dd671422, type: 3} + 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!1 &3326706725254864107 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2699789555794789249} + - component: {fileID: 8725212443281664752} + - component: {fileID: 3914488700080302779} + - component: {fileID: 6599324117435394003} + m_Layer: 5 + m_Name: CardUI + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &2699789555794789249 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3326706725254864107} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 8321041088571283042} + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 300, y: 450} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &8725212443281664752 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3326706725254864107} + m_CullTransparentMesh: 1 +--- !u!114 &3914488700080302779 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3326706725254864107} + 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: 0} + 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: 10907, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + 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!114 &6599324117435394003 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3326706725254864107} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: aed7c581bdb84200a05dd8a7df409ab0, type: 3} + m_Name: + m_EditorClassIdentifier: AppleHillsScripts::AppleHills.UI.CardSystem.CardUIElement + cardNameText: {fileID: 2550939788652313610} + cardImage: {fileID: 959067373316088928} + frameImage: {fileID: 1665411369613789579} + backgroundImage: {fileID: 3062587662617271504} + backgroundShape: {fileID: 8871089254192903045} + cardDefinition: {fileID: 11400000, guid: 28dbfbd7a6b2cd84b8274bd1126b220b, type: 2} + cardData: + Id: aca05c10-f25d-4636-95bf-8497c841b95a + DefinitionId: ee1e2aec-bdb6-4c68-8d7a-061c7f5e8583 + Rarity: 2 + CopiesOwned: 1 + visualConfig: {fileID: 11400000, guid: 473a9bc98f6f6684e8023126fc557a88, type: 2} +--- !u!1 &3429746996164215956 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5853287755371765300} + - component: {fileID: 8909872439431770690} + - component: {fileID: 8871089254192903045} + m_Layer: 5 + m_Name: BackgroundShape + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &5853287755371765300 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3429746996164215956} + 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: 8321041088571283042} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: 29} + m_SizeDelta: {x: 250, y: 250} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &8909872439431770690 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3429746996164215956} + m_CullTransparentMesh: 1 +--- !u!114 &8871089254192903045 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3429746996164215956} + 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: 8542402908941169558, guid: 84a9632f9bdc1ee4bab91cf4b764b5f7, type: 3} + 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!1 &5412331388939213537 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1376284209458560831} + - component: {fileID: 9097459168520965074} + - component: {fileID: 959067373316088928} + m_Layer: 5 + m_Name: Portrait + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1376284209458560831 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5412331388939213537} + 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: 8321041088571283042} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: 29} + m_SizeDelta: {x: 150, y: 150} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &9097459168520965074 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5412331388939213537} + m_CullTransparentMesh: 1 +--- !u!114 &959067373316088928 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5412331388939213537} + 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: -9213056636207805707, guid: 00354ded9d8f8d643acc14837a229544, type: 3} + 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!1 &5760001742287037279 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6467154550771149323} + - component: {fileID: 1731110110200268733} + - component: {fileID: 1665411369613789579} + m_Layer: 5 + m_Name: BorderFrame + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &6467154550771149323 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5760001742287037279} + 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: 8321041088571283042} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &1731110110200268733 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5760001742287037279} + m_CullTransparentMesh: 1 +--- !u!114 &1665411369613789579 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5760001742287037279} + 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: 0, g: 0.19755316, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 0 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 855352274089539417, guid: bd7528147fbfb4e40b0c06c68e99e217, type: 3} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 2.5 diff --git a/Assets/Prefabs/UI/Cards/CardUI.prefab.meta b/Assets/Prefabs/UI/Cards/CardUI.prefab.meta new file mode 100644 index 00000000..a2e80a14 --- /dev/null +++ b/Assets/Prefabs/UI/Cards/CardUI.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 594aad71e4281174da8fb4f47a8d19b0 +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scenes/MiniGames/DivingForPictures.unity b/Assets/Scenes/MiniGames/DivingForPictures.unity index 5e06b81d..75813ab8 100644 --- a/Assets/Scenes/MiniGames/DivingForPictures.unity +++ b/Assets/Scenes/MiniGames/DivingForPictures.unity @@ -557,7 +557,7 @@ GameObject: m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 - m_IsActive: 1 + m_IsActive: 0 --- !u!114 &323864664 MonoBehaviour: m_ObjectHideFlags: 0 @@ -603,8 +603,9 @@ GameObject: m_Component: - component: {fileID: 424805726} - component: {fileID: 424805725} + - component: {fileID: 424805727} m_Layer: 0 - m_Name: MinigameManager + m_Name: MinigameManagers m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 @@ -647,6 +648,19 @@ Transform: m_Children: [] m_Father: {fileID: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &424805727 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 424805724} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: e5a6d17776b84719a2599fdc35c7076d, type: 3} + m_Name: + m_EditorClassIdentifier: AppleHillsScripts::Minigames.DivingForPictures.PictureCamera.CameraViewfinderManager + targetCanvas: {fileID: 116234200} --- !u!1 &461301695 GameObject: m_ObjectHideFlags: 0 @@ -867,6 +881,7 @@ GameObject: - component: {fileID: 747976403} - component: {fileID: 747976404} - component: {fileID: 747976405} + - component: {fileID: 747976406} m_Layer: 0 m_Name: BottleMarine m_TagString: Player @@ -1061,6 +1076,19 @@ Animator: m_AllowConstantClipSamplingOptimization: 1 m_KeepAnimatorStateOnDisable: 0 m_WriteDefaultValuesOnDisable: 0 +--- !u!114 &747976406 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 747976396} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: cf50e6f7c05d5a14296152b8c3fbb923, type: 3} + m_Name: + m_EditorClassIdentifier: AppleHillsScripts::Minigames.DivingForPictures.Utilities.BottlePauser + wobbleReference: {fileID: 747976399} --- !u!1 &824396214 GameObject: m_ObjectHideFlags: 0 @@ -1985,24 +2013,24 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: tilePrefabs: + - {fileID: 2956826569642009690, guid: 423507a5af73a9640b858d93224a2659, type: 3} - {fileID: 2956826569642009690, guid: 9526b05f428f464459def30747966859, type: 3} - - {fileID: 2956826569642009690, guid: f9bab4478abe3d445b1f01a513a2c7e6, type: 3} - - {fileID: 2956826569642009690, guid: 71d7b85ecf91de44b9aa4335a349d8c8, type: 3} - - {fileID: 2956826569642009690, guid: b5fc5929ab94faf42bf9ebfc918a3597, type: 3} - - {fileID: 2956826569642009690, guid: c1e94865d6c6ccf49b342dfb286c7231, type: 3} - - {fileID: 2956826569642009690, guid: 8c90ffd155e124c46a063e1bd76e60fd, type: 3} - - {fileID: 2956826569642009690, guid: 257e799913b77da4cb840a3d799fec3d, type: 3} - - {fileID: 2956826569642009690, guid: be9f1ba3224927d47bdba480c08ff788, type: 3} - - {fileID: 2956826569642009690, guid: a1482a2f9a3028b4b9a3859eda1049c3, type: 3} - - {fileID: 2956826569642009690, guid: c0bbd17f27729404fb8813ad56fd3d8f, type: 3} - - {fileID: 2956826569642009690, guid: c68bd81229be16241bdbd8b6582a8b6d, type: 3} - - {fileID: 2956826569642009690, guid: 5099267fccf4be0478d710de2f3d4b3c, type: 3} - - {fileID: 2956826569642009690, guid: 693abc4534c5b604cb4ad954c57490f7, type: 3} - - {fileID: 2956826569642009690, guid: c9e945fe46bcda34eaf9f6249183e36e, type: 3} - - {fileID: 2956826569642009690, guid: 2c8ff0569f4f59e4a9f8a4f918e524c7, type: 3} - - {fileID: 2956826569642009690, guid: 30f32f6da706b44428c9a104c403b5f7, type: 3} - - {fileID: 2956826569642009690, guid: a3ec47438b74c664ba026bf41f43a368, type: 3} - - {fileID: 2956826569642009690, guid: 95c046aefbdd7a0418e9ea0305e3567c, type: 3} + - {fileID: 2956826569642009690, guid: a3703750ec2f316408a6ff952b40c004, type: 3} + - {fileID: 2956826569642009690, guid: 1b645d98085a76545acaa8db4fb0f7e0, type: 3} + - {fileID: 2956826569642009690, guid: 86b321848a9c3d94d9fd461a4482ac7b, type: 3} + - {fileID: 2956826569642009690, guid: 4575c161d62b1e64e85ca638108e7015, type: 3} + - {fileID: 2956826569642009690, guid: 7f20defacde3de742a72ab659b2eeb56, type: 3} + - {fileID: 2956826569642009690, guid: 40c6d595022652b4bac2563e4f7a3f40, type: 3} + - {fileID: 2956826569642009690, guid: 4ba2e030d29d88b4b935487b793ac77b, type: 3} + - {fileID: 2956826569642009690, guid: 4692f9279f981b34eb596c6c263bec82, type: 3} + - {fileID: 2956826569642009690, guid: b44a4567ae637b3409d34c8b463aaf41, type: 3} + - {fileID: 2956826569642009690, guid: 09a8470180f44c049a1f137e091b5581, type: 3} + - {fileID: 2956826569642009690, guid: 0a73c9b6214318a429f319762ad25b99, type: 3} + - {fileID: 2956826569642009690, guid: 0f9b70cfab4dd454298ce9a509f01a35, type: 3} + - {fileID: 2956826569642009690, guid: 85e400c58e60c47458059c1e24c8576a, type: 3} + - {fileID: 2956826569642009690, guid: b3501bc08c6afbf4f868bc7b6c2a2d92, type: 3} + - {fileID: 2956826569642009690, guid: 4f9c8bd3fb844484492a54a2998b9b3b, type: 3} + - {fileID: 2956826569642009690, guid: 16ad8a46d2c7c534982f4ee943e06f74, type: 3} onTileSpawned: m_PersistentCalls: m_Calls: [] @@ -2012,6 +2040,37 @@ MonoBehaviour: onLastTileLeft: m_PersistentCalls: m_Calls: [] +--- !u!1 &1787733334 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1787733335} + m_Layer: 0 + m_Name: ---- Managers and Controls ---- + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1787733335 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1787733334} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 4.15698, y: 1.79286, 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} --- !u!1 &1834056336 GameObject: m_ObjectHideFlags: 0 @@ -2261,6 +2320,7 @@ GameObject: - component: {fileID: 2106431002} - component: {fileID: 2106431003} - component: {fileID: 2106431004} + - component: {fileID: 2106431005} m_Layer: 0 m_Name: Rock m_TagString: Rock @@ -2319,6 +2379,20 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 9072050a53fc4b539f4f4716bab53c07, type: 3} m_Name: m_EditorClassIdentifier: +--- !u!114 &2106431005 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2106431001} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a392c919de2df0340b700309e221b7b1, type: 3} + m_Name: + m_EditorClassIdentifier: AppleHillsScripts::Minigames.DivingForPictures.Utilities.RockPauser + rockReference: {fileID: 2106431003} + rockWobbleReference: {fileID: 2106431004} --- !u!1660057539 &9223372036854775807 SceneRoots: m_ObjectHideFlags: 0 @@ -2326,12 +2400,13 @@ SceneRoots: - {fileID: 1063641114} - {fileID: 224729333} - {fileID: 747976397} - - {fileID: 1003335105} - {fileID: 2106431002} - - {fileID: 1679185998} - - {fileID: 424805726} - {fileID: 116234201} - {fileID: 824396217} - - {fileID: 323864665} - {fileID: 461301697} - {fileID: 2064311129} + - {fileID: 1787733335} + - {fileID: 1003335105} + - {fileID: 1679185998} + - {fileID: 323864665} + - {fileID: 424805726} diff --git a/Assets/Scripts/Core/GameManager.cs b/Assets/Scripts/Core/GameManager.cs index ceaac3c7..0dde7ffc 100644 --- a/Assets/Scripts/Core/GameManager.cs +++ b/Assets/Scripts/Core/GameManager.cs @@ -182,7 +182,7 @@ public class GameManager : MonoBehaviour // Resume all registered components foreach (var component in _pausableComponents) { - component.Resume(); + component.DoResume(); } // Broadcast resume event diff --git a/Assets/Scripts/Core/Interfaces/IPausable.cs b/Assets/Scripts/Core/Interfaces/IPausable.cs index 81739c39..9347e157 100644 --- a/Assets/Scripts/Core/Interfaces/IPausable.cs +++ b/Assets/Scripts/Core/Interfaces/IPausable.cs @@ -15,7 +15,7 @@ namespace AppleHills.Core.Interfaces /// /// Resumes the component's functionality /// - void Resume(); + void DoResume(); /// /// Gets whether the component is currently paused diff --git a/Assets/Scripts/Utility/SceneOrientationEnforcer.cs b/Assets/Scripts/Core/SceneOrientationEnforcer.cs similarity index 100% rename from Assets/Scripts/Utility/SceneOrientationEnforcer.cs rename to Assets/Scripts/Core/SceneOrientationEnforcer.cs diff --git a/Assets/Scripts/Utility/SceneOrientationEnforcer.cs.meta b/Assets/Scripts/Core/SceneOrientationEnforcer.cs.meta similarity index 100% rename from Assets/Scripts/Utility/SceneOrientationEnforcer.cs.meta rename to Assets/Scripts/Core/SceneOrientationEnforcer.cs.meta diff --git a/Assets/Scripts/Core/Settings/DivingMinigameSettings.cs b/Assets/Scripts/Core/Settings/DivingMinigameSettings.cs index 4a395ac9..2d19789d 100644 --- a/Assets/Scripts/Core/Settings/DivingMinigameSettings.cs +++ b/Assets/Scripts/Core/Settings/DivingMinigameSettings.cs @@ -126,6 +126,38 @@ namespace AppleHills.Core.Settings [Tooltip("Whether to block player input during bump movement")] [SerializeField] private bool blockInputDuringBump = true; + [Header("Camera Viewfinder")] + [Tooltip("The prefab to use for the camera viewfinder UI")] + [SerializeField] private GameObject viewfinderPrefab; + + [Tooltip("Duration in seconds for the viewfinder to shrink")] + [SerializeField] private float viewfinderShrinkDuration = 1.5f; + + [Tooltip("Speed at which the viewfinder moves toward the target")] + [SerializeField] private float viewfinderMoveSpeed = 5f; + + [Tooltip("Animation curve for the shrinking effect")] + [SerializeField] private AnimationCurve viewfinderShrinkCurve = AnimationCurve.EaseInOut(0, 1, 1, 0); + + [Tooltip("Padding factor to add space around the monster (1.0 = exact size, 1.2 = 20% extra)")] + [SerializeField] private float paddingFactor = 1.2f; + + [Tooltip("Minimum size of the viewfinder as a percentage of screen width (0.15 = 15%)")] + [SerializeField] private float minSizePercent = 0.15f; + + [Tooltip("Maximum size of the viewfinder as a percentage of screen width (0.8 = 80%)")] + [SerializeField] private float maxSizePercent = 0.8f; + + + [Tooltip("Starting scale of the viewfinder (relative to screen width)")] + [SerializeField] private float viewfinderStartScale = 1.0f; + + [Tooltip("Final scale of the viewfinder")] + [SerializeField] private float viewfinderEndScale = 0.25f; + + [Tooltip("Progress percentages at which to trigger events (0-1)")] + [SerializeField] private float[] viewfinderProgressThresholds = new float[] { 0.25f, 0.5f, 0.75f, 1.0f }; + // IDivingMinigameSettings implementation - Basic Movement public float LerpSpeed => lerpSpeed; public float MaxOffset => maxOffset; @@ -177,6 +209,18 @@ namespace AppleHills.Core.Settings public float SmoothMoveSpeed => smoothMoveSpeed; public bool BlockInputDuringBump => blockInputDuringBump; + // IDivingMinigameSettings implementation - Camera Viewfinder + public GameObject ViewfinderPrefab => viewfinderPrefab; + public float ViewfinderShrinkDuration => viewfinderShrinkDuration; + public float ViewfinderMoveSpeed => viewfinderMoveSpeed; + public AnimationCurve ViewfinderShrinkCurve => viewfinderShrinkCurve; + public float ViewfinderStartScale => viewfinderStartScale; + public float ViewfinderEndScale => viewfinderEndScale; + public float[] ViewfinderProgressThresholds => viewfinderProgressThresholds; + public float PaddingFactor => paddingFactor; + public float MaxSizePercent => maxSizePercent; + public float MinSizePercent => minSizePercent; + public override void OnValidate() { base.OnValidate(); @@ -238,6 +282,16 @@ namespace AppleHills.Core.Settings damageImmunityDuration = Mathf.Max(0.1f, damageImmunityDuration); bumpForce = Mathf.Max(0.1f, bumpForce); smoothMoveSpeed = Mathf.Max(0.1f, smoothMoveSpeed); + + // Validate camera viewfinder settings + viewfinderShrinkDuration = Mathf.Max(0.1f, viewfinderShrinkDuration); + viewfinderMoveSpeed = Mathf.Max(0.1f, viewfinderMoveSpeed); + viewfinderStartScale = Mathf.Max(0.01f, viewfinderStartScale); + viewfinderEndScale = Mathf.Max(viewfinderStartScale, viewfinderEndScale); + for (int i = 0; i < viewfinderProgressThresholds.Length; i++) + { + viewfinderProgressThresholds[i] = Mathf.Clamp01(viewfinderProgressThresholds[i]); + } } } } diff --git a/Assets/Scripts/Core/Settings/SettingsInterfaces.cs b/Assets/Scripts/Core/Settings/SettingsInterfaces.cs index 4b48f197..a2706dc6 100644 --- a/Assets/Scripts/Core/Settings/SettingsInterfaces.cs +++ b/Assets/Scripts/Core/Settings/SettingsInterfaces.cs @@ -108,5 +108,17 @@ namespace AppleHills.Core.Settings float BumpForce { get; } float SmoothMoveSpeed { get; } bool BlockInputDuringBump { get; } + + // Camera Viewfinder Settings + GameObject ViewfinderPrefab { get; } + float ViewfinderShrinkDuration { get; } + float ViewfinderMoveSpeed { get; } + AnimationCurve ViewfinderShrinkCurve { get; } + float ViewfinderStartScale { get; } + float ViewfinderEndScale { get; } + float[] ViewfinderProgressThresholds { get; } + float PaddingFactor { get; } + float MaxSizePercent { get; } + float MinSizePercent { get; } } } diff --git a/Assets/Scripts/Data/CardSystem.meta b/Assets/Scripts/Data/CardSystem.meta new file mode 100644 index 00000000..17db497e --- /dev/null +++ b/Assets/Scripts/Data/CardSystem.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 52a47d9c5b29456faca1c9b43f8f4750 +timeCreated: 1759923654 \ No newline at end of file diff --git a/Assets/Scripts/Data/CardSystem/CardData.cs b/Assets/Scripts/Data/CardSystem/CardData.cs new file mode 100644 index 00000000..e607f652 --- /dev/null +++ b/Assets/Scripts/Data/CardSystem/CardData.cs @@ -0,0 +1,115 @@ +using System; +using UnityEngine; + +namespace AppleHills.Data.CardSystem +{ + [Serializable] + public class CardData + { + // Core data (serialized) + public string Id; // Auto-generated unique ID (GUID) + public string DefinitionId; // ID of the card definition this instance was created from + public CardRarity Rarity; // Current rarity (may be upgraded from original) + public int CopiesOwned; // Number of copies the player has (for stacking) + + // Reference back to the definition (not serialized) + [NonSerialized] + private CardDefinition _definition; + + // Properties that reference definition data + public string Name => _definition?.Name; + public string Description => _definition?.Description; + public CardZone Zone => _definition?.Zone ?? CardZone.AppleHills; + public int CollectionIndex => _definition?.CollectionIndex ?? 0; + public Sprite CardImage => _definition?.CardImage; + + // Derived properties + public Color BackgroundColor => _definition?.GetBackgroundColor() ?? Color.white; + + // Get frame shape based on rarity + public string GetFrameShapeName() + { + return $"Frame_{Rarity}"; + } + + // Default constructor + public CardData() + { + Id = Guid.NewGuid().ToString(); + CopiesOwned = 0; + } + + // Constructor from definition + public CardData(CardDefinition definition) + { + Id = Guid.NewGuid().ToString(); + DefinitionId = definition.Id; + Rarity = definition.Rarity; + CopiesOwned = 1; + _definition = definition; + } + + // Copy constructor + public CardData(CardData other) + { + Id = other.Id; + DefinitionId = other.DefinitionId; + Rarity = other.Rarity; + CopiesOwned = other.CopiesOwned; + _definition = other._definition; + } + + // Method to link this card data to its definition + public void SetDefinition(CardDefinition definition) + { + if (definition != null) + { + _definition = definition; + DefinitionId = definition.Id; + } + } + + // Method to upgrade rarity when enough copies are collected + public bool TryUpgradeRarity() + { + // Simple implementation - each rarity needs twice as many copies to upgrade + int requiredCopies = (int)Rarity * 2 + 1; + + if (CopiesOwned >= requiredCopies && Rarity < CardRarity.Legendary) + { + Rarity += 1; + CopiesOwned -= requiredCopies; + return true; + } + + return false; + } + + // ToString method for debugging + public override string ToString() + { + return $"CardData [ID: {Id}, Name: {Name}, Rarity: {Rarity}, Zone: {Zone}, " + + $"DefinitionID: {DefinitionId}, Copies: {CopiesOwned}, " + + $"Has Definition: {_definition != null}, Has Image: {CardImage != null}]"; + } + } + + // Enums for card attributes + public enum CardRarity + { + Common = 0, + Uncommon = 1, + Rare = 2, + Epic = 3, + Legendary = 4 + } + + public enum CardZone + { + AppleHills, + Quarry, + Forest, + Mountain, + Beach + } +} diff --git a/Assets/Scripts/Data/CardSystem/CardData.cs.meta b/Assets/Scripts/Data/CardSystem/CardData.cs.meta new file mode 100644 index 00000000..8be56ab3 --- /dev/null +++ b/Assets/Scripts/Data/CardSystem/CardData.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 812f681e555841c584d5791cb66278de +timeCreated: 1759923654 \ No newline at end of file diff --git a/Assets/Scripts/Data/CardSystem/CardDefinition.cs b/Assets/Scripts/Data/CardSystem/CardDefinition.cs new file mode 100644 index 00000000..0fa7902d --- /dev/null +++ b/Assets/Scripts/Data/CardSystem/CardDefinition.cs @@ -0,0 +1,61 @@ +using System; +using UnityEngine; + +namespace AppleHills.Data.CardSystem +{ + /// + /// Scriptable object defining a collectible card's properties. + /// Used as a template for generating CardData instances. + /// + [CreateAssetMenu(fileName = "New Card", menuName = "Apple Hills/Card System/Card Definition")] + public class CardDefinition : ScriptableObject + { + [Header("Identification")] + [Tooltip("Unique identifier for this card definition")] + public string Id = Guid.NewGuid().ToString(); + + [Header("Basic Info")] + public string Name; + [TextArea(3, 5)] + public string Description; + public CardRarity Rarity; + public CardZone Zone; + + [Header("Visual Elements")] + public Sprite CardImage; // The actual card image + + [Header("Collection Info")] + public int CollectionIndex; // Position in the album + + /// + /// Creates a new CardData instance from this definition + /// + public CardData CreateCardData() + { + return new CardData(this); + } + + /// + /// Gets the background color for this card based on its zone + /// + public Color GetBackgroundColor() + { + // Colors based on zone + switch (Zone) + { + case CardZone.AppleHills: + return new Color(0.8f, 0.9f, 0.8f); // Light green + case CardZone.Quarry: + return new Color(0.85f, 0.8f, 0.7f); // Sandy brown + case CardZone.Forest: + return new Color(0.6f, 0.8f, 0.6f); // Forest green + case CardZone.Mountain: + return new Color(0.7f, 0.7f, 0.9f); // Bluish + case CardZone.Beach: + return new Color(0.9f, 0.85f, 0.7f); // Sandy yellow + default: + return Color.white; + } + } + } +} diff --git a/Assets/Scripts/Data/CardSystem/CardDefinition.cs.meta b/Assets/Scripts/Data/CardSystem/CardDefinition.cs.meta new file mode 100644 index 00000000..34724df0 --- /dev/null +++ b/Assets/Scripts/Data/CardSystem/CardDefinition.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 2a80cc88c9884512b8b633110d838780 +timeCreated: 1759923702 \ No newline at end of file diff --git a/Assets/Scripts/Data/CardSystem/CardSystemManager.cs b/Assets/Scripts/Data/CardSystem/CardSystemManager.cs new file mode 100644 index 00000000..c80ed549 --- /dev/null +++ b/Assets/Scripts/Data/CardSystem/CardSystemManager.cs @@ -0,0 +1,264 @@ +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace AppleHills.Data.CardSystem +{ + /// + /// Manages the player's card collection, booster packs, and related operations. + /// Uses a singleton pattern for global access. + /// + public class CardSystemManager : MonoBehaviour + { + private static CardSystemManager _instance; + private static bool _isQuitting = false; + + public static CardSystemManager Instance + { + get + { + if (_instance == null && Application.isPlaying && !_isQuitting) + { + _instance = FindAnyObjectByType(); + if (_instance == null) + { + var go = new GameObject("CardSystemManager"); + _instance = go.AddComponent(); + DontDestroyOnLoad(go); + } + } + return _instance; + } + } + + [Header("Card Collection")] + [SerializeField] private List availableCards = new List(); + + // Runtime data - will be serialized for save/load + [SerializeField] private CardInventory playerInventory = new CardInventory(); + + // Dictionary to quickly look up card definitions by ID + private Dictionary _definitionLookup = new Dictionary(); + + // Event callbacks using System.Action + public event Action> OnBoosterOpened; + public event Action OnCardCollected; + public event Action OnCardRarityUpgraded; + public event Action OnBoosterCountChanged; + + private void Awake() + { + if (_instance != null && _instance != this) + { + Destroy(gameObject); + return; + } + + _instance = this; + DontDestroyOnLoad(gameObject); + + // Build lookup dictionary + BuildDefinitionLookup(); + } + + private void OnApplicationQuit() + { + _isQuitting = true; + } + + /// + /// Builds a lookup dictionary for quick access to card definitions by ID + /// + private void BuildDefinitionLookup() + { + _definitionLookup.Clear(); + + foreach (var cardDef in availableCards) + { + if (cardDef != null && !string.IsNullOrEmpty(cardDef.Id)) + { + _definitionLookup[cardDef.Id] = cardDef; + } + } + + // Link existing card data to their definitions + foreach (var cardData in playerInventory.CollectedCards.Values) + { + if (!string.IsNullOrEmpty(cardData.DefinitionId) && + _definitionLookup.TryGetValue(cardData.DefinitionId, out CardDefinition def)) + { + cardData.SetDefinition(def); + } + } + } + + /// + /// Adds a booster pack to the player's inventory + /// + public void AddBoosterPack(int count = 1) + { + playerInventory.BoosterPackCount += count; + OnBoosterCountChanged?.Invoke(playerInventory.BoosterPackCount); + Debug.Log($"[CardSystemManager] Added {count} booster pack(s). Total: {playerInventory.BoosterPackCount}"); + } + + /// + /// Opens a booster pack and returns the newly obtained cards + /// + public List OpenBoosterPack() + { + if (playerInventory.BoosterPackCount <= 0) + { + Debug.LogWarning("[CardSystemManager] Attempted to open a booster pack, but none are available."); + return new List(); + } + + playerInventory.BoosterPackCount--; + OnBoosterCountChanged?.Invoke(playerInventory.BoosterPackCount); + + // Draw 3 cards based on rarity distribution + List drawnCards = DrawRandomCards(3); + + // Add cards to the inventory + foreach (var card in drawnCards) + { + AddCardToInventory(card); + } + + // Notify listeners + OnBoosterOpened?.Invoke(drawnCards); + + Debug.Log($"[CardSystemManager] Opened a booster pack and obtained {drawnCards.Count} cards. Remaining boosters: {playerInventory.BoosterPackCount}"); + return drawnCards; + } + + /// + /// Adds a card to the player's inventory, handles duplicates + /// + private void AddCardToInventory(CardData card) + { + // Check if the player already has this card type (definition) + if (playerInventory.CollectedCards.TryGetValue(card.DefinitionId, out CardData existingCard)) + { + existingCard.CopiesOwned++; + + // Check if the card can be upgraded + if (existingCard.TryUpgradeRarity()) + { + OnCardRarityUpgraded?.Invoke(existingCard); + } + + Debug.Log($"[CardSystemManager] Added duplicate card '{card.Name}'. Now have {existingCard.CopiesOwned} copies."); + } + else + { + // Add new card + playerInventory.CollectedCards.Add(card.DefinitionId, new CardData(card)); + OnCardCollected?.Invoke(card); + + Debug.Log($"[CardSystemManager] Added new card '{card.Name}' to collection."); + } + } + + /// + /// Draws random cards based on rarity distribution + /// + private List DrawRandomCards(int count) + { + List result = new List(); + + if (availableCards.Count == 0) + { + Debug.LogError("[CardSystemManager] No available cards defined!"); + return result; + } + + // Simple weighted random selection based on rarity + for (int i = 0; i < count; i++) + { + // Determine card rarity first + CardRarity rarity = DetermineRandomRarity(); + + // Filter cards by the selected rarity + List cardsOfRarity = availableCards.FindAll(c => c.Rarity == rarity); + + if (cardsOfRarity.Count > 0) + { + // Select a random card of this rarity + int randomIndex = UnityEngine.Random.Range(0, cardsOfRarity.Count); + CardDefinition selectedDef = cardsOfRarity[randomIndex]; + + // Create card data from definition + CardData newCard = selectedDef.CreateCardData(); + result.Add(newCard); + } + else + { + // Fallback if no cards of the selected rarity + Debug.LogWarning($"[CardSystemManager] No cards of rarity {rarity} available, selecting a random card instead."); + int randomIndex = UnityEngine.Random.Range(0, availableCards.Count); + CardDefinition randomDef = availableCards[randomIndex]; + + CardData newCard = randomDef.CreateCardData(); + result.Add(newCard); + } + } + + return result; + } + + /// + /// Determines a random card rarity with appropriate weighting + /// + private CardRarity DetermineRandomRarity() + { + // Simple weighted random - can be adjusted for better distribution + float rand = UnityEngine.Random.value; + + if (rand < 0.6f) return CardRarity.Common; + if (rand < 0.85f) return CardRarity.Uncommon; + if (rand < 0.95f) return CardRarity.Rare; + if (rand < 0.99f) return CardRarity.Epic; + return CardRarity.Legendary; + } + + /// + /// Returns all cards from the player's collection + /// + public List GetAllCollectedCards() + { + List result = new List(); + foreach (var card in playerInventory.CollectedCards.Values) + { + result.Add(card); + } + return result; + } + + /// + /// Returns the number of booster packs the player has + /// + public int GetBoosterPackCount() + { + return playerInventory.BoosterPackCount; + } + + /// + /// Returns whether a specific card definition has been collected + /// + public bool IsCardCollected(string definitionId) + { + return playerInventory.CollectedCards.ContainsKey(definitionId); + } + } + + /// + /// Serializable class to store the player's card inventory + /// + [Serializable] + public class CardInventory + { + public Dictionary CollectedCards = new Dictionary(); + public int BoosterPackCount; + } +} diff --git a/Assets/Scripts/Data/CardSystem/CardSystemManager.cs.meta b/Assets/Scripts/Data/CardSystem/CardSystemManager.cs.meta new file mode 100644 index 00000000..dce5702f --- /dev/null +++ b/Assets/Scripts/Data/CardSystem/CardSystemManager.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 8d80347e4bd04c87be23a9399860783d +timeCreated: 1759923691 \ No newline at end of file diff --git a/Assets/Scripts/Data/CardSystem/CardVisualConfig.cs b/Assets/Scripts/Data/CardSystem/CardVisualConfig.cs new file mode 100644 index 00000000..9d1488f0 --- /dev/null +++ b/Assets/Scripts/Data/CardSystem/CardVisualConfig.cs @@ -0,0 +1,203 @@ +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace AppleHills.Data.CardSystem +{ + /// + /// ScriptableObject containing visual configuration for card display + /// Maps card rarities to colors and zones to colors/shapes + /// + [CreateAssetMenu(fileName = "CardVisualConfig", menuName = "Apple Hills/Card System/Visual Config")] + public class CardVisualConfig : ScriptableObject + { + [Serializable] + public class RarityColorMapping + { + public CardRarity rarity; + public Color color = Color.white; + } + + [Serializable] + public class ZoneVisualMapping + { + public CardZone zone; + public Color color = Color.white; + public Sprite backgroundShape; + } + + [Header("Rarity Configuration")] + [Tooltip("Color mappings for different card rarities")] + [SerializeField] private List rarityColors = new List(); + + [Header("Zone Configuration")] + [Tooltip("Visual mappings for different card zones")] + [SerializeField] private List zoneVisuals = new List(); + + private Dictionary _rarityColorLookup; + private Dictionary _zoneColorLookup; + private Dictionary _zoneShapeLookup; + + /// + /// Initialize the lookup dictionaries when the asset is loaded + /// + private void OnEnable() + { + InitializeLookups(); + } + + /// + /// Builds the lookup dictionaries from the serialized lists + /// + private void InitializeLookups() + { + // Build rarity color lookup + _rarityColorLookup = new Dictionary(); + foreach (var mapping in rarityColors) + { + _rarityColorLookup[mapping.rarity] = mapping.color; + } + + // Build zone color and shape lookups + _zoneColorLookup = new Dictionary(); + _zoneShapeLookup = new Dictionary(); + + foreach (var mapping in zoneVisuals) + { + _zoneColorLookup[mapping.zone] = mapping.color; + _zoneShapeLookup[mapping.zone] = mapping.backgroundShape; + } + } + + /// + /// Get the color for a specific card rarity + /// + public Color GetRarityColor(CardRarity rarity) + { + // Initialize lookups if needed + if (_rarityColorLookup == null) + { + InitializeLookups(); + } + + // Return the color if found, otherwise white + if (_rarityColorLookup.TryGetValue(rarity, out Color color)) + { + return color; + } + + Debug.LogWarning($"[CardVisualConfig] No color mapping found for rarity {rarity}, using default"); + return Color.white; + } + + /// + /// Get the color for a specific card zone + /// + public Color GetZoneColor(CardZone zone) + { + // Initialize lookups if needed + if (_zoneColorLookup == null) + { + InitializeLookups(); + } + + // Return the color if found, otherwise white + if (_zoneColorLookup.TryGetValue(zone, out Color color)) + { + return color; + } + + Debug.LogWarning($"[CardVisualConfig] No color mapping found for zone {zone}, using default"); + return Color.white; + } + + /// + /// Get the background shape sprite for a specific zone + /// + public Sprite GetZoneShape(CardZone zone) + { + // Initialize lookups if needed + if (_zoneShapeLookup == null) + { + InitializeLookups(); + } + + // Return the sprite if found, otherwise null + if (_zoneShapeLookup.TryGetValue(zone, out Sprite sprite)) + { + return sprite; + } + + Debug.LogWarning($"[CardVisualConfig] No shape mapping found for zone {zone}"); + return null; + } + +#if UNITY_EDITOR + /// + /// Editor-only utility to reset the config with default values + /// + public void ResetWithDefaults() + { + // Clear existing mappings + rarityColors.Clear(); + zoneVisuals.Clear(); + + // Add default rarity colors + rarityColors.Add(new RarityColorMapping { rarity = CardRarity.Common, color = Color.gray }); + rarityColors.Add(new RarityColorMapping { rarity = CardRarity.Uncommon, color = Color.green }); + rarityColors.Add(new RarityColorMapping { rarity = CardRarity.Rare, color = Color.blue }); + rarityColors.Add(new RarityColorMapping { rarity = CardRarity.Epic, color = new Color(0.5f, 0, 0.5f) }); + rarityColors.Add(new RarityColorMapping { rarity = CardRarity.Legendary, color = Color.yellow }); + + // Add default zone colors + zoneVisuals.Add(new ZoneVisualMapping { + zone = CardZone.AppleHills, + color = new Color(0.8f, 0.9f, 0.8f) + }); + + zoneVisuals.Add(new ZoneVisualMapping { + zone = CardZone.Quarry, + color = new Color(0.85f, 0.8f, 0.7f) + }); + + zoneVisuals.Add(new ZoneVisualMapping { + zone = CardZone.Forest, + color = new Color(0.6f, 0.8f, 0.6f) + }); + + zoneVisuals.Add(new ZoneVisualMapping { + zone = CardZone.Mountain, + color = new Color(0.7f, 0.7f, 0.9f) + }); + + zoneVisuals.Add(new ZoneVisualMapping { + zone = CardZone.Beach, + color = new Color(0.9f, 0.85f, 0.7f) + }); + + // Initialize the lookups + InitializeLookups(); + } +#endif + } + +#if UNITY_EDITOR + [UnityEditor.CustomEditor(typeof(CardVisualConfig))] + public class CardVisualConfigEditor : UnityEditor.Editor + { + public override void OnInspectorGUI() + { + DrawDefaultInspector(); + + CardVisualConfig config = (CardVisualConfig)target; + + UnityEditor.EditorGUILayout.Space(); + if (GUILayout.Button("Reset with Defaults")) + { + config.ResetWithDefaults(); + UnityEditor.EditorUtility.SetDirty(config); + } + } + } +#endif +} diff --git a/Assets/Scripts/Data/CardSystem/CardVisualConfig.cs.meta b/Assets/Scripts/Data/CardSystem/CardVisualConfig.cs.meta new file mode 100644 index 00000000..05d43792 --- /dev/null +++ b/Assets/Scripts/Data/CardSystem/CardVisualConfig.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: a82f88f485b4410e9eb7c383b44557cf +timeCreated: 1759931508 \ No newline at end of file diff --git a/Assets/Scripts/Input/InputManager.cs b/Assets/Scripts/Input/InputManager.cs index 80d110ae..bb8929ad 100644 --- a/Assets/Scripts/Input/InputManager.cs +++ b/Assets/Scripts/Input/InputManager.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; // Added for List using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.InputSystem; @@ -27,6 +28,9 @@ namespace Input private static InputManager _instance; private static bool _isQuitting = false; + // Override consumer stack - using a list to support multiple overrides that can be removed in LIFO order + private readonly List _overrideConsumers = new List(); + public static InputManager Instance { get @@ -38,7 +42,6 @@ namespace Input { var go = new GameObject("InputManager"); _instance = go.AddComponent(); - // DontDestroyOnLoad(go); } } return _instance; @@ -58,7 +61,6 @@ namespace Input void Awake() { _instance = this; - // DontDestroyOnLoad(gameObject); // Initialize settings reference _interactionSettings = GameManager.GetSettingsObject(); @@ -157,23 +159,27 @@ namespace Input /// private void OnTapMovePerformed(InputAction.CallbackContext ctx) { - if (EventSystem.current.IsPointerOverGameObject()) - { - return; - } - Vector2 screenPos = positionAction.ReadValue(); Vector3 worldPos = Camera.main.ScreenToWorldPoint(screenPos); Vector2 worldPos2D = new Vector2(worldPos.x, worldPos.y); Debug.Log($"[InputManager] TapMove performed at {worldPos2D}"); - if (!TryDelegateToInteractable(worldPos2D)) + + // First try to delegate to an override consumer if available + if (TryDelegateToOverrideConsumer(screenPos, worldPos2D)) { - Debug.Log("[InputManager] No interactable found, forwarding tap to default consumer"); + Debug.Log("[InputManager] Tap delegated to override consumer"); + return; + } + + // Then try to delegate to any ITouchInputConsumer (UI or world interactable) + if (!TryDelegateToAnyInputConsumer(screenPos, worldPos2D)) + { + Debug.Log("[InputManager] No input consumer found, forwarding tap to default consumer"); defaultConsumer?.OnTap(worldPos2D); } else { - Debug.Log("[InputManager] Tap delegated to interactable"); + Debug.Log("[InputManager] Tap delegated to input consumer"); } } @@ -219,14 +225,84 @@ namespace Input } } + /// + /// Attempts to delegate a tap to any ITouchInputConsumer at the given position. + /// Checks both UI elements and world interactables. + /// + private bool TryDelegateToAnyInputConsumer(Vector2 screenPos, Vector2 worldPos) + { + // First check if we hit a UI element implementing ITouchInputConsumer + if (TryDelegateToUIInputConsumer(screenPos)) + { + return true; + } + + // If no UI element with ITouchInputConsumer, try world interactables + return TryDelegateToInteractable(worldPos); + } + + /// + /// Attempts to delegate a tap to a UI element implementing ITouchInputConsumer. + /// + private bool TryDelegateToUIInputConsumer(Vector2 screenPos) + { + // Check for UI elements under the pointer + var eventData = new PointerEventData(EventSystem.current) + { + position = screenPos + }; + + var results = new System.Collections.Generic.List(); + EventSystem.current.RaycastAll(eventData, results); + + foreach (var result in results) + { + // Try to get ITouchInputConsumer component + var consumer = result.gameObject.GetComponent(); + if (consumer == null) + { + consumer = result.gameObject.GetComponentInParent(); + } + if (consumer != null) + { + Debug.unityLogger.Log("Interactable", $"[InputManager] Delegating tap to UI consumer at {screenPos} (GameObject: {result.gameObject.name})"); + consumer.OnTap(screenPos); + return true; + } + } + + return false; + } + /// /// Attempts to delegate a tap to an interactable at the given world position. /// Traces on the "Interactable" channel and logs detailed info. /// private bool TryDelegateToInteractable(Vector2 worldPos) { - LayerMask mask = _interactionSettings != null ? _interactionSettings.InteractableLayerMask : -1; - Collider2D hit = Physics2D.OverlapPoint(worldPos, mask); + // First try with the interaction layer mask if available + if (_interactionSettings != null) + { + LayerMask mask = _interactionSettings.InteractableLayerMask; + Collider2D hitWithMask = Physics2D.OverlapPoint(worldPos, mask); + if (hitWithMask != null) + { + var consumer = hitWithMask.GetComponent(); + if (consumer == null) + { + consumer = hitWithMask.GetComponentInParent(); + } + if (consumer != null) + { + Debug.unityLogger.Log("Interactable", $"[InputManager] Delegating tap to consumer at {worldPos} (GameObject: {hitWithMask.gameObject.name})"); + consumer.OnTap(worldPos); + return true; + } + } + } + + // If no hit with the mask or no settings available, try with all colliders + Collider2D hit = Physics2D.OverlapPoint(worldPos); if (hit != null) { var consumer = hit.GetComponent(); @@ -244,5 +320,54 @@ namespace Input } return false; } + + /// + /// Registers an override consumer to receive input events. + /// The most recently registered consumer will receive input first. + /// + public void RegisterOverrideConsumer(ITouchInputConsumer consumer) + { + if (consumer == null || _overrideConsumers.Contains(consumer)) + return; + + _overrideConsumers.Add(consumer); + Debug.Log($"[InputManager] Override consumer registered: {consumer}"); + } + + /// + /// Unregisters an override consumer, removing it from the input event delegation. + /// + public void UnregisterOverrideConsumer(ITouchInputConsumer consumer) + { + if (consumer == null || !_overrideConsumers.Contains(consumer)) + return; + + _overrideConsumers.Remove(consumer); + Debug.Log($"[InputManager] Override consumer unregistered: {consumer}"); + } + + /// + /// Clears all registered override consumers. + /// + public void ClearOverrideConsumers() + { + _overrideConsumers.Clear(); + Debug.Log("[InputManager] All override consumers cleared."); + } + + /// + /// Attempts to delegate a tap to the topmost registered override consumer, if any. + /// + private bool TryDelegateToOverrideConsumer(Vector2 screenPos, Vector2 worldPos) + { + if (_overrideConsumers.Count == 0) + return false; + + // Get the topmost override consumer (last registered) + var consumer = _overrideConsumers[_overrideConsumers.Count - 1]; + Debug.unityLogger.Log("Interactable", $"[InputManager] Delegating tap to override consumer at {worldPos} (GameObject: {consumer})"); + consumer.OnTap(worldPos); + return true; + } } } diff --git a/Assets/Scripts/Minigames/DivingForPictures/Bubbles/Bubble.cs b/Assets/Scripts/Minigames/DivingForPictures/Bubbles/Bubble.cs index a50d8629..b01aad7c 100644 --- a/Assets/Scripts/Minigames/DivingForPictures/Bubbles/Bubble.cs +++ b/Assets/Scripts/Minigames/DivingForPictures/Bubbles/Bubble.cs @@ -20,7 +20,7 @@ namespace Minigames.DivingForPictures private float maxScale = 1.2f; private float baseScale = 1f; - private Camera mainCamera; + private UnityEngine.Camera mainCamera; private BubblePool parentPool; // Coroutine references @@ -48,7 +48,7 @@ namespace Minigames.DivingForPictures } // Cache camera reference - mainCamera = Camera.main; + mainCamera = UnityEngine.Camera.main; } private void OnEnable() @@ -78,7 +78,7 @@ namespace Minigames.DivingForPictures /// /// Resumes all bubble behaviors /// - public void Resume() + public void DoResume() { if (!_isPaused) return; // Already running @@ -94,7 +94,7 @@ namespace Minigames.DivingForPictures /// private void StartBubbleBehavior() { - if (_isPaused) return; // Don't start if paused + if (_isPaused || !isActiveAndEnabled) return; // Don't start if paused _movementCoroutine = StartCoroutine(MovementCoroutine()); _wobbleCoroutine = StartCoroutine(WobbleCoroutine()); diff --git a/Assets/Scripts/Minigames/DivingForPictures/Bubbles/BubbleSpawner.cs b/Assets/Scripts/Minigames/DivingForPictures/Bubbles/BubbleSpawner.cs index 101d353b..0d4b702f 100644 --- a/Assets/Scripts/Minigames/DivingForPictures/Bubbles/BubbleSpawner.cs +++ b/Assets/Scripts/Minigames/DivingForPictures/Bubbles/BubbleSpawner.cs @@ -1,6 +1,5 @@ using System.Collections; using UnityEngine; -using Pooling; using AppleHills.Core.Settings; using AppleHills.Core.Interfaces; @@ -20,7 +19,7 @@ namespace Minigames.DivingForPictures private float _timer; private float _nextSpawnInterval; private BubblePool _bubblePool; - private Camera _mainCamera; // Cache camera reference + private UnityEngine.Camera _mainCamera; // Cache camera reference private bool _isSurfacing = false; // Pause state @@ -34,7 +33,7 @@ namespace Minigames.DivingForPictures void Awake() { - _mainCamera = Camera.main; + _mainCamera = UnityEngine.Camera.main; // Get developer settings and game settings _devSettings = GameManager.GetDeveloperSettings(); @@ -67,12 +66,7 @@ namespace Minigames.DivingForPictures void Start() { - // Register with DivingGameManager for pause/resume events - DivingGameManager gameManager = FindFirstObjectByType(); - if (gameManager != null) - { - gameManager.RegisterPausableComponent(this); - } + DivingGameManager.Instance.RegisterPausableComponent(this); // Start spawning if not paused StartSpawningCoroutine(); @@ -80,12 +74,7 @@ namespace Minigames.DivingForPictures void OnDestroy() { - // Unregister from DivingGameManager - DivingGameManager gameManager = FindFirstObjectByType(); - if (gameManager != null) - { - gameManager.UnregisterPausableComponent(this); - } + DivingGameManager.Instance.UnregisterPausableComponent(this); // Clean up any active coroutines StopAllCoroutines(); @@ -123,7 +112,7 @@ namespace Minigames.DivingForPictures /// /// Resumes the bubble spawner and all bubbles /// - public void Resume() + public void DoResume() { if (!_isPaused) return; // Already running @@ -138,7 +127,7 @@ namespace Minigames.DivingForPictures { if (bubble != null) { - bubble.Resume(); + bubble.DoResume(); } } diff --git a/Assets/Scripts/Minigames/DivingForPictures/DivingGameManager.cs b/Assets/Scripts/Minigames/DivingForPictures/DivingGameManager.cs index 646ad61c..eed65640 100644 --- a/Assets/Scripts/Minigames/DivingForPictures/DivingGameManager.cs +++ b/Assets/Scripts/Minigames/DivingForPictures/DivingGameManager.cs @@ -2,12 +2,15 @@ using System.Collections.Generic; using System; using System.Collections; +using System.Linq; using UnityEngine.Events; using UnityEngine.Playables; using AppleHills.Core.Settings; using Utility; using AppleHills.Core.Interfaces; +using Input; using UI; +using Minigames.DivingForPictures.PictureCamera; namespace Minigames.DivingForPictures { @@ -24,9 +27,11 @@ namespace Minigames.DivingForPictures [Header("Surfacing Settings")] [Tooltip("Reference to the PlayableDirector that will play the surfacing timeline")] [SerializeField] private PlayableDirector surfacingTimeline; + + private CameraViewfinderManager viewfinderManager; // Settings reference - private IDivingMinigameSettings _settings; + private IDivingMinigameSettings settings; // Private state variables private int playerScore = 0; @@ -37,13 +42,13 @@ namespace Minigames.DivingForPictures // Velocity management // Velocity state tracking - private float _currentVelocityFactor = 1.0f; // 1.0 = normal descent speed, -1.0 * surfacingSpeedFactor = full surfacing speed - private Coroutine _velocityTransitionCoroutine; - private Coroutine _surfacingSequenceCoroutine; + private float currentVelocityFactor = 1.0f; // 1.0 = normal descent speed, -1.0 * surfacingSpeedFactor = full surfacing speed + private Coroutine velocityTransitionCoroutine; + private Coroutine surfacingSequenceCoroutine; // Public properties public int PlayerScore => playerScore; - public float CurrentVelocityFactor => _currentVelocityFactor; + public float CurrentVelocityFactor => currentVelocityFactor; // Events public event Action OnScoreChanged; @@ -76,18 +81,58 @@ namespace Minigames.DivingForPictures // IPausable implementation public bool IsPaused => _isPaused; + + // Photo sequence state + private bool _isPhotoSequenceActive = false; + private Monster _currentPhotoTarget = null; + private Dictionary _pauseStateBackup = new Dictionary(); + private float _capturedProximity = 0f; // New: tracks how close to target the photo was taken (0-1) + + // List of components to exempt from pausing during photo sequence + private List _exemptFromPhotoSequencePausing = new List(); + + // Photo sequence events + public event Action OnPhotoSequenceStarted; + public event Action OnPhotoSequenceCompleted; // Now includes proximity score + public event Action OnPhotoSequenceProgressUpdated; + + private static DivingGameManager _instance; + private static bool _isQuitting = false; + public static DivingGameManager Instance + { + get + { + if (_instance == null && Application.isPlaying && !_isQuitting) + { + _instance = FindAnyObjectByType(); + if (_instance == null) + { + var go = new GameObject("DivingGameManager"); + _instance = go.AddComponent(); + } + } + return _instance; + } + } private void Awake() { - // Get settings from GameManager - _settings = GameManager.GetSettingsObject(); - if (_settings == null) - { - Debug.LogError("[DivingGameManager] Failed to load diving minigame settings!"); - } + settings = GameManager.GetSettingsObject(); + currentSpawnProbability = settings?.BaseSpawnProbability ?? 0.2f; - // Initialize with base probability from settings - currentSpawnProbability = _settings?.BaseSpawnProbability ?? 0.2f; + if (_instance == null) + { + _instance = this; + } + else if (_instance != this) + { + Destroy(gameObject); + } + } + + private void OnApplicationQuit() + { + _isQuitting = true; } private void Start() @@ -97,7 +142,7 @@ namespace Minigames.DivingForPictures if (pauseMenu != null) { pauseMenu.OnGamePaused += Pause; - pauseMenu.OnGameResumed += Resume; + pauseMenu.OnGameResumed += DoResume; Debug.Log("[DivingGameManager] Subscribed to PauseMenu events"); } @@ -135,35 +180,26 @@ namespace Minigames.DivingForPictures // Validate rope references (this doesn't depend on initialization) ValidateRopeReferences(); - } - /// - /// Initializes the game components once the orientation is correct. - /// This is called by SceneOrientationEnforcer when the device is properly oriented. - /// - public void InitializeGame() - { - // Prevent double initialization - if (_isGameInitialized) return; + viewfinderManager = CameraViewfinderManager.Instance; - Debug.Log("[DivingGameManager] Initializing game"); - - // Subscribe to tile spawned event - TrenchTileSpawner tileSpawner = FindFirstObjectByType(); - if (tileSpawner != null) + // Subscribe to viewfinder events if found + if (viewfinderManager != null) { - tileSpawner.onTileSpawned.AddListener(OnTileSpawned); - } - else - { - Debug.LogWarning("No TrenchTileSpawner found in scene. Monster spawning won't work."); + viewfinderManager.OnAnimationCompleted += OnViewfinderAnimationCompleted; + viewfinderManager.OnViewfinderTapped += OnViewfinderTapped; + viewfinderManager.OnProximityUpdated += OnProximityUpdated; + viewfinderManager.OnViewfinderTappedDuringAnimation += OnViewfinderTappedDuringAnimation; + viewfinderManager.OnReverseAnimationStarted += OnReverseAnimationStarted; + + // Add the viewfinder manager to exempt list to ensure it keeps working during photo sequences + if (viewfinderManager is IPausable viewfinderPausable) + { + RegisterExemptFromPhotoSequencePausing(viewfinderPausable); + } } - // Mark as initialized - _isGameInitialized = true; - - // Notify all listeners that the game is initialized - OnGameInitialized?.Invoke(); + OnMonsterSpawned += DoMonsterSpawned; } private void OnDestroy() @@ -181,7 +217,7 @@ namespace Minigames.DivingForPictures if (pauseMenu != null) { pauseMenu.OnGamePaused -= Pause; - pauseMenu.OnGameResumed -= Resume; + pauseMenu.OnGameResumed -= DoResume; } // Unregister from GameManager @@ -192,6 +228,16 @@ namespace Minigames.DivingForPictures // Unregister all pausable components _pausableComponents.Clear(); + + // Unsubscribe from viewfinder events + if (viewfinderManager != null) + { + viewfinderManager.OnAnimationCompleted -= OnViewfinderAnimationCompleted; + viewfinderManager.OnViewfinderTapped -= OnViewfinderTapped; + viewfinderManager.OnProximityUpdated -= OnProximityUpdated; + viewfinderManager.OnViewfinderTappedDuringAnimation -= OnViewfinderTappedDuringAnimation; + viewfinderManager.OnReverseAnimationStarted -= OnReverseAnimationStarted; + } } private void Update() @@ -200,10 +246,10 @@ namespace Minigames.DivingForPictures // Gradually increase spawn probability over time float previousProbability = currentSpawnProbability; - if (currentSpawnProbability < _settings.MaxSpawnProbability) + if (currentSpawnProbability < settings.MaxSpawnProbability) { - currentSpawnProbability += _settings.ProbabilityIncreaseRate * Time.deltaTime; - currentSpawnProbability = Mathf.Min(currentSpawnProbability, _settings.MaxSpawnProbability); + currentSpawnProbability += settings.ProbabilityIncreaseRate * Time.deltaTime; + currentSpawnProbability = Mathf.Min(currentSpawnProbability, settings.MaxSpawnProbability); // Only fire event if probability changed significantly if (Mathf.Abs(currentSpawnProbability - previousProbability) > 0.01f) @@ -223,8 +269,8 @@ namespace Minigames.DivingForPictures // If we're surfacing, don't spawn new monsters if (_isSurfacing) return; - bool forceSpawn = timeSinceLastSpawn >= _settings.GuaranteedSpawnTime; - bool onCooldown = timeSinceLastSpawn < _settings.SpawnCooldown; + bool forceSpawn = timeSinceLastSpawn >= settings.GuaranteedSpawnTime; + bool onCooldown = timeSinceLastSpawn < settings.SpawnCooldown; // Don't spawn if on cooldown, unless forced if (onCooldown && !forceSpawn) return; @@ -241,7 +287,7 @@ namespace Minigames.DivingForPictures // Reset timer and adjust probability lastSpawnTime = Time.time; timeSinceLastSpawn = 0f; - currentSpawnProbability = _settings.BaseSpawnProbability; + currentSpawnProbability = settings.BaseSpawnProbability; OnSpawnProbabilityChanged?.Invoke(currentSpawnProbability); } } @@ -265,14 +311,7 @@ namespace Minigames.DivingForPictures { // Parent the monster to the spawn point so it moves with the tile monsterObj.transform.SetParent(spawnPoint); - - // Subscribe to monster events - monster.OnPictureTaken += OnMonsterPictureTaken; - monster.OnMonsterDespawned += OnMonsterDespawned; - - // Add to active monsters list - activeMonsters.Add(monster); - + // Fire event OnMonsterSpawned?.Invoke(monster); } @@ -283,11 +322,11 @@ namespace Minigames.DivingForPictures } } - private void OnMonsterPictureTaken(Monster monster) + private void DoPictureTaken(Monster monster) { // Calculate points based on depth - int depthBonus = Mathf.FloorToInt(Mathf.Abs(monster.transform.position.y) * _settings.DepthMultiplier); - int pointsAwarded = _settings.BasePoints + depthBonus; + int depthBonus = Mathf.FloorToInt(Mathf.Abs(monster.transform.position.y) * settings.DepthMultiplier); + int pointsAwarded = settings.BasePoints + depthBonus; // Add score playerScore += pointsAwarded; @@ -296,17 +335,7 @@ namespace Minigames.DivingForPictures OnScoreChanged?.Invoke(playerScore); OnPictureTaken?.Invoke(monster, pointsAwarded); } - - private void OnMonsterDespawned(Monster monster) - { - // Remove from active list - activeMonsters.Remove(monster); - - // Unsubscribe from events - monster.OnPictureTaken -= OnMonsterPictureTaken; - monster.OnMonsterDespawned -= OnMonsterDespawned; - } - + /// /// Called when the player takes damage from any collision /// @@ -438,7 +467,7 @@ namespace Minigames.DivingForPictures _isSurfacing = true; // 1. Initiate smooth velocity transition to surfacing speed - float targetVelocityFactor = -1.0f * _settings.SurfacingSpeedFactor; + float targetVelocityFactor = -1.0f * settings.SurfacingSpeedFactor; SetVelocityFactor(targetVelocityFactor); // 2. Find and notify trench tile spawner about direction change (for spawning/despawning logic) @@ -457,7 +486,7 @@ namespace Minigames.DivingForPictures tileSpawner.StartSurfacing(); // Immediately send current velocity factor - tileSpawner.OnVelocityFactorChanged(_currentVelocityFactor); + tileSpawner.OnVelocityFactorChanged(currentVelocityFactor); } // Handle the Rock object - disable components and animate it falling offscreen @@ -525,15 +554,15 @@ namespace Minigames.DivingForPictures obstacleSpawner.StartSurfacing(); // Immediately send current velocity factor - obstacleSpawner.OnVelocityFactorChanged(_currentVelocityFactor); + obstacleSpawner.OnVelocityFactorChanged(currentVelocityFactor); } // Start the surfacing sequence coroutine - if (_surfacingSequenceCoroutine != null) + if (surfacingSequenceCoroutine != null) { - StopCoroutine(_surfacingSequenceCoroutine); + StopCoroutine(surfacingSequenceCoroutine); } - _surfacingSequenceCoroutine = StartCoroutine(SurfacingSequence()); + surfacingSequenceCoroutine = StartCoroutine(SurfacingSequence()); Debug.Log($"[DivingGameManager] Started surfacing with target velocity factor: {targetVelocityFactor}"); } @@ -546,7 +575,7 @@ namespace Minigames.DivingForPictures Vector3 startPosition = rockTransform.position; // Calculate position below the screen - Camera mainCamera = Camera.main; + UnityEngine.Camera mainCamera = UnityEngine.Camera.main; if (mainCamera == null) { Debug.LogWarning("[DivingGameManager] Cannot find main camera to calculate offscreen position"); @@ -609,7 +638,7 @@ namespace Minigames.DivingForPictures private IEnumerator SurfacingSequence() { // Wait for the configured delay - yield return new WaitForSeconds(_settings.SurfacingSpawnDelay); + yield return new WaitForSeconds(settings.SurfacingSpawnDelay); // Find tile spawner and tell it to stop spawning TrenchTileSpawner tileSpawner = FindFirstObjectByType(); @@ -662,12 +691,12 @@ namespace Minigames.DivingForPictures /// Target velocity factor (e.g., -1.0 for surfacing speed) public void SetVelocityFactor(float targetFactor) { - if (_velocityTransitionCoroutine != null) + if (velocityTransitionCoroutine != null) { - StopCoroutine(_velocityTransitionCoroutine); + StopCoroutine(velocityTransitionCoroutine); } - _velocityTransitionCoroutine = StartCoroutine(TransitionVelocityFactor(targetFactor)); + velocityTransitionCoroutine = StartCoroutine(TransitionVelocityFactor(targetFactor)); } /// @@ -675,29 +704,29 @@ namespace Minigames.DivingForPictures /// private IEnumerator TransitionVelocityFactor(float targetFactor) { - float startFactor = _currentVelocityFactor; + float startFactor = currentVelocityFactor; float elapsed = 0f; - while (elapsed < _settings.SpeedTransitionDuration) + while (elapsed < settings.SpeedTransitionDuration) { elapsed += Time.deltaTime; - float t = Mathf.Clamp01(elapsed / _settings.SpeedTransitionDuration); + float t = Mathf.Clamp01(elapsed / settings.SpeedTransitionDuration); // Smooth step interpolation float smoothStep = t * t * (3f - 2f * t); - _currentVelocityFactor = Mathf.Lerp(startFactor, targetFactor, smoothStep); + currentVelocityFactor = Mathf.Lerp(startFactor, targetFactor, smoothStep); // Notify listeners about the velocity factor change - OnVelocityFactorChanged?.Invoke(_currentVelocityFactor); + OnVelocityFactorChanged?.Invoke(currentVelocityFactor); yield return null; } - _currentVelocityFactor = targetFactor; + currentVelocityFactor = targetFactor; // Final assignment to ensure exact target value - OnVelocityFactorChanged?.Invoke(_currentVelocityFactor); + OnVelocityFactorChanged?.Invoke(currentVelocityFactor); } /// @@ -737,6 +766,11 @@ namespace Minigames.DivingForPictures /// Pause the game and all registered components /// public void Pause() + { + DoPause(); + } + + public void DoPause(bool turnOffGameInput = true) { if (_isPaused) return; // Already paused @@ -748,13 +782,17 @@ namespace Minigames.DivingForPictures component.Pause(); } + // Change input mode to UI when menu is open + if(turnOffGameInput) + InputManager.Instance.SetInputMode(InputMode.UI); + Debug.Log($"[DivingGameManager] Game paused. Paused {_pausableComponents.Count} components."); } /// /// Resume the game and all registered components /// - public void Resume() + public void DoResume() { if (!_isPaused) return; // Already running @@ -763,10 +801,281 @@ namespace Minigames.DivingForPictures // Resume all registered components foreach (var component in _pausableComponents) { - component.Resume(); + component.DoResume(); } + // Change input mode to UI when menu is open + InputManager.Instance.SetInputMode(InputMode.GameAndUI); + Debug.Log($"[DivingGameManager] Game resumed. Resumed {_pausableComponents.Count} components."); } + + #region Photo Sequence Methods + + /// + /// Called when the viewfinder animation phase changes to reverse (zoom out) + /// + private void OnReverseAnimationStarted() + { + Debug.Log("[DivingGameManager] Viewfinder animation entering reverse (zoom-out) phase"); + } + + /// + /// Called when proximity value is updated during animation + /// + private void OnProximityUpdated(float proximity) + { + // Store the current proximity value for potential use in scoring + _capturedProximity = proximity; + } + + /// + /// Called when the player taps during the viewfinder animation + /// + private void OnViewfinderTappedDuringAnimation(float proximity) + { + if (!_isPhotoSequenceActive || _currentPhotoTarget == null) + return; + + // Store the proximity value at the time of tap for scoring + _capturedProximity = proximity; + + Debug.Log($"[DivingGameManager] Player tapped during animation! Proximity: {proximity:F2}"); + + // Take the picture at the current proximity + TakePicture(); + } + + /// + /// Takes the picture with the current proximity value for scoring + /// + private void TakePicture() + { + if (!_isPhotoSequenceActive || _currentPhotoTarget == null) + return; + + // Notify the monster that its picture was taken + _currentPhotoTarget.NotifyPictureTaken(); + + // Calculate score based on proximity and depth + CalculateScore(_currentPhotoTarget, _capturedProximity); + + // Complete the sequence + CompletePhotoSequence(); + } + + /// + /// Calculates the score for a picture based on proximity to target and monster depth + /// + private void CalculateScore(Monster monster, float proximity) + { + if (monster == null) return; + + // Calculate base points from depth + int depthBonus = Mathf.FloorToInt(Mathf.Abs(monster.transform.position.y) * settings.DepthMultiplier); + + // Apply proximity multiplier (0-100%) + float proximityMultiplier = Mathf.Clamp01(proximity); // Ensure it's in 0-1 range + int proximityBonus = Mathf.RoundToInt(settings.BasePoints * proximityMultiplier); + + // Calculate total score + int pointsAwarded = settings.BasePoints + proximityBonus + depthBonus; + + Debug.Log($"[DivingGameManager] Picture score calculation: base={proximityBonus} (proximity={proximity:F2}), " + + $"depth bonus={depthBonus}, total={pointsAwarded}"); + + // Add score + playerScore += pointsAwarded; + + // Fire events + OnScoreChanged?.Invoke(playerScore); + OnPictureTaken?.Invoke(monster, pointsAwarded); + } + + /// + /// Handles completion of the viewfinder animation + /// + private void OnViewfinderAnimationCompleted() + { + if (!_isPhotoSequenceActive || _currentPhotoTarget == null) + return; + + // Take the picture at whatever the final proximity was + TakePicture(); + } + + /// + /// Cleans up and completes the picture-taking sequence + /// + private void CompletePhotoSequence() + { + if (!_isPhotoSequenceActive) + return; + + // Notify listeners that photo sequence has completed (with proximity score) + if (_currentPhotoTarget != null) + { + OnPhotoSequenceCompleted?.Invoke(_currentPhotoTarget, _capturedProximity); + + // We no longer despawn the monster after taking a picture + // _currentPhotoTarget.Despawn(false); + + // Just mark the photo sequence as no longer in progress + _currentPhotoTarget.NotifyPictureTaken(); + } + + DoResume(); + + // Reset state + _isPhotoSequenceActive = false; + _currentPhotoTarget = null; + + Debug.Log($"[DivingGameManager] Completed photo sequence with proximity score: {_capturedProximity:F2}"); + } + + /// + /// Register a component to be exempt from pausing during photo sequence + /// + public void RegisterExemptFromPhotoSequencePausing(IPausable component) + { + if (!_exemptFromPhotoSequencePausing.Contains(component)) + { + _exemptFromPhotoSequencePausing.Add(component); + } + } + + #endregion + + #region Game Initialization + + /// + /// Initializes the game components once the orientation is correct. + /// This is called by SceneOrientationEnforcer when the device is properly oriented. + /// + public void InitializeGame() + { + // Prevent double initialization + if (_isGameInitialized) return; + + Debug.Log("[DivingGameManager] Initializing game"); + + // Subscribe to tile spawned event + TrenchTileSpawner tileSpawner = FindFirstObjectByType(); + if (tileSpawner != null) + { + tileSpawner.onTileSpawned.AddListener(OnTileSpawned); + } + else + { + Debug.LogWarning("No TrenchTileSpawner found in scene. Monster spawning won't work."); + } + + // Mark as initialized + _isGameInitialized = true; + + // Notify all listeners that the game is initialized + OnGameInitialized?.Invoke(); + } + + #endregion + + private void DoMonsterSpawned(Monster monster) + { + if (monster != null) + { + // Subscribe to monster enter/exit events + monster.OnPlayerEnterDetectionRange += OnPlayerEnterMonsterRange; + monster.OnPlayerExitDetectionRange += OnPlayerExitMonsterRange; + monster.OnMonsterDespawned += DoMonsterDespawned; + + // Add to active monsters list + activeMonsters.Add(monster); + } + } + + private void DoMonsterDespawned(Monster monster) + { + // Remove from active list + activeMonsters.Remove(monster); + + // Unsubscribe from monster events + if (monster != null) + { + monster.OnPlayerEnterDetectionRange -= OnPlayerEnterMonsterRange; + monster.OnPlayerExitDetectionRange -= OnPlayerExitMonsterRange; + monster.OnMonsterDespawned -= DoMonsterDespawned; + } + } + + // Handles player entering monster detection range + private void OnPlayerEnterMonsterRange(Monster monster) + { + if (monster != null && !_isPhotoSequenceActive) + { + // Store current target for later use + _currentPhotoTarget = monster; + + // Show the full-screen viewfinder (first step in two-step process) + if (viewfinderManager != null) + { + viewfinderManager.ShowFullScreenViewfinder(); + Debug.Log($"[DivingGameManager] Player entered range of monster {monster.name}, showing full-screen viewfinder"); + } + } + } + + // Handles player exiting monster detection range + private void OnPlayerExitMonsterRange(Monster monster) + { + // Only hide viewfinder if we're not already in a photo sequence + if (!_isPhotoSequenceActive && monster == _currentPhotoTarget) + { + // Hide the viewfinder + if (viewfinderManager != null) + { + viewfinderManager.HideViewfinder(); + Debug.Log($"[DivingGameManager] Player exited range of monster {monster.name}, hiding viewfinder"); + } + + // Clear current target + _currentPhotoTarget = null; + } + } + + // Called when the player taps on the viewfinder + private void OnViewfinderTapped() + { + // Only proceed if we have a valid target and not already in a sequence + if (_currentPhotoTarget != null && !_isPhotoSequenceActive && _currentPhotoTarget.IsPlayerInDetectionRange) + { + // Pause the game immediately + DoPause(false); + Debug.Log($"[DivingGameManager] Pausing game before starting viewfinder animation"); + + // Mark the photo sequence as active + _isPhotoSequenceActive = true; + + // Mark monster as in photo sequence + _currentPhotoTarget.SetPhotoSequenceInProgress(); + + // Reset captured proximity + _capturedProximity = 0f; + + // Notify listeners that photo sequence has started + OnPhotoSequenceStarted?.Invoke(_currentPhotoTarget); + + // Start the complete animation sequence to target monster + if (viewfinderManager != null) + { + viewfinderManager.StartViewfinderSequence(_currentPhotoTarget.transform); + Debug.Log($"[DivingGameManager] Viewfinder tapped for monster {_currentPhotoTarget.name}, starting animation sequence"); + } + else + { + Debug.LogError("[DivingGameManager] No ViewfinderManager available!"); + CompletePhotoSequence(); + } + } + } } } diff --git a/Assets/Scripts/Minigames/DivingForPictures/DivingScoreUI.cs b/Assets/Scripts/Minigames/DivingForPictures/DivingScoreUI.cs index 81f39524..ddc6128f 100644 --- a/Assets/Scripts/Minigames/DivingForPictures/DivingScoreUI.cs +++ b/Assets/Scripts/Minigames/DivingForPictures/DivingScoreUI.cs @@ -9,25 +9,15 @@ namespace Minigames.DivingForPictures [SerializeField] private GameObject scorePopupPrefab; [SerializeField] private Transform popupParent; - private DivingGameManager gameManager; - private void Start() { - gameManager = FindFirstObjectByType(); + // Subscribe to events + DivingGameManager.Instance.OnScoreChanged += UpdateScoreDisplay; + DivingGameManager.Instance.OnPictureTaken += ShowScorePopup; - if (gameManager != null) - { - // Subscribe to events - gameManager.OnScoreChanged += UpdateScoreDisplay; - gameManager.OnPictureTaken += ShowScorePopup; - - // Initialize display - UpdateScoreDisplay(gameManager.PlayerScore); - } - else - { - Debug.LogWarning("No DivingGameManager found in scene."); - } + // Initialize display + UpdateScoreDisplay(DivingGameManager.Instance.PlayerScore); + // Create popup parent if needed if (popupParent == null) @@ -38,12 +28,9 @@ namespace Minigames.DivingForPictures private void OnDestroy() { - if (gameManager != null) - { - // Unsubscribe from events - gameManager.OnScoreChanged -= UpdateScoreDisplay; - gameManager.OnPictureTaken -= ShowScorePopup; - } + // Unsubscribe from events + DivingGameManager.Instance.OnScoreChanged -= UpdateScoreDisplay; + DivingGameManager.Instance.OnPictureTaken -= ShowScorePopup; } private void UpdateScoreDisplay(int score) diff --git a/Assets/Scripts/Minigames/DivingForPictures/Monster/Monster.cs b/Assets/Scripts/Minigames/DivingForPictures/Monster/Monster.cs index 5320fc6c..5e30a5ad 100644 --- a/Assets/Scripts/Minigames/DivingForPictures/Monster/Monster.cs +++ b/Assets/Scripts/Minigames/DivingForPictures/Monster/Monster.cs @@ -10,22 +10,29 @@ namespace Minigames.DivingForPictures [SerializeField] private CircleCollider2D detectionCollider; private bool pictureAlreadyTaken = false; - private Camera mainCamera; + private bool photoSequenceInProgress = false; + private UnityEngine.Camera mainCamera; + // Track if player is in detection range + private bool playerInDetectionRange = false; + // Events - public event Action OnPictureTaken; - public event Action OnMonsterSpawned; public event Action OnMonsterDespawned; + public event Action OnPlayerEnterDetectionRange; + public event Action OnPlayerExitDetectionRange; // Properties public float PictureRadius => detectionCollider != null ? detectionCollider.radius : 0f; + public bool IsPhotoSequenceInProgress => photoSequenceInProgress; + public bool IsPlayerInDetectionRange => playerInDetectionRange; + public bool IsPictureTaken => pictureAlreadyTaken; private void Awake() { if (detectionCollider == null) detectionCollider = GetComponent(); - mainCamera = Camera.main; + mainCamera = UnityEngine.Camera.main; // Start checking if monster is off-screen StartCoroutine(CheckIfOffScreen()); @@ -34,7 +41,7 @@ namespace Minigames.DivingForPictures private void OnEnable() { pictureAlreadyTaken = false; - OnMonsterSpawned?.Invoke(this); + photoSequenceInProgress = false; } private IEnumerator CheckIfOffScreen() @@ -56,7 +63,7 @@ namespace Minigames.DivingForPictures private bool IsVisibleToCamera() { if (mainCamera == null) - mainCamera = Camera.main; + mainCamera = UnityEngine.Camera.main; if (mainCamera == null) return false; @@ -81,18 +88,67 @@ namespace Minigames.DivingForPictures // Check if it's the player if (other.CompareTag("Player") && !pictureAlreadyTaken) { - TakePicture(); + playerInDetectionRange = true; + // Fire the event so the game manager can display the viewfinder without pausing + OnPlayerEnterDetectionRange?.Invoke(this); } } - // Called when a picture is taken of this monster - public void TakePicture() + private void OnTriggerExit2D(Collider2D other) + { + // Check if it's the player + if (other.CompareTag("Player")) + { + playerInDetectionRange = false; + // Fire the event so the game manager can hide the viewfinder + OnPlayerExitDetectionRange?.Invoke(this); + } + } + + /// + /// Mark this monster as having its photo sequence in progress + /// + public void SetPhotoSequenceInProgress(bool inProgress = true) + { + if (pictureAlreadyTaken) return; + photoSequenceInProgress = inProgress; + } + + /// + /// Notify that a picture has been taken of this monster + /// This is now called by DivingGameManager instead of handling the logic internally + /// + public void NotifyPictureTaken() { if (pictureAlreadyTaken) return; pictureAlreadyTaken = true; - OnPictureTaken?.Invoke(this); + photoSequenceInProgress = false; + } + /// + /// Despawn this monster (can be called externally) + /// + /// Whether to despawn immediately or after a delay + public void Despawn(bool immediate = false) + { + if (immediate) + { + DespawnMonster(); + } + else + { + // Add small delay before despawning + StartCoroutine(DelayedDespawn()); + } + } + + /// + /// Coroutine to despawn after a short delay + /// + private IEnumerator DelayedDespawn() + { + yield return new WaitForSeconds(1.0f); // 1-second delay before despawn DespawnMonster(); } @@ -106,20 +162,7 @@ namespace Minigames.DivingForPictures Destroy(gameObject); } } - - // Visualization for the picture radius in editor - private void OnDrawGizmosSelected() - { - // Get the collider in edit mode - if (detectionCollider == null) - detectionCollider = GetComponent(); - - if (detectionCollider != null) - { - Gizmos.color = Color.yellow; - Gizmos.DrawWireSphere(transform.position, detectionCollider.radius / 2); - } - } + #if UNITY_EDITOR // Update collider radius in editor diff --git a/Assets/Scripts/Minigames/DivingForPictures/Obstacles/FloatingObstacle.cs b/Assets/Scripts/Minigames/DivingForPictures/Obstacles/FloatingObstacle.cs index 4ad62ade..a6fd12e9 100644 --- a/Assets/Scripts/Minigames/DivingForPictures/Obstacles/FloatingObstacle.cs +++ b/Assets/Scripts/Minigames/DivingForPictures/Obstacles/FloatingObstacle.cs @@ -45,7 +45,7 @@ namespace Minigames.DivingForPictures // Private fields private Collider2D _collider; - private Camera _mainCamera; + private UnityEngine.Camera _mainCamera; private float _screenTop; private float _screenBottom; // Added to track bottom of screen private Coroutine _movementCoroutine; @@ -78,7 +78,7 @@ namespace Minigames.DivingForPictures Debug.LogError($"[FloatingObstacle] No Collider2D found on {gameObject.name}!"); } - _mainCamera = Camera.main; + _mainCamera = UnityEngine.Camera.main; // Get settings _settings = GameManager.GetSettingsObject(); @@ -153,7 +153,7 @@ namespace Minigames.DivingForPictures /// /// Resume this obstacle's movement and behavior /// - public void Resume() + public void DoResume() { if (!_isPaused) return; // Already running @@ -168,6 +168,9 @@ namespace Minigames.DivingForPictures /// private void StartObstacleCoroutines() { + if (!isActiveAndEnabled) + return; + if (enableMovement && _movementCoroutine == null) { _movementCoroutine = StartCoroutine(MovementCoroutine()); @@ -281,7 +284,7 @@ namespace Minigames.DivingForPictures { if (_mainCamera == null) { - _mainCamera = Camera.main; + _mainCamera = UnityEngine.Camera.main; if (_mainCamera == null) return; } @@ -357,7 +360,7 @@ namespace Minigames.DivingForPictures { // Reset all state first _screenTop = 0f; // Reset cached screen bounds - _mainCamera = Camera.main; // Refresh camera reference + _mainCamera = UnityEngine.Camera.main; // Refresh camera reference // Re-enable the collider for reuse if (_collider != null) diff --git a/Assets/Scripts/Minigames/DivingForPictures/Obstacles/ObstacleSpawner.cs b/Assets/Scripts/Minigames/DivingForPictures/Obstacles/ObstacleSpawner.cs index e03bd5ec..65dc729a 100644 --- a/Assets/Scripts/Minigames/DivingForPictures/Obstacles/ObstacleSpawner.cs +++ b/Assets/Scripts/Minigames/DivingForPictures/Obstacles/ObstacleSpawner.cs @@ -31,7 +31,7 @@ namespace Minigames.DivingForPictures // Private fields private ObstaclePool _obstaclePool; - private Camera _mainCamera; + private UnityEngine.Camera _mainCamera; private float _screenBottom; private float _spawnRangeX; private Coroutine _spawnCoroutine; @@ -50,7 +50,7 @@ namespace Minigames.DivingForPictures private void Awake() { - _mainCamera = Camera.main; + _mainCamera = UnityEngine.Camera.main; // Get settings from GameManager _settings = GameManager.GetSettingsObject(); @@ -84,38 +84,23 @@ namespace Minigames.DivingForPictures private void Start() { - // Find DivingGameManager and subscribe to its initialization event - DivingGameManager gameManager = FindFirstObjectByType(); - if (gameManager != null) + DivingGameManager.Instance.OnGameInitialized += Initialize; + + // Register with the DivingGameManager for pause/resume events + DivingGameManager.Instance.RegisterPausableComponent(this); + + // If game is already initialized, initialize immediately + if (DivingGameManager.Instance.GetType().GetField("_isGameInitialized", + System.Reflection.BindingFlags.NonPublic | + System.Reflection.BindingFlags.Instance)?.GetValue(DivingGameManager.Instance) is bool isInitialized && isInitialized) { - gameManager.OnGameInitialized += Initialize; - - // Register with the DivingGameManager for pause/resume events - gameManager.RegisterPausableComponent(this); - - // If game is already initialized, initialize immediately - if (gameManager.GetType().GetField("_isGameInitialized", - System.Reflection.BindingFlags.NonPublic | - System.Reflection.BindingFlags.Instance)?.GetValue(gameManager) is bool isInitialized && isInitialized) - { - Initialize(); - } - } - else - { - Debug.LogWarning("[ObstacleSpawner] DivingGameManager not found. Initializing immediately."); Initialize(); } } private void OnDestroy() { - // Unregister from DivingGameManager - DivingGameManager gameManager = FindFirstObjectByType(); - if (gameManager != null) - { - gameManager.UnregisterPausableComponent(this); - } + DivingGameManager.Instance.UnregisterPausableComponent(this); // Clean up any active coroutines StopAllCoroutines(); @@ -172,7 +157,7 @@ namespace Minigames.DivingForPictures /// /// Resumes the spawner and all associated processes /// - public void Resume() + public void DoResume() { if (!_isPaused) return; // Already running @@ -192,7 +177,7 @@ namespace Minigames.DivingForPictures FloatingObstacle obstacleComponent = obstacle.GetComponent(); if (obstacleComponent != null) { - obstacleComponent.Resume(); + obstacleComponent.DoResume(); } } } @@ -314,7 +299,7 @@ namespace Minigames.DivingForPictures { if (_mainCamera == null) { - _mainCamera = Camera.main; + _mainCamera = UnityEngine.Camera.main; if (_mainCamera == null) { Debug.LogError("[ObstacleSpawner] No main camera found!"); @@ -751,7 +736,7 @@ namespace Minigames.DivingForPictures if (_mainCamera == null) { - _mainCamera = Camera.main; + _mainCamera = UnityEngine.Camera.main; if (_mainCamera == null) { yield return new WaitForSeconds(checkInterval); diff --git a/Assets/Scripts/Minigames/DivingForPictures/PictureCamera.meta b/Assets/Scripts/Minigames/DivingForPictures/PictureCamera.meta new file mode 100644 index 00000000..0fb855cd --- /dev/null +++ b/Assets/Scripts/Minigames/DivingForPictures/PictureCamera.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: ddda7563ddf04d63ae19527266695bd2 +timeCreated: 1760016807 \ No newline at end of file diff --git a/Assets/Scripts/Minigames/DivingForPictures/PictureCamera/CameraViewfinderManager.cs b/Assets/Scripts/Minigames/DivingForPictures/PictureCamera/CameraViewfinderManager.cs new file mode 100644 index 00000000..85973ef7 --- /dev/null +++ b/Assets/Scripts/Minigames/DivingForPictures/PictureCamera/CameraViewfinderManager.cs @@ -0,0 +1,776 @@ +using UnityEngine; +using System; +using System.Collections; +using AppleHills.Core.Settings; + +namespace Minigames.DivingForPictures.PictureCamera +{ + /// + /// Manages the camera viewfinder visual representation and animation + /// Responsible only for visual aspects with no game logic + /// + public class CameraViewfinderManager : MonoBehaviour + { + // Singleton instance + private static CameraViewfinderManager _instance; + private static bool _isQuitting = false; + + public static CameraViewfinderManager Instance + { + get + { + if (_instance == null && Application.isPlaying && !_isQuitting) + { + _instance = FindAnyObjectByType(); + if (_instance == null) + { + var go = new GameObject("CameraViewfinderManager"); + _instance = go.AddComponent(); + } + } + + return _instance; + } + } + + [Header("References")] [Tooltip("The Canvas to spawn the viewfinder UI on")] [SerializeField] + private Canvas targetCanvas; + + // References + private GameObject viewfinderInstance; + private RectTransform viewfinderRectTransform; + private Viewfinder viewfinderComponent; + private UnityEngine.Camera mainCamera; + + // Animation state + private float animationProgress = 0f; + private bool isAnimating = false; + private bool isReversePhase = false; // Whether we're in the zoom-out phase + private float currentProximity = 0f; // How close we are to the target (0=far, 1=directly over target) + private Transform targetTransform; + private Coroutine animationCoroutine; + + // Target position and size (calculated once at start) + private Vector3 targetScreenPosition; + private float targetViewfinderSize; + private Vector2 targetAnchoredPosition; // target position in canvas units + + // Store settings + private IDivingMinigameSettings settings; + + // Events for progress milestones + public event Action OnProgressUpdated; // Continuous progress updates (0-1) + public event Action OnAnimationStarted; + public event Action OnAnimationCompleted; + public event Action OnReverseAnimationStarted; // New event for when zoom-out phase starts + public event Action OnProximityUpdated; // New event for proximity updates + public event Action OnProgressThresholdReached; // Fires at configured thresholds (25%, 50%, etc.) + public event Action OnViewfinderTapped; // Event when viewfinder is tapped during normal display + public event Action OnViewfinderTappedDuringAnimation; // Event when viewfinder is tapped during animation (with proximity) + + private void Awake() + { + if (_instance == null) + { + _instance = this; + } + else if (_instance != this) + { + Destroy(gameObject); + } + } + + private void OnApplicationQuit() + { + _isQuitting = true; + } + + private void Start() + { + settings = GameManager.GetSettingsObject(); + mainCamera = UnityEngine.Camera.main; + } + + /// + /// Begin the viewfinder animation targeting a specific transform + /// + /// The transform to focus on (usually the monster) + public void StartViewfinderAnimation(Transform target) + { + if (isAnimating) + { + StopViewfinderAnimation(); + } + + if (settings.ViewfinderPrefab == null) + { + Debug.LogError("[CameraViewfinderManager] No viewfinder prefab assigned!"); + return; + } + + if (targetCanvas == null) + { + Debug.LogError("[CameraViewfinderManager] No canvas assigned!"); + return; + } + + targetTransform = target; + + // Calculate target screen position and size only once at the start + CalculateTargetScreenPositionAndSize(); + + // Create viewfinder as UI element + viewfinderInstance = Instantiate(settings.ViewfinderPrefab, targetCanvas.transform); + viewfinderRectTransform = viewfinderInstance.GetComponent(); + viewfinderComponent = viewfinderInstance.GetComponent(); + if (viewfinderRectTransform == null) + { + Debug.LogError("[CameraViewfinderManager] Viewfinder prefab doesn't have a RectTransform component!"); + Destroy(viewfinderInstance); + return; + } + + // Initialize viewfinder with a reference to this manager + if (viewfinderComponent != null) + { + viewfinderComponent.Initialize(this); + viewfinderComponent.SetupInputOverride(); + viewfinderComponent.OnViewfinderTapped += HandleViewfinderTapped; + } + + // Reset state + animationProgress = 0f; + isAnimating = true; + + // Determine canvas width for CanvasScaler-consistent sizing + RectTransform canvasRect = targetCanvas.transform as RectTransform; + float canvasWidth = canvasRect != null ? canvasRect.rect.width : Screen.width; + + // Initialize viewfinder size and position to full canvas width (square) at center + float startSize = canvasWidth; + viewfinderRectTransform.sizeDelta = new Vector2(startSize, startSize); + viewfinderRectTransform.anchorMin = new Vector2(0.5f, 0.5f); + viewfinderRectTransform.anchorMax = new Vector2(0.5f, 0.5f); + viewfinderRectTransform.pivot = new Vector2(0.5f, 0.5f); + viewfinderRectTransform.anchoredPosition = Vector2.zero; + + // Compute target anchored position in canvas units from previously calculated screen position + targetAnchoredPosition = ScreenToAnchoredPosition(targetScreenPosition); + + // Fire starting event + OnAnimationStarted?.Invoke(); + + // Start animation coroutine + animationCoroutine = StartCoroutine(AnimateViewfinder()); + } + + /// + /// Calculates the target screen position and size based on monster's sprite bounds + /// + private void CalculateTargetScreenPositionAndSize() + { + if (targetTransform == null || mainCamera == null) return; + + RectTransform canvasRect = targetCanvas != null ? targetCanvas.transform as RectTransform : null; + if (canvasRect == null) + { + Debug.LogError("[CameraViewfinderManager] Target canvas RectTransform not found."); + return; + } + + // Choose UI camera for coordinate conversion + Camera uiCamera = null; + if (targetCanvas.renderMode == RenderMode.ScreenSpaceCamera || + targetCanvas.renderMode == RenderMode.WorldSpace) + { + uiCamera = targetCanvas.worldCamera; + } + + // Get sprite renderer from the monster + SpriteRenderer spriteRenderer = targetTransform.GetComponent(); + if (spriteRenderer == null || spriteRenderer.sprite == null) + { + // Fallback to transform position and default size if no sprite renderer + targetScreenPosition = mainCamera.WorldToScreenPoint(targetTransform.position); + // Convert to anchored UI position + RectTransformUtility.ScreenPointToLocalPointInRectangle(canvasRect, targetScreenPosition, uiCamera, + out targetAnchoredPosition); + + // Default size: fraction of canvas width (canvas units) + float canvasWidth = canvasRect.rect.width; + targetViewfinderSize = canvasWidth * 0.25f; + + Debug.LogWarning("[CameraViewfinderManager] No SpriteRenderer found on target, using default size"); + return; + } + + // Calculate world bounds of the sprite and apply padding + Bounds spriteBounds = spriteRenderer.bounds; + Vector3 paddedSize = spriteBounds.size * settings.PaddingFactor; + Bounds paddedBounds = new Bounds(spriteBounds.center, paddedSize); + + // Convert bounds corners to screen space + Vector3[] worldCorners = new Vector3[4]; + worldCorners[0] = new Vector3(paddedBounds.min.x, paddedBounds.min.y, paddedBounds.center.z); // BL + worldCorners[1] = new Vector3(paddedBounds.max.x, paddedBounds.min.y, paddedBounds.center.z); // BR + worldCorners[2] = new Vector3(paddedBounds.min.x, paddedBounds.max.y, paddedBounds.center.z); // TL + worldCorners[3] = new Vector3(paddedBounds.max.x, paddedBounds.max.y, paddedBounds.center.z); // TR + + // Convert screen-space corners to canvas local points (canvas units) + bool anyFailed = false; + Vector2[] localCorners = new Vector2[4]; + for (int i = 0; i < 4; i++) + { + Vector3 screenPos = mainCamera.WorldToScreenPoint(worldCorners[i]); + if (!RectTransformUtility.ScreenPointToLocalPointInRectangle(canvasRect, screenPos, uiCamera, + out localCorners[i])) + { + anyFailed = true; + } + } + + // Fallback: if conversion failed for some reason, keep original behavior (pixels -> clamp -> convert later) + if (anyFailed) + { + Vector2 minScreen = new Vector2(float.MaxValue, float.MaxValue); + Vector2 maxScreen = new Vector2(float.MinValue, float.MinValue); + foreach (Vector3 corner in worldCorners) + { + Vector3 sp = mainCamera.WorldToScreenPoint(corner); + minScreen.x = Mathf.Min(minScreen.x, sp.x); + minScreen.y = Mathf.Min(minScreen.y, sp.y); + maxScreen.x = Mathf.Max(maxScreen.x, sp.x); + maxScreen.y = Mathf.Max(maxScreen.y, sp.y); + } + + float widthPx = maxScreen.x - minScreen.x; + float heightPx = maxScreen.y - minScreen.y; + float canvasWidth = canvasRect.rect.width; + float scaleX = Screen.width > 0 ? canvasWidth / Screen.width : 1f; + targetViewfinderSize = Mathf.Max(widthPx, heightPx) * scaleX; // approximate conversion + float minCanvas = canvasWidth * settings.MinSizePercent; + float maxCanvas = canvasWidth * settings.MaxSizePercent; + targetViewfinderSize = Mathf.Clamp(targetViewfinderSize, minCanvas, maxCanvas); + + // Target position + targetScreenPosition = mainCamera.WorldToScreenPoint(spriteBounds.center); + RectTransformUtility.ScreenPointToLocalPointInRectangle(canvasRect, targetScreenPosition, uiCamera, + out targetAnchoredPosition); + return; + } + + // Compute width/height in canvas units from local corners + float minX = float.MaxValue, minY = float.MaxValue, maxX = float.MinValue, maxY = float.MinValue; + for (int i = 0; i < 4; i++) + { + minX = Mathf.Min(minX, localCorners[i].x); + minY = Mathf.Min(minY, localCorners[i].y); + maxX = Mathf.Max(maxX, localCorners[i].x); + maxY = Mathf.Max(maxY, localCorners[i].y); + } + + float widthCanvas = Mathf.Max(0f, maxX - minX); + float heightCanvas = Mathf.Max(0f, maxY - minY); + float canvasSquare = Mathf.Max(widthCanvas, heightCanvas); + + // Clamp using canvas width + float canvasW = canvasRect.rect.width; + float minSizeCanvas = canvasW * settings.MinSizePercent; + float maxSizeCanvas = canvasW * settings.MaxSizePercent; + targetViewfinderSize = Mathf.Clamp(canvasSquare, minSizeCanvas, maxSizeCanvas); + + // Target position in both screen and canvas units + targetScreenPosition = mainCamera.WorldToScreenPoint(spriteBounds.center); + RectTransformUtility.ScreenPointToLocalPointInRectangle(canvasRect, targetScreenPosition, uiCamera, + out targetAnchoredPosition); + + Debug.Log( + $"[CameraViewfinderManager] Target size (canvas): {targetViewfinderSize}, target anchored: {targetAnchoredPosition}"); + } + + /// + /// Stop the current viewfinder animation and clean up + /// + public void StopViewfinderAnimation() + { + if (animationCoroutine != null) + { + StopCoroutine(animationCoroutine); + animationCoroutine = null; + } + + if (viewfinderInstance != null) + { + Destroy(viewfinderInstance); + viewfinderInstance = null; + } + + isAnimating = false; + targetTransform = null; + } + + /// + /// Coroutine that handles the viewfinder animation + /// + private IEnumerator AnimateViewfinder() + { + RectTransform canvasRect = targetCanvas.transform as RectTransform; + float canvasWidth = canvasRect != null ? canvasRect.rect.width : Screen.width; + + // IMPORTANT: We're animating from full canvas width DOWN to the target size + float startSize = canvasWidth; // Always start with full canvas width + float endSize = targetViewfinderSize; // End at the calculated target size + + float elapsedTime = 0f; + bool[] thresholdTriggered = new bool[settings.ViewfinderProgressThresholds.Length]; + + // Debug the actual values + Debug.Log($"[CameraViewfinderManager] Animation starting: startSize={startSize}, endSize={endSize}, " + + $"current sizeDelta={viewfinderRectTransform.sizeDelta}"); + + // Verify the initial size is set correctly + viewfinderRectTransform.sizeDelta = new Vector2(startSize, startSize); + + while (elapsedTime < settings.ViewfinderShrinkDuration) + { + if (targetTransform == null) + { + StopViewfinderAnimation(); + yield break; + } + + elapsedTime += Time.unscaledDeltaTime; + animationProgress = Mathf.Clamp01(elapsedTime / settings.ViewfinderShrinkDuration); + + // The curve value might be inverted - ensure we're shrinking not growing + float curveValue = settings.ViewfinderShrinkCurve.Evaluate(animationProgress); + + // FIX: Ensure we're interpolating from large (start) to small (end) + // This is critical - we must ensure the start and end are in the right order + float currentSize = Mathf.Lerp(startSize, endSize, curveValue); + + // Additional check to ensure size is actually shrinking + if (startSize > endSize && currentSize > startSize) + { + Debug.LogWarning($"[CameraViewfinderManager] Animation curve producing wrong direction! " + + $"progress={animationProgress:F2}, curveValue={curveValue:F2}"); + // Force correct behavior + curveValue = animationProgress; // Override with linear interpolation + currentSize = Mathf.Lerp(startSize, endSize, curveValue); + } + + viewfinderRectTransform.sizeDelta = new Vector2(currentSize, currentSize); + + // Move in UI space towards the anchored target position + Vector2 currentPos = viewfinderRectTransform.anchoredPosition; + Vector2 newPos = Vector2.Lerp(currentPos, targetAnchoredPosition, + settings.ViewfinderMoveSpeed * Time.unscaledDeltaTime); + viewfinderRectTransform.anchoredPosition = newPos; + + // Log the animation state occasionally for debugging + if (animationProgress % 0.25f <= 0.01f || animationProgress >= 0.99f) + { + Debug.Log($"[CameraViewfinderManager] Animation progress: {animationProgress:F2}, " + + $"curveValue={curveValue:F2}, currentSize={currentSize:F2}, currentPos={newPos}"); + } + + for (int i = 0; i < settings.ViewfinderProgressThresholds.Length; i++) + { + if (!thresholdTriggered[i] && animationProgress >= settings.ViewfinderProgressThresholds[i]) + { + thresholdTriggered[i] = true; + OnProgressThresholdReached?.Invoke(settings.ViewfinderProgressThresholds[i]); + } + } + + OnProgressUpdated?.Invoke(animationProgress); + yield return null; + } + + // Ensure we reach the exact end size + viewfinderRectTransform.sizeDelta = new Vector2(endSize, endSize); + + animationProgress = 1f; + OnProgressUpdated?.Invoke(animationProgress); + OnAnimationCompleted?.Invoke(); + + // Log final state to confirm we reached the target size + Debug.Log( + $"[CameraViewfinderManager] Animation completed: final size={viewfinderRectTransform.sizeDelta}"); + + yield return new WaitForSecondsRealtime(0.5f); + StopViewfinderAnimation(); + } + + // Converts a screen-space point to a RectTransform anchoredPosition for the target canvas + private Vector2 ScreenToAnchoredPosition(Vector3 screenPosition) + { + if (targetCanvas == null) + { + return new Vector2(screenPosition.x, screenPosition.y); + } + + RectTransform canvasRect = targetCanvas.transform as RectTransform; + Camera uiCamera = null; + if (targetCanvas.renderMode == RenderMode.ScreenSpaceCamera || + targetCanvas.renderMode == RenderMode.WorldSpace) + { + uiCamera = targetCanvas.worldCamera; + } + + Vector2 localPoint; + RectTransformUtility.ScreenPointToLocalPointInRectangle(canvasRect, screenPosition, uiCamera, + out localPoint); + return localPoint; + } + + private void OnDestroy() + { + StopViewfinderAnimation(); + + if (_instance == this) + { + _instance = null; + } + } + + /// + /// Handles tap event from the viewfinder and forwards it + /// + private void HandleViewfinderTapped() + { + // Forward the tap event to any listeners + OnViewfinderTapped?.Invoke(); + } + + /// + /// Hides the currently displayed viewfinder + /// + public void HideViewfinder() + { + if (viewfinderInstance != null) + { + // Unsubscribe from the viewfinder's tap event + if (viewfinderComponent != null) + { + viewfinderComponent.OnViewfinderTapped -= HandleViewfinderTapped; + } + + Destroy(viewfinderInstance); + viewfinderInstance = null; + viewfinderComponent = null; + viewfinderRectTransform = null; + Debug.Log("[CameraViewfinderManager] Hid viewfinder"); + } + } + + /// + /// Shows the viewfinder in the middle of the screen at full size without animation + /// This is the first step in the two-step process, showing the UI without targeting a monster yet + /// + public void ShowFullScreenViewfinder() + { + if (viewfinderInstance != null) + { + // Already showing a viewfinder, destroy it first + Destroy(viewfinderInstance); + } + + if (settings.ViewfinderPrefab == null) + { + Debug.LogError("[CameraViewfinderManager] No viewfinder prefab assigned!"); + return; + } + + if (targetCanvas == null) + { + Debug.LogError("[CameraViewfinderManager] No canvas assigned!"); + return; + } + + isAnimating = false; + + // Create viewfinder as UI element + viewfinderInstance = Instantiate(settings.ViewfinderPrefab, targetCanvas.transform); + viewfinderRectTransform = viewfinderInstance.GetComponent(); + viewfinderComponent = viewfinderInstance.GetComponent(); + + if (viewfinderRectTransform == null) + { + Debug.LogError("[CameraViewfinderManager] Viewfinder prefab doesn't have a RectTransform component!"); + Destroy(viewfinderInstance); + return; + } + + // Initialize viewfinder with a reference to this manager + if (viewfinderComponent != null) + { + viewfinderComponent.Initialize(this); + viewfinderComponent.SetupInputOverride(); + viewfinderComponent.OnViewfinderTapped += HandleViewfinderTapped; + + } + + // Determine canvas width for full-screen sizing + RectTransform canvasRect = targetCanvas.transform as RectTransform; + float canvasWidth = canvasRect != null ? canvasRect.rect.width : Screen.width; + + // Set up the viewfinder in the center of the screen at full canvas width + viewfinderRectTransform.anchorMin = new Vector2(0.5f, 0.5f); + viewfinderRectTransform.anchorMax = new Vector2(0.5f, 0.5f); + viewfinderRectTransform.pivot = new Vector2(0.5f, 0.5f); + viewfinderRectTransform.sizeDelta = new Vector2(canvasWidth, canvasWidth); + viewfinderRectTransform.anchoredPosition = Vector2.zero; + + Debug.Log($"[CameraViewfinderManager] Showed full-screen viewfinder with size {canvasWidth}"); + } + + /// + /// Starts the complete viewfinder animation sequence (zoom in, then zoom out) + /// + /// The transform to focus on (usually the monster) + public void StartViewfinderSequence(Transform target) + { + if (isAnimating) + { + StopViewfinderAnimation(); + } + + if (settings.ViewfinderPrefab == null) + { + Debug.LogError("[CameraViewfinderManager] No viewfinder prefab assigned!"); + return; + } + + if (targetCanvas == null) + { + Debug.LogError("[CameraViewfinderManager] No canvas assigned!"); + return; + } + + targetTransform = target; + isReversePhase = false; + currentProximity = 0f; + + // Calculate target screen position and size based on monster's sprite bounds + CalculateTargetScreenPositionAndSize(); + + // Reuse existing viewfinder instance if it exists + if (viewfinderInstance == null) + { + // Create viewfinder as UI element if it doesn't exist yet + viewfinderInstance = Instantiate(settings.ViewfinderPrefab, targetCanvas.transform); + viewfinderRectTransform = viewfinderInstance.GetComponent(); + viewfinderComponent = viewfinderInstance.GetComponent(); + + if (viewfinderRectTransform == null) + { + Debug.LogError("[CameraViewfinderManager] Viewfinder prefab doesn't have a RectTransform component!"); + Destroy(viewfinderInstance); + return; + } + } + else + { + // Unsubscribe from any existing event to prevent multiple subscriptions + if (viewfinderComponent != null) + { + viewfinderComponent.OnViewfinderTapped -= HandleViewfinderTapped; + viewfinderComponent.OnViewfinderTapped -= HandleViewfinderTappedDuringAnimation; + } + + // Subscribe to the viewfinder's tap event for interrupting the animation + viewfinderComponent.OnViewfinderTapped += HandleViewfinderTappedDuringAnimation; + } + + // Reset state + animationProgress = 0f; + isAnimating = true; + + // Determine canvas width for CanvasScaler-consistent sizing + RectTransform canvasRect = targetCanvas.transform as RectTransform; + float canvasWidth = canvasRect != null ? canvasRect.rect.width : Screen.width; + + // Initialize viewfinder size and position to full canvas width (square) at center + float startSize = canvasWidth; + viewfinderRectTransform.sizeDelta = new Vector2(startSize, startSize); + viewfinderRectTransform.anchorMin = new Vector2(0.5f, 0.5f); + viewfinderRectTransform.anchorMax = new Vector2(0.5f, 0.5f); + viewfinderRectTransform.pivot = new Vector2(0.5f, 0.5f); + viewfinderRectTransform.anchoredPosition = Vector2.zero; + + // Compute target anchored position in canvas units from previously calculated screen position + targetAnchoredPosition = ScreenToAnchoredPosition(targetScreenPosition); + + // Fire starting event + OnAnimationStarted?.Invoke(); + + // Start sequence coroutine + animationCoroutine = StartCoroutine(AnimateViewfinderSequence()); + } + + /// + /// Coroutine that handles the complete viewfinder animation sequence (zoom in, then zoom out) + /// + private IEnumerator AnimateViewfinderSequence() + { + RectTransform canvasRect = targetCanvas.transform as RectTransform; + float canvasWidth = canvasRect != null ? canvasRect.rect.width : Screen.width; + + // Phase 1: Zoom in (from full screen to monster) + float startSize = canvasWidth; // Always start with full canvas width + float endSize = targetViewfinderSize; // End at the calculated target size + Vector2 startPos = Vector2.zero; // Center of screen + Vector2 endPos = targetAnchoredPosition; // Target position + + float elapsedTime = 0f; + bool[] thresholdTriggered = new bool[settings.ViewfinderProgressThresholds.Length]; + + // Debug the actual values + Debug.Log($"[CameraViewfinderManager] Animation sequence starting: startSize={startSize}, endSize={endSize}"); + + // Verify the initial size is set correctly + viewfinderRectTransform.sizeDelta = new Vector2(startSize, startSize); + + // Phase 1: Zoom In + while (elapsedTime < settings.ViewfinderShrinkDuration && !isReversePhase) + { + if (targetTransform == null) + { + StopViewfinderAnimation(); + yield break; + } + + elapsedTime += Time.unscaledDeltaTime; + animationProgress = Mathf.Clamp01(elapsedTime / settings.ViewfinderShrinkDuration); + + // Calculate proximity - it increases as we get closer to the target + currentProximity = animationProgress; + OnProximityUpdated?.Invoke(currentProximity); + + // The curve value might be inverted - ensure we're shrinking not growing + float curveValue = settings.ViewfinderShrinkCurve.Evaluate(animationProgress); + + // Interpolate size + float currentSize = Mathf.Lerp(startSize, endSize, curveValue); + viewfinderRectTransform.sizeDelta = new Vector2(currentSize, currentSize); + + // Interpolate position + Vector2 currentPos = viewfinderRectTransform.anchoredPosition; + Vector2 newPos = Vector2.Lerp(startPos, endPos, curveValue); + viewfinderRectTransform.anchoredPosition = newPos; + + // Log the animation state occasionally for debugging + if (animationProgress % 0.25f <= 0.01f || animationProgress >= 0.99f) + { + Debug.Log($"[CameraViewfinderManager] Animation progress: {animationProgress:F2}, " + + $"curveValue={curveValue:F2}, currentSize={currentSize:F2}, currentPos={newPos}, proximity={currentProximity:F2}"); + } + + for (int i = 0; i < settings.ViewfinderProgressThresholds.Length; i++) + { + if (!thresholdTriggered[i] && animationProgress >= settings.ViewfinderProgressThresholds[i]) + { + thresholdTriggered[i] = true; + OnProgressThresholdReached?.Invoke(settings.ViewfinderProgressThresholds[i]); + } + } + + OnProgressUpdated?.Invoke(animationProgress); + yield return null; + } + + // Ensure we reach the exact end size and position for phase 1 + viewfinderRectTransform.sizeDelta = new Vector2(endSize, endSize); + viewfinderRectTransform.anchoredPosition = endPos; + currentProximity = 1.0f; // At target + OnProximityUpdated?.Invoke(currentProximity); + + // Brief pause at target + yield return new WaitForSecondsRealtime(0.2f); + + // Start phase 2 - reverse animation + isReversePhase = true; + OnReverseAnimationStarted?.Invoke(); + + // Reset for reverse phase + elapsedTime = 0f; + animationProgress = 0f; + + // Phase 2: Zoom Out (from monster back to full screen) + while (elapsedTime < settings.ViewfinderShrinkDuration && isReversePhase) + { + if (targetTransform == null) + { + StopViewfinderAnimation(); + yield break; + } + + elapsedTime += Time.unscaledDeltaTime; + animationProgress = Mathf.Clamp01(elapsedTime / settings.ViewfinderShrinkDuration); + + // Calculate proximity - it decreases as we move away from target + currentProximity = 1.0f - animationProgress; + OnProximityUpdated?.Invoke(currentProximity); + + // The curve value for zooming out + float curveValue = settings.ViewfinderShrinkCurve.Evaluate(animationProgress); + + // Interpolate size (now growing) + float currentSize = Mathf.Lerp(endSize, startSize, curveValue); + viewfinderRectTransform.sizeDelta = new Vector2(currentSize, currentSize); + + // Interpolate position (now returning to center) + Vector2 currentPos = viewfinderRectTransform.anchoredPosition; + Vector2 newPos = Vector2.Lerp(endPos, startPos, curveValue); + viewfinderRectTransform.anchoredPosition = newPos; + + // Log the animation state occasionally for debugging + if (animationProgress % 0.25f <= 0.01f || animationProgress >= 0.99f) + { + Debug.Log($"[CameraViewfinderManager] Reverse animation progress: {animationProgress:F2}, " + + $"curveValue={curveValue:F2}, currentSize={currentSize:F2}, currentPos={newPos}, proximity={currentProximity:F2}"); + } + + OnProgressUpdated?.Invoke(animationProgress); + yield return null; + } + + // Animation completed (both phases) + HandleViewfinderTappedDuringAnimation(); + } + + /// + /// Handle tap events during animation (for capturing at current proximity) + /// + private void HandleViewfinderTappedDuringAnimation() + { + if (isAnimating) + { + // Fire event with current proximity value for scoring + OnViewfinderTappedDuringAnimation?.Invoke(currentProximity); + + // Complete the animation immediately + if (animationCoroutine != null) + { + StopCoroutine(animationCoroutine); + animationCoroutine = null; + } + + // Fire completed event + OnAnimationCompleted?.Invoke(); + isAnimating = false; + isReversePhase = false; + + // Hide the viewfinder on the second tap + viewfinderComponent.RemoveInputOverride(); + HideViewfinder(); + } + else + { + // Regular tap handling when not animating + HandleViewfinderTapped(); + } + } + } +} diff --git a/Assets/Scripts/Minigames/DivingForPictures/PictureCamera/CameraViewfinderManager.cs.meta b/Assets/Scripts/Minigames/DivingForPictures/PictureCamera/CameraViewfinderManager.cs.meta new file mode 100644 index 00000000..f9d20b51 --- /dev/null +++ b/Assets/Scripts/Minigames/DivingForPictures/PictureCamera/CameraViewfinderManager.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: e5a6d17776b84719a2599fdc35c7076d +timeCreated: 1760016840 \ No newline at end of file diff --git a/Assets/Scripts/Minigames/DivingForPictures/PictureCamera/Viewfinder.cs b/Assets/Scripts/Minigames/DivingForPictures/PictureCamera/Viewfinder.cs new file mode 100644 index 00000000..ca1d78b5 --- /dev/null +++ b/Assets/Scripts/Minigames/DivingForPictures/PictureCamera/Viewfinder.cs @@ -0,0 +1,119 @@ +using UnityEngine; +using UnityEngine.EventSystems; +using UnityEngine.UI; +using Input; + +namespace Minigames.DivingForPictures.PictureCamera +{ + /// + /// Attached to the viewfinder UI prefab. Handles tap detection and other viewfinder-specific operations. + /// + public class Viewfinder : MonoBehaviour, ITouchInputConsumer + { + [SerializeField] + private Image[] viewfinderImages; // Array of Image components to tint based on proximity + + // Events + public event System.Action OnViewfinderTapped; + + // State + private bool isActive = true; + private RectTransform _rectTransform; + private CameraViewfinderManager _viewfinderManager; + + private void Awake() + { + _rectTransform = GetComponent(); + } + + /// + /// Initializes the viewfinder with a reference to its manager + /// + /// Reference to the CameraViewfinderManager + public void Initialize(CameraViewfinderManager manager) + { + _viewfinderManager = manager; + + if (_viewfinderManager != null) + { + _viewfinderManager.OnProximityUpdated += UpdateProximityColor; + } + } + + private void OnDisable() + { + // Unsubscribe from events when disabled + if (_viewfinderManager != null) + { + _viewfinderManager.OnProximityUpdated -= UpdateProximityColor; + } + } + + /// + /// Updates the color of all viewfinder images based on proximity value + /// + /// Proximity value between 0 and 1 (0=far, 1=close) + private void UpdateProximityColor(float proximity) + { + // Lerp between green (close) and red (far) + Color tintColor = Color.Lerp(Color.red, Color.green, proximity); + + // Apply the color to all referenced image components + if (viewfinderImages != null && viewfinderImages.Length > 0) + { + foreach (Image image in viewfinderImages) + { + if (image != null) + { + image.color = tintColor; + } + } + } + } + + /// + /// Enable or disable input reception + /// + public void SetActive(bool active) + { + isActive = active; + } + + #region ITouchInputConsumer Implementation + + public void SetupInputOverride() + { + InputManager.Instance.RegisterOverrideConsumer(this); + } + + public void RemoveInputOverride() + { + InputManager.Instance.UnregisterOverrideConsumer(this); + } + + public void OnTap(Vector2 position) + { + if (isActive) + { + // Fire the tap event that PhotoSequenceController will listen to + OnViewfinderTapped?.Invoke(); + Debug.Log($"[MDPI] Viewfinder OnTap: {position}"); + } + } + + // Required interface methods (no-op implementations) + public void OnHoldStart(Vector2 position) { } + public void OnHoldMove(Vector2 position) { } + public void OnHoldEnd(Vector2 position) { } + + #endregion + + /// + /// Check if a point is within the viewfinder's bounds + /// + public bool ContainsPoint(Vector2 screenPoint) + { + return RectTransformUtility.RectangleContainsScreenPoint(_rectTransform, screenPoint); + } + } +} diff --git a/Assets/Scripts/Minigames/DivingForPictures/PictureCamera/Viewfinder.cs.meta b/Assets/Scripts/Minigames/DivingForPictures/PictureCamera/Viewfinder.cs.meta new file mode 100644 index 00000000..dcadc0be --- /dev/null +++ b/Assets/Scripts/Minigames/DivingForPictures/PictureCamera/Viewfinder.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 4b4b818dd8cb454abe85b8edcaece1db +timeCreated: 1760032922 \ No newline at end of file diff --git a/Assets/Scripts/Minigames/DivingForPictures/Player/PlayerController.cs b/Assets/Scripts/Minigames/DivingForPictures/Player/PlayerController.cs index 4a9c61b4..f171b715 100644 --- a/Assets/Scripts/Minigames/DivingForPictures/Player/PlayerController.cs +++ b/Assets/Scripts/Minigames/DivingForPictures/Player/PlayerController.cs @@ -42,23 +42,13 @@ namespace Minigames.DivingForPictures _targetFingerX = transform.position.x; _isTouchActive = false; - // Find DivingGameManager and subscribe to its initialization event - DivingGameManager gameManager = FindFirstObjectByType(); - if (gameManager != null) + DivingGameManager.Instance.OnGameInitialized += Initialize; + + // If game is already initialized, initialize immediately + if (DivingGameManager.Instance.GetType().GetField("_isGameInitialized", + System.Reflection.BindingFlags.NonPublic | + System.Reflection.BindingFlags.Instance)?.GetValue(DivingGameManager.Instance) is bool isInitialized && isInitialized) { - gameManager.OnGameInitialized += Initialize; - - // If game is already initialized, initialize immediately - if (gameManager.GetType().GetField("_isGameInitialized", - System.Reflection.BindingFlags.NonPublic | - System.Reflection.BindingFlags.Instance)?.GetValue(gameManager) is bool isInitialized && isInitialized) - { - Initialize(); - } - } - else - { - Debug.LogWarning("[PlayerController] DivingGameManager not found. Initializing immediately."); Initialize(); } } @@ -79,12 +69,7 @@ namespace Minigames.DivingForPictures private void OnDestroy() { - // Unsubscribe from events to prevent memory leaks - DivingGameManager gameManager = FindFirstObjectByType(); - if (gameManager != null) - { - gameManager.OnGameInitialized -= Initialize; - } + DivingGameManager.Instance.OnGameInitialized -= Initialize; } /// diff --git a/Assets/Scripts/Minigames/DivingForPictures/Player/RopeEndPhysicsFollower.cs b/Assets/Scripts/Minigames/DivingForPictures/Player/RopeEndPhysicsFollower.cs index b9ac81fa..a18babb5 100644 --- a/Assets/Scripts/Minigames/DivingForPictures/Player/RopeEndPhysicsFollower.cs +++ b/Assets/Scripts/Minigames/DivingForPictures/Player/RopeEndPhysicsFollower.cs @@ -31,7 +31,7 @@ public class RopeEndPhysicsFollower : MonoBehaviour private Vector2 offset; private Vector3 lastTargetPosition; private bool initialized = false; - private bool debugLog = true; + private bool debugLog = false; // Rope reference to get the actual rope length private Rope attachedRope; diff --git a/Assets/Scripts/Minigames/DivingForPictures/Tiles/TrenchTileSpawner.cs b/Assets/Scripts/Minigames/DivingForPictures/Tiles/TrenchTileSpawner.cs index f5a68231..0e15af05 100644 --- a/Assets/Scripts/Minigames/DivingForPictures/Tiles/TrenchTileSpawner.cs +++ b/Assets/Scripts/Minigames/DivingForPictures/Tiles/TrenchTileSpawner.cs @@ -37,7 +37,7 @@ namespace Minigames.DivingForPictures private int _spawnCounter; private float _speedUpTimer; - private Camera _mainCamera; + private UnityEngine.Camera _mainCamera; private float _screenBottom; private float _screenTop; private TrenchTilePool _tilePool; @@ -76,7 +76,7 @@ namespace Minigames.DivingForPictures private void Awake() { - _mainCamera = Camera.main; + _mainCamera = UnityEngine.Camera.main; // Get settings from GameManager _settings = GameManager.GetSettingsObject(); @@ -125,38 +125,23 @@ namespace Minigames.DivingForPictures private void Start() { - // Find DivingGameManager and subscribe to its initialization event - DivingGameManager gameManager = FindFirstObjectByType(); - if (gameManager != null) + DivingGameManager.Instance.OnGameInitialized += Initialize; + + // Register with the DivingGameManager for pause/resume events + DivingGameManager.Instance.RegisterPausableComponent(this); + + // If game is already initialized, initialize immediately + if (DivingGameManager.Instance.GetType().GetField("_isGameInitialized", + System.Reflection.BindingFlags.NonPublic | + System.Reflection.BindingFlags.Instance)?.GetValue(DivingGameManager.Instance) is bool isInitialized && isInitialized) { - gameManager.OnGameInitialized += Initialize; - - // Register with the DivingGameManager for pause/resume events - gameManager.RegisterPausableComponent(this); - - // If game is already initialized, initialize immediately - if (gameManager.GetType().GetField("_isGameInitialized", - System.Reflection.BindingFlags.NonPublic | - System.Reflection.BindingFlags.Instance)?.GetValue(gameManager) is bool isInitialized && isInitialized) - { - Initialize(); - } - } - else - { - Debug.LogWarning("[TrenchTileSpawner] DivingGameManager not found. Initializing immediately."); Initialize(); } } private void OnDestroy() { - // Unregister from DivingGameManager - DivingGameManager gameManager = FindFirstObjectByType(); - if (gameManager != null) - { - gameManager.UnregisterPausableComponent(this); - } + DivingGameManager.Instance.UnregisterPausableComponent(this); } /// @@ -199,7 +184,7 @@ namespace Minigames.DivingForPictures /// /// Resumes the spawner and all associated processes /// - public void Resume() + public void DoResume() { if (!_isPaused) return; // Already running @@ -386,7 +371,7 @@ namespace Minigames.DivingForPictures { if (_mainCamera == null) { - _mainCamera = Camera.main; + _mainCamera = UnityEngine.Camera.main; if (_mainCamera == null) { Debug.LogError("No main camera found!"); @@ -904,7 +889,7 @@ namespace Minigames.DivingForPictures if (!Application.isPlaying) { // Only try to calculate this if _screenBottom hasn't been set by the game - Camera editorCam = Camera.main; + UnityEngine.Camera editorCam = UnityEngine.Camera.main; if (editorCam != null) { Vector3 bottom = editorCam.ViewportToWorldPoint(new Vector3(0.5f, 0f, editorCam.nearClipPlane)); diff --git a/Assets/Scripts/Minigames/DivingForPictures/Utilities.meta b/Assets/Scripts/Minigames/DivingForPictures/Utilities.meta new file mode 100644 index 00000000..26e2fa72 --- /dev/null +++ b/Assets/Scripts/Minigames/DivingForPictures/Utilities.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0892ac3d8370a274b8d5847ca51ac046 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Minigames/DivingForPictures/Utilities/BottlePauser.cs b/Assets/Scripts/Minigames/DivingForPictures/Utilities/BottlePauser.cs new file mode 100644 index 00000000..b524057e --- /dev/null +++ b/Assets/Scripts/Minigames/DivingForPictures/Utilities/BottlePauser.cs @@ -0,0 +1,31 @@ +using AppleHills.Core.Interfaces; +using UnityEngine; + +namespace Minigames.DivingForPictures.Utilities +{ + public class BottlePauser : MonoBehaviour, IPausable + { + [SerializeField] private WobbleBehavior wobbleReference; + + private bool isPaused = false; + + private void Awake() + { + DivingGameManager.Instance.RegisterPausableComponent(this); + } + + public void Pause() + { + wobbleReference.enabled = false; + isPaused = true; + } + + public void DoResume() + { + wobbleReference.enabled = true; + isPaused = false; + } + + public bool IsPaused => isPaused; + } +} diff --git a/Assets/Scripts/Minigames/DivingForPictures/Utilities/BottlePauser.cs.meta b/Assets/Scripts/Minigames/DivingForPictures/Utilities/BottlePauser.cs.meta new file mode 100644 index 00000000..08707fe4 --- /dev/null +++ b/Assets/Scripts/Minigames/DivingForPictures/Utilities/BottlePauser.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: cf50e6f7c05d5a14296152b8c3fbb923 \ No newline at end of file diff --git a/Assets/Scripts/Minigames/DivingForPictures/Utilities/RockPauser.cs b/Assets/Scripts/Minigames/DivingForPictures/Utilities/RockPauser.cs new file mode 100644 index 00000000..5d09a221 --- /dev/null +++ b/Assets/Scripts/Minigames/DivingForPictures/Utilities/RockPauser.cs @@ -0,0 +1,34 @@ +using AppleHills.Core.Interfaces; +using UnityEngine; + +namespace Minigames.DivingForPictures.Utilities +{ + public class RockPauser : MonoBehaviour, IPausable + { + [SerializeField] private RockFollower rockReference; + [SerializeField] private WobbleBehavior rockWobbleReference; + + private bool isPaused = false; + + private void Awake() + { + DivingGameManager.Instance.RegisterPausableComponent(this); + } + + public void Pause() + { + rockReference.enabled = false; + rockWobbleReference.enabled = false; + isPaused = true; + } + + public void DoResume() + { + rockReference.enabled = true; + rockWobbleReference.enabled = true; + isPaused = false; + } + + public bool IsPaused => isPaused; + } +} diff --git a/Assets/Scripts/Minigames/DivingForPictures/Utilities/RockPauser.cs.meta b/Assets/Scripts/Minigames/DivingForPictures/Utilities/RockPauser.cs.meta new file mode 100644 index 00000000..004658b5 --- /dev/null +++ b/Assets/Scripts/Minigames/DivingForPictures/Utilities/RockPauser.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: a392c919de2df0340b700309e221b7b1 \ No newline at end of file diff --git a/Assets/Scripts/UI/CardSystem.meta b/Assets/Scripts/UI/CardSystem.meta new file mode 100644 index 00000000..1590cbd4 --- /dev/null +++ b/Assets/Scripts/UI/CardSystem.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 27f0915ceda44ccf9415c3f344645b38 +timeCreated: 1759923720 \ No newline at end of file diff --git a/Assets/Scripts/UI/CardSystem/AlbumViewPage.cs b/Assets/Scripts/UI/CardSystem/AlbumViewPage.cs new file mode 100644 index 00000000..08bc1341 --- /dev/null +++ b/Assets/Scripts/UI/CardSystem/AlbumViewPage.cs @@ -0,0 +1,343 @@ +using System.Collections.Generic; +using AppleHills.Data.CardSystem; +using Pixelplacement; +using UnityEngine; +using UnityEngine.UI; + +namespace AppleHills.UI.CardSystem +{ + /// + /// UI page for viewing and organizing the player's card collection in an album. + /// + public class AlbumViewPage : UIPage + { + [Header("Album UI Elements")] + [SerializeField] private GridLayoutGroup albumGrid; + [SerializeField] private RectTransform cardStackContainer; + [SerializeField] private GameObject emptyAlbumMessage; + [SerializeField] private GameObject cardSlotPrefab; + [SerializeField] private GameObject cardPrefab; + + // Runtime references + private CardSystemManager _cardManager; + private List _displayedCards = new List(); + private Dictionary _albumSlots = new Dictionary(); + + // Drag and drop handling + private CardUIElement _currentlyDraggedCard = null; + private Vector3 _cardOriginalPosition; + + private void Awake() + { + _cardManager = CardSystemManager.Instance; + } + + /// + /// Sets up the album when the page becomes active + /// + public override void TransitionIn() + { + base.TransitionIn(); + + // Initialize the album when the page becomes active + InitializeAlbum(); + } + + /// + /// Initializes the album with card slots and the player's collection + /// + private void InitializeAlbum() + { + // Clear any previous setup + ClearAlbum(); + + // Get all collected cards + List collectedCards = _cardManager.GetAllCollectedCards(); + + // Show/hide empty message based on collection + if (emptyAlbumMessage != null) + { + emptyAlbumMessage.SetActive(collectedCards.Count == 0); + } + + if (collectedCards.Count == 0) + { + return; + } + + // Set up the album slots + SetupAlbumSlots(); + + // Create card UI elements for the stack + CreateCardStack(collectedCards); + } + + /// + /// Sets up empty slots in the album grid + /// + private void SetupAlbumSlots() + { + if (albumGrid == null || cardSlotPrefab == null) return; + + // Create predefined slots in the album + // For a simple implementation, we'll create a 5x5 grid of slots + int slotsPerZone = 5; // 5 slots per zone (one row) + int totalZones = System.Enum.GetValues(typeof(CardZone)).Length; + + for (int zone = 0; zone < totalZones; zone++) + { + for (int i = 0; i < slotsPerZone; i++) + { + // Create a slot at this position + GameObject slotObj = Instantiate(cardSlotPrefab, albumGrid.transform); + + // Calculate the collection index for this slot + int collectionIndex = zone * 100 + i; // Zone*100 + position to ensure unique indices + + // Store the slot reference + _albumSlots[collectionIndex] = slotObj.transform; + + // Set the slot label (optional) + Text slotLabel = slotObj.GetComponentInChildren(); + if (slotLabel != null) + { + CardZone zoneEnum = (CardZone)zone; + slotLabel.text = $"{zoneEnum} #{i+1}"; + } + } + } + } + + /// + /// Creates UI elements for the player's collected cards + /// + private void CreateCardStack(List cards) + { + if (cardStackContainer == null || cardPrefab == null) return; + + // Stack offset for visual effect + Vector3 stackOffset = new Vector3(5f, -5f, 0f); + Vector3 basePosition = Vector3.zero; + + // Sort cards by collection index + cards.Sort((a, b) => a.CollectionIndex.CompareTo(b.CollectionIndex)); + + // Create card UI elements + for (int i = 0; i < cards.Count; i++) + { + GameObject cardObj = Instantiate(cardPrefab, cardStackContainer); + CardUIElement cardUI = cardObj.GetComponent(); + + if (cardUI != null) + { + // Position in stack + cardObj.GetComponent().anchoredPosition = basePosition + (stackOffset * i); + + // Set up card data + cardUI.SetupCard(cards[i]); + + // Add drag handlers + SetupCardDragHandlers(cardUI); + + // Add to tracked cards + _displayedCards.Add(cardUI); + + // Check if this card should be placed in a slot already + int collectionIndex = cards[i].CollectionIndex; + if (_albumSlots.TryGetValue(collectionIndex, out Transform slot)) + { + // Card has a designated slot, place it there + PlaceCardInSlot(cardUI, slot); + } + } + } + } + + /// + /// Sets up drag and drop handlers for a card + /// + private void SetupCardDragHandlers(CardUIElement cardUI) + { + // // Get drag handler component (you might need to implement this) + // DragHandler dragHandler = cardUI.GetComponent(); + // if (dragHandler == null) + // { + // // This is a stub for the drag handler + // // In a real implementation, you'd have a proper drag handler component + // // For now, we'll just add click listeners + // + // // Add click listener + // Button cardButton = cardUI.GetComponent