Merge branch 'main' of https://www.nakjungit.site/sharedacc520k/WhaleAdventure_VR_Diet
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c60ef9a2426e27f41addd32bf4fda47c
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Binary file not shown.
BIN
Assets/09_UI/talk/menu_panel_REAL_transparent_cropped.png
LFS
Normal file
BIN
Assets/09_UI/talk/menu_panel_REAL_transparent_cropped.png
LFS
Normal file
Binary file not shown.
130
Assets/09_UI/talk/menu_panel_REAL_transparent_cropped.png.meta
Normal file
130
Assets/09_UI/talk/menu_panel_REAL_transparent_cropped.png.meta
Normal file
@@ -0,0 +1,130 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0e533587a03b84940b08e956a8615adf
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
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: 0
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 1
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 8
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 0
|
||||
swizzle: 50462976
|
||||
cookieLightType: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 4
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 4
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 4
|
||||
buildTarget: 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
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
customData:
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID: 5e97eb03825dee720800000000000000
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
spriteCustomMetadata:
|
||||
entries: []
|
||||
nameFileIdTable: {}
|
||||
mipmapLimitGroupName:
|
||||
pSDRemoveMatte: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Assets/09_UI/talk/pinocchio_title_banner_REAL_transparent_cropped.png
LFS
Normal file
BIN
Assets/09_UI/talk/pinocchio_title_banner_REAL_transparent_cropped.png
LFS
Normal file
Binary file not shown.
@@ -0,0 +1,130 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e947b9df5e461fd48a18b65eae417346
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
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: 0
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 1
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 8
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 0
|
||||
swizzle: 50462976
|
||||
cookieLightType: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 4
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 4
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 4
|
||||
buildTarget: 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
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
customData:
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID: 5e97eb03825dee720800000000000000
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
spriteCustomMetadata:
|
||||
entries: []
|
||||
nameFileIdTable: {}
|
||||
mipmapLimitGroupName:
|
||||
pSDRemoveMatte: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Assets/09_UI/talk/wood_button_plain_REAL_transparent.png
LFS
Normal file
BIN
Assets/09_UI/talk/wood_button_plain_REAL_transparent.png
LFS
Normal file
Binary file not shown.
130
Assets/09_UI/talk/wood_button_plain_REAL_transparent.png.meta
Normal file
130
Assets/09_UI/talk/wood_button_plain_REAL_transparent.png.meta
Normal file
@@ -0,0 +1,130 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4e0c1ffb4b7796341b9614ba8650b534
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
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: 0
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 1
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 8
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 0
|
||||
swizzle: 50462976
|
||||
cookieLightType: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 4
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 4
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 4
|
||||
buildTarget: 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
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
customData:
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID: 5e97eb03825dee720800000000000000
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
spriteCustomMetadata:
|
||||
entries: []
|
||||
nameFileIdTable: {}
|
||||
mipmapLimitGroupName:
|
||||
pSDRemoveMatte: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@@ -12,6 +12,23 @@ public class FishingItemIconData
|
||||
[TextArea] public string hintText;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reel-only fishing UI.
|
||||
///
|
||||
/// Removed from the old mixed version:
|
||||
/// - circular timing gauge references
|
||||
/// - pointer / success zone rendering
|
||||
/// - Perfect / Good / Miss result type helpers
|
||||
/// - debug catch button handling
|
||||
///
|
||||
/// Keeps:
|
||||
/// - reel progress gauge
|
||||
/// - line length text
|
||||
/// - pond cleanup progress
|
||||
/// - caught item panel
|
||||
/// - final result panel
|
||||
/// - slot highlight / simple UI effects
|
||||
/// </summary>
|
||||
public class FishingGaugeUI : MonoBehaviour
|
||||
{
|
||||
[Header("Auto Bind")]
|
||||
@@ -25,7 +42,6 @@ public class FishingGaugeUI : MonoBehaviour
|
||||
[SerializeField] private GameObject controllerGuidePanel;
|
||||
[SerializeField] private GameObject memoryPieceNoticePanel;
|
||||
[SerializeField] private GameObject finalResultPanel;
|
||||
[SerializeField] private GameObject catchButton;
|
||||
|
||||
[Header("Top Texts")]
|
||||
[SerializeField] private TMP_Text titleText;
|
||||
@@ -34,8 +50,6 @@ public class FishingGaugeUI : MonoBehaviour
|
||||
|
||||
[Header("Counter Panel Texts")]
|
||||
[SerializeField] private TMP_Text catchCountText;
|
||||
[SerializeField] private TMP_Text successText;
|
||||
[SerializeField] private TMP_Text failText;
|
||||
[SerializeField] private TMP_Text cleanupProgressText;
|
||||
|
||||
[Header("Cleanup Gauge")]
|
||||
@@ -43,12 +57,6 @@ public class FishingGaugeUI : MonoBehaviour
|
||||
[SerializeField] private Image cleanupGaugeFill;
|
||||
[SerializeField] private TMP_Text cleanupPercentText;
|
||||
|
||||
[Header("Gauge UI")]
|
||||
[SerializeField] private RectTransform gaugeGroupRect;
|
||||
[SerializeField] private RectTransform pointerPivot;
|
||||
[Tooltip("SuccessZone. Image Type = Filled, Fill Method = Radial 360")]
|
||||
[SerializeField] private Image successZone;
|
||||
|
||||
[Header("Simple Reel UI")]
|
||||
[Tooltip("릴 감기 진행도 게이지 루트입니다. 없으면 텍스트만 업데이트됩니다.")]
|
||||
[SerializeField] private GameObject reelProgressGaugeRoot;
|
||||
@@ -63,7 +71,7 @@ public class FishingGaugeUI : MonoBehaviour
|
||||
[SerializeField] private string simpleReelIdleText = "릴 손잡이를 잡고 돌려라";
|
||||
[SerializeField] private string simpleReelReelingText = "좋다, 계속 감아라!";
|
||||
|
||||
[Header("Round Result UI")]
|
||||
[Header("Result UI")]
|
||||
[SerializeField] private TMP_Text resultText;
|
||||
|
||||
[Header("Caught Item UI")]
|
||||
@@ -71,7 +79,7 @@ public class FishingGaugeUI : MonoBehaviour
|
||||
[SerializeField] private TMP_Text caughtItemText;
|
||||
[SerializeField] private TMP_Text itemHintText;
|
||||
|
||||
[Header("Item Slot UI - Fish")]
|
||||
[Header("Item Slot UI - Fish / Other")]
|
||||
[SerializeField] private GameObject fishSlot;
|
||||
[SerializeField] private Image fishSlotBackground;
|
||||
[SerializeField] private Image fishIcon;
|
||||
@@ -116,10 +124,6 @@ public class FishingGaugeUI : MonoBehaviour
|
||||
[SerializeField] private float noticeShowTime = 2.2f;
|
||||
[SerializeField] private float finalPanelPopScale = 1.08f;
|
||||
[SerializeField] private float finalPanelPopTime = 0.22f;
|
||||
[SerializeField] private float gaugePopScale = 1.035f;
|
||||
[SerializeField] private float gaugePopTime = 0.16f;
|
||||
[SerializeField] private float missShakeStrength = 12f;
|
||||
[SerializeField] private float missShakeTime = 0.18f;
|
||||
|
||||
[Header("Slot Visual Settings")]
|
||||
[Range(0f, 1f)] [SerializeField] private float emptyIconAlpha = 0.35f;
|
||||
@@ -130,22 +134,14 @@ public class FishingGaugeUI : MonoBehaviour
|
||||
[SerializeField] private float slotHighlightScale = 1.08f;
|
||||
[SerializeField] private Color slotHighlightColor = new Color(0.35f, 1f, 0.9f, 1f);
|
||||
|
||||
[Header("Feedback UI")]
|
||||
[SerializeField] private Image feedbackFlash;
|
||||
[Range(0f, 1f)] [SerializeField] private float flashMaxAlpha = 0.25f;
|
||||
[SerializeField] private float flashTime = 0.16f;
|
||||
|
||||
[Header("Notice UI")]
|
||||
[SerializeField] private TMP_Text noticeText;
|
||||
|
||||
[Header("Final Result UI")]
|
||||
[SerializeField] private TMP_Text finalResultText;
|
||||
[SerializeField] private bool hideCounterOnFinalResult = true;
|
||||
[SerializeField] private bool hideCaughtItemOnFinalResult = true;
|
||||
[SerializeField] private bool hideGuideOnFinalResult = true;
|
||||
|
||||
[Header("Final Result Only Mode")]
|
||||
[Tooltip("게임 클리어/실패 최종 결과가 뜰 때 진행 UI를 전부 숨기고 FinalResultPanel만 보이게 합니다.")]
|
||||
[Tooltip("게임 클리어 최종 결과가 뜰 때 진행 UI를 전부 숨기고 FinalResultPanel만 보이게 합니다.")]
|
||||
[SerializeField] private bool showOnlyFinalResult = true;
|
||||
|
||||
[Tooltip("FinalResultPanel을 숨길 때 진행 UI를 다시 켤지 결정합니다. 클리어 후 UI를 완전히 닫는 구조면 Off로 두세요.")]
|
||||
@@ -157,18 +153,11 @@ public class FishingGaugeUI : MonoBehaviour
|
||||
[Tooltip("CleanupGauge 루트 오브젝트입니다.")]
|
||||
[SerializeField] private GameObject cleanupGaugeRoot;
|
||||
|
||||
[Tooltip("GaugeGroup 루트 오브젝트입니다.")]
|
||||
[SerializeField] private GameObject gaugeGroupRoot;
|
||||
|
||||
[Header("Item Icons")]
|
||||
[SerializeField] private FishingItemIconData[] itemIcons;
|
||||
|
||||
[Header("Zone Visual Correction")]
|
||||
[SerializeField] private float zoneVisualOffset = 0f;
|
||||
|
||||
[Header("Guide / Debug UI")]
|
||||
[Header("Guide UI")]
|
||||
[SerializeField] private bool showControllerGuideOnInitialize = true;
|
||||
[SerializeField] private bool showCatchButtonOnInitialize = true;
|
||||
|
||||
[Header("Text Settings")]
|
||||
[SerializeField] private string titleDefaultText = "기묘한 낚시터";
|
||||
@@ -176,16 +165,33 @@ public class FishingGaugeUI : MonoBehaviour
|
||||
[SerializeField] private string objectiveCleanText = "기억의 조각을 찾아보자";
|
||||
[SerializeField] private string objectiveClearText = "기억의 조각을 획득했다";
|
||||
|
||||
[Header("Result Colors")]
|
||||
[SerializeField] private Color perfectColor = new Color(1f, 0.85f, 0.25f, 1f);
|
||||
[SerializeField] private Color goodColor = new Color(0.25f, 1f, 0.8f, 1f);
|
||||
[SerializeField] private Color missColor = new Color(1f, 0.3f, 0.2f, 1f);
|
||||
[SerializeField] private Color defaultResultColor = Color.white;
|
||||
|
||||
[Header("VR Follow")]
|
||||
[Tooltip("켜면 FishingCanvas가 플레이어 머리 앞을 따라갑니다.")]
|
||||
[SerializeField] private bool followPlayerHead = true;
|
||||
|
||||
[Tooltip("비워두면 Camera.main을 자동으로 사용합니다. XR Origin의 Main Camera를 넣는 것을 추천합니다.")]
|
||||
[SerializeField] private Transform playerHead;
|
||||
|
||||
[Tooltip("실제로 이동시킬 UI 루트입니다. 비워두면 이 FishingGaugeUI가 붙은 오브젝트를 이동합니다.")]
|
||||
[SerializeField] private Transform followRoot;
|
||||
|
||||
[SerializeField] private float followDistance = 1.6f;
|
||||
[SerializeField] private float followHeightOffset = -0.15f;
|
||||
[SerializeField] private float followSideOffset = 0f;
|
||||
|
||||
[Tooltip("고개를 위아래로 숙여도 UI는 수평으로 유지합니다. VR에서는 켜는 것을 추천합니다.")]
|
||||
[SerializeField] private bool followYawOnly = true;
|
||||
|
||||
[SerializeField] private float followPositionSpeed = 8f;
|
||||
[SerializeField] private float followRotationSpeed = 10f;
|
||||
|
||||
[Tooltip("UI가 카메라와 같은 방향을 바라보게 합니다. 글자가 뒤집히면 이 값을 바꾸거나 Canvas Y Rotation을 180도로 돌리세요.")]
|
||||
[SerializeField] private bool faceSameDirectionAsHead = true;
|
||||
|
||||
private Coroutine resultRoutine;
|
||||
private Coroutine caughtItemRoutine;
|
||||
private Coroutine noticeRoutine;
|
||||
private bool initialized;
|
||||
private float lastCleanupFill = -1f;
|
||||
|
||||
private void Awake()
|
||||
@@ -202,6 +208,11 @@ private void OnDisable()
|
||||
StopRunningRoutines();
|
||||
}
|
||||
|
||||
private void LateUpdate()
|
||||
{
|
||||
UpdateFollowPlayerHead();
|
||||
}
|
||||
|
||||
private void OnValidate()
|
||||
{
|
||||
cleanupFillTime = Mathf.Max(0f, cleanupFillTime);
|
||||
@@ -215,18 +226,78 @@ private void OnValidate()
|
||||
noticeShowTime = Mathf.Max(0f, noticeShowTime);
|
||||
finalPanelPopScale = Mathf.Max(1f, finalPanelPopScale);
|
||||
finalPanelPopTime = Mathf.Max(0.01f, finalPanelPopTime);
|
||||
gaugePopScale = Mathf.Max(1f, gaugePopScale);
|
||||
gaugePopTime = Mathf.Max(0.01f, gaugePopTime);
|
||||
missShakeStrength = Mathf.Max(0f, missShakeStrength);
|
||||
missShakeTime = Mathf.Max(0.01f, missShakeTime);
|
||||
slotHighlightTime = Mathf.Max(0.01f, slotHighlightTime);
|
||||
slotHighlightScale = Mathf.Max(1f, slotHighlightScale);
|
||||
flashMaxAlpha = Mathf.Clamp01(flashMaxAlpha);
|
||||
flashTime = Mathf.Max(0.01f, flashTime);
|
||||
emptyIconAlpha = Mathf.Clamp01(emptyIconAlpha);
|
||||
filledIconAlpha = Mathf.Clamp01(filledIconAlpha);
|
||||
emptySlotAlpha = Mathf.Clamp01(emptySlotAlpha);
|
||||
filledSlotAlpha = Mathf.Clamp01(filledSlotAlpha);
|
||||
followDistance = Mathf.Max(0.2f, followDistance);
|
||||
followPositionSpeed = Mathf.Max(0.01f, followPositionSpeed);
|
||||
followRotationSpeed = Mathf.Max(0.01f, followRotationSpeed);
|
||||
}
|
||||
|
||||
|
||||
private void UpdateFollowPlayerHead()
|
||||
{
|
||||
if (!followPlayerHead)
|
||||
return;
|
||||
|
||||
Transform root = followRoot != null ? followRoot : transform;
|
||||
|
||||
if (playerHead == null)
|
||||
{
|
||||
Camera mainCamera = Camera.main;
|
||||
if (mainCamera == null)
|
||||
return;
|
||||
|
||||
playerHead = mainCamera.transform;
|
||||
}
|
||||
|
||||
Vector3 forward = playerHead.forward;
|
||||
Vector3 right = playerHead.right;
|
||||
|
||||
if (followYawOnly)
|
||||
{
|
||||
forward.y = 0f;
|
||||
|
||||
if (forward.sqrMagnitude < 0.0001f)
|
||||
forward = root.forward;
|
||||
|
||||
forward.Normalize();
|
||||
right = Vector3.Cross(Vector3.up, forward).normalized;
|
||||
}
|
||||
|
||||
Vector3 targetPosition =
|
||||
playerHead.position +
|
||||
forward * followDistance +
|
||||
Vector3.up * followHeightOffset +
|
||||
right * followSideOffset;
|
||||
|
||||
float positionT = 1f - Mathf.Exp(-followPositionSpeed * Time.deltaTime);
|
||||
root.position = Vector3.Lerp(root.position, targetPosition, positionT);
|
||||
|
||||
Quaternion targetRotation;
|
||||
|
||||
if (faceSameDirectionAsHead)
|
||||
{
|
||||
targetRotation = Quaternion.LookRotation(forward, Vector3.up);
|
||||
}
|
||||
else
|
||||
{
|
||||
Vector3 lookDirection = root.position - playerHead.position;
|
||||
|
||||
if (followYawOnly)
|
||||
lookDirection.y = 0f;
|
||||
|
||||
if (lookDirection.sqrMagnitude < 0.0001f)
|
||||
lookDirection = forward;
|
||||
|
||||
targetRotation = Quaternion.LookRotation(lookDirection.normalized, Vector3.up);
|
||||
}
|
||||
|
||||
float rotationT = 1f - Mathf.Exp(-followRotationSpeed * Time.deltaTime);
|
||||
root.rotation = Quaternion.Slerp(root.rotation, targetRotation, rotationT);
|
||||
}
|
||||
|
||||
private void EnsureEffectReferences()
|
||||
@@ -253,13 +324,12 @@ private void EnsureEffectReferences()
|
||||
finalResultCanvasGroup = effects.EnsureCanvasGroup(finalResultPanel);
|
||||
}
|
||||
|
||||
[ContextMenu("Auto Bind UI References")]
|
||||
[ContextMenu("Auto Bind Reel UI References")]
|
||||
public void AutoBindMissingReferences()
|
||||
{
|
||||
if (backgroundPanel == null) backgroundPanel = FindGameObject("BackgroundPanel");
|
||||
if (gameplayBackgroundRoot == null) gameplayBackgroundRoot = backgroundPanel;
|
||||
if (cleanupGaugeRoot == null) cleanupGaugeRoot = FindGameObject("CleanupGauge");
|
||||
if (gaugeGroupRoot == null) gaugeGroupRoot = FindGameObject("GaugeGroup");
|
||||
|
||||
if (counterPanel == null) counterPanel = FindGameObject("CounterPanel");
|
||||
if (itemSlotPanel == null) itemSlotPanel = FindGameObject("ItemSlotPanel");
|
||||
@@ -267,23 +337,17 @@ public void AutoBindMissingReferences()
|
||||
if (controllerGuidePanel == null) controllerGuidePanel = FindGameObject("ControllerGuidePanel");
|
||||
if (memoryPieceNoticePanel == null) memoryPieceNoticePanel = FindGameObject("MemoryPieceNoticePanel");
|
||||
if (finalResultPanel == null) finalResultPanel = FindGameObject("FinalResultPanel");
|
||||
if (catchButton == null) catchButton = FindGameObject("CatchButton", "DebugCatchButton");
|
||||
|
||||
if (titleText == null) titleText = FindComponentByName<TMP_Text>("TitleText");
|
||||
if (pondStateText == null) pondStateText = FindComponentByName<TMP_Text>("PondStateText");
|
||||
if (objectiveText == null) objectiveText = FindComponentByName<TMP_Text>("ObjectiveText");
|
||||
|
||||
if (catchCountText == null) catchCountText = FindComponentByName<TMP_Text>("CatchCountText", "SuccessText");
|
||||
if (successText == null) successText = FindComponentByName<TMP_Text>("SuccessText");
|
||||
if (failText == null) failText = FindComponentByName<TMP_Text>("FailText");
|
||||
if (cleanupProgressText == null) cleanupProgressText = FindComponentByName<TMP_Text>("CleanupProgressText");
|
||||
|
||||
if (cleanupGaugeFill == null) cleanupGaugeFill = FindComponentByName<Image>("CleanupGaugeFill", "CleanupGaugeFillImage");
|
||||
if (cleanupPercentText == null) cleanupPercentText = FindComponentByName<TMP_Text>("CleanupPercentText", "CleanupGaugePercentText");
|
||||
|
||||
if (gaugeGroupRect == null) gaugeGroupRect = FindComponentByName<RectTransform>("GaugeGroup");
|
||||
if (pointerPivot == null) pointerPivot = FindComponentByName<RectTransform>("PointerPivot");
|
||||
if (successZone == null) successZone = FindComponentByName<Image>("SuccessZone");
|
||||
if (reelProgressGaugeRoot == null) reelProgressGaugeRoot = FindGameObject("ReelProgressGauge", "ReelProgressGroup", "ReelFightProgressGauge");
|
||||
if (reelProgressGaugeFill == null) reelProgressGaugeFill = FindComponentByName<Image>("ReelProgressGaugeFill", "ReelProgressFill", "ReelFightProgressFill");
|
||||
if (lineLengthText == null) lineLengthText = FindComponentByName<TMP_Text>("LineLengthText", "Line Length Text", "LineText");
|
||||
@@ -313,7 +377,6 @@ public void AutoBindMissingReferences()
|
||||
if (compassIcon == null) compassIcon = FindComponentByName<Image>("CompassIcon", "Compass Icon");
|
||||
if (compassCountText == null) compassCountText = FindComponentByName<TMP_Text>("CompassCountText", "Compass CountText");
|
||||
|
||||
if (feedbackFlash == null) feedbackFlash = FindComponentByName<Image>("FeedbackFlash");
|
||||
if (finalResultText == null) finalResultText = FindComponentByName<TMP_Text>("FinalResultText");
|
||||
if (noticeText == null) noticeText = FindComponentByName<TMP_Text>("NoticeText");
|
||||
|
||||
@@ -330,166 +393,88 @@ public void InitializeFishingUI()
|
||||
|
||||
SetGameplayUIVisible(true);
|
||||
|
||||
initialized = false;
|
||||
|
||||
if (titleText != null && !string.IsNullOrWhiteSpace(titleDefaultText))
|
||||
titleText.text = titleDefaultText;
|
||||
|
||||
ShowCounter();
|
||||
SetItemSlotPanelVisible(true);
|
||||
SetControllerGuideVisible(showControllerGuideOnInitialize, true);
|
||||
SetCatchButtonVisible(showCatchButtonOnInitialize);
|
||||
HideRoundResult();
|
||||
HideCaughtItem(true);
|
||||
HideNotice(true);
|
||||
HideFinalResult(true, true);
|
||||
SetFeedbackFlashVisible(false, Color.clear);
|
||||
UpdateInventoryUI(0, 0, 0, 0);
|
||||
HideFinalResult(false, true);
|
||||
UpdateInventoryUI(0, 0, 0);
|
||||
lastCleanupFill = -1f;
|
||||
SetCleanupFill(0f, true);
|
||||
SetSimpleReelUIVisible(false);
|
||||
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
private void StopRunningRoutines()
|
||||
{
|
||||
if (resultRoutine != null) StopCoroutine(resultRoutine);
|
||||
if (caughtItemRoutine != null) StopCoroutine(caughtItemRoutine);
|
||||
if (noticeRoutine != null) StopCoroutine(noticeRoutine);
|
||||
if (resultRoutine != null)
|
||||
{
|
||||
StopCoroutine(resultRoutine);
|
||||
resultRoutine = null;
|
||||
}
|
||||
|
||||
resultRoutine = null;
|
||||
caughtItemRoutine = null;
|
||||
noticeRoutine = null;
|
||||
if (caughtItemRoutine != null)
|
||||
{
|
||||
StopCoroutine(caughtItemRoutine);
|
||||
caughtItemRoutine = null;
|
||||
}
|
||||
|
||||
if (effects != null)
|
||||
effects.StopAllEffects();
|
||||
}
|
||||
|
||||
public void SetPointerRotation(float angle)
|
||||
{
|
||||
if (pointerPivot == null)
|
||||
return;
|
||||
|
||||
pointerPivot.localEulerAngles = new Vector3(0f, 0f, -angle);
|
||||
}
|
||||
|
||||
public void SetZone(float centerAngle, float size)
|
||||
{
|
||||
SetZoneSize(size);
|
||||
SetZoneRotation(centerAngle, size);
|
||||
}
|
||||
|
||||
public void SetZoneSize(float size)
|
||||
{
|
||||
if (successZone == null)
|
||||
return;
|
||||
|
||||
successZone.fillAmount = Mathf.Clamp01(size / 360f);
|
||||
}
|
||||
|
||||
public void SetZoneRotation(float centerAngle, float size)
|
||||
{
|
||||
if (successZone == null)
|
||||
return;
|
||||
|
||||
float startAngle = centerAngle - size * 0.5f + zoneVisualOffset;
|
||||
successZone.rectTransform.localEulerAngles = new Vector3(0f, 0f, -startAngle);
|
||||
}
|
||||
|
||||
public void UpdateCounter(int success, int successTarget, int fail, int failTarget)
|
||||
{
|
||||
ShowCounter();
|
||||
|
||||
if (catchCountText != null)
|
||||
catchCountText.text = $"낚기 {success}/{successTarget}";
|
||||
|
||||
if (successText != null && successText != catchCountText)
|
||||
successText.text = $"낚기 {success}/{successTarget}";
|
||||
|
||||
if (failText != null)
|
||||
failText.text = $"실패 {fail}/{failTarget}";
|
||||
}
|
||||
|
||||
public void SetTimingGaugeVisible(bool visible)
|
||||
{
|
||||
if (gaugeGroupRoot != null)
|
||||
gaugeGroupRoot.SetActive(visible);
|
||||
else if (gaugeGroupRect != null)
|
||||
gaugeGroupRect.gameObject.SetActive(visible);
|
||||
if (noticeRoutine != null)
|
||||
{
|
||||
StopCoroutine(noticeRoutine);
|
||||
noticeRoutine = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetSimpleReelUIVisible(bool visible)
|
||||
{
|
||||
if (reelProgressGaugeRoot != null)
|
||||
reelProgressGaugeRoot.SetActive(visible);
|
||||
|
||||
if (lineLengthText != null)
|
||||
lineLengthText.gameObject.SetActive(visible);
|
||||
}
|
||||
|
||||
public void UpdateSimpleReelUI(float progress, float lineLength, bool isReeling)
|
||||
{
|
||||
ShowCounter();
|
||||
|
||||
progress = Mathf.Clamp01(progress);
|
||||
lineLength = Mathf.Max(0f, lineLength);
|
||||
int progressPercent = Mathf.RoundToInt(progress * 100f);
|
||||
|
||||
if (catchCountText != null)
|
||||
catchCountText.text = $"끌어올리기 {progressPercent}%";
|
||||
|
||||
if (successText != null && successText != catchCountText)
|
||||
successText.text = $"끌어올리기 {progressPercent}%";
|
||||
|
||||
if (failText != null)
|
||||
failText.text = $"줄 길이 {lineLength:0.0}m";
|
||||
|
||||
if (lineLengthText != null)
|
||||
lineLengthText.text = $"줄 길이 {lineLength:0.0}m";
|
||||
|
||||
if (reelProgressGaugeFill != null)
|
||||
reelProgressGaugeFill.fillAmount = progress;
|
||||
|
||||
if (lineLengthText != null)
|
||||
{
|
||||
string stateText = isReeling ? simpleReelReelingText : simpleReelIdleText;
|
||||
lineLengthText.text = $"줄 길이 {lineLength:0.00}m\n진행도 {Mathf.RoundToInt(progress * 100f)}%\n{stateText}";
|
||||
}
|
||||
|
||||
if (objectiveText != null && !string.IsNullOrWhiteSpace(simpleReelObjectiveText))
|
||||
objectiveText.text = simpleReelObjectiveText;
|
||||
|
||||
if (resultText != null && resultText.gameObject.activeSelf)
|
||||
{
|
||||
if (isReeling && progress < 1f)
|
||||
resultText.text = simpleReelReelingText;
|
||||
else if (progress < 1f && !string.IsNullOrWhiteSpace(simpleReelIdleText))
|
||||
resultText.text = simpleReelIdleText;
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateFishingProgress(int cleanupItemCount, int cleanupTarget, bool pondCleaned, bool memoryPieceCollected, int totalCaughtItems)
|
||||
{
|
||||
cleanupTarget = Mathf.Max(1, cleanupTarget);
|
||||
int clampedCleanupCount = Mathf.Clamp(cleanupItemCount, 0, cleanupTarget);
|
||||
float progress = Mathf.Clamp01((float)clampedCleanupCount / cleanupTarget);
|
||||
float progress = Mathf.Clamp01((float)cleanupItemCount / cleanupTarget);
|
||||
|
||||
if (catchCountText != null)
|
||||
catchCountText.text = $"획득 {totalCaughtItems}";
|
||||
|
||||
if (cleanupProgressText != null)
|
||||
{
|
||||
cleanupProgressText.text = memoryPieceCollected
|
||||
? $"정화 완료 {cleanupTarget}/{cleanupTarget}"
|
||||
: $"쓰레기 수거 {clampedCleanupCount}/{cleanupTarget}";
|
||||
}
|
||||
|
||||
SetCleanupFill(progress, !initialized || !animateCleanupGauge);
|
||||
|
||||
if (cleanupPercentText != null)
|
||||
cleanupPercentText.text = $"{Mathf.RoundToInt(progress * 100f)}%";
|
||||
cleanupProgressText.text = pondCleaned ? "연못 정화 완료" : $"정화 {cleanupItemCount}/{cleanupTarget}";
|
||||
|
||||
if (pondStateText != null)
|
||||
{
|
||||
if (memoryPieceCollected)
|
||||
pondStateText.text = "기억의 조각 획득";
|
||||
pondStateText.text = "기억의 조각을 찾았다";
|
||||
else if (pondCleaned)
|
||||
pondStateText.text = "연못이 맑아졌다!";
|
||||
else if (progress >= 0.66f)
|
||||
pondStateText.text = "연못 상태: 거의 맑아짐";
|
||||
else if (progress >= 0.33f)
|
||||
pondStateText.text = "연못 상태: 조금 맑아짐";
|
||||
pondStateText.text = "맑아진 연못";
|
||||
else
|
||||
pondStateText.text = "연못 상태: 탁함";
|
||||
pondStateText.text = "오염된 연못";
|
||||
}
|
||||
|
||||
if (objectiveText != null)
|
||||
@@ -501,94 +486,95 @@ public void UpdateFishingProgress(int cleanupItemCount, int cleanupTarget, bool
|
||||
else
|
||||
objectiveText.text = objectiveDirtyText;
|
||||
}
|
||||
|
||||
SetCleanupFill(progress, false);
|
||||
}
|
||||
|
||||
private void SetCleanupFill(float progress, bool instant)
|
||||
{
|
||||
if (cleanupGaugeFill == null)
|
||||
return;
|
||||
|
||||
progress = Mathf.Clamp01(progress);
|
||||
|
||||
if (!instant && Mathf.Abs(lastCleanupFill - progress) < 0.001f)
|
||||
return;
|
||||
if (cleanupGaugeFill != null)
|
||||
{
|
||||
if (instant || !animateCleanupGauge || effects == null || lastCleanupFill < 0f)
|
||||
cleanupGaugeFill.fillAmount = progress;
|
||||
else if (!Mathf.Approximately(lastCleanupFill, progress))
|
||||
effects.FillImage(cleanupGaugeFill, progress, cleanupFillTime);
|
||||
}
|
||||
|
||||
if (cleanupPercentText != null)
|
||||
cleanupPercentText.text = $"{Mathf.RoundToInt(progress * 100f)}%";
|
||||
|
||||
lastCleanupFill = progress;
|
||||
|
||||
if (instant || effects == null)
|
||||
cleanupGaugeFill.fillAmount = progress;
|
||||
else
|
||||
effects.FillImage(cleanupGaugeFill, progress, cleanupFillTime);
|
||||
}
|
||||
|
||||
public void UpdateInventoryUI(int fishCount, int trashCount, int memoryPieceCount, int compassCount = 0)
|
||||
public void UpdateInventoryUI(int fishCount, int trashCount, int memoryPieceCount)
|
||||
{
|
||||
fishCount = Mathf.Max(0, fishCount);
|
||||
trashCount = Mathf.Max(0, trashCount);
|
||||
memoryPieceCount = Mathf.Max(0, memoryPieceCount);
|
||||
compassCount = Mathf.Max(0, compassCount);
|
||||
|
||||
if (fishCountText != null)
|
||||
fishCountText.text = $"생선\nx{fishCount}";
|
||||
|
||||
if (trashCountText != null)
|
||||
trashCountText.text = $"쓰레기\nx{trashCount}";
|
||||
|
||||
if (memoryPieceCountText != null)
|
||||
memoryPieceCountText.text = $"기억의 조각\nx{memoryPieceCount}";
|
||||
|
||||
if (compassCountText != null)
|
||||
compassCountText.text = $"나침반\nx{compassCount}";
|
||||
if (fishCountText != null) fishCountText.text = fishCount.ToString();
|
||||
if (trashCountText != null) trashCountText.text = trashCount.ToString();
|
||||
if (memoryPieceCountText != null) memoryPieceCountText.text = memoryPieceCount.ToString();
|
||||
|
||||
ApplySlotState(fishSlot, fishSlotBackground, fishIcon, fishCount > 0);
|
||||
ApplySlotState(trashSlot, trashSlotBackground, trashIcon, trashCount > 0);
|
||||
ApplySlotState(memorySlot, memorySlotBackground, memoryIcon, memoryPieceCount > 0);
|
||||
ApplySlotState(compassSlot, compassSlotBackground, compassIcon, compassCount > 0);
|
||||
|
||||
// 이제 낚시 아이템은 물고기 / 쓰레기 / 기억의 조각 3종만 사용합니다.
|
||||
// 기존 Compass 슬롯이 하이어라키에 남아 있으면 자동으로 숨깁니다.
|
||||
if (compassSlot != null)
|
||||
compassSlot.SetActive(false);
|
||||
}
|
||||
|
||||
public void HighlightSlotForItem(FishingItemType itemType)
|
||||
{
|
||||
GameObject targetSlot = GetSlotForItem(itemType);
|
||||
Image targetBackground = GetSlotBackgroundForItem(itemType);
|
||||
Image targetIcon = GetSlotIconForItem(itemType);
|
||||
switch (itemType)
|
||||
{
|
||||
case FishingItemType.Fish:
|
||||
StartSlotHighlight(fishSlotBackground, fishIcon);
|
||||
break;
|
||||
|
||||
if (targetSlot == null && targetBackground == null && targetIcon == null)
|
||||
return;
|
||||
case FishingItemType.Trash:
|
||||
StartSlotHighlight(trashSlotBackground, trashIcon);
|
||||
break;
|
||||
|
||||
if (effects != null)
|
||||
effects.HighlightSlot(targetBackground, targetIcon, targetSlot != null ? targetSlot.transform : null, slotHighlightColor, slotHighlightTime, slotHighlightScale);
|
||||
else
|
||||
StartCoroutine(SimpleSlotHighlightRoutine(targetBackground, targetIcon));
|
||||
case FishingItemType.MemoryPiece:
|
||||
StartSlotHighlight(memorySlotBackground, memoryIcon);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void StartSlotHighlight(Image background, Image icon)
|
||||
{
|
||||
if (background != null)
|
||||
StartCoroutine(SimpleSlotHighlightRoutine(background, icon));
|
||||
else if (icon != null && effects != null)
|
||||
effects.Pop(icon.transform, slotHighlightScale, slotHighlightTime);
|
||||
}
|
||||
|
||||
private IEnumerator SimpleSlotHighlightRoutine(Image background, Image icon)
|
||||
{
|
||||
Color? originalBackground = null;
|
||||
Color? originalIcon = null;
|
||||
|
||||
if (background != null)
|
||||
{
|
||||
originalBackground = background.color;
|
||||
Color c = background.color;
|
||||
c.a = 1f;
|
||||
background.color = c;
|
||||
}
|
||||
Color originalBackgroundColor = background.color;
|
||||
Color originalIconColor = icon != null ? icon.color : Color.white;
|
||||
|
||||
background.color = slotHighlightColor;
|
||||
if (icon != null)
|
||||
{
|
||||
originalIcon = icon.color;
|
||||
Color c = icon.color;
|
||||
c.a = 1f;
|
||||
icon.color = c;
|
||||
Color highlightedIcon = icon.color;
|
||||
highlightedIcon.a = filledIconAlpha;
|
||||
icon.color = highlightedIcon;
|
||||
}
|
||||
|
||||
if (effects != null)
|
||||
{
|
||||
effects.Pop(background.transform, slotHighlightScale, slotHighlightTime);
|
||||
if (icon != null)
|
||||
effects.Pop(icon.transform, slotHighlightScale, slotHighlightTime);
|
||||
}
|
||||
|
||||
yield return new WaitForSeconds(slotHighlightTime);
|
||||
|
||||
if (background != null && originalBackground.HasValue)
|
||||
background.color = originalBackground.Value;
|
||||
|
||||
if (icon != null && originalIcon.HasValue)
|
||||
icon.color = originalIcon.Value;
|
||||
background.color = originalBackgroundColor;
|
||||
if (icon != null)
|
||||
icon.color = originalIconColor;
|
||||
}
|
||||
|
||||
private void ApplySlotState(GameObject slotRoot, Image slotBackground, Image icon, bool hasItem)
|
||||
@@ -610,64 +596,20 @@ private void SetImageAlpha(Image image, float alpha)
|
||||
image.color = color;
|
||||
}
|
||||
|
||||
private GameObject GetSlotForItem(FishingItemType itemType)
|
||||
{
|
||||
switch (itemType)
|
||||
{
|
||||
case FishingItemType.Fish: return fishSlot;
|
||||
case FishingItemType.Trash:
|
||||
case FishingItemType.Bottle:
|
||||
case FishingItemType.PlasticBag: return trashSlot;
|
||||
case FishingItemType.MemoryPiece: return memorySlot;
|
||||
case FishingItemType.OldCompass: return compassSlot;
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
|
||||
private Image GetSlotBackgroundForItem(FishingItemType itemType)
|
||||
{
|
||||
switch (itemType)
|
||||
{
|
||||
case FishingItemType.Fish: return fishSlotBackground;
|
||||
case FishingItemType.Trash:
|
||||
case FishingItemType.Bottle:
|
||||
case FishingItemType.PlasticBag: return trashSlotBackground;
|
||||
case FishingItemType.MemoryPiece: return memorySlotBackground;
|
||||
case FishingItemType.OldCompass: return compassSlotBackground;
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
|
||||
private Image GetSlotIconForItem(FishingItemType itemType)
|
||||
{
|
||||
switch (itemType)
|
||||
{
|
||||
case FishingItemType.Fish: return fishIcon;
|
||||
case FishingItemType.Trash:
|
||||
case FishingItemType.Bottle:
|
||||
case FishingItemType.PlasticBag: return trashIcon;
|
||||
case FishingItemType.MemoryPiece: return memoryIcon;
|
||||
case FishingItemType.OldCompass: return compassIcon;
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void ShowCounter()
|
||||
{
|
||||
if (counterPanel != null)
|
||||
counterPanel.SetActive(true);
|
||||
SetCounterVisible(true);
|
||||
}
|
||||
|
||||
public void HideCounter()
|
||||
{
|
||||
if (counterPanel != null)
|
||||
counterPanel.SetActive(false);
|
||||
SetCounterVisible(false);
|
||||
}
|
||||
|
||||
public void SetCounterVisible(bool visible)
|
||||
{
|
||||
if (visible) ShowCounter();
|
||||
else HideCounter();
|
||||
if (counterPanel != null)
|
||||
counterPanel.SetActive(visible);
|
||||
}
|
||||
|
||||
public void SetItemSlotPanelVisible(bool visible)
|
||||
@@ -678,14 +620,11 @@ public void SetItemSlotPanelVisible(bool visible)
|
||||
|
||||
public void ShowResult(string text)
|
||||
{
|
||||
ShowResult(text, defaultResultColor);
|
||||
ShowResult(text, Color.white);
|
||||
}
|
||||
|
||||
public void ShowResult(string text, Color color)
|
||||
{
|
||||
if (resultText == null)
|
||||
return;
|
||||
|
||||
if (resultRoutine != null)
|
||||
StopCoroutine(resultRoutine);
|
||||
|
||||
@@ -694,57 +633,36 @@ public void ShowResult(string text, Color color)
|
||||
|
||||
public void ShowPersistentResult(string text)
|
||||
{
|
||||
ShowPersistentResult(text, defaultResultColor);
|
||||
ShowPersistentResult(text, Color.white);
|
||||
}
|
||||
|
||||
public void ShowPersistentResult(string text, Color color)
|
||||
{
|
||||
if (resultText == null)
|
||||
return;
|
||||
|
||||
if (resultRoutine != null)
|
||||
{
|
||||
StopCoroutine(resultRoutine);
|
||||
resultRoutine = null;
|
||||
}
|
||||
|
||||
resultText.gameObject.SetActive(true);
|
||||
resultText.color = color;
|
||||
resultText.text = text;
|
||||
|
||||
if (effects != null)
|
||||
effects.Pop(resultText.transform, resultPopScale, resultPopTime);
|
||||
}
|
||||
|
||||
public void ShowResultForType(FishingGameManager.ResultType resultType)
|
||||
{
|
||||
switch (resultType)
|
||||
if (resultText != null)
|
||||
{
|
||||
case FishingGameManager.ResultType.Perfect:
|
||||
ShowResult("완벽!", perfectColor);
|
||||
if (effects != null && gaugeGroupRect != null)
|
||||
effects.Pop(gaugeGroupRect, gaugePopScale, gaugePopTime);
|
||||
break;
|
||||
resultText.gameObject.SetActive(true);
|
||||
resultText.text = text;
|
||||
resultText.color = color;
|
||||
|
||||
case FishingGameManager.ResultType.Good:
|
||||
ShowResult("성공!", goodColor);
|
||||
if (effects != null && gaugeGroupRect != null)
|
||||
effects.Pop(gaugeGroupRect, gaugePopScale, gaugePopTime);
|
||||
break;
|
||||
|
||||
case FishingGameManager.ResultType.Miss:
|
||||
ShowResult("실패!", missColor);
|
||||
if (effects != null && gaugeGroupRect != null)
|
||||
effects.Shake(gaugeGroupRect, missShakeStrength, missShakeTime);
|
||||
break;
|
||||
if (effects != null)
|
||||
effects.Pop(resultText.transform, resultPopScale, resultPopTime);
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerator ResultRoutine(string text, Color color)
|
||||
{
|
||||
if (resultText == null)
|
||||
yield break;
|
||||
|
||||
resultText.gameObject.SetActive(true);
|
||||
resultText.color = color;
|
||||
resultText.text = text;
|
||||
resultText.color = color;
|
||||
|
||||
if (effects != null)
|
||||
effects.Pop(resultText.transform, resultPopScale, resultPopTime);
|
||||
@@ -911,13 +829,8 @@ private string GetCaughtMessage(FishingItemType itemType, string displayName)
|
||||
|
||||
switch (itemType)
|
||||
{
|
||||
case FishingItemType.Fish: return "생선을 낚았다!";
|
||||
case FishingItemType.RottenFish: return "상한 생선을 낚았다...";
|
||||
case FishingItemType.Fish: return "물고기를 낚았다!";
|
||||
case FishingItemType.Trash: return "쓰레기를 건져냈다!";
|
||||
case FishingItemType.Bottle: return "병을 건져냈다!";
|
||||
case FishingItemType.PlasticBag: return "비닐봉지를 건져냈다!";
|
||||
case FishingItemType.JellyfishPowder: return "해파리 가루를 얻었다!";
|
||||
case FishingItemType.OldCompass: return "낡은 나침반을 얻었다!";
|
||||
case FishingItemType.MemoryPiece: return "기억의 조각을 찾았다!";
|
||||
default: return string.IsNullOrWhiteSpace(displayName) ? "무언가를 낚았다!" : displayName;
|
||||
}
|
||||
@@ -935,10 +848,7 @@ private string GetDefaultHint(FishingItemType itemType, bool countsAsCleanupItem
|
||||
|
||||
switch (itemType)
|
||||
{
|
||||
case FishingItemType.Fish: return "생선은 고양이들이 좋아할 것 같다.";
|
||||
case FishingItemType.RottenFish: return "냄새가 심하다. 쓸 수 있을까?";
|
||||
case FishingItemType.JellyfishPowder: return "이상한 빛을 내는 가루다.";
|
||||
case FishingItemType.OldCompass: return "길을 찾는 데 도움이 될 것 같다.";
|
||||
case FishingItemType.Fish: return "평범한 물고기다.";
|
||||
case FishingItemType.MemoryPiece: return "잃어버린 기억의 일부다.";
|
||||
default: return string.Empty;
|
||||
}
|
||||
@@ -1061,53 +971,6 @@ private void SetControllerGuideVisible(bool visible, bool instant)
|
||||
}
|
||||
}
|
||||
|
||||
public void SetCatchButtonVisible(bool visible)
|
||||
{
|
||||
if (catchButton != null)
|
||||
catchButton.SetActive(visible);
|
||||
}
|
||||
|
||||
public void FlashFeedback(Color color)
|
||||
{
|
||||
if (feedbackFlash == null)
|
||||
return;
|
||||
|
||||
if (effects != null)
|
||||
effects.Flash(feedbackFlash, color, flashMaxAlpha, flashTime);
|
||||
else
|
||||
{
|
||||
Color clear = color;
|
||||
clear.a = 0f;
|
||||
feedbackFlash.color = clear;
|
||||
feedbackFlash.gameObject.SetActive(false);
|
||||
}
|
||||
}
|
||||
|
||||
public void FlashFeedbackForType(FishingGameManager.ResultType resultType)
|
||||
{
|
||||
switch (resultType)
|
||||
{
|
||||
case FishingGameManager.ResultType.Perfect:
|
||||
FlashFeedback(perfectColor);
|
||||
break;
|
||||
case FishingGameManager.ResultType.Good:
|
||||
FlashFeedback(goodColor);
|
||||
break;
|
||||
case FishingGameManager.ResultType.Miss:
|
||||
FlashFeedback(missColor);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void SetFeedbackFlashVisible(bool visible, Color color)
|
||||
{
|
||||
if (feedbackFlash == null)
|
||||
return;
|
||||
|
||||
feedbackFlash.gameObject.SetActive(visible);
|
||||
feedbackFlash.color = color;
|
||||
}
|
||||
|
||||
public void HideRoundResult()
|
||||
{
|
||||
if (resultRoutine != null)
|
||||
@@ -1120,7 +983,6 @@ public void HideRoundResult()
|
||||
resultText.gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
|
||||
private void SetGameplayUIVisible(bool visible)
|
||||
{
|
||||
SetGameObjectVisible(gameplayBackgroundRoot, visible);
|
||||
@@ -1137,24 +999,14 @@ private void SetGameplayUIVisible(bool visible)
|
||||
SetGameObjectVisible(counterPanel, visible);
|
||||
SetGameObjectVisible(itemSlotPanel, visible);
|
||||
SetGameObjectVisible(cleanupGaugeRoot, visible);
|
||||
|
||||
if (!visible)
|
||||
SetSimpleReelUIVisible(false);
|
||||
|
||||
if (gaugeGroupRoot != null)
|
||||
gaugeGroupRoot.SetActive(visible);
|
||||
else if (gaugeGroupRect != null)
|
||||
gaugeGroupRect.gameObject.SetActive(visible);
|
||||
|
||||
SetSimpleReelUIVisible(visible);
|
||||
SetControllerGuideVisible(visible && showControllerGuideOnInitialize, true);
|
||||
SetCatchButtonVisible(visible && showCatchButtonOnInitialize);
|
||||
|
||||
if (!visible)
|
||||
{
|
||||
HideRoundResult();
|
||||
HideCaughtItem(true);
|
||||
HideNotice(true);
|
||||
SetFeedbackFlashVisible(false, Color.clear);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1167,24 +1019,13 @@ private void SetGameObjectVisible(GameObject target, bool visible)
|
||||
public void ShowFinalResult(string text)
|
||||
{
|
||||
HideRoundResult();
|
||||
|
||||
if (hideCaughtItemOnFinalResult)
|
||||
HideCaughtItem(true);
|
||||
|
||||
HideCaughtItem(true);
|
||||
HideNotice(true);
|
||||
|
||||
if (showOnlyFinalResult)
|
||||
{
|
||||
SetGameplayUIVisible(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (hideCounterOnFinalResult)
|
||||
HideCounter();
|
||||
|
||||
if (hideGuideOnFinalResult)
|
||||
SetControllerGuideVisible(false, true);
|
||||
}
|
||||
SetControllerGuideVisible(false, true);
|
||||
|
||||
if (finalResultPanel != null)
|
||||
finalResultPanel.SetActive(true);
|
||||
@@ -1219,12 +1060,12 @@ public void HideFinalResult()
|
||||
HideFinalResult(true, false);
|
||||
}
|
||||
|
||||
public void HideFinalResult(bool showCounterAfterHide)
|
||||
public void HideFinalResult(bool showGameplayAfterHide)
|
||||
{
|
||||
HideFinalResult(showCounterAfterHide, false);
|
||||
HideFinalResult(showGameplayAfterHide, false);
|
||||
}
|
||||
|
||||
private void HideFinalResult(bool showCounterAfterHide, bool instant)
|
||||
private void HideFinalResult(bool showGameplayAfterHide, bool instant)
|
||||
{
|
||||
if (instant || effects == null)
|
||||
{
|
||||
@@ -1246,18 +1087,8 @@ private void HideFinalResult(bool showCounterAfterHide, bool instant)
|
||||
if (finalResultText != null)
|
||||
finalResultText.gameObject.SetActive(false);
|
||||
|
||||
if (showCounterAfterHide)
|
||||
{
|
||||
if (showOnlyFinalResult)
|
||||
{
|
||||
if (restoreGameplayUIAfterFinalResult)
|
||||
SetGameplayUIVisible(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
ShowCounter();
|
||||
}
|
||||
}
|
||||
if (showGameplayAfterHide && showOnlyFinalResult && restoreGameplayUIAfterFinalResult)
|
||||
SetGameplayUIVisible(true);
|
||||
}
|
||||
|
||||
private GameObject FindGameObject(params string[] names)
|
||||
|
||||
@@ -4,21 +4,11 @@ public class FishingInventory : MonoBehaviour
|
||||
{
|
||||
[Header("Item Counts")]
|
||||
[SerializeField] private int fishCount;
|
||||
[SerializeField] private int rottenFishCount;
|
||||
[SerializeField] private int trashCount;
|
||||
[SerializeField] private int bottleCount;
|
||||
[SerializeField] private int plasticBagCount;
|
||||
[SerializeField] private int jellyfishPowderCount;
|
||||
[SerializeField] private int oldCompassCount;
|
||||
[SerializeField] private int memoryPieceCount;
|
||||
|
||||
public int FishCount => fishCount;
|
||||
public int RottenFishCount => rottenFishCount;
|
||||
public int TrashCount => trashCount;
|
||||
public int BottleCount => bottleCount;
|
||||
public int PlasticBagCount => plasticBagCount;
|
||||
public int JellyfishPowderCount => jellyfishPowderCount;
|
||||
public int OldCompassCount => oldCompassCount;
|
||||
public int MemoryPieceCount => memoryPieceCount;
|
||||
|
||||
private void OnValidate()
|
||||
@@ -29,12 +19,7 @@ private void OnValidate()
|
||||
private void ClampCounts()
|
||||
{
|
||||
fishCount = Mathf.Max(0, fishCount);
|
||||
rottenFishCount = Mathf.Max(0, rottenFishCount);
|
||||
trashCount = Mathf.Max(0, trashCount);
|
||||
bottleCount = Mathf.Max(0, bottleCount);
|
||||
plasticBagCount = Mathf.Max(0, plasticBagCount);
|
||||
jellyfishPowderCount = Mathf.Max(0, jellyfishPowderCount);
|
||||
oldCompassCount = Mathf.Max(0, oldCompassCount);
|
||||
memoryPieceCount = Mathf.Max(0, memoryPieceCount);
|
||||
}
|
||||
|
||||
@@ -49,34 +34,16 @@ public void AddItem(FishingItemType itemType, int amount = 1)
|
||||
fishCount += amount;
|
||||
break;
|
||||
|
||||
case FishingItemType.RottenFish:
|
||||
rottenFishCount += amount;
|
||||
break;
|
||||
|
||||
case FishingItemType.Trash:
|
||||
trashCount += amount;
|
||||
break;
|
||||
|
||||
case FishingItemType.Bottle:
|
||||
bottleCount += amount;
|
||||
break;
|
||||
|
||||
case FishingItemType.PlasticBag:
|
||||
plasticBagCount += amount;
|
||||
break;
|
||||
|
||||
case FishingItemType.JellyfishPowder:
|
||||
jellyfishPowderCount += amount;
|
||||
break;
|
||||
|
||||
case FishingItemType.OldCompass:
|
||||
oldCompassCount += amount;
|
||||
break;
|
||||
|
||||
case FishingItemType.MemoryPiece:
|
||||
memoryPieceCount += amount;
|
||||
break;
|
||||
}
|
||||
|
||||
ClampCounts();
|
||||
}
|
||||
|
||||
public bool HasItem(FishingItemType itemType, int amount = 1)
|
||||
@@ -98,35 +65,16 @@ public bool ConsumeItem(FishingItemType itemType, int amount = 1)
|
||||
fishCount -= amount;
|
||||
break;
|
||||
|
||||
case FishingItemType.RottenFish:
|
||||
rottenFishCount -= amount;
|
||||
break;
|
||||
|
||||
case FishingItemType.Trash:
|
||||
trashCount -= amount;
|
||||
break;
|
||||
|
||||
case FishingItemType.Bottle:
|
||||
bottleCount -= amount;
|
||||
break;
|
||||
|
||||
case FishingItemType.PlasticBag:
|
||||
plasticBagCount -= amount;
|
||||
break;
|
||||
|
||||
case FishingItemType.JellyfishPowder:
|
||||
jellyfishPowderCount -= amount;
|
||||
break;
|
||||
|
||||
case FishingItemType.OldCompass:
|
||||
oldCompassCount -= amount;
|
||||
break;
|
||||
|
||||
case FishingItemType.MemoryPiece:
|
||||
memoryPieceCount -= amount;
|
||||
break;
|
||||
}
|
||||
|
||||
ClampCounts();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -137,24 +85,9 @@ public int GetItemCount(FishingItemType itemType)
|
||||
case FishingItemType.Fish:
|
||||
return fishCount;
|
||||
|
||||
case FishingItemType.RottenFish:
|
||||
return rottenFishCount;
|
||||
|
||||
case FishingItemType.Trash:
|
||||
return trashCount;
|
||||
|
||||
case FishingItemType.Bottle:
|
||||
return bottleCount;
|
||||
|
||||
case FishingItemType.PlasticBag:
|
||||
return plasticBagCount;
|
||||
|
||||
case FishingItemType.JellyfishPowder:
|
||||
return jellyfishPowderCount;
|
||||
|
||||
case FishingItemType.OldCompass:
|
||||
return oldCompassCount;
|
||||
|
||||
case FishingItemType.MemoryPiece:
|
||||
return memoryPieceCount;
|
||||
|
||||
@@ -167,12 +100,7 @@ public int GetItemCount(FishingItemType itemType)
|
||||
public void ResetInventory()
|
||||
{
|
||||
fishCount = 0;
|
||||
rottenFishCount = 0;
|
||||
trashCount = 0;
|
||||
bottleCount = 0;
|
||||
plasticBagCount = 0;
|
||||
jellyfishPowderCount = 0;
|
||||
oldCompassCount = 0;
|
||||
memoryPieceCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// Connects FishingGameManager's caught-item event to FishingInventory.
|
||||
/// Add this to the same prefab/root object, then assign Game Manager and Inventory.
|
||||
/// </summary>
|
||||
public class FishingInventoryBinder : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private FishingGameManager gameManager;
|
||||
[SerializeField] private FishingInventory inventory;
|
||||
|
||||
private void Reset()
|
||||
{
|
||||
AutoBind();
|
||||
}
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
AutoBind();
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
if (gameManager != null)
|
||||
gameManager.ItemCaught += OnItemCaught;
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
if (gameManager != null)
|
||||
gameManager.ItemCaught -= OnItemCaught;
|
||||
}
|
||||
|
||||
[ContextMenu("Auto Bind Inventory Binder")]
|
||||
public void AutoBind()
|
||||
{
|
||||
if (gameManager == null)
|
||||
gameManager = GetComponentInParent<FishingGameManager>();
|
||||
|
||||
if (inventory == null)
|
||||
inventory = GetComponentInParent<FishingInventory>();
|
||||
|
||||
if (inventory == null && gameManager != null)
|
||||
inventory = gameManager.GetComponentInChildren<FishingInventory>(true);
|
||||
}
|
||||
|
||||
private void OnItemCaught(FishingItemType itemType, int amount)
|
||||
{
|
||||
if (inventory == null)
|
||||
return;
|
||||
|
||||
inventory.AddItem(itemType, amount);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a6aa548e80b5ed040b1d663b9d7bafa7
|
||||
@@ -2,11 +2,6 @@ public enum FishingItemType
|
||||
{
|
||||
None,
|
||||
Fish,
|
||||
RottenFish,
|
||||
Trash,
|
||||
Bottle,
|
||||
PlasticBag,
|
||||
JellyfishPowder,
|
||||
OldCompass,
|
||||
MemoryPiece
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ public class FishingRewardSystem : MonoBehaviour
|
||||
public class LootEntry
|
||||
{
|
||||
public FishingItemType itemType = FishingItemType.Fish;
|
||||
public string displayName = "생선";
|
||||
public string displayName = "물고기";
|
||||
[Min(0f)] public float weight = 1f;
|
||||
|
||||
public LootEntry(FishingItemType itemType, string displayName, float weight)
|
||||
@@ -36,11 +36,11 @@ public CatchResult(FishingItemType itemType, string displayName, bool countsAsCl
|
||||
}
|
||||
|
||||
[Header("Loot Table - Dirty Pond")]
|
||||
[Tooltip("연못이 정화되기 전 낚이는 아이템 목록입니다. 기억의 조각은 이 테이블에 있어도 자동 제외됩니다.")]
|
||||
[Tooltip("연못이 정화되기 전에는 물고기와 쓰레기만 낚입니다. 기억의 조각은 자동 제외됩니다.")]
|
||||
[SerializeField] private List<LootEntry> dirtyPondLootTable = new List<LootEntry>();
|
||||
|
||||
[Header("Loot Table - Clean Pond")]
|
||||
[Tooltip("연못이 정화된 뒤 낚이는 아이템 목록입니다. 기억의 조각을 포함할 수 있습니다.")]
|
||||
[Tooltip("연못이 정화된 뒤에는 기억의 조각이 낚입니다.")]
|
||||
[SerializeField] private List<LootEntry> cleanPondLootTable = new List<LootEntry>();
|
||||
|
||||
[Header("Debug")]
|
||||
@@ -74,6 +74,10 @@ private void EnsureLootTables()
|
||||
if (cleanPondLootTable == null)
|
||||
cleanPondLootTable = new List<LootEntry>();
|
||||
|
||||
// 이전 버전의 상한 생선/병/봉지/나침반 등이 인스펙터에 남아 있어도
|
||||
// 런타임에서는 물고기 / 쓰레기 / 기억의 조각 3종만 남도록 정리합니다.
|
||||
SanitizeLootTables();
|
||||
|
||||
if (dirtyPondLootTable.Count == 0)
|
||||
SetDefaultDirtyLootTable();
|
||||
|
||||
@@ -81,6 +85,45 @@ private void EnsureLootTables()
|
||||
SetDefaultCleanLootTable();
|
||||
}
|
||||
|
||||
private void SanitizeLootTables()
|
||||
{
|
||||
SanitizeTable(dirtyPondLootTable, allowFish: true, allowTrash: true, allowMemoryPiece: false);
|
||||
SanitizeTable(cleanPondLootTable, allowFish: false, allowTrash: false, allowMemoryPiece: true);
|
||||
}
|
||||
|
||||
private void SanitizeTable(List<LootEntry> table, bool allowFish, bool allowTrash, bool allowMemoryPiece)
|
||||
{
|
||||
if (table == null)
|
||||
return;
|
||||
|
||||
for (int i = table.Count - 1; i >= 0; i--)
|
||||
{
|
||||
LootEntry entry = table[i];
|
||||
|
||||
if (entry == null || !IsAllowedInTable(entry.itemType, allowFish, allowTrash, allowMemoryPiece))
|
||||
table.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsAllowedInTable(FishingItemType itemType, bool allowFish, bool allowTrash, bool allowMemoryPiece)
|
||||
{
|
||||
switch (itemType)
|
||||
{
|
||||
case FishingItemType.Fish:
|
||||
return allowFish;
|
||||
|
||||
case FishingItemType.Trash:
|
||||
return allowTrash;
|
||||
|
||||
case FishingItemType.MemoryPiece:
|
||||
return allowMemoryPiece;
|
||||
|
||||
case FishingItemType.None:
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void SetDefaultLootTables()
|
||||
{
|
||||
SetDefaultDirtyLootTable();
|
||||
@@ -91,13 +134,8 @@ private void SetDefaultDirtyLootTable()
|
||||
{
|
||||
dirtyPondLootTable = new List<LootEntry>
|
||||
{
|
||||
new LootEntry(FishingItemType.Fish, "생선", 25f),
|
||||
new LootEntry(FishingItemType.RottenFish, "상한 생선", 8f),
|
||||
new LootEntry(FishingItemType.Trash, "쓰레기", 28f),
|
||||
new LootEntry(FishingItemType.Bottle, "병", 18f),
|
||||
new LootEntry(FishingItemType.PlasticBag, "봉지", 18f),
|
||||
new LootEntry(FishingItemType.JellyfishPowder, "해파리 가루", 6f),
|
||||
new LootEntry(FishingItemType.OldCompass, "낡은 나침반", 4f)
|
||||
new LootEntry(FishingItemType.Fish, "물고기", 35f),
|
||||
new LootEntry(FishingItemType.Trash, "쓰레기", 65f)
|
||||
};
|
||||
}
|
||||
|
||||
@@ -105,11 +143,7 @@ private void SetDefaultCleanLootTable()
|
||||
{
|
||||
cleanPondLootTable = new List<LootEntry>
|
||||
{
|
||||
new LootEntry(FishingItemType.MemoryPiece, "기억의 조각", 30f),
|
||||
new LootEntry(FishingItemType.Fish, "생선", 30f),
|
||||
new LootEntry(FishingItemType.OldCompass, "낡은 나침반", 15f),
|
||||
new LootEntry(FishingItemType.JellyfishPowder, "해파리 가루", 15f),
|
||||
new LootEntry(FishingItemType.RottenFish, "상한 생선", 4f)
|
||||
new LootEntry(FishingItemType.MemoryPiece, "기억의 조각", 100f)
|
||||
};
|
||||
}
|
||||
|
||||
@@ -122,14 +156,14 @@ private void ClampLootTable(List<LootEntry> table)
|
||||
{
|
||||
if (table[i] == null)
|
||||
{
|
||||
table[i] = new LootEntry(FishingItemType.Fish, "생선", 1f);
|
||||
table[i] = new LootEntry(FishingItemType.Fish, "물고기", 1f);
|
||||
continue;
|
||||
}
|
||||
|
||||
table[i].weight = Mathf.Max(0f, table[i].weight);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(table[i].displayName))
|
||||
table[i].displayName = GetDefaultDisplayName(table[i].itemType);
|
||||
// 이전 버전에서 남은 표시 이름을 3종 아이템 이름으로 정리합니다.
|
||||
table[i].displayName = GetDefaultDisplayName(table[i].itemType);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,7 +176,8 @@ public CatchResult RollCatch(bool pondCleaned, bool forceMemoryPiece)
|
||||
LootEntry selectedEntry = RollFromTable(table, pondCleaned);
|
||||
|
||||
if (selectedEntry == null)
|
||||
return CreateCatchResult(FishingItemType.Fish, GetDefaultDisplayName(FishingItemType.Fish));
|
||||
return CreateCatchResult(pondCleaned ? FishingItemType.MemoryPiece : FishingItemType.Fish,
|
||||
GetDefaultDisplayName(pondCleaned ? FishingItemType.MemoryPiece : FishingItemType.Fish));
|
||||
|
||||
return CreateCatchResult(selectedEntry.itemType, selectedEntry.displayName);
|
||||
}
|
||||
@@ -194,10 +229,15 @@ private bool IsRollableEntry(LootEntry entry, bool pondCleaned)
|
||||
if (entry.weight <= 0f)
|
||||
return false;
|
||||
|
||||
if (entry.itemType == FishingItemType.None)
|
||||
return false;
|
||||
|
||||
if (!pondCleaned && entry.itemType == FishingItemType.MemoryPiece)
|
||||
return false;
|
||||
|
||||
return entry.itemType != FishingItemType.None;
|
||||
return entry.itemType == FishingItemType.Fish ||
|
||||
entry.itemType == FishingItemType.Trash ||
|
||||
entry.itemType == FishingItemType.MemoryPiece;
|
||||
}
|
||||
|
||||
private CatchResult CreateCatchResult(FishingItemType itemType, string displayName)
|
||||
@@ -214,9 +254,7 @@ private CatchResult CreateCatchResult(FishingItemType itemType, string displayNa
|
||||
|
||||
public bool IsCleanupItem(FishingItemType itemType)
|
||||
{
|
||||
return itemType == FishingItemType.Trash ||
|
||||
itemType == FishingItemType.Bottle ||
|
||||
itemType == FishingItemType.PlasticBag;
|
||||
return itemType == FishingItemType.Trash;
|
||||
}
|
||||
|
||||
public string GetDefaultDisplayName(FishingItemType itemType)
|
||||
@@ -224,26 +262,11 @@ public string GetDefaultDisplayName(FishingItemType itemType)
|
||||
switch (itemType)
|
||||
{
|
||||
case FishingItemType.Fish:
|
||||
return "생선";
|
||||
|
||||
case FishingItemType.RottenFish:
|
||||
return "상한 생선";
|
||||
return "물고기";
|
||||
|
||||
case FishingItemType.Trash:
|
||||
return "쓰레기";
|
||||
|
||||
case FishingItemType.Bottle:
|
||||
return "병";
|
||||
|
||||
case FishingItemType.PlasticBag:
|
||||
return "봉지";
|
||||
|
||||
case FishingItemType.JellyfishPowder:
|
||||
return "해파리 가루";
|
||||
|
||||
case FishingItemType.OldCompass:
|
||||
return "낡은 나침반";
|
||||
|
||||
case FishingItemType.MemoryPiece:
|
||||
return "기억의 조각";
|
||||
|
||||
|
||||
@@ -46,6 +46,18 @@ public enum StartMode
|
||||
ManualOnly
|
||||
}
|
||||
|
||||
public enum BiteStartMode
|
||||
{
|
||||
[Tooltip("캐스팅이 끝나면 물 감지와 상관없이 입질 대기를 시작합니다. 개발/테스트 단계에서 추천합니다.")]
|
||||
AfterCastAlways,
|
||||
|
||||
[Tooltip("BobberLineStartPoint가 Water Collider로 감지될 때만 입질 대기를 시작합니다. 완성 단계에서 추천합니다.")]
|
||||
WhenBobberInWater,
|
||||
|
||||
[Tooltip("자동 입질 대기를 시작하지 않습니다. ForceBite() 또는 별도 이벤트로만 입질을 발생시킵니다.")]
|
||||
ManualOnly
|
||||
}
|
||||
|
||||
[Header("Core References")]
|
||||
[SerializeField] private FishingGameManager fishingGameManager;
|
||||
[SerializeField] private FishingHapticManager haptic;
|
||||
@@ -158,6 +170,10 @@ public enum StartMode
|
||||
[SerializeField] private bool useWaterTag = true;
|
||||
[SerializeField] private string waterTag = "Water";
|
||||
|
||||
[Header("Bite Start Rule")]
|
||||
[Tooltip("입질 대기를 언제 시작할지 결정합니다. 테스트 중에는 AfterCastAlways, 실제 물 판정이 필요하면 WhenBobberInWater를 사용하세요.")]
|
||||
[SerializeField] private BiteStartMode biteStartMode = BiteStartMode.AfterCastAlways;
|
||||
|
||||
[Header("Bite")]
|
||||
[SerializeField] private bool useBiteTimer = true;
|
||||
[SerializeField] private Vector2 biteDelayRange = new Vector2(1.5f, 4.0f);
|
||||
@@ -181,7 +197,7 @@ public enum StartMode
|
||||
[Tooltip("If On, Reel Hold Action must be pressed to reel. If Off and Use Reel Grab Events is also Off, being near the reel is enough.")]
|
||||
[SerializeField] private bool useReelHoldAction = true;
|
||||
|
||||
[Tooltip("Button/Grip action used while reeling. Example binding: <XRController>{LeftHand}/gripPressed or <XRController>{LeftHand}/triggerPressed.")]
|
||||
[Tooltip("Button/Grip action used while reeling. Example binding: <XRController>{RightHand}/gripPressed or <XRController>{RightHand}/triggerPressed when the right hand reels.")]
|
||||
[SerializeField] private InputActionReference reelHoldAction;
|
||||
|
||||
[Tooltip("If On, call MarkReelHandleGrabbed/MarkReelHandleReleased from a reel handle XR Grab Interactable or trigger volume.")]
|
||||
@@ -597,9 +613,53 @@ private IEnumerator CastRoutine(Vector3 target)
|
||||
state = BobberState.WaitingInWater;
|
||||
|
||||
Log("찌 캐스팅 완료");
|
||||
HandleBiteStartAfterCast();
|
||||
}
|
||||
|
||||
if (!useWaterOverlapCheck && useBiteTimer)
|
||||
StartWaitingForBite();
|
||||
private void HandleBiteStartAfterCast()
|
||||
{
|
||||
if (!useBiteTimer)
|
||||
{
|
||||
Log("입질 타이머가 꺼져 있어 입질 대기를 시작하지 않습니다.");
|
||||
return;
|
||||
}
|
||||
|
||||
switch (biteStartMode)
|
||||
{
|
||||
case BiteStartMode.AfterCastAlways:
|
||||
Log("캐스팅 완료 후 입질 대기를 시작합니다. 물 감지는 진행을 막지 않습니다.");
|
||||
StartWaitingForBite();
|
||||
break;
|
||||
|
||||
case BiteStartMode.WhenBobberInWater:
|
||||
if (!useWaterOverlapCheck)
|
||||
{
|
||||
Log("물 감지가 꺼져 있어 캐스팅 완료 후 입질 대기를 시작합니다.");
|
||||
StartWaitingForBite();
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsBobberOverlappingWater())
|
||||
{
|
||||
if (!bobberInWater)
|
||||
{
|
||||
bobberInWater = true;
|
||||
Log("찌가 물에 들어감");
|
||||
}
|
||||
|
||||
StartWaitingForBite();
|
||||
}
|
||||
else
|
||||
{
|
||||
bobberInWater = false;
|
||||
Log("캐스팅은 완료됐지만 찌가 물로 감지되지 않았습니다. Water Collider/Tag/Layer와 BobberLineStartPoint 위치를 확인하세요.");
|
||||
}
|
||||
break;
|
||||
|
||||
case BiteStartMode.ManualOnly:
|
||||
Log("수동 입질 모드입니다. ForceBite() 또는 별도 이벤트로 입질을 발생시켜야 합니다.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerator MoveBobberRoutine(Vector3 target, float duration, BobberState endState)
|
||||
@@ -625,7 +685,10 @@ private IEnumerator MoveBobberRoutine(Vector3 target, float duration, BobberStat
|
||||
private void StartWaitingForBite()
|
||||
{
|
||||
if (!useBiteTimer)
|
||||
{
|
||||
Log("입질 타이머가 꺼져 있어 입질 대기를 시작하지 않습니다.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (biteWaitRoutine != null || state == BobberState.Bite || state == BobberState.MiniGameActive)
|
||||
return;
|
||||
@@ -644,8 +707,9 @@ private IEnumerator BiteWaitRoutine()
|
||||
{
|
||||
timer += Time.deltaTime;
|
||||
|
||||
if (useWaterOverlapCheck && !bobberInWater)
|
||||
if (biteStartMode == BiteStartMode.WhenBobberInWater && useWaterOverlapCheck && !bobberInWater)
|
||||
{
|
||||
Log("찌가 물에서 벗어나 입질 대기를 취소합니다.");
|
||||
biteWaitRoutine = null;
|
||||
yield break;
|
||||
}
|
||||
@@ -806,14 +870,19 @@ private void UpdateWaterState()
|
||||
if (bobberInWater)
|
||||
{
|
||||
Log("찌가 물에 들어감");
|
||||
if (state == BobberState.Casting || state == BobberState.WaitingInWater || state == BobberState.Idle)
|
||||
|
||||
if (biteStartMode == BiteStartMode.WhenBobberInWater &&
|
||||
(state == BobberState.Casting || state == BobberState.WaitingInWater || state == BobberState.Idle))
|
||||
{
|
||||
StartWaitingForBite();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Log("찌가 물에서 나감");
|
||||
|
||||
if (state == BobberState.WaitingInWater || state == BobberState.Bite)
|
||||
if (biteStartMode == BiteStartMode.WhenBobberInWater &&
|
||||
(state == BobberState.WaitingInWater || state == BobberState.Bite))
|
||||
{
|
||||
StopBiteWaitOnly();
|
||||
StopBiteShakeOnly();
|
||||
|
||||
8
Assets/My project/Fishing Scripts/model.meta
Normal file
8
Assets/My project/Fishing Scripts/model.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b2e082a09cbefc649856544b86523b55
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Binary file not shown.
@@ -0,0 +1,28 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fe3d1baeb660bcc439902d62dfc02c1b
|
||||
ScriptedImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
script: {fileID: 11500000, guid: 715df9372183c47e389bb6e19fbc3b52, type: 3}
|
||||
editorImportSettings:
|
||||
generateSecondaryUVSet: 0
|
||||
importSettings:
|
||||
nodeNameMethod: 1
|
||||
animationMethod: 2
|
||||
generateMipMaps: 1
|
||||
texturesReadable: 0
|
||||
defaultMinFilterMode: 9729
|
||||
defaultMagFilterMode: 9729
|
||||
anisotropicFilterLevel: 1
|
||||
instantiationSettings:
|
||||
mask: -1
|
||||
layer: 0
|
||||
skinUpdateWhenOffscreen: 1
|
||||
lightIntensityFactor: 1
|
||||
sceneObjectCreation: 2
|
||||
assetDependencies: []
|
||||
reportItems: []
|
||||
@@ -1,5 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
<<<<<<< HEAD
|
||||
guid: c9e7644bbc6b3324eb679151bb0018fa
|
||||
=======
|
||||
guid: a32c27501966c844da3c4e2e54236880
|
||||
>>>>>>> 3887731db4d2b6ac4d3d2887acc3414ddf555690
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
|
||||
Binary file not shown.
@@ -1,5 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
<<<<<<< HEAD
|
||||
guid: 96e0f6dd612977042b62b4b18a2f8c9a
|
||||
=======
|
||||
guid: 5e660f31b31a3c1489ac3a3e5804f0aa
|
||||
>>>>>>> 3887731db4d2b6ac4d3d2887acc3414ddf555690
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
<<<<<<< HEAD
|
||||
guid: 73f8b205cedf821488958abbf597e518
|
||||
=======
|
||||
guid: 897f994e3e3765248902eea88350c6f7
|
||||
>>>>>>> 3887731db4d2b6ac4d3d2887acc3414ddf555690
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 0
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
<<<<<<< HEAD
|
||||
guid: 7f4320a32f7a846409fcf9cc7fa5fda1
|
||||
=======
|
||||
guid: 779ddf707232c4f49a357660d770bcf9
|
||||
>>>>>>> 3887731db4d2b6ac4d3d2887acc3414ddf555690
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
|
||||
BIN
Assets/XR/Settings/OpenXR Package Settings.asset
LFS
Normal file
BIN
Assets/XR/Settings/OpenXR Package Settings.asset
LFS
Normal file
Binary file not shown.
8
Assets/XR/Settings/OpenXR Package Settings.asset.meta
Normal file
8
Assets/XR/Settings/OpenXR Package Settings.asset.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9c0e704ea9510154c87905364d1e2058
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 11400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -3420,7 +3420,7 @@
|
||||
{
|
||||
"name": "",
|
||||
"id": "deb6a7a2-8de5-46b1-812b-d24b20c907a2",
|
||||
"path": "<XRController>{RightHand}/secondaryButton",
|
||||
"path": "<XRController>{LeftHand}/secondaryButton",
|
||||
"interactions": "",
|
||||
"processors": "",
|
||||
"groups": "",
|
||||
@@ -3431,7 +3431,7 @@
|
||||
{
|
||||
"name": "",
|
||||
"id": "22448257-ef2a-42bf-a6c0-66fad17ee5e8",
|
||||
"path": "<XRController>{RightHand}/primaryButton",
|
||||
"path": "<XRController>{LeftHand}/primaryButton",
|
||||
"interactions": "",
|
||||
"processors": "",
|
||||
"groups": "",
|
||||
@@ -3442,7 +3442,7 @@
|
||||
{
|
||||
"name": "",
|
||||
"id": "a6cfa3d8-bd52-4c0e-8ff2-414ab0f22663",
|
||||
"path": "<XRController>{LeftHand}/gripPressed",
|
||||
"path": "<XRController>{RightHand}/gripPressed",
|
||||
"interactions": "",
|
||||
"processors": "",
|
||||
"groups": "",
|
||||
|
||||
Reference in New Issue
Block a user