From d340446b19c2746357e77f4e8d91282cf1ea8ba7 Mon Sep 17 00:00:00 2001 From: "NJ\\skrwn" Date: Sun, 5 Jul 2026 19:51:17 +0900 Subject: [PATCH] =?UTF-8?q?2026-07-05=20=EB=8C=80=ED=99=94=EC=8B=9C?= =?UTF-8?q?=EC=8A=A4=ED=85=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Assets/01_Scenes/BasicScene.meta | 8 + Assets/01_Scenes/BasicScene.unity.meta | 7 + .../BasicScene/Grid_Light_512x512.png.meta | 169 ++++++++++++++++++ Assets/01_Scenes/SampleScene.meta | 8 + Assets/01_Scenes/SampleScene.unity.meta | 7 + .../SampleScene/LightingData.asset.meta | 8 + .../SampleScene/Lightmap-0_comp_dir.png.meta | 169 ++++++++++++++++++ .../Lightmap-0_comp_light.exr.meta | 169 ++++++++++++++++++ .../Lightmap-0_comp_shadowmask.png.meta | 169 ++++++++++++++++++ .../SampleScene/ReflectionProbe-0.exr.meta | 169 ++++++++++++++++++ .../SampleScene/ReflectionProbe-1.exr.meta | 169 ++++++++++++++++++ .../Communication/Dialog/AffectionModifier.cs | 11 ++ .../Dialog/AffectionModifier.cs.meta | 2 + .../Communication/Dialog/DialogCondition.cs | 41 +++++ .../Dialog/DialogCondition.cs.meta | 2 + .../Communication/Dialog/DialogPlayer.cs | 112 ++++++------ .../Communication/Dialog/DialogRegion.cs | 27 --- .../Communication/Dialog/DialogRegion.cs.meta | 2 - .../GraphTool/Editor/DialogGraphImporter.cs | 2 +- Assets/02_Scripts/Managers/StoryState.cs | 135 ++++++++++++++ Assets/02_Scripts/Managers/StoryState.cs.meta | 2 + .../XR/Settings/OpenXRPackageSettings.asset | 4 +- 22 files changed, 1301 insertions(+), 91 deletions(-) create mode 100644 Assets/01_Scenes/BasicScene.meta create mode 100644 Assets/01_Scenes/BasicScene.unity.meta create mode 100644 Assets/01_Scenes/BasicScene/Grid_Light_512x512.png.meta create mode 100644 Assets/01_Scenes/SampleScene.meta create mode 100644 Assets/01_Scenes/SampleScene.unity.meta create mode 100644 Assets/01_Scenes/SampleScene/LightingData.asset.meta create mode 100644 Assets/01_Scenes/SampleScene/Lightmap-0_comp_dir.png.meta create mode 100644 Assets/01_Scenes/SampleScene/Lightmap-0_comp_light.exr.meta create mode 100644 Assets/01_Scenes/SampleScene/Lightmap-0_comp_shadowmask.png.meta create mode 100644 Assets/01_Scenes/SampleScene/ReflectionProbe-0.exr.meta create mode 100644 Assets/01_Scenes/SampleScene/ReflectionProbe-1.exr.meta create mode 100644 Assets/02_Scripts/Communication/Dialog/AffectionModifier.cs create mode 100644 Assets/02_Scripts/Communication/Dialog/AffectionModifier.cs.meta create mode 100644 Assets/02_Scripts/Communication/Dialog/DialogCondition.cs create mode 100644 Assets/02_Scripts/Communication/Dialog/DialogCondition.cs.meta delete mode 100644 Assets/02_Scripts/Communication/Dialog/DialogRegion.cs delete mode 100644 Assets/02_Scripts/Communication/Dialog/DialogRegion.cs.meta create mode 100644 Assets/02_Scripts/Managers/StoryState.cs create mode 100644 Assets/02_Scripts/Managers/StoryState.cs.meta diff --git a/Assets/01_Scenes/BasicScene.meta b/Assets/01_Scenes/BasicScene.meta new file mode 100644 index 00000000..b40fe456 --- /dev/null +++ b/Assets/01_Scenes/BasicScene.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: cb9fcb5a0196ab7469f2a4163cac0828 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/01_Scenes/BasicScene.unity.meta b/Assets/01_Scenes/BasicScene.unity.meta new file mode 100644 index 00000000..f43c63a4 --- /dev/null +++ b/Assets/01_Scenes/BasicScene.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 365f11f1befe49548b61b2315d417a74 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/01_Scenes/BasicScene/Grid_Light_512x512.png.meta b/Assets/01_Scenes/BasicScene/Grid_Light_512x512.png.meta new file mode 100644 index 00000000..fa8fd320 --- /dev/null +++ b/Assets/01_Scenes/BasicScene/Grid_Light_512x512.png.meta @@ -0,0 +1,169 @@ +fileFormatVersion: 2 +guid: 547b449607768af4f87837b77f89e3b0 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 13 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + 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: 0 + wrapV: 0 + wrapW: 0 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 0 + spriteTessellationDetail: -1 + textureType: 0 + 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: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/01_Scenes/SampleScene.meta b/Assets/01_Scenes/SampleScene.meta new file mode 100644 index 00000000..10ece7fc --- /dev/null +++ b/Assets/01_Scenes/SampleScene.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f33f134a007ebfd49bccc22e42337b46 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/01_Scenes/SampleScene.unity.meta b/Assets/01_Scenes/SampleScene.unity.meta new file mode 100644 index 00000000..5638ef1e --- /dev/null +++ b/Assets/01_Scenes/SampleScene.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 2e64d1b1d70a111468601208bd20ce6d +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/01_Scenes/SampleScene/LightingData.asset.meta b/Assets/01_Scenes/SampleScene/LightingData.asset.meta new file mode 100644 index 00000000..690665b5 --- /dev/null +++ b/Assets/01_Scenes/SampleScene/LightingData.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3df7e28f67e55f643a7b97c98a1b611e +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/01_Scenes/SampleScene/Lightmap-0_comp_dir.png.meta b/Assets/01_Scenes/SampleScene/Lightmap-0_comp_dir.png.meta new file mode 100644 index 00000000..9a7e9adf --- /dev/null +++ b/Assets/01_Scenes/SampleScene/Lightmap-0_comp_dir.png.meta @@ -0,0 +1,169 @@ +fileFormatVersion: 2 +guid: a5e19dcd810e54340a0fd4d04bac9878 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 13 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + 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: 0 + wrapV: 0 + wrapW: 0 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 0 + spriteTessellationDetail: -1 + textureType: 0 + 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: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/01_Scenes/SampleScene/Lightmap-0_comp_light.exr.meta b/Assets/01_Scenes/SampleScene/Lightmap-0_comp_light.exr.meta new file mode 100644 index 00000000..82e687d4 --- /dev/null +++ b/Assets/01_Scenes/SampleScene/Lightmap-0_comp_light.exr.meta @@ -0,0 +1,169 @@ +fileFormatVersion: 2 +guid: 619f7f98b0a67954fb4d330dda8f7cd0 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 13 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + 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: 0 + wrapV: 0 + wrapW: 0 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 0 + spriteTessellationDetail: -1 + textureType: 0 + 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: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/01_Scenes/SampleScene/Lightmap-0_comp_shadowmask.png.meta b/Assets/01_Scenes/SampleScene/Lightmap-0_comp_shadowmask.png.meta new file mode 100644 index 00000000..0acd65b5 --- /dev/null +++ b/Assets/01_Scenes/SampleScene/Lightmap-0_comp_shadowmask.png.meta @@ -0,0 +1,169 @@ +fileFormatVersion: 2 +guid: f15a4ef7d1f12d442a126a0d34bd41e5 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 13 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + 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: 0 + wrapV: 0 + wrapW: 0 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 0 + spriteTessellationDetail: -1 + textureType: 0 + 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: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/01_Scenes/SampleScene/ReflectionProbe-0.exr.meta b/Assets/01_Scenes/SampleScene/ReflectionProbe-0.exr.meta new file mode 100644 index 00000000..55ec4e3b --- /dev/null +++ b/Assets/01_Scenes/SampleScene/ReflectionProbe-0.exr.meta @@ -0,0 +1,169 @@ +fileFormatVersion: 2 +guid: bca78663c7064dd4ea7650bb71d545ec +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 13 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + 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: 0 + wrapV: 0 + wrapW: 0 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 0 + spriteTessellationDetail: -1 + textureType: 0 + 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: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/01_Scenes/SampleScene/ReflectionProbe-1.exr.meta b/Assets/01_Scenes/SampleScene/ReflectionProbe-1.exr.meta new file mode 100644 index 00000000..8c54b0f6 --- /dev/null +++ b/Assets/01_Scenes/SampleScene/ReflectionProbe-1.exr.meta @@ -0,0 +1,169 @@ +fileFormatVersion: 2 +guid: cc4e7b27e28de2a47ba3b22a7284ff48 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 13 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + 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: 0 + wrapV: 0 + wrapW: 0 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 0 + spriteTessellationDetail: -1 + textureType: 0 + 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: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/02_Scripts/Communication/Dialog/AffectionModifier.cs b/Assets/02_Scripts/Communication/Dialog/AffectionModifier.cs new file mode 100644 index 00000000..7eb0456b --- /dev/null +++ b/Assets/02_Scripts/Communication/Dialog/AffectionModifier.cs @@ -0,0 +1,11 @@ +using UnityEngine; + +// 인스펙터 이벤트에서 호감도를 조작하기 위한 헬퍼. +// 예: 선택지 뒤 노드에 EventKey를 걸고 → DialogPlayer의 NodeEvent → +// 이 컴포넌트의 Add(5)를 연결하면 그 선택을 했을 때 호감도가 오른다. +public class AffectionModifier : MonoBehaviour +{ + [SerializeField] private CharacterData _character; + + public void Add(int delta) => StoryState.AddAffection(_character, delta); +} diff --git a/Assets/02_Scripts/Communication/Dialog/AffectionModifier.cs.meta b/Assets/02_Scripts/Communication/Dialog/AffectionModifier.cs.meta new file mode 100644 index 00000000..3efa1c62 --- /dev/null +++ b/Assets/02_Scripts/Communication/Dialog/AffectionModifier.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 04fdb10aa14325a4c8767f7d3cce49de \ No newline at end of file diff --git a/Assets/02_Scripts/Communication/Dialog/DialogCondition.cs b/Assets/02_Scripts/Communication/Dialog/DialogCondition.cs new file mode 100644 index 00000000..5a513bda --- /dev/null +++ b/Assets/02_Scripts/Communication/Dialog/DialogCondition.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using UnityEngine; + +// DialogGroup 하나가 활성화되기 위한 조건 묶음. 모든 항목을 만족해야 한다(AND). +// 값이 0이거나 목록이 비어있으면 그 항목은 조건 없음으로 통과된다. +[Serializable] +public class DialogCondition +{ + [Tooltip("메인 진행도가 이 값 이상이어야 함 (0 = 조건 없음)")] + [Min(0)] public int MinMainProgress; + + [Tooltip("이 NPC의 호감도가 이 값 이상이어야 함 (0 = 조건 없음)")] + [Min(0)] public int MinAffection; + + [Tooltip("먼저 완료했어야 하는 대화들 (전부 완료 필요)")] + public List RequiredDialogs = new(); + + [Tooltip("골랐어야 하는 선택지 Code들 (전부 필요)")] + public List RequiredChoiceCodes = new(); + + // affectionTarget: 호감도 조건을 검사할 캐릭터 (보통 대화를 거는 NPC 자신) + public bool IsMet(CharacterData affectionTarget) + { + if (StoryState.MainProgress < MinMainProgress) + return false; + + if (MinAffection > 0 && StoryState.GetAffection(affectionTarget) < MinAffection) + return false; + + foreach (var group in RequiredDialogs) + if (group != null && !StoryState.IsDialogCompleted(group.name)) + return false; + + foreach (var code in RequiredChoiceCodes) + if (!string.IsNullOrEmpty(code) && !StoryState.HasChosen(code)) + return false; + + return true; + } +} diff --git a/Assets/02_Scripts/Communication/Dialog/DialogCondition.cs.meta b/Assets/02_Scripts/Communication/Dialog/DialogCondition.cs.meta new file mode 100644 index 00000000..d6636ac1 --- /dev/null +++ b/Assets/02_Scripts/Communication/Dialog/DialogCondition.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 1f307619d54e9a74990a68cda19bff5b \ No newline at end of file diff --git a/Assets/02_Scripts/Communication/Dialog/DialogPlayer.cs b/Assets/02_Scripts/Communication/Dialog/DialogPlayer.cs index 14e7ee8e..d1175e01 100644 --- a/Assets/02_Scripts/Communication/Dialog/DialogPlayer.cs +++ b/Assets/02_Scripts/Communication/Dialog/DialogPlayer.cs @@ -7,30 +7,31 @@ [RequireComponent(typeof(CharacterVoiceObject))] public class DialogPlayer : MonoBehaviour { + // 대화 후보 하나. 리스트에서 위에 있을수록 우선순위가 높다. + // (스토리 대화를 위에, 조건 없는 기본 잡담을 맨 아래에 두는 것을 권장) [System.Serializable] - public struct RegionGroup + public struct DialogEntry { - public string Region; // 영역 이름 (NPC마다 자유롭게 지정 — 그룹 이름과 무관) public DialogGroup Group; + public DialogCondition Condition; + + [Tooltip("켜면 완료 후에도 반복 재생 가능(잡담용). 끄면 1회성(스토리 대화)")] + public bool Repeatable; + + [Tooltip("이 대화를 처음 완료하면 메인 진행도 +N (필수 대화가 아니면 0)")] + [Min(0)] public int ProgressOnComplete; } - // 마지막 선택지 코드(LastChoiceCode)를 인자로 넘기는 UnityEvent (인스펙터 노출용 구체 타입) - [System.Serializable] - public class ChoiceCodeEvent : UnityEvent { } - - // 노드의 EventKey ↔ 그 노드 재생 시 호출할 이벤트. 인자로 LastChoiceCode가 전달됨. + // 노드의 EventKey ↔ 그 노드 재생 시 호출할 이벤트. [System.Serializable] public struct NodeEvent { public string Key; - public ChoiceCodeEvent Event; + public UnityEvent Event; } - [Tooltip("영역 이름 ↔ 그 영역에서 재생할 DialogGroup")] - [SerializeField] private List _regionGroups; - - [Header("Region")] - [SerializeField] private string _currentRegion; // 현재 영역 이름. DialogRegion 트리거가 갱신 + [Tooltip("이 NPC의 대화 후보들. 위에서부터 조건을 검사해 첫 번째로 만족하는 대화를 재생")] + [SerializeField] private List _dialogs = new(); [Header("Dialog HUD Placement")] // 씬에서 캐릭터 위치/주변(벽 등)에 맞춰 조절 [SerializeField] private float _hudChestHeight = 1.2f; // 화자 발 기준 가슴 높이 @@ -41,7 +42,7 @@ public struct NodeEvent [Tooltip("노드의 Event Key와 같은 Key가 그 노드 재생 시 호출됨")] [SerializeField] private List _nodeEvents = new(); - private Dictionary _regionMap; + private CharacterVoiceObject _voice; // 이 NPC의 캐릭터 정보 (호감도 조건 대상) private Animator _animator; private int _initialGestureHash; private int _initialExpressionHash; @@ -49,17 +50,9 @@ public struct NodeEvent private readonly Dictionary _originalRotations = new(); public bool IsPlaying { get; private set; } - // 마지막으로 고른 선택지 (인덱스/코드). DialogVariables에도 lastChoiceIndex / lastChoiceCode 로 저장됨 - public int LastChoiceIndex { get; private set; } = -1; - public string LastChoiceCode { get; private set; } - public event Action OnChoiceSelected; // (index, code) - private void Awake() { - _regionMap = new Dictionary(); - foreach (var e in _regionGroups) - if (e.Group != null) _regionMap[e.Region] = e.Group; - + _voice = GetComponent(); _animator = GetComponentInChildren(); if (_animator != null) @@ -74,38 +67,38 @@ private void Awake() } public async Awaitable Play() - { - var region = ResolveRegion(); - if (region != null) - await Play(region); - } - - // 현재 영역. 영역이 없거나 매칭 그룹이 없으면 리스트 첫 항목으로 폴백. - private string ResolveRegion() - { - if (!string.IsNullOrEmpty(_currentRegion) && _regionMap.ContainsKey(_currentRegion)) - return _currentRegion; - return _regionGroups.Count > 0 ? _regionGroups[0].Region : null; - } - - // 영역 전환 (DialogRegion 트리거가 호출). 다음 Play()부터 해당 영역 대화가 재생됨. - public void SetRegion(string region) => _currentRegion = region; - - public string CurrentRegion => _currentRegion; - - public async Awaitable Play(string region) { if (IsPlaying) return; - if (!_regionMap.TryGetValue(region, out var group)) + + int index = FindPlayableIndex(); + if (index < 0) { - Debug.LogWarning($"[DialogPlayer] 영역 대화 없음: {region}"); + Debug.Log($"[DialogPlayer] 조건에 맞는 대화가 없음: {name}"); return; } + await PlayEntry(_dialogs[index]); + } + // 리스트 순서 = 우선순위. 조건을 만족하고 (반복 가능하거나 아직 안 한) 첫 대화. + private int FindPlayableIndex() + { + for (int i = 0; i < _dialogs.Count; i++) + { + var entry = _dialogs[i]; + if (entry.Group == null) continue; + if (!entry.Repeatable && StoryState.IsDialogCompleted(entry.Group.name)) continue; + if (entry.Condition != null && !entry.Condition.IsMet(_voice.Character)) continue; + return i; + } + return -1; + } + + private async Awaitable PlayEntry(DialogEntry entry) + { IsPlaying = true; try { - var node = group.StartNode; + var node = entry.Group.StartNode; while (node != null) { await PlayNode(node); @@ -121,6 +114,15 @@ public async Awaitable Play(string region) node = node.Next; } } + + // 여기까지 왔으면 자연 종료(끝까지 재생) — 이때만 완료로 기록한다. + // (중간에 오브젝트 파괴 등으로 끊기면 예외로 빠져나가 기록되지 않음) + bool firstTime = StoryState.MarkDialogCompleted(entry.Group.name); + if (firstTime && entry.ProgressOnComplete > 0) + StoryState.MainProgress += entry.ProgressOnComplete; + StoryState.Save(); + + Debug.Log($"[DialogPlayer] 대화 종료: {entry.Group.name}"); } finally { @@ -130,8 +132,6 @@ public async Awaitable Play(string region) RestoreDefaultAnimations(); RestoreRotations(); } - - Debug.Log("[DialogPlayer] 대화 종료"); } private void RestoreDefaultAnimations() @@ -242,37 +242,31 @@ private void RaiseNodeEvent(string key) { if (string.IsNullOrEmpty(key)) return; foreach (var e in _nodeEvents) - if (e.Key == key) e.Event?.Invoke(LastChoiceCode); // 마지막 선택지 코드를 인자로 전달 + if (e.Key == key) e.Event?.Invoke(); } - // 선택 결과 기록: 인덱스/코드를 프로퍼티 + DialogVariables에 저장하고 이벤트 발행 + // 선택 기록: 선택지 Code를 StoryState에 영구 기록 (대화 활성화 조건 판정에 사용) private void RecordChoice(DialogNode node, int index) { string code = (node.Choices != null && index >= 0 && index < node.Choices.Count) ? node.Choices[index].Code : null; code = DialogVariables.Format(code); // {token} 치환 → 동적으로 생성된 코드 반영 - LastChoiceIndex = index; - LastChoiceCode = code; - - DialogVariables.Set("lastChoiceIndex", index.ToString()); if (!string.IsNullOrEmpty(code)) - DialogVariables.Set("lastChoiceCode", code); - - OnChoiceSelected?.Invoke(index, code); + StoryState.RecordChoice(code); } private async Awaitable WaitForChoice(DialogNode node) { //선택을 기다리는 함수 수정해서 사용할것 - + if (ChoiceHud.Instance == null) { Debug.LogWarning("[DialogPlayer] ChoiceHud 없음 — 0번 자동 선택"); return 0; } return await ChoiceHud.Instance.Show(node.ChoiceQuestion, node.Choices); - + } // 대화 진행 입력(OnDialogNext = VR B버튼) 한 번을 대기 diff --git a/Assets/02_Scripts/Communication/Dialog/DialogRegion.cs b/Assets/02_Scripts/Communication/Dialog/DialogRegion.cs deleted file mode 100644 index ab3bd11c..00000000 --- a/Assets/02_Scripts/Communication/Dialog/DialogRegion.cs +++ /dev/null @@ -1,27 +0,0 @@ -using UnityEngine; - -// 영역 트리거. 이 콜라이더(isTrigger) 안으로 NPC(DialogPlayer 보유)가 들어오면 -// 그 NPC의 현재 영역을 _regionKey로 전환한다. -// _regionKey는 해당 영역에서 재생할 DialogGroup의 이름과 일치해야 한다 (예: "Coast", "Hill"). -// -// 주의: OnTriggerEnter가 동작하려면 들어오는 쪽(또는 트리거 쪽)에 Rigidbody가 있어야 하고, -// 이 오브젝트의 Collider는 Is Trigger여야 한다. -[RequireComponent(typeof(Collider))] -public class DialogRegion : MonoBehaviour -{ - [SerializeField] private string _regionKey; // DialogGroup 이름과 일치 - - private void Reset() - { - // 컴포넌트 추가 시 편의상 트리거로 설정 - var col = GetComponent(); - if (col != null) col.isTrigger = true; - } - - private void OnTriggerEnter(Collider other) - { - var player = other.GetComponentInParent(); - if (player != null) - player.SetRegion(_regionKey); - } -} diff --git a/Assets/02_Scripts/Communication/Dialog/DialogRegion.cs.meta b/Assets/02_Scripts/Communication/Dialog/DialogRegion.cs.meta deleted file mode 100644 index f2f1a35e..00000000 --- a/Assets/02_Scripts/Communication/Dialog/DialogRegion.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 1fb6dce8c4da85e478d7da770f057cf3 \ No newline at end of file diff --git a/Assets/02_Scripts/Communication/Dialog/GraphTool/Editor/DialogGraphImporter.cs b/Assets/02_Scripts/Communication/Dialog/GraphTool/Editor/DialogGraphImporter.cs index 27e21f26..aa9e4f80 100644 --- a/Assets/02_Scripts/Communication/Dialog/GraphTool/Editor/DialogGraphImporter.cs +++ b/Assets/02_Scripts/Communication/Dialog/GraphTool/Editor/DialogGraphImporter.cs @@ -22,7 +22,7 @@ public override void OnImportAsset(AssetImportContext ctx) return; } - // 메인 에셋: DialogGroup (이름은 파일명 기준 — DialogPlayer가 이름으로 조회) + // 메인 에셋: DialogGroup (이름은 파일명 기준 — StoryState 대화 이력의 키로 쓰임) var groupName = Path.GetFileNameWithoutExtension(ctx.assetPath); var group = ScriptableObject.CreateInstance(); group.name = groupName; diff --git a/Assets/02_Scripts/Managers/StoryState.cs b/Assets/02_Scripts/Managers/StoryState.cs new file mode 100644 index 00000000..7b01eda8 --- /dev/null +++ b/Assets/02_Scripts/Managers/StoryState.cs @@ -0,0 +1,135 @@ +using System; +using System.Collections.Generic; +using System.IO; +using UnityEngine; + +// 이야기 진행 상태의 중앙 저장소 (메인 진행도 / 호감도 / 대화 이력 / 선택 이력). +// DialogCondition이 대화 활성화 판정의 근거로 조회하고, DialogPlayer가 기록한다. +// +// 저장: Save()가 JSON 파일로 기록한다. DialogPlayer가 대화 완료 시마다 호출한다. +// 로드: 플레이 시작 시 항상 빈 상태로 시작한다 (테스트 반복이 꼬이지 않게). +// 이어하기를 만들 때 타이틀 화면 등에서 Load()를 호출하면 된다. +public static class StoryState +{ + private static int _mainProgress; + private static readonly Dictionary _affection = new(); + private static readonly HashSet _completedDialogs = new(); + private static readonly HashSet _chosenCodes = new(); + + // 상태가 바뀔 때마다 발행 (호감도 게이지 등 UI 갱신용) + public static event Action Changed; + + // ── 메인 진행도 ────────────────────────────────────────────── + public static int MainProgress + { + get => _mainProgress; + set + { + if (_mainProgress == value) return; + _mainProgress = value; + Changed?.Invoke(); + } + } + + // ── 호감도 ────────────────────────────────────────────────── + public static int GetAffection(CharacterData character) + => character != null && _affection.TryGetValue(IdOf(character), out var v) ? v : 0; + + public static void AddAffection(CharacterData character, int delta) + { + if (character == null || delta == 0) return; + _affection[IdOf(character)] = GetAffection(character) + delta; + Changed?.Invoke(); + } + + // CharacterData의 Id를 키로 사용 (비어있으면 에셋 이름) + private static string IdOf(CharacterData c) => string.IsNullOrEmpty(c.Id) ? c.name : c.Id; + + // ── 대화 이력 ──────────────────────────────────────────────── + public static bool IsDialogCompleted(string groupName) => _completedDialogs.Contains(groupName); + + // 완료 기록. 처음 완료한 경우에만 true (진행도 보상 중복 방지용) + public static bool MarkDialogCompleted(string groupName) + { + if (string.IsNullOrEmpty(groupName) || !_completedDialogs.Add(groupName)) + return false; + Changed?.Invoke(); + return true; + } + + // ── 선택 이력 ──────────────────────────────────────────────── + public static bool HasChosen(string code) => _chosenCodes.Contains(code); + + public static void RecordChoice(string code) + { + if (string.IsNullOrEmpty(code) || !_chosenCodes.Add(code)) return; + Changed?.Invoke(); + } + + // ── 저장 / 로드 ────────────────────────────────────────────── + [Serializable] + private class SaveData + { + public int MainProgress; + public List AffectionIds = new(); + public List AffectionValues = new(); + public List CompletedDialogs = new(); + public List ChosenCodes = new(); + } + + private static string SavePath => Path.Combine(Application.persistentDataPath, "story_state.json"); + + public static void Save() + { + var data = new SaveData { MainProgress = _mainProgress }; + foreach (var kvp in _affection) + { + data.AffectionIds.Add(kvp.Key); + data.AffectionValues.Add(kvp.Value); + } + data.CompletedDialogs.AddRange(_completedDialogs); + data.ChosenCodes.AddRange(_chosenCodes); + File.WriteAllText(SavePath, JsonUtility.ToJson(data, prettyPrint: true)); + } + + // 저장 파일이 있으면 불러온다. 성공 여부 반환. + public static bool Load() + { + if (!File.Exists(SavePath)) return false; + + var data = JsonUtility.FromJson(File.ReadAllText(SavePath)); + if (data == null) return false; + + _mainProgress = data.MainProgress; + _affection.Clear(); + for (int i = 0; i < data.AffectionIds.Count && i < data.AffectionValues.Count; i++) + _affection[data.AffectionIds[i]] = data.AffectionValues[i]; + _completedDialogs.Clear(); + _completedDialogs.UnionWith(data.CompletedDialogs); + _chosenCodes.Clear(); + _chosenCodes.UnionWith(data.ChosenCodes); + Changed?.Invoke(); + return true; + } + + // 새 게임용 초기화 (저장 파일은 다음 Save 때 덮어써짐) + public static void ResetAll() + { + _mainProgress = 0; + _affection.Clear(); + _completedDialogs.Clear(); + _chosenCodes.Clear(); + Changed?.Invoke(); + } + + // 플레이 시작마다 초기화 (Enter Play Mode에서 도메인 리로드를 꺼도 이전 값이 안 남게) + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)] + private static void ResetOnPlay() + { + _mainProgress = 0; + _affection.Clear(); + _completedDialogs.Clear(); + _chosenCodes.Clear(); + Changed = null; + } +} diff --git a/Assets/02_Scripts/Managers/StoryState.cs.meta b/Assets/02_Scripts/Managers/StoryState.cs.meta new file mode 100644 index 00000000..666810db --- /dev/null +++ b/Assets/02_Scripts/Managers/StoryState.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: d47259c7403ae7e42b37a411170bc21c \ No newline at end of file diff --git a/Assets/XR/Settings/OpenXRPackageSettings.asset b/Assets/XR/Settings/OpenXRPackageSettings.asset index bd7ca03e..b6592f88 100644 --- a/Assets/XR/Settings/OpenXRPackageSettings.asset +++ b/Assets/XR/Settings/OpenXRPackageSettings.asset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a41385b0b14add4801fb13bd100d78b9a0c638559cd995fca0f8d23507a48730 -size 108094 +oid sha256:770cdc52ceb4745ce37ca6768e686ccb7eae92c49e54098dda3002dc7640c5ac +size 108096