Fix : 보스 레이드 시스템 업데이트
This commit is contained in:
parent
4aa22756e5
commit
71b9521372
BIN
Assets/Resources/BossRaidWeb/bossraid_script.txt
(Stored with Git LFS)
BIN
Assets/Resources/BossRaidWeb/bossraid_script.txt
(Stored with Git LFS)
Binary file not shown.
BIN
Assets/Resources/BossRaidWeb/bossraid_style.txt
(Stored with Git LFS)
BIN
Assets/Resources/BossRaidWeb/bossraid_style.txt
(Stored with Git LFS)
Binary file not shown.
BIN
Assets/Resources/BossRaidWeb/bossraid_template.txt
(Stored with Git LFS)
BIN
Assets/Resources/BossRaidWeb/bossraid_template.txt
(Stored with Git LFS)
Binary file not shown.
@ -2,21 +2,35 @@
|
|||||||
%TAG !u! tag:unity3d.com,2011:
|
%TAG !u! tag:unity3d.com,2011:
|
||||||
--- !u!21 &2100000
|
--- !u!21 &2100000
|
||||||
Material:
|
Material:
|
||||||
serializedVersion: 6
|
serializedVersion: 8
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
m_PrefabInstance: {fileID: 0}
|
m_PrefabInstance: {fileID: 0}
|
||||||
m_PrefabAsset: {fileID: 0}
|
m_PrefabAsset: {fileID: 0}
|
||||||
m_Name: cfxr fire circle plain hdr ab
|
m_Name: cfxr fire circle plain hdr ab
|
||||||
m_Shader: {fileID: 4800000, guid: e198026df304af84a85675be636192ea, type: 3}
|
m_Shader: {fileID: 4800000, guid: e198026df304af84a85675be636192ea, type: 3}
|
||||||
m_ShaderKeywords: _ALPHATEST_ON _FADING_ON _CFXR_HDR_BOOST _CFXR_SINGLE_CHANNEL
|
m_Parent: {fileID: 0}
|
||||||
_CFXR_EDGE_FADING _CFXR_UV_DISTORTION
|
m_ModifiedSerializedProperties: 0
|
||||||
|
m_ValidKeywords:
|
||||||
|
- _ALPHABLEND_ON
|
||||||
|
- _ALPHATEST_ON
|
||||||
|
- _CFXR_EDGE_FADING
|
||||||
|
- _CFXR_HDR_BOOST
|
||||||
|
- _CFXR_SINGLE_CHANNEL
|
||||||
|
- _CFXR_UV_DISTORTION
|
||||||
|
- _FADING_ON
|
||||||
|
m_InvalidKeywords:
|
||||||
|
- _
|
||||||
|
- _CFXR_DITHERED_SHADOWS_OFF
|
||||||
|
- _CFXR_OVERLAYBLEND_RGBA
|
||||||
|
- _CFXR_OVERLAYTEX_OFF
|
||||||
m_LightmapFlags: 0
|
m_LightmapFlags: 0
|
||||||
m_EnableInstancingVariants: 0
|
m_EnableInstancingVariants: 0
|
||||||
m_DoubleSidedGI: 0
|
m_DoubleSidedGI: 0
|
||||||
m_CustomRenderQueue: -1
|
m_CustomRenderQueue: -1
|
||||||
stringTagMap: {}
|
stringTagMap: {}
|
||||||
disabledShaderPasses: []
|
disabledShaderPasses: []
|
||||||
|
m_LockedProperties:
|
||||||
m_SavedProperties:
|
m_SavedProperties:
|
||||||
serializedVersion: 3
|
serializedVersion: 3
|
||||||
m_TexEnvs:
|
m_TexEnvs:
|
||||||
@ -52,6 +66,7 @@ Material:
|
|||||||
m_Texture: {fileID: 0}
|
m_Texture: {fileID: 0}
|
||||||
m_Scale: {x: 1, y: 1}
|
m_Scale: {x: 1, y: 1}
|
||||||
m_Offset: {x: 0, y: 0}
|
m_Offset: {x: 0, y: 0}
|
||||||
|
m_Ints: []
|
||||||
m_Floats:
|
m_Floats:
|
||||||
- _BacklightTransmittance: 1
|
- _BacklightTransmittance: 1
|
||||||
- _BlendingType: 0
|
- _BlendingType: 0
|
||||||
@ -64,6 +79,7 @@ Material:
|
|||||||
- _DirectLightingRamp: 1
|
- _DirectLightingRamp: 1
|
||||||
- _DissolveSmooth: 0.1
|
- _DissolveSmooth: 0.1
|
||||||
- _Distort: 0.3
|
- _Distort: 0.3
|
||||||
|
- _DoubleDissolve: 0
|
||||||
- _DstBlend: 10
|
- _DstBlend: 10
|
||||||
- _EdgeFadePow: 1
|
- _EdgeFadePow: 1
|
||||||
- _FadeAlongU: 1
|
- _FadeAlongU: 1
|
||||||
@ -85,6 +101,7 @@ Material:
|
|||||||
- _UseAlphaClip: 1
|
- _UseAlphaClip: 1
|
||||||
- _UseBackLighting: 0
|
- _UseBackLighting: 0
|
||||||
- _UseDissolve: 0
|
- _UseDissolve: 0
|
||||||
|
- _UseDissolveOffsetUV: 0
|
||||||
- _UseEF: 1
|
- _UseEF: 1
|
||||||
- _UseEmission: 0
|
- _UseEmission: 0
|
||||||
- _UseFB: 0
|
- _UseFB: 0
|
||||||
@ -99,7 +116,10 @@ Material:
|
|||||||
- _UseUVDistortion: 1
|
- _UseUVDistortion: 1
|
||||||
- _ZWrite: 0
|
- _ZWrite: 0
|
||||||
m_Colors:
|
m_Colors:
|
||||||
|
- _DissolveScroll: {r: 0, g: 0, b: 0, a: 0}
|
||||||
- _DistortScrolling: {r: 0, g: -1, b: 1, a: 1}
|
- _DistortScrolling: {r: 0, g: -1, b: 1, a: 1}
|
||||||
- _OverlayTex_Scroll: {r: 0.1, g: 0.1, b: 1, a: 1}
|
- _OverlayTex_Scroll: {r: 0.1, g: 0.1, b: 1, a: 1}
|
||||||
- _ShadowColor: {r: 0, g: 0, b: 0, a: 1}
|
- _ShadowColor: {r: 0, g: 0, b: 0, a: 1}
|
||||||
- _SoftParticlesFadeDistance: {r: 0, g: 1, b: 0, a: 0}
|
- _SoftParticlesFadeDistance: {r: 0, g: 1, b: 0, a: 0}
|
||||||
|
m_BuildTextureStacks: []
|
||||||
|
m_AllowLocking: 1
|
||||||
|
|||||||
@ -2,21 +2,35 @@
|
|||||||
%TAG !u! tag:unity3d.com,2011:
|
%TAG !u! tag:unity3d.com,2011:
|
||||||
--- !u!21 &2100000
|
--- !u!21 &2100000
|
||||||
Material:
|
Material:
|
||||||
serializedVersion: 6
|
serializedVersion: 8
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
m_PrefabInstance: {fileID: 0}
|
m_PrefabInstance: {fileID: 0}
|
||||||
m_PrefabAsset: {fileID: 0}
|
m_PrefabAsset: {fileID: 0}
|
||||||
m_Name: cfxr fire stepped fade hdr ab
|
m_Name: cfxr fire stepped fade hdr ab
|
||||||
m_Shader: {fileID: 4800000, guid: e198026df304af84a85675be636192ea, type: 3}
|
m_Shader: {fileID: 4800000, guid: e198026df304af84a85675be636192ea, type: 3}
|
||||||
m_ShaderKeywords: _ALPHATEST_ON _CFXR_EDGE_FADING _CFXR_HDR_BOOST _CFXR_SINGLE_CHANNEL
|
m_Parent: {fileID: 0}
|
||||||
_CFXR_UV_DISTORTION _FADING_ON
|
m_ModifiedSerializedProperties: 0
|
||||||
|
m_ValidKeywords:
|
||||||
|
- _ALPHABLEND_ON
|
||||||
|
- _ALPHATEST_ON
|
||||||
|
- _CFXR_EDGE_FADING
|
||||||
|
- _CFXR_HDR_BOOST
|
||||||
|
- _CFXR_SINGLE_CHANNEL
|
||||||
|
- _CFXR_UV_DISTORTION
|
||||||
|
- _FADING_ON
|
||||||
|
m_InvalidKeywords:
|
||||||
|
- _
|
||||||
|
- _CFXR_DITHERED_SHADOWS_OFF
|
||||||
|
- _CFXR_OVERLAYBLEND_RGBA
|
||||||
|
- _CFXR_OVERLAYTEX_OFF
|
||||||
m_LightmapFlags: 0
|
m_LightmapFlags: 0
|
||||||
m_EnableInstancingVariants: 0
|
m_EnableInstancingVariants: 0
|
||||||
m_DoubleSidedGI: 0
|
m_DoubleSidedGI: 0
|
||||||
m_CustomRenderQueue: -1
|
m_CustomRenderQueue: -1
|
||||||
stringTagMap: {}
|
stringTagMap: {}
|
||||||
disabledShaderPasses: []
|
disabledShaderPasses: []
|
||||||
|
m_LockedProperties:
|
||||||
m_SavedProperties:
|
m_SavedProperties:
|
||||||
serializedVersion: 3
|
serializedVersion: 3
|
||||||
m_TexEnvs:
|
m_TexEnvs:
|
||||||
@ -52,6 +66,7 @@ Material:
|
|||||||
m_Texture: {fileID: 0}
|
m_Texture: {fileID: 0}
|
||||||
m_Scale: {x: 1, y: 1}
|
m_Scale: {x: 1, y: 1}
|
||||||
m_Offset: {x: 0, y: 0}
|
m_Offset: {x: 0, y: 0}
|
||||||
|
m_Ints: []
|
||||||
m_Floats:
|
m_Floats:
|
||||||
- _BacklightTransmittance: 1
|
- _BacklightTransmittance: 1
|
||||||
- _BlendingType: 0
|
- _BlendingType: 0
|
||||||
@ -64,6 +79,7 @@ Material:
|
|||||||
- _DirectLightingRamp: 1
|
- _DirectLightingRamp: 1
|
||||||
- _DissolveSmooth: 0.1
|
- _DissolveSmooth: 0.1
|
||||||
- _Distort: 0.75
|
- _Distort: 0.75
|
||||||
|
- _DoubleDissolve: 0
|
||||||
- _DstBlend: 10
|
- _DstBlend: 10
|
||||||
- _EdgeFadePow: 2
|
- _EdgeFadePow: 2
|
||||||
- _FadeAlongU: 1
|
- _FadeAlongU: 1
|
||||||
@ -85,6 +101,7 @@ Material:
|
|||||||
- _UseAlphaClip: 1
|
- _UseAlphaClip: 1
|
||||||
- _UseBackLighting: 0
|
- _UseBackLighting: 0
|
||||||
- _UseDissolve: 0
|
- _UseDissolve: 0
|
||||||
|
- _UseDissolveOffsetUV: 0
|
||||||
- _UseEF: 1
|
- _UseEF: 1
|
||||||
- _UseEmission: 0
|
- _UseEmission: 0
|
||||||
- _UseFB: 0
|
- _UseFB: 0
|
||||||
@ -99,7 +116,10 @@ Material:
|
|||||||
- _UseUVDistortion: 1
|
- _UseUVDistortion: 1
|
||||||
- _ZWrite: 0
|
- _ZWrite: 0
|
||||||
m_Colors:
|
m_Colors:
|
||||||
|
- _DissolveScroll: {r: 0, g: 0, b: 0, a: 0}
|
||||||
- _DistortScrolling: {r: 0, g: -1.2, b: 1, a: 1}
|
- _DistortScrolling: {r: 0, g: -1.2, b: 1, a: 1}
|
||||||
- _OverlayTex_Scroll: {r: 0.1, g: 0.1, b: 1, a: 1}
|
- _OverlayTex_Scroll: {r: 0.1, g: 0.1, b: 1, a: 1}
|
||||||
- _ShadowColor: {r: 0, g: 0, b: 0, a: 1}
|
- _ShadowColor: {r: 0, g: 0, b: 0, a: 1}
|
||||||
- _SoftParticlesFadeDistance: {r: 0, g: 1, b: 0, a: 0}
|
- _SoftParticlesFadeDistance: {r: 0, g: 1, b: 0, a: 0}
|
||||||
|
m_BuildTextureStacks: []
|
||||||
|
m_AllowLocking: 1
|
||||||
|
|||||||
@ -2,21 +2,32 @@
|
|||||||
%TAG !u! tag:unity3d.com,2011:
|
%TAG !u! tag:unity3d.com,2011:
|
||||||
--- !u!21 &2100000
|
--- !u!21 &2100000
|
||||||
Material:
|
Material:
|
||||||
serializedVersion: 6
|
serializedVersion: 8
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
m_PrefabInstance: {fileID: 0}
|
m_PrefabInstance: {fileID: 0}
|
||||||
m_PrefabAsset: {fileID: 0}
|
m_PrefabAsset: {fileID: 0}
|
||||||
m_Name: cfxr magic star hdr ab
|
m_Name: cfxr magic star hdr ab
|
||||||
m_Shader: {fileID: 4800000, guid: e198026df304af84a85675be636192ea, type: 3}
|
m_Shader: {fileID: 4800000, guid: e198026df304af84a85675be636192ea, type: 3}
|
||||||
m_ShaderKeywords: _CFXR_DITHERED_SHADOWS_ON _CFXR_HDR_BOOST _CFXR_SINGLE_CHANNEL
|
m_Parent: {fileID: 0}
|
||||||
_FADING_ON
|
m_ModifiedSerializedProperties: 0
|
||||||
|
m_ValidKeywords:
|
||||||
|
- _ALPHABLEND_ON
|
||||||
|
- _CFXR_DITHERED_SHADOWS_ON
|
||||||
|
- _CFXR_HDR_BOOST
|
||||||
|
- _CFXR_SINGLE_CHANNEL
|
||||||
|
- _FADING_ON
|
||||||
|
m_InvalidKeywords:
|
||||||
|
- _
|
||||||
|
- _CFXR_OVERLAYBLEND_RGBA
|
||||||
|
- _CFXR_OVERLAYTEX_OFF
|
||||||
m_LightmapFlags: 0
|
m_LightmapFlags: 0
|
||||||
m_EnableInstancingVariants: 0
|
m_EnableInstancingVariants: 0
|
||||||
m_DoubleSidedGI: 0
|
m_DoubleSidedGI: 0
|
||||||
m_CustomRenderQueue: -1
|
m_CustomRenderQueue: -1
|
||||||
stringTagMap: {}
|
stringTagMap: {}
|
||||||
disabledShaderPasses: []
|
disabledShaderPasses: []
|
||||||
|
m_LockedProperties:
|
||||||
m_SavedProperties:
|
m_SavedProperties:
|
||||||
serializedVersion: 3
|
serializedVersion: 3
|
||||||
m_TexEnvs:
|
m_TexEnvs:
|
||||||
@ -52,6 +63,7 @@ Material:
|
|||||||
m_Texture: {fileID: 0}
|
m_Texture: {fileID: 0}
|
||||||
m_Scale: {x: 1, y: 1}
|
m_Scale: {x: 1, y: 1}
|
||||||
m_Offset: {x: 0, y: 0}
|
m_Offset: {x: 0, y: 0}
|
||||||
|
m_Ints: []
|
||||||
m_Floats:
|
m_Floats:
|
||||||
- _BacklightTransmittance: 1
|
- _BacklightTransmittance: 1
|
||||||
- _BlendingType: 0
|
- _BlendingType: 0
|
||||||
@ -64,6 +76,7 @@ Material:
|
|||||||
- _DirectLightingRamp: 1
|
- _DirectLightingRamp: 1
|
||||||
- _DissolveSmooth: 0.1
|
- _DissolveSmooth: 0.1
|
||||||
- _Distort: 0.1
|
- _Distort: 0.1
|
||||||
|
- _DoubleDissolve: 0
|
||||||
- _DstBlend: 10
|
- _DstBlend: 10
|
||||||
- _EdgeFadePow: 1
|
- _EdgeFadePow: 1
|
||||||
- _FadeAlongU: 0
|
- _FadeAlongU: 0
|
||||||
@ -84,6 +97,7 @@ Material:
|
|||||||
- _UseAlphaClip: 0
|
- _UseAlphaClip: 0
|
||||||
- _UseBackLighting: 0
|
- _UseBackLighting: 0
|
||||||
- _UseDissolve: 0
|
- _UseDissolve: 0
|
||||||
|
- _UseDissolveOffsetUV: 0
|
||||||
- _UseEF: 0
|
- _UseEF: 0
|
||||||
- _UseEmission: 0
|
- _UseEmission: 0
|
||||||
- _UseFB: 0
|
- _UseFB: 0
|
||||||
@ -99,7 +113,10 @@ Material:
|
|||||||
- _ZWrite: 0
|
- _ZWrite: 0
|
||||||
m_Colors:
|
m_Colors:
|
||||||
- _Color: {r: 3.8792846, g: 3.8792846, b: 3.8792846, a: 0}
|
- _Color: {r: 3.8792846, g: 3.8792846, b: 3.8792846, a: 0}
|
||||||
|
- _DissolveScroll: {r: 0, g: 0, b: 0, a: 0}
|
||||||
- _DistortScrolling: {r: 0, g: 0, b: 1, a: 1}
|
- _DistortScrolling: {r: 0, g: 0, b: 1, a: 1}
|
||||||
- _EmissionColor: {r: 0, g: 0, b: 0, a: 0}
|
- _EmissionColor: {r: 0, g: 0, b: 0, a: 0}
|
||||||
- _OverlayTex_Scroll: {r: 0.1, g: 0.1, b: 1, a: 1}
|
- _OverlayTex_Scroll: {r: 0.1, g: 0.1, b: 1, a: 1}
|
||||||
- _ShadowColor: {r: 0, g: 0, b: 0, a: 1}
|
- _ShadowColor: {r: 0, g: 0, b: 0, a: 1}
|
||||||
|
m_BuildTextureStacks: []
|
||||||
|
m_AllowLocking: 1
|
||||||
|
|||||||
@ -2,21 +2,32 @@
|
|||||||
%TAG !u! tag:unity3d.com,2011:
|
%TAG !u! tag:unity3d.com,2011:
|
||||||
--- !u!21 &2100000
|
--- !u!21 &2100000
|
||||||
Material:
|
Material:
|
||||||
serializedVersion: 6
|
serializedVersion: 8
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
m_PrefabInstance: {fileID: 0}
|
m_PrefabInstance: {fileID: 0}
|
||||||
m_PrefabAsset: {fileID: 0}
|
m_PrefabAsset: {fileID: 0}
|
||||||
m_Name: cfxr stretch rectangle ray hdr ab
|
m_Name: cfxr stretch rectangle ray hdr ab
|
||||||
m_Shader: {fileID: 4800000, guid: e198026df304af84a85675be636192ea, type: 3}
|
m_Shader: {fileID: 4800000, guid: e198026df304af84a85675be636192ea, type: 3}
|
||||||
m_ShaderKeywords: _ALPHABLEND_ON _CFXR_DITHERED_SHADOWS_ON _CFXR_HDR_BOOST _CFXR_SINGLE_CHANNEL
|
m_Parent: {fileID: 0}
|
||||||
_FADING_ON
|
m_ModifiedSerializedProperties: 0
|
||||||
|
m_ValidKeywords:
|
||||||
|
- _ALPHABLEND_ON
|
||||||
|
- _CFXR_HDR_BOOST
|
||||||
|
- _CFXR_SINGLE_CHANNEL
|
||||||
|
- _FADING_ON
|
||||||
|
m_InvalidKeywords:
|
||||||
|
- _
|
||||||
|
- _CFXR_DITHERED_SHADOWS_OFF
|
||||||
|
- _CFXR_OVERLAYBLEND_RGBA
|
||||||
|
- _CFXR_OVERLAYTEX_OFF
|
||||||
m_LightmapFlags: 0
|
m_LightmapFlags: 0
|
||||||
m_EnableInstancingVariants: 0
|
m_EnableInstancingVariants: 0
|
||||||
m_DoubleSidedGI: 0
|
m_DoubleSidedGI: 0
|
||||||
m_CustomRenderQueue: -1
|
m_CustomRenderQueue: -1
|
||||||
stringTagMap: {}
|
stringTagMap: {}
|
||||||
disabledShaderPasses: []
|
disabledShaderPasses: []
|
||||||
|
m_LockedProperties:
|
||||||
m_SavedProperties:
|
m_SavedProperties:
|
||||||
serializedVersion: 3
|
serializedVersion: 3
|
||||||
m_TexEnvs:
|
m_TexEnvs:
|
||||||
@ -52,6 +63,7 @@ Material:
|
|||||||
m_Texture: {fileID: 0}
|
m_Texture: {fileID: 0}
|
||||||
m_Scale: {x: 1, y: 1}
|
m_Scale: {x: 1, y: 1}
|
||||||
m_Offset: {x: 0, y: 0}
|
m_Offset: {x: 0, y: 0}
|
||||||
|
m_Ints: []
|
||||||
m_Floats:
|
m_Floats:
|
||||||
- _AmbientColor: 0.5
|
- _AmbientColor: 0.5
|
||||||
- _AmbientIntensity: 1
|
- _AmbientIntensity: 1
|
||||||
@ -66,6 +78,7 @@ Material:
|
|||||||
- _DirectLightingRamp: 1
|
- _DirectLightingRamp: 1
|
||||||
- _DissolveSmooth: 0.1
|
- _DissolveSmooth: 0.1
|
||||||
- _Distort: 0.1
|
- _Distort: 0.1
|
||||||
|
- _DoubleDissolve: 0
|
||||||
- _DstBlend: 10
|
- _DstBlend: 10
|
||||||
- _EdgeFadePow: 1
|
- _EdgeFadePow: 1
|
||||||
- _FadeAlongU: 0
|
- _FadeAlongU: 0
|
||||||
@ -87,6 +100,7 @@ Material:
|
|||||||
- _UseAlphaClip: 0
|
- _UseAlphaClip: 0
|
||||||
- _UseBackLighting: 0
|
- _UseBackLighting: 0
|
||||||
- _UseDissolve: 0
|
- _UseDissolve: 0
|
||||||
|
- _UseDissolveOffsetUV: 0
|
||||||
- _UseEF: 0
|
- _UseEF: 0
|
||||||
- _UseEmission: 0
|
- _UseEmission: 0
|
||||||
- _UseFB: 0
|
- _UseFB: 0
|
||||||
@ -102,7 +116,10 @@ Material:
|
|||||||
- _ZWrite: 0
|
- _ZWrite: 0
|
||||||
m_Colors:
|
m_Colors:
|
||||||
- _Color: {r: 2, g: 2, b: 2, a: 0}
|
- _Color: {r: 2, g: 2, b: 2, a: 0}
|
||||||
|
- _DissolveScroll: {r: 0, g: 0, b: 0, a: 0}
|
||||||
- _DistortScrolling: {r: 0, g: 0, b: 1, a: 1}
|
- _DistortScrolling: {r: 0, g: 0, b: 1, a: 1}
|
||||||
- _OverlayTex_Scroll: {r: 0.1, g: 0.1, b: 1, a: 1}
|
- _OverlayTex_Scroll: {r: 0.1, g: 0.1, b: 1, a: 1}
|
||||||
- _ShadowColor: {r: 0, g: 0, b: 0, a: 1}
|
- _ShadowColor: {r: 0, g: 0, b: 0, a: 1}
|
||||||
- _SoftParticlesFadeDistance: {r: 0, g: 1, b: 0, a: 0}
|
- _SoftParticlesFadeDistance: {r: 0, g: 1, b: 0, a: 0}
|
||||||
|
m_BuildTextureStacks: []
|
||||||
|
m_AllowLocking: 1
|
||||||
|
|||||||
Binary file not shown.
BIN
Assets/Scripts/Contents/BossRaid/=== BossRaid System ===.prefab
(Stored with Git LFS)
BIN
Assets/Scripts/Contents/BossRaid/=== BossRaid System ===.prefab
(Stored with Git LFS)
Binary file not shown.
@ -31,6 +31,16 @@ namespace Streamingle.Contents.BossRaid
|
|||||||
public const string SFX_DAMAGE_POPUP = "sfx_damage_popup";
|
public const string SFX_DAMAGE_POPUP = "sfx_damage_popup";
|
||||||
public const string SFX_PHASE_TRANSITION = "sfx_phase_transition";
|
public const string SFX_PHASE_TRANSITION = "sfx_phase_transition";
|
||||||
|
|
||||||
|
// 보스 공격
|
||||||
|
public const string SFX_BOSS_BREATH = "sfx_boss_breath";
|
||||||
|
public const string SFX_BOSS_SLAM = "sfx_boss_slam";
|
||||||
|
public const string SFX_BOSS_CHARGE = "sfx_boss_charge";
|
||||||
|
|
||||||
|
// 유저 피격
|
||||||
|
public const string SFX_PLAYER_HIT = "sfx_player_hit";
|
||||||
|
public const string SFX_PLAYER_DEATH = "sfx_player_death";
|
||||||
|
public const string SFX_GAME_OVER = "sfx_game_over";
|
||||||
|
|
||||||
// BGM 키
|
// BGM 키
|
||||||
public const string BGM_BATTLE_NORMAL = "bgm_battle_normal";
|
public const string BGM_BATTLE_NORMAL = "bgm_battle_normal";
|
||||||
public const string BGM_BATTLE_RAGE = "bgm_battle_rage";
|
public const string BGM_BATTLE_RAGE = "bgm_battle_rage";
|
||||||
@ -182,6 +192,8 @@ namespace Streamingle.Contents.BossRaid
|
|||||||
SFX_HIT_NORMAL, SFX_HIT_CRITICAL, SFX_HIT_MISS,
|
SFX_HIT_NORMAL, SFX_HIT_CRITICAL, SFX_HIT_MISS,
|
||||||
SFX_BOSS_APPEAR, SFX_BOSS_RAGE, SFX_BOSS_DEATH,
|
SFX_BOSS_APPEAR, SFX_BOSS_RAGE, SFX_BOSS_DEATH,
|
||||||
SFX_VICTORY, SFX_DAMAGE_POPUP, SFX_PHASE_TRANSITION,
|
SFX_VICTORY, SFX_DAMAGE_POPUP, SFX_PHASE_TRANSITION,
|
||||||
|
SFX_BOSS_BREATH, SFX_BOSS_SLAM, SFX_BOSS_CHARGE,
|
||||||
|
SFX_PLAYER_HIT, SFX_PLAYER_DEATH, SFX_GAME_OVER,
|
||||||
BGM_BATTLE_NORMAL, BGM_BATTLE_RAGE, BGM_VICTORY,
|
BGM_BATTLE_NORMAL, BGM_BATTLE_RAGE, BGM_VICTORY,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
236
Assets/Scripts/Contents/BossRaid/Core/BossAttack.cs
Normal file
236
Assets/Scripts/Contents/BossRaid/Core/BossAttack.cs
Normal file
@ -0,0 +1,236 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Streamingle.Contents.BossRaid
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 보스 공격 연출을 관리합니다.
|
||||||
|
/// 웹/인스펙터에서 수동 트리거합니다.
|
||||||
|
/// </summary>
|
||||||
|
public class BossAttack : MonoBehaviour
|
||||||
|
{
|
||||||
|
#region Enums
|
||||||
|
|
||||||
|
public enum AttackType
|
||||||
|
{
|
||||||
|
Breath,
|
||||||
|
Slam,
|
||||||
|
RageBurst
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Events
|
||||||
|
|
||||||
|
/// <summary>공격이 유저에게 데미지를 줄 때 (attackType, damage)</summary>
|
||||||
|
public event Action<AttackType, int> OnAttackHit;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Fields
|
||||||
|
|
||||||
|
[Header("브레스")]
|
||||||
|
[SerializeField] private int breathDamage = 15;
|
||||||
|
[SerializeField] private float breathChargeTime = 0.5f;
|
||||||
|
[SerializeField] private float breathDuration = 2f;
|
||||||
|
[SerializeField] private int breathTickCount = 4;
|
||||||
|
|
||||||
|
[Header("내려찍기")]
|
||||||
|
[SerializeField] private int slamDamage = 25;
|
||||||
|
[SerializeField] private float slamChargeTime = 0.8f;
|
||||||
|
|
||||||
|
[Header("분노 폭발")]
|
||||||
|
[SerializeField] private int rageDamage = 30;
|
||||||
|
|
||||||
|
[Header("파티클 프리팹 (비어있으면 Resources/Particles에서 자동 로드)")]
|
||||||
|
public GameObject breathFXPrefab;
|
||||||
|
public GameObject slamImpactFXPrefab;
|
||||||
|
public GameObject rageBurstFXPrefab;
|
||||||
|
public GameObject playerHitFXPrefab;
|
||||||
|
|
||||||
|
private BossRaidAudio _audio;
|
||||||
|
private ScreenEffect _screenEffect;
|
||||||
|
private BossVisualEffect _bossVisual;
|
||||||
|
private Transform _bossTransform;
|
||||||
|
private ParticlePool _particlePool;
|
||||||
|
private Coroutine _attackCoroutine;
|
||||||
|
private bool _isAttacking;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
|
||||||
|
public bool IsAttacking => _isAttacking;
|
||||||
|
public int BreathDamage { get => breathDamage; set => breathDamage = value; }
|
||||||
|
public int SlamDamage { get => slamDamage; set => slamDamage = value; }
|
||||||
|
public int RageDamage { get => rageDamage; set => rageDamage = value; }
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Public Methods
|
||||||
|
|
||||||
|
public void Initialize(Transform bossTransform, BossRaidAudio audio, ScreenEffect screenEffect, BossVisualEffect bossVisual, ParticlePool particlePool)
|
||||||
|
{
|
||||||
|
_bossTransform = bossTransform;
|
||||||
|
_audio = audio;
|
||||||
|
_screenEffect = screenEffect;
|
||||||
|
_bossVisual = bossVisual;
|
||||||
|
_particlePool = particlePool;
|
||||||
|
|
||||||
|
// 비어있는 파티클은 Resources에서 자동 로드
|
||||||
|
if (breathFXPrefab == null) breathFXPrefab = Resources.Load<GameObject>("Particles/BreathFX");
|
||||||
|
if (slamImpactFXPrefab == null) slamImpactFXPrefab = Resources.Load<GameObject>("Particles/SlamImpactFX");
|
||||||
|
if (rageBurstFXPrefab == null) rageBurstFXPrefab = Resources.Load<GameObject>("Particles/RageBurstFX");
|
||||||
|
if (playerHitFXPrefab == null) playerHitFXPrefab = Resources.Load<GameObject>("Particles/PlayerHitFX");
|
||||||
|
|
||||||
|
int loaded = (breathFXPrefab != null ? 1 : 0) + (slamImpactFXPrefab != null ? 1 : 0)
|
||||||
|
+ (rageBurstFXPrefab != null ? 1 : 0) + (playerHitFXPrefab != null ? 1 : 0);
|
||||||
|
Debug.Log($"[BossAttack] 파티클 {loaded}/4개 로드 완료");
|
||||||
|
|
||||||
|
// 파티클 웜업
|
||||||
|
if (_particlePool != null)
|
||||||
|
{
|
||||||
|
_particlePool.Warmup(breathFXPrefab, 1);
|
||||||
|
_particlePool.Warmup(slamImpactFXPrefab, 1);
|
||||||
|
_particlePool.Warmup(rageBurstFXPrefab, 1);
|
||||||
|
_particlePool.Warmup(playerHitFXPrefab, 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 브레스 공격 실행
|
||||||
|
/// </summary>
|
||||||
|
public void ExecuteBreath()
|
||||||
|
{
|
||||||
|
if (_isAttacking) return;
|
||||||
|
if (_attackCoroutine != null) StopCoroutine(_attackCoroutine);
|
||||||
|
_attackCoroutine = StartCoroutine(BreathCoroutine());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 내려찍기 공격 실행
|
||||||
|
/// </summary>
|
||||||
|
public void ExecuteSlam()
|
||||||
|
{
|
||||||
|
if (_isAttacking) return;
|
||||||
|
if (_attackCoroutine != null) StopCoroutine(_attackCoroutine);
|
||||||
|
_attackCoroutine = StartCoroutine(SlamCoroutine());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 분노 폭발 실행
|
||||||
|
/// </summary>
|
||||||
|
public void ExecuteRageBurst()
|
||||||
|
{
|
||||||
|
if (_isAttacking) return;
|
||||||
|
if (_attackCoroutine != null) StopCoroutine(_attackCoroutine);
|
||||||
|
_attackCoroutine = StartCoroutine(RageBurstCoroutine());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CancelAttack()
|
||||||
|
{
|
||||||
|
if (_attackCoroutine != null)
|
||||||
|
{
|
||||||
|
StopCoroutine(_attackCoroutine);
|
||||||
|
_attackCoroutine = null;
|
||||||
|
}
|
||||||
|
_isAttacking = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Private Methods
|
||||||
|
|
||||||
|
private Vector3 BossPos => _bossTransform != null ? _bossTransform.position : Vector3.zero;
|
||||||
|
|
||||||
|
private IEnumerator BreathCoroutine()
|
||||||
|
{
|
||||||
|
_isAttacking = true;
|
||||||
|
|
||||||
|
// 차징
|
||||||
|
_audio?.PlaySFX(BossRaidAudio.SFX_BOSS_CHARGE);
|
||||||
|
yield return new WaitForSeconds(breathChargeTime);
|
||||||
|
|
||||||
|
// 브레스 발사 (보스 forward 방향, 프리팹 회전 유지)
|
||||||
|
_audio?.PlaySFX(BossRaidAudio.SFX_BOSS_BREATH);
|
||||||
|
Quaternion bossRot = _bossTransform != null ? _bossTransform.rotation : Quaternion.identity;
|
||||||
|
Vector3 forward = _bossTransform != null ? _bossTransform.forward : Vector3.forward;
|
||||||
|
Vector3 spawnPos = BossPos + Vector3.up * 1.5f + forward * 1f;
|
||||||
|
_particlePool?.Spawn(breathFXPrefab, spawnPos, bossRot);
|
||||||
|
|
||||||
|
// 틱 데미지
|
||||||
|
float tickInterval = breathDuration / breathTickCount;
|
||||||
|
for (int i = 0; i < breathTickCount; i++)
|
||||||
|
{
|
||||||
|
OnAttackHit?.Invoke(AttackType.Breath, breathDamage / breathTickCount);
|
||||||
|
_screenEffect?.PlayShake(0.15f, 0.1f);
|
||||||
|
yield return new WaitForSeconds(tickInterval);
|
||||||
|
}
|
||||||
|
|
||||||
|
_isAttacking = false;
|
||||||
|
_attackCoroutine = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerator SlamCoroutine()
|
||||||
|
{
|
||||||
|
_isAttacking = true;
|
||||||
|
|
||||||
|
// 차징 (보스 위로 솟기)
|
||||||
|
_audio?.PlaySFX(BossRaidAudio.SFX_BOSS_CHARGE);
|
||||||
|
Vector3 originalPos = BossPos;
|
||||||
|
|
||||||
|
if (_bossTransform != null)
|
||||||
|
{
|
||||||
|
float elapsed = 0f;
|
||||||
|
while (elapsed < slamChargeTime)
|
||||||
|
{
|
||||||
|
elapsed += Time.deltaTime;
|
||||||
|
float t = elapsed / slamChargeTime;
|
||||||
|
float yOffset = Mathf.Sin(t * Mathf.PI) * 1.5f;
|
||||||
|
_bossTransform.position = originalPos + Vector3.up * yOffset;
|
||||||
|
yield return null;
|
||||||
|
}
|
||||||
|
_bossTransform.position = originalPos;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 내려찍기
|
||||||
|
_audio?.PlaySFX(BossRaidAudio.SFX_BOSS_SLAM);
|
||||||
|
Vector3 impactPos = BossPos;
|
||||||
|
impactPos.y = 0f;
|
||||||
|
_particlePool?.Spawn(slamImpactFXPrefab, impactPos);
|
||||||
|
_screenEffect?.PlayShake(0.6f, 0.3f);
|
||||||
|
_screenEffect?.PlayFlash(new Color(1f, 0.8f, 0.3f), 0.15f);
|
||||||
|
|
||||||
|
OnAttackHit?.Invoke(AttackType.Slam, slamDamage);
|
||||||
|
|
||||||
|
yield return new WaitForSeconds(0.3f);
|
||||||
|
_isAttacking = false;
|
||||||
|
_attackCoroutine = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerator RageBurstCoroutine()
|
||||||
|
{
|
||||||
|
_isAttacking = true;
|
||||||
|
|
||||||
|
// 차징 (강한 흔들림)
|
||||||
|
_audio?.PlaySFX(BossRaidAudio.SFX_BOSS_RAGE);
|
||||||
|
_screenEffect?.PlayShake(0.3f, 1f);
|
||||||
|
|
||||||
|
yield return new WaitForSeconds(1f);
|
||||||
|
|
||||||
|
// 폭발
|
||||||
|
_particlePool?.Spawn(rageBurstFXPrefab, BossPos);
|
||||||
|
_screenEffect?.PlayFlash(new Color(1f, 0.2f, 0.1f), 0.3f);
|
||||||
|
_screenEffect?.PlayShake(0.8f, 0.5f);
|
||||||
|
|
||||||
|
OnAttackHit?.Invoke(AttackType.RageBurst, rageDamage);
|
||||||
|
|
||||||
|
yield return new WaitForSeconds(0.5f);
|
||||||
|
_isAttacking = false;
|
||||||
|
_attackCoroutine = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
2
Assets/Scripts/Contents/BossRaid/Core/BossAttack.cs.meta
Normal file
2
Assets/Scripts/Contents/BossRaid/Core/BossAttack.cs.meta
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 71e07d6d0d75ea8439d98479b164ce19
|
||||||
@ -36,6 +36,12 @@ namespace Streamingle.Contents.BossRaid
|
|||||||
[SerializeField] private BossData bossData;
|
[SerializeField] private BossData bossData;
|
||||||
[SerializeField] private Transform bossSpawnPoint;
|
[SerializeField] private Transform bossSpawnPoint;
|
||||||
|
|
||||||
|
[Header("유저")]
|
||||||
|
[SerializeField] private PlayerController playerController;
|
||||||
|
[SerializeField]
|
||||||
|
[Tooltip("유저 HP (0이면 BossData 기본값 사용)")]
|
||||||
|
private int playerMaxHP = 100;
|
||||||
|
|
||||||
[Header("설정")]
|
[Header("설정")]
|
||||||
[SerializeField]
|
[SerializeField]
|
||||||
[Tooltip("보스 등장 연출 시간 (초)")]
|
[Tooltip("보스 등장 연출 시간 (초)")]
|
||||||
@ -62,6 +68,10 @@ namespace Streamingle.Contents.BossRaid
|
|||||||
private BossRaidAudio _audio;
|
private BossRaidAudio _audio;
|
||||||
private PhaseTransition _phaseTransition;
|
private PhaseTransition _phaseTransition;
|
||||||
private ParticlePool _particlePool;
|
private ParticlePool _particlePool;
|
||||||
|
private PlayerHPBar _playerHPBar;
|
||||||
|
private PlayerHitEffect _playerHitEffect;
|
||||||
|
private GameOverScreen _gameOverScreen;
|
||||||
|
private BossAttack _bossAttack;
|
||||||
|
|
||||||
private RaidState _currentState = RaidState.Idle;
|
private RaidState _currentState = RaidState.Idle;
|
||||||
private GameObject _bossInstance;
|
private GameObject _bossInstance;
|
||||||
@ -82,6 +92,8 @@ namespace Streamingle.Contents.BossRaid
|
|||||||
public RaidState CurrentState => _currentState;
|
public RaidState CurrentState => _currentState;
|
||||||
public BossController Boss => _bossController;
|
public BossController Boss => _bossController;
|
||||||
public BossRaidSafety Safety => _safety;
|
public BossRaidSafety Safety => _safety;
|
||||||
|
public PlayerController Player => playerController;
|
||||||
|
public BossAttack Attack => _bossAttack;
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@ -102,6 +114,10 @@ namespace Streamingle.Contents.BossRaid
|
|||||||
_victoryScreen = GetComponentInChildren<VictoryScreen>();
|
_victoryScreen = GetComponentInChildren<VictoryScreen>();
|
||||||
_audio = GetComponentInChildren<BossRaidAudio>();
|
_audio = GetComponentInChildren<BossRaidAudio>();
|
||||||
_phaseTransition = GetComponentInChildren<PhaseTransition>();
|
_phaseTransition = GetComponentInChildren<PhaseTransition>();
|
||||||
|
_playerHPBar = GetComponentInChildren<PlayerHPBar>();
|
||||||
|
_playerHitEffect = GetComponentInChildren<PlayerHitEffect>();
|
||||||
|
_gameOverScreen = GetComponentInChildren<GameOverScreen>();
|
||||||
|
_bossAttack = GetComponentInChildren<BossAttack>();
|
||||||
|
|
||||||
// 파티클 풀 초기화
|
// 파티클 풀 초기화
|
||||||
_particlePool = GetComponentInChildren<ParticlePool>();
|
_particlePool = GetComponentInChildren<ParticlePool>();
|
||||||
@ -156,6 +172,14 @@ namespace Streamingle.Contents.BossRaid
|
|||||||
_hpBar?.Hide();
|
_hpBar?.Hide();
|
||||||
_comboCounter?.Hide();
|
_comboCounter?.Hide();
|
||||||
_victoryScreen?.Hide();
|
_victoryScreen?.Hide();
|
||||||
|
_playerHPBar?.Hide();
|
||||||
|
_gameOverScreen?.Hide();
|
||||||
|
_bossAttack?.CancelAttack();
|
||||||
|
UnsubscribePlayerEvents();
|
||||||
|
if (_bossAttack != null)
|
||||||
|
_bossAttack.OnAttackHit -= HandleBossAttackHit;
|
||||||
|
if (playerController != null)
|
||||||
|
playerController.RestoreColor();
|
||||||
if (_phaseAuraInstance != null)
|
if (_phaseAuraInstance != null)
|
||||||
_phaseAuraInstance.Stop(true, ParticleSystemStopBehavior.StopEmittingAndClear);
|
_phaseAuraInstance.Stop(true, ParticleSystemStopBehavior.StopEmittingAndClear);
|
||||||
SetState(RaidState.Idle);
|
SetState(RaidState.Idle);
|
||||||
@ -233,6 +257,28 @@ namespace Streamingle.Contents.BossRaid
|
|||||||
|
|
||||||
yield return new WaitForSeconds(appearDuration);
|
yield return new WaitForSeconds(appearDuration);
|
||||||
|
|
||||||
|
// === 플레이어 초기화 ===
|
||||||
|
if (playerController != null)
|
||||||
|
{
|
||||||
|
playerController.Initialize(playerMaxHP);
|
||||||
|
playerController.OnDamaged += HandlePlayerDamaged;
|
||||||
|
playerController.OnDeath += HandlePlayerDeath;
|
||||||
|
playerController.OnHPChanged += HandlePlayerHPChanged;
|
||||||
|
|
||||||
|
if (_playerHPBar != null && playerController.HeadTransform != null)
|
||||||
|
{
|
||||||
|
_playerHPBar.Initialize(playerController.HeadTransform, "", playerController.HPBarOffset);
|
||||||
|
_playerHPBar.Show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// === 보스 공격 초기화 ===
|
||||||
|
if (_bossAttack != null && _bossInstance != null)
|
||||||
|
{
|
||||||
|
_bossAttack.Initialize(_bossInstance.transform, _audio, _screenEffect, _bossVisual, _particlePool);
|
||||||
|
_bossAttack.OnAttackHit += HandleBossAttackHit;
|
||||||
|
}
|
||||||
|
|
||||||
// === Battle ===
|
// === Battle ===
|
||||||
SetState(RaidState.Battle);
|
SetState(RaidState.Battle);
|
||||||
_audio?.PlayBGM(BossRaidAudio.BGM_BATTLE_NORMAL);
|
_audio?.PlayBGM(BossRaidAudio.BGM_BATTLE_NORMAL);
|
||||||
@ -241,7 +287,7 @@ namespace Streamingle.Contents.BossRaid
|
|||||||
|
|
||||||
Debug.Log("[BossRaidManager] 전투 시작!");
|
Debug.Log("[BossRaidManager] 전투 시작!");
|
||||||
|
|
||||||
// Battle은 OnBossDeath 이벤트로 종료됨
|
// Battle은 OnBossDeath / OnPlayerDeath 이벤트로 종료됨
|
||||||
}
|
}
|
||||||
|
|
||||||
private IEnumerator DefeatSequence()
|
private IEnumerator DefeatSequence()
|
||||||
@ -490,6 +536,83 @@ namespace Streamingle.Contents.BossRaid
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region Private Methods - Player Events
|
||||||
|
|
||||||
|
private void HandleBossAttackHit(BossAttack.AttackType type, int damage)
|
||||||
|
{
|
||||||
|
if (playerController == null || playerController.IsDead) return;
|
||||||
|
|
||||||
|
playerController.TakeDamage(damage);
|
||||||
|
|
||||||
|
// 유저 피격 파티클 (HitEffectPoint 우선, 없으면 머리)
|
||||||
|
if (_bossAttack?.playerHitFXPrefab != null && playerController.HitEffectPoint != null)
|
||||||
|
{
|
||||||
|
Vector3 pos = playerController.HitEffectPoint.position;
|
||||||
|
_particlePool?.Spawn(_bossAttack.playerHitFXPrefab, pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandlePlayerDamaged(int damage)
|
||||||
|
{
|
||||||
|
_audio?.PlaySFX(BossRaidAudio.SFX_PLAYER_HIT);
|
||||||
|
_playerHitEffect?.Play(playerController);
|
||||||
|
_screenEffect?.PlayShake(0.2f, 0.15f);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandlePlayerDeath()
|
||||||
|
{
|
||||||
|
_audio?.PlaySFX(BossRaidAudio.SFX_PLAYER_DEATH);
|
||||||
|
_hitDetector.IsActive = false;
|
||||||
|
_bossAttack?.CancelAttack();
|
||||||
|
StartCoroutine(GameOverSequence());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandlePlayerHPChanged(int currentHP, int maxHP)
|
||||||
|
{
|
||||||
|
float ratio = maxHP > 0 ? (float)currentHP / maxHP : 0f;
|
||||||
|
_playerHPBar?.SetHP(ratio);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UnsubscribePlayerEvents()
|
||||||
|
{
|
||||||
|
if (playerController != null)
|
||||||
|
{
|
||||||
|
playerController.OnDamaged -= HandlePlayerDamaged;
|
||||||
|
playerController.OnDeath -= HandlePlayerDeath;
|
||||||
|
playerController.OnHPChanged -= HandlePlayerHPChanged;
|
||||||
|
}
|
||||||
|
if (_bossAttack != null)
|
||||||
|
_bossAttack.OnAttackHit -= HandleBossAttackHit;
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerator GameOverSequence()
|
||||||
|
{
|
||||||
|
yield return new WaitForSeconds(0.5f);
|
||||||
|
|
||||||
|
_audio?.StopBGM();
|
||||||
|
_audio?.PlaySFX(BossRaidAudio.SFX_GAME_OVER);
|
||||||
|
_gameOverScreen?.Show();
|
||||||
|
|
||||||
|
Debug.Log("[BossRaidManager] GAME OVER!");
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Public Methods - Boss Attack (웹/Stream Deck 연동)
|
||||||
|
|
||||||
|
public void ExecuteBreath() => _bossAttack?.ExecuteBreath();
|
||||||
|
public void ExecuteSlam() => _bossAttack?.ExecuteSlam();
|
||||||
|
public void ExecuteRageBurst() => _bossAttack?.ExecuteRageBurst();
|
||||||
|
|
||||||
|
public void SetPlayerHP(float ratio) => playerController?.SetHPRatio(ratio);
|
||||||
|
public void HealPlayer() => playerController?.FullHeal();
|
||||||
|
public void SetPlayerGodMode(bool on)
|
||||||
|
{
|
||||||
|
if (playerController != null) playerController.GodMode = on;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
#region Private Methods - Utility
|
#region Private Methods - Utility
|
||||||
|
|
||||||
private void SetState(RaidState newState)
|
private void SetState(RaidState newState)
|
||||||
@ -548,6 +671,18 @@ namespace Streamingle.Contents.BossRaid
|
|||||||
{
|
{
|
||||||
if (bossData == null || _particlePool == null) return;
|
if (bossData == null || _particlePool == null) return;
|
||||||
|
|
||||||
|
// 비어있는 파티클은 Resources에서 자동 로드
|
||||||
|
if (bossData.hitParticlePrefab == null)
|
||||||
|
bossData.hitParticlePrefab = Resources.Load<GameObject>("Particles/HitSpark");
|
||||||
|
if (bossData.criticalParticlePrefab == null)
|
||||||
|
bossData.criticalParticlePrefab = Resources.Load<GameObject>("Particles/CriticalHit");
|
||||||
|
if (bossData.deathParticlePrefab == null)
|
||||||
|
bossData.deathParticlePrefab = Resources.Load<GameObject>("Particles/BossExplosion");
|
||||||
|
if (bossData.victoryParticlePrefab == null)
|
||||||
|
bossData.victoryParticlePrefab = Resources.Load<GameObject>("Particles/VictoryConfetti");
|
||||||
|
if (bossData.phaseAuraParticlePrefab == null)
|
||||||
|
bossData.phaseAuraParticlePrefab = Resources.Load<GameObject>("Particles/PhaseAura");
|
||||||
|
|
||||||
// 히트 파티클은 자주 쓰이므로 넉넉하게
|
// 히트 파티클은 자주 쓰이므로 넉넉하게
|
||||||
_particlePool.Warmup(bossData.hitParticlePrefab, 5);
|
_particlePool.Warmup(bossData.hitParticlePrefab, 5);
|
||||||
_particlePool.Warmup(bossData.criticalParticlePrefab, 3);
|
_particlePool.Warmup(bossData.criticalParticlePrefab, 3);
|
||||||
|
|||||||
@ -56,7 +56,7 @@ namespace Streamingle.Contents.BossRaid
|
|||||||
/// 풀에서 파티클을 가져와 위치에 배치하고 재생합니다.
|
/// 풀에서 파티클을 가져와 위치에 배치하고 재생합니다.
|
||||||
/// 재생 완료 후 자동으로 풀에 반환됩니다.
|
/// 재생 완료 후 자동으로 풀에 반환됩니다.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public GameObject Spawn(GameObject prefab, Vector3 position)
|
public GameObject Spawn(GameObject prefab, Vector3 position, Quaternion? rotation = null)
|
||||||
{
|
{
|
||||||
if (prefab == null) return null;
|
if (prefab == null) return null;
|
||||||
|
|
||||||
@ -69,7 +69,6 @@ namespace Streamingle.Contents.BossRaid
|
|||||||
if (pool.Count > 0)
|
if (pool.Count > 0)
|
||||||
{
|
{
|
||||||
go = pool.Dequeue();
|
go = pool.Dequeue();
|
||||||
// 풀에서 꺼낸 것이 파괴되었으면 새로 생성
|
|
||||||
if (go == null)
|
if (go == null)
|
||||||
go = CreateInstance(prefab);
|
go = CreateInstance(prefab);
|
||||||
}
|
}
|
||||||
@ -79,7 +78,7 @@ namespace Streamingle.Contents.BossRaid
|
|||||||
}
|
}
|
||||||
|
|
||||||
go.transform.position = position;
|
go.transform.position = position;
|
||||||
go.transform.rotation = Quaternion.identity;
|
go.transform.rotation = rotation ?? Quaternion.identity;
|
||||||
go.SetActive(true);
|
go.SetActive(true);
|
||||||
|
|
||||||
var ps = go.GetComponent<ParticleSystem>();
|
var ps = go.GetComponent<ParticleSystem>();
|
||||||
|
|||||||
195
Assets/Scripts/Contents/BossRaid/Core/PlayerController.cs
Normal file
195
Assets/Scripts/Contents/BossRaid/Core/PlayerController.cs
Normal file
@ -0,0 +1,195 @@
|
|||||||
|
using System;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Streamingle.Contents.BossRaid
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 유저(아바타)의 HP, 피격, 무적, 사망을 관리합니다.
|
||||||
|
/// </summary>
|
||||||
|
public class PlayerController : MonoBehaviour
|
||||||
|
{
|
||||||
|
#region Events
|
||||||
|
|
||||||
|
public event Action<int, int> OnHPChanged;
|
||||||
|
public event Action<int> OnDamaged;
|
||||||
|
public event Action OnDeath;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Fields
|
||||||
|
|
||||||
|
[Header("데이터")]
|
||||||
|
[SerializeField]
|
||||||
|
[Tooltip("비어있으면 Resources에서 자동 로드")]
|
||||||
|
private PlayerData playerData;
|
||||||
|
|
||||||
|
[Header("참조")]
|
||||||
|
[SerializeField]
|
||||||
|
[Tooltip("아바타의 NiloToonPerCharacterRenderController")]
|
||||||
|
private MonoBehaviour niloToonController;
|
||||||
|
|
||||||
|
[SerializeField]
|
||||||
|
[Tooltip("HP바를 띄울 머리 Transform")]
|
||||||
|
private Transform headTransform;
|
||||||
|
|
||||||
|
[SerializeField]
|
||||||
|
[Tooltip("HP바 위치 오프셋 (머리 기준)")]
|
||||||
|
private Vector3 hpBarOffset = new Vector3(0f, 0.3f, 0f);
|
||||||
|
|
||||||
|
[SerializeField]
|
||||||
|
[Tooltip("피격 이펙트 위치 Transform (비어있으면 머리 사용)")]
|
||||||
|
private Transform hitEffectPoint;
|
||||||
|
|
||||||
|
private int _currentHP;
|
||||||
|
private bool _isDead;
|
||||||
|
private bool _isInvincible;
|
||||||
|
private float _invincibleTimer;
|
||||||
|
private bool _godMode;
|
||||||
|
|
||||||
|
// NiloToon 색상 캐시
|
||||||
|
private Color _originalTintColor = Color.white;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
|
||||||
|
public int CurrentHP => _currentHP;
|
||||||
|
public int MaxHP => playerData != null ? playerData.maxHP : 100;
|
||||||
|
public float HPRatio => MaxHP > 0 ? (float)_currentHP / MaxHP : 0f;
|
||||||
|
public PlayerData Data => playerData;
|
||||||
|
public bool IsDead => _isDead;
|
||||||
|
public bool IsInvincible => _isInvincible || _godMode;
|
||||||
|
public Transform HeadTransform => headTransform;
|
||||||
|
public Vector3 HPBarOffset => hpBarOffset;
|
||||||
|
public Transform HitEffectPoint => hitEffectPoint != null ? hitEffectPoint : headTransform;
|
||||||
|
|
||||||
|
public bool GodMode
|
||||||
|
{
|
||||||
|
get => _godMode;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_godMode = value;
|
||||||
|
Debug.Log($"[PlayerController] 무적 모드: {(_godMode ? "ON" : "OFF")}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Unity Messages
|
||||||
|
|
||||||
|
private void Update()
|
||||||
|
{
|
||||||
|
if (_isInvincible && !_godMode)
|
||||||
|
{
|
||||||
|
_invincibleTimer -= Time.deltaTime;
|
||||||
|
if (_invincibleTimer <= 0f)
|
||||||
|
_isInvincible = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private float InvincibilityDuration => playerData != null ? playerData.invincibilityDuration : 1.5f;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Public Methods
|
||||||
|
|
||||||
|
public void Initialize(int hp = -1)
|
||||||
|
{
|
||||||
|
// PlayerData 자동 로드
|
||||||
|
if (playerData == null)
|
||||||
|
playerData = Resources.Load<PlayerData>("PlayerData");
|
||||||
|
|
||||||
|
if (hp > 0 && playerData != null)
|
||||||
|
playerData.maxHP = hp;
|
||||||
|
|
||||||
|
_currentHP = MaxHP;
|
||||||
|
_isDead = false;
|
||||||
|
_isInvincible = false;
|
||||||
|
_godMode = false;
|
||||||
|
|
||||||
|
// NiloToon 원본 색상 저장
|
||||||
|
if (niloToonController != null)
|
||||||
|
{
|
||||||
|
var field = niloToonController.GetType().GetField("perCharacterTintColor",
|
||||||
|
System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance);
|
||||||
|
if (field != null)
|
||||||
|
_originalTintColor = (Color)field.GetValue(niloToonController);
|
||||||
|
}
|
||||||
|
|
||||||
|
OnHPChanged?.Invoke(_currentHP, MaxHP);
|
||||||
|
Debug.Log($"[PlayerController] 초기화 완료. HP: {_currentHP}/{MaxHP}");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void TakeDamage(int damage)
|
||||||
|
{
|
||||||
|
if (_isDead || IsInvincible) return;
|
||||||
|
|
||||||
|
_currentHP = Mathf.Max(0, _currentHP - damage);
|
||||||
|
OnDamaged?.Invoke(damage);
|
||||||
|
OnHPChanged?.Invoke(_currentHP, MaxHP);
|
||||||
|
|
||||||
|
// 무적 시작
|
||||||
|
_isInvincible = true;
|
||||||
|
_invincibleTimer = InvincibilityDuration;
|
||||||
|
|
||||||
|
Debug.Log($"[PlayerController] 피격! -{damage} | HP: {_currentHP}/{MaxHP}");
|
||||||
|
|
||||||
|
if (_currentHP <= 0)
|
||||||
|
{
|
||||||
|
_isDead = true;
|
||||||
|
OnDeath?.Invoke();
|
||||||
|
Debug.Log("[PlayerController] 사망!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetHPRatio(float ratio)
|
||||||
|
{
|
||||||
|
ratio = Mathf.Clamp01(ratio);
|
||||||
|
_currentHP = Mathf.RoundToInt(MaxHP * ratio);
|
||||||
|
_isDead = false;
|
||||||
|
_isInvincible = false;
|
||||||
|
OnHPChanged?.Invoke(_currentHP, MaxHP);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void FullHeal()
|
||||||
|
{
|
||||||
|
_currentHP = MaxHP;
|
||||||
|
_isDead = false;
|
||||||
|
_isInvincible = false;
|
||||||
|
OnHPChanged?.Invoke(_currentHP, MaxHP);
|
||||||
|
Debug.Log("[PlayerController] HP 전체 회복");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// NiloToon 피격 색상 플래시
|
||||||
|
/// </summary>
|
||||||
|
public void FlashHitColor(Color color)
|
||||||
|
{
|
||||||
|
SetNiloToonTint(color);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// NiloToon 원래 색상 복원
|
||||||
|
/// </summary>
|
||||||
|
public void RestoreColor()
|
||||||
|
{
|
||||||
|
SetNiloToonTint(_originalTintColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Private Methods
|
||||||
|
|
||||||
|
private void SetNiloToonTint(Color color)
|
||||||
|
{
|
||||||
|
if (niloToonController == null) return;
|
||||||
|
|
||||||
|
var field = niloToonController.GetType().GetField("perCharacterTintColor",
|
||||||
|
System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance);
|
||||||
|
if (field != null)
|
||||||
|
field.SetValue(niloToonController, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 2b316dc2527714246985aaf40f4ba95a
|
||||||
33
Assets/Scripts/Contents/BossRaid/Data/PlayerData.cs
Normal file
33
Assets/Scripts/Contents/BossRaid/Data/PlayerData.cs
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
using System;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Streamingle.Contents.BossRaid
|
||||||
|
{
|
||||||
|
[CreateAssetMenu(fileName = "PlayerData", menuName = "Streamingle/Contents/BossRaid/Player Data")]
|
||||||
|
public class PlayerData : ScriptableObject
|
||||||
|
{
|
||||||
|
[Header("스탯")]
|
||||||
|
[Min(1)]
|
||||||
|
public int maxHP = 100;
|
||||||
|
|
||||||
|
[Header("무적")]
|
||||||
|
[Tooltip("피격 후 무적 시간 (초)")]
|
||||||
|
[Range(0f, 5f)]
|
||||||
|
public float invincibilityDuration = 1.5f;
|
||||||
|
|
||||||
|
[Header("피격 연출")]
|
||||||
|
[Tooltip("NiloToon 피격 틴트 색상")]
|
||||||
|
public Color hitTintColor = new Color(1f, 0.3f, 0.3f);
|
||||||
|
|
||||||
|
[Tooltip("피격 틴트 지속 시간")]
|
||||||
|
[Range(0.05f, 1f)]
|
||||||
|
public float hitTintDuration = 0.3f;
|
||||||
|
|
||||||
|
[Tooltip("비네트 색상")]
|
||||||
|
public Color vignetteColor = new Color(1f, 0f, 0f, 0.4f);
|
||||||
|
|
||||||
|
[Tooltip("비네트 지속 시간")]
|
||||||
|
[Range(0.1f, 1f)]
|
||||||
|
public float vignetteDuration = 0.4f;
|
||||||
|
}
|
||||||
|
}
|
||||||
2
Assets/Scripts/Contents/BossRaid/Data/PlayerData.cs.meta
Normal file
2
Assets/Scripts/Contents/BossRaid/Data/PlayerData.cs.meta
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: ff44b8d33db660441900bc40df940114
|
||||||
@ -62,7 +62,24 @@ namespace Streamingle.Contents.BossRaid.Editor
|
|||||||
webObj.transform.SetParent(root.transform);
|
webObj.transform.SetParent(root.transform);
|
||||||
webObj.AddComponent<BossRaidWebServer>();
|
webObj.AddComponent<BossRaidWebServer>();
|
||||||
|
|
||||||
// === 11. 파티클 프리팹 연결 ===
|
// === 11. 유저 시스템 ===
|
||||||
|
PlayerData playerData = FindOrCreatePlayerData();
|
||||||
|
|
||||||
|
var playerObj = new GameObject("Player");
|
||||||
|
playerObj.transform.SetParent(root.transform);
|
||||||
|
playerObj.AddComponent<PlayerHPBar>();
|
||||||
|
playerObj.AddComponent<PlayerHitEffect>();
|
||||||
|
playerObj.AddComponent<GameOverScreen>();
|
||||||
|
|
||||||
|
Debug.Log("[BossRaid] PlayerController는 아바타에 직접 부착 후 BossRaidManager의 Player Controller에 할당하세요.");
|
||||||
|
Debug.Log("[BossRaid] PlayerController에 Head Transform(머리)과 NiloToonController를 할당하세요.");
|
||||||
|
|
||||||
|
// === 12. 보스 공격 ===
|
||||||
|
var attackObj = new GameObject("BossAttack");
|
||||||
|
attackObj.transform.SetParent(root.transform);
|
||||||
|
attackObj.AddComponent<BossAttack>();
|
||||||
|
|
||||||
|
// === 13. 파티클 프리팹 연결 ===
|
||||||
AssignParticlePrefabs(bossData);
|
AssignParticlePrefabs(bossData);
|
||||||
|
|
||||||
// === 완료 ===
|
// === 완료 ===
|
||||||
@ -107,6 +124,31 @@ namespace Streamingle.Contents.BossRaid.Editor
|
|||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static PlayerData FindOrCreatePlayerData()
|
||||||
|
{
|
||||||
|
string[] guids = AssetDatabase.FindAssets("t:PlayerData");
|
||||||
|
if (guids.Length > 0)
|
||||||
|
{
|
||||||
|
string path = AssetDatabase.GUIDToAssetPath(guids[0]);
|
||||||
|
var existing = AssetDatabase.LoadAssetAtPath<PlayerData>(path);
|
||||||
|
if (existing != null)
|
||||||
|
{
|
||||||
|
Debug.Log($"[BossRaid] 기존 PlayerData 사용: {path}");
|
||||||
|
return existing;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
string dataPath = "Assets/Scripts/Contents/BossRaid/Resources";
|
||||||
|
EnsureFolder(dataPath);
|
||||||
|
|
||||||
|
var data = ScriptableObject.CreateInstance<PlayerData>();
|
||||||
|
string assetPath = dataPath + "/PlayerData.asset";
|
||||||
|
AssetDatabase.CreateAsset(data, assetPath);
|
||||||
|
AssetDatabase.SaveAssets();
|
||||||
|
Debug.Log($"[BossRaid] PlayerData 생성: {assetPath}");
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
static void EnsureParticlePrefabs()
|
static void EnsureParticlePrefabs()
|
||||||
{
|
{
|
||||||
string particlePath = "Assets/Scripts/Contents/BossRaid/Resources/Particles";
|
string particlePath = "Assets/Scripts/Contents/BossRaid/Resources/Particles";
|
||||||
|
|||||||
@ -512,6 +512,184 @@ def gen_phase_transition():
|
|||||||
save_wav("sfx_phase_transition.wav", result)
|
save_wav("sfx_phase_transition.wav", result)
|
||||||
|
|
||||||
|
|
||||||
|
def gen_boss_breath():
|
||||||
|
"""보스 브레스 발사 - 에너지 차징 → 발사"""
|
||||||
|
# 차징 (고주파 수렴)
|
||||||
|
charge = pitch_sweep(1500, 400, 0.3, exponential=True)
|
||||||
|
t_ch = np.linspace(0, 1, len(charge))
|
||||||
|
charge = charge * (0.3 + 0.7 * np.power(t_ch, 0.5))
|
||||||
|
charge = adsr(charge, attack=0.05, decay=0.05, sustain=0.9, release=0.02) * 0.4
|
||||||
|
|
||||||
|
charge_noise = periodic_noise(3000, 0.3) * 0.2
|
||||||
|
charge_noise = charge_noise * np.power(t_ch, 1.5)
|
||||||
|
|
||||||
|
charge_part = mix_layers((charge, 1.0), (charge_noise, 0.5))
|
||||||
|
|
||||||
|
# 발사 (폭발적 방출)
|
||||||
|
blast = pitch_sweep(300, 60, 0.4, exponential=True)
|
||||||
|
blast = adsr(blast, attack=0.001, decay=0.25, sustain=0.1, release=0.15) * 0.8
|
||||||
|
|
||||||
|
blast_noise = noise(0.35) * 0.6
|
||||||
|
blast_noise = adsr(blast_noise, attack=0.001, decay=0.2, sustain=0.1, release=0.15)
|
||||||
|
|
||||||
|
sizzle = periodic_noise(5000, 0.3) * 0.3
|
||||||
|
sizzle = adsr(sizzle, attack=0.001, decay=0.15, sustain=0.1, release=0.15)
|
||||||
|
|
||||||
|
blast_part = mix_layers((blast, 1.0), (blast_noise, 0.6), (sizzle, 0.4))
|
||||||
|
blast_part = delay_effect(blast_part, delay_time=0.06, feedback=0.3, mix_amount=0.2)
|
||||||
|
|
||||||
|
result = concat(charge_part, blast_part)
|
||||||
|
result = quantize_8bit(result, levels=64)
|
||||||
|
save_wav("sfx_boss_breath.wav", result)
|
||||||
|
|
||||||
|
|
||||||
|
def gen_boss_slam():
|
||||||
|
"""보스 내려찍기 - 무거운 임팩트"""
|
||||||
|
windup = pitch_sweep(200, 600, 0.08, exponential=True)
|
||||||
|
windup = adsr(windup, attack=0.01, decay=0.04, sustain=0.3, release=0.03) * 0.3
|
||||||
|
|
||||||
|
impact = pitch_sweep(150, 20, 0.25, exponential=True)
|
||||||
|
impact = adsr(impact, attack=0.001, decay=0.18, sustain=0.05, release=0.07) * 0.9
|
||||||
|
|
||||||
|
sub = triangle_wave(35, 0.2) * 0.6
|
||||||
|
sub = adsr(sub, attack=0.001, decay=0.15, sustain=0.0, release=0.05)
|
||||||
|
|
||||||
|
crumble = noise(0.3) * 0.7
|
||||||
|
crumble = adsr(crumble, attack=0.001, decay=0.15, sustain=0.15, release=0.15)
|
||||||
|
|
||||||
|
debris1 = pitch_sweep(400, 150, 0.06, exponential=True) * 0.2
|
||||||
|
debris1 = adsr(debris1, attack=0.001, decay=0.04, sustain=0.0, release=0.02)
|
||||||
|
debris2 = pitch_sweep(500, 200, 0.05, exponential=True) * 0.15
|
||||||
|
debris2 = adsr(debris2, attack=0.001, decay=0.03, sustain=0.0, release=0.02)
|
||||||
|
|
||||||
|
impact_part = mix_layers((impact, 1.0), (sub, 0.7), (crumble, 0.5))
|
||||||
|
impact_part = delay_effect(impact_part, delay_time=0.08, feedback=0.35, mix_amount=0.25)
|
||||||
|
|
||||||
|
result = concat(windup, impact_part, silence(0.05), debris1, silence(0.03), debris2)
|
||||||
|
result = quantize_8bit(result, levels=64)
|
||||||
|
save_wav("sfx_boss_slam.wav", result)
|
||||||
|
|
||||||
|
|
||||||
|
def gen_boss_charge():
|
||||||
|
"""보스 차징 예고 - 위협적인 경고음"""
|
||||||
|
beep1 = square_wave(880, 0.06) * 0.5
|
||||||
|
beep1 = adsr(beep1, attack=0.003, decay=0.02, sustain=0.4, release=0.02)
|
||||||
|
beep2 = square_wave(880, 0.06) * 0.5
|
||||||
|
beep2 = adsr(beep2, attack=0.003, decay=0.02, sustain=0.4, release=0.02)
|
||||||
|
|
||||||
|
charge = pitch_sweep(100, 900, 0.4, exponential=True)
|
||||||
|
t_ch = np.linspace(0, 1, len(charge))
|
||||||
|
trem_freq = np.linspace(4, 25, len(charge))
|
||||||
|
trem_env = 0.5 + 0.5 * np.sin(np.cumsum(2 * np.pi * trem_freq / SAMPLE_RATE))
|
||||||
|
charge = charge * trem_env
|
||||||
|
charge = adsr(charge, attack=0.05, decay=0.05, sustain=0.8, release=0.05) * 0.5
|
||||||
|
|
||||||
|
ch_noise = periodic_noise(2000, 0.4) * 0.25
|
||||||
|
ch_noise = ch_noise * np.power(t_ch, 1.5)
|
||||||
|
|
||||||
|
hi = pulse_wave(1200, 0.4, duty=0.125) * 0.15
|
||||||
|
hi = hi * np.power(t_ch, 2)
|
||||||
|
hi = adsr(hi, attack=0.1, decay=0.1, sustain=0.7, release=0.05)
|
||||||
|
|
||||||
|
charge_part = mix_layers((charge, 1.0), (ch_noise, 0.5), (hi, 0.4))
|
||||||
|
|
||||||
|
result = concat(beep1, silence(0.04), beep2, silence(0.06), charge_part)
|
||||||
|
result = quantize_8bit(result, levels=64)
|
||||||
|
result = delay_effect(result, delay_time=0.05, feedback=0.2, mix_amount=0.15)
|
||||||
|
save_wav("sfx_boss_charge.wav", result)
|
||||||
|
|
||||||
|
|
||||||
|
def gen_player_hit():
|
||||||
|
"""아바타 피격 - 플레이어가 맞는 소리"""
|
||||||
|
shock = pitch_sweep(1800, 400, 0.08, exponential=True)
|
||||||
|
shock = adsr(shock, attack=0.001, decay=0.05, sustain=0.1, release=0.03) * 0.6
|
||||||
|
|
||||||
|
hit = square_wave(300, 0.03) * 0.7
|
||||||
|
hit = adsr(hit, attack=0.001, decay=0.02, sustain=0.0, release=0.01)
|
||||||
|
|
||||||
|
n = noise(0.06) * 0.5
|
||||||
|
n = adsr(n, attack=0.001, decay=0.04, sustain=0.0, release=0.02)
|
||||||
|
|
||||||
|
wobble = vibrato(250, 0.12, vib_freq=20, vib_depth=0.08)
|
||||||
|
wobble = adsr(wobble, attack=0.01, decay=0.06, sustain=0.15, release=0.05) * 0.3
|
||||||
|
|
||||||
|
sub = triangle_wave(80, 0.06) * 0.3
|
||||||
|
sub = adsr(sub, attack=0.001, decay=0.04, sustain=0.0, release=0.02)
|
||||||
|
|
||||||
|
first = mix_layers((shock, 0.8), (hit, 1.0), (n, 0.6), (sub, 0.5))
|
||||||
|
result = concat(first, wobble)
|
||||||
|
result = quantize_8bit(result, levels=64)
|
||||||
|
save_wav("sfx_player_hit.wav", result)
|
||||||
|
|
||||||
|
|
||||||
|
def gen_player_death():
|
||||||
|
"""아바타 사망 - 슬픈 하강음"""
|
||||||
|
def sad_note(freq, dur):
|
||||||
|
w = square_wave(freq, dur) * 0.45
|
||||||
|
h = triangle_wave(freq, dur) * 0.2
|
||||||
|
combined = mix_layers((w, 1.0), (h, 0.5))
|
||||||
|
return adsr(combined, attack=0.005, decay=0.05, sustain=0.5, release=0.05)
|
||||||
|
|
||||||
|
p = silence(0.03)
|
||||||
|
n1 = sad_note(784, 0.15) # G5
|
||||||
|
n2 = sad_note(659, 0.15) # E5
|
||||||
|
n3 = sad_note(523, 0.15) # C5
|
||||||
|
n4 = sad_note(415, 0.35) # Ab4
|
||||||
|
|
||||||
|
melody = concat(n1, p, n2, p, n3, p, n4)
|
||||||
|
|
||||||
|
bass = pitch_sweep(200, 60, 0.8, wave_type='triangle', exponential=True)
|
||||||
|
bass = adsr(bass, attack=0.01, decay=0.4, sustain=0.2, release=0.3) * 0.25
|
||||||
|
|
||||||
|
max_len = max(len(melody), len(bass))
|
||||||
|
if len(melody) < max_len:
|
||||||
|
melody = np.pad(melody, (0, max_len - len(melody)))
|
||||||
|
if len(bass) < max_len:
|
||||||
|
bass = np.pad(bass, (0, max_len - len(bass)))
|
||||||
|
|
||||||
|
result = mix_layers((melody, 1.0), (bass, 0.5))
|
||||||
|
result = quantize_8bit(result, levels=64)
|
||||||
|
result = delay_effect(result, delay_time=0.1, feedback=0.4, mix_amount=0.3)
|
||||||
|
save_wav("sfx_player_death.wav", result)
|
||||||
|
|
||||||
|
|
||||||
|
def gen_game_over():
|
||||||
|
"""게임 오버 - 무거운 패배 징글"""
|
||||||
|
doom1 = chord([196, 233, 294], 0.25) # Gm
|
||||||
|
doom1 = adsr(doom1, attack=0.01, decay=0.08, sustain=0.6, release=0.06) * 0.5
|
||||||
|
|
||||||
|
doom2 = chord([175, 220, 262], 0.25) # F
|
||||||
|
doom2 = adsr(doom2, attack=0.01, decay=0.08, sustain=0.6, release=0.06) * 0.5
|
||||||
|
|
||||||
|
doom3 = chord([165, 196, 247], 0.25) # Em
|
||||||
|
doom3 = adsr(doom3, attack=0.01, decay=0.08, sustain=0.6, release=0.06) * 0.5
|
||||||
|
|
||||||
|
final = chord([131, 156, 196], 0.6) # Cm
|
||||||
|
final = adsr(final, attack=0.01, decay=0.2, sustain=0.4, release=0.35) * 0.55
|
||||||
|
|
||||||
|
p = silence(0.04)
|
||||||
|
melody = concat(doom1, p, doom2, p, doom3, p, final)
|
||||||
|
|
||||||
|
bass_drone = pitch_sweep(80, 40, 1.5, wave_type='triangle', exponential=True)
|
||||||
|
bass_drone = adsr(bass_drone, attack=0.05, decay=0.5, sustain=0.3, release=0.5) * 0.3
|
||||||
|
|
||||||
|
dark_noise = noise(1.5) * 0.1
|
||||||
|
dark_noise = adsr(dark_noise, attack=0.1, decay=0.5, sustain=0.15, release=0.5)
|
||||||
|
|
||||||
|
max_len = max(len(melody), len(bass_drone), len(dark_noise))
|
||||||
|
if len(melody) < max_len:
|
||||||
|
melody = np.pad(melody, (0, max_len - len(melody)))
|
||||||
|
if len(bass_drone) < max_len:
|
||||||
|
bass_drone = np.pad(bass_drone, (0, max_len - len(bass_drone)))
|
||||||
|
if len(dark_noise) < max_len:
|
||||||
|
dark_noise = np.pad(dark_noise, (0, max_len - len(dark_noise)))
|
||||||
|
|
||||||
|
result = mix_layers((melody, 1.0), (bass_drone, 0.5), (dark_noise, 0.4))
|
||||||
|
result = quantize_8bit(result, levels=64)
|
||||||
|
result = delay_effect(result, delay_time=0.12, feedback=0.4, mix_amount=0.3)
|
||||||
|
save_wav("sfx_game_over.wav", result)
|
||||||
|
|
||||||
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
print("Generating 8-bit SFX v2 (enhanced quality)...")
|
print("Generating 8-bit SFX v2 (enhanced quality)...")
|
||||||
@ -526,5 +704,11 @@ if __name__ == "__main__":
|
|||||||
gen_victory()
|
gen_victory()
|
||||||
gen_damage_popup()
|
gen_damage_popup()
|
||||||
gen_phase_transition()
|
gen_phase_transition()
|
||||||
|
gen_boss_breath()
|
||||||
|
gen_boss_slam()
|
||||||
|
gen_boss_charge()
|
||||||
|
gen_player_hit()
|
||||||
|
gen_player_death()
|
||||||
|
gen_game_over()
|
||||||
|
|
||||||
print("\nDone! 9 SFX files generated (v2).")
|
print("\nDone! 15 SFX files generated (v2).")
|
||||||
|
|||||||
BIN
Assets/Scripts/Contents/BossRaid/Resources/Audio/sfx_boss_appear.mp3
(Stored with Git LFS)
BIN
Assets/Scripts/Contents/BossRaid/Resources/Audio/sfx_boss_appear.mp3
(Stored with Git LFS)
Binary file not shown.
BIN
Assets/Scripts/Contents/BossRaid/Resources/Audio/sfx_boss_breath.mp3
(Stored with Git LFS)
Normal file
BIN
Assets/Scripts/Contents/BossRaid/Resources/Audio/sfx_boss_breath.mp3
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,23 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: cd4815834216deb458eb99d267bdbb05
|
||||||
|
AudioImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 8
|
||||||
|
defaultSettings:
|
||||||
|
serializedVersion: 2
|
||||||
|
loadType: 0
|
||||||
|
sampleRateSetting: 0
|
||||||
|
sampleRateOverride: 44100
|
||||||
|
compressionFormat: 1
|
||||||
|
quality: 1
|
||||||
|
conversionMode: 0
|
||||||
|
preloadAudioData: 0
|
||||||
|
platformSettingOverrides: {}
|
||||||
|
forceToMono: 0
|
||||||
|
normalize: 1
|
||||||
|
loadInBackground: 0
|
||||||
|
ambisonic: 0
|
||||||
|
3D: 1
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
BIN
Assets/Scripts/Contents/BossRaid/Resources/Audio/sfx_boss_charge.mp3
(Stored with Git LFS)
Normal file
BIN
Assets/Scripts/Contents/BossRaid/Resources/Audio/sfx_boss_charge.mp3
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,23 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: b8f77e6e668266546bb9d1bccf93af50
|
||||||
|
AudioImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 8
|
||||||
|
defaultSettings:
|
||||||
|
serializedVersion: 2
|
||||||
|
loadType: 0
|
||||||
|
sampleRateSetting: 0
|
||||||
|
sampleRateOverride: 44100
|
||||||
|
compressionFormat: 1
|
||||||
|
quality: 1
|
||||||
|
conversionMode: 0
|
||||||
|
preloadAudioData: 0
|
||||||
|
platformSettingOverrides: {}
|
||||||
|
forceToMono: 0
|
||||||
|
normalize: 1
|
||||||
|
loadInBackground: 0
|
||||||
|
ambisonic: 0
|
||||||
|
3D: 1
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
BIN
Assets/Scripts/Contents/BossRaid/Resources/Audio/sfx_boss_death.mp3
(Stored with Git LFS)
BIN
Assets/Scripts/Contents/BossRaid/Resources/Audio/sfx_boss_death.mp3
(Stored with Git LFS)
Binary file not shown.
BIN
Assets/Scripts/Contents/BossRaid/Resources/Audio/sfx_boss_rage.mp3
(Stored with Git LFS)
BIN
Assets/Scripts/Contents/BossRaid/Resources/Audio/sfx_boss_rage.mp3
(Stored with Git LFS)
Binary file not shown.
BIN
Assets/Scripts/Contents/BossRaid/Resources/Audio/sfx_boss_slam.mp3
(Stored with Git LFS)
Normal file
BIN
Assets/Scripts/Contents/BossRaid/Resources/Audio/sfx_boss_slam.mp3
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,23 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 955407f9973c3b74386bdb0e3db3301f
|
||||||
|
AudioImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 8
|
||||||
|
defaultSettings:
|
||||||
|
serializedVersion: 2
|
||||||
|
loadType: 0
|
||||||
|
sampleRateSetting: 0
|
||||||
|
sampleRateOverride: 44100
|
||||||
|
compressionFormat: 1
|
||||||
|
quality: 1
|
||||||
|
conversionMode: 0
|
||||||
|
preloadAudioData: 0
|
||||||
|
platformSettingOverrides: {}
|
||||||
|
forceToMono: 0
|
||||||
|
normalize: 1
|
||||||
|
loadInBackground: 0
|
||||||
|
ambisonic: 0
|
||||||
|
3D: 1
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
BIN
Assets/Scripts/Contents/BossRaid/Resources/Audio/sfx_damage_popup.mp3
(Stored with Git LFS)
BIN
Assets/Scripts/Contents/BossRaid/Resources/Audio/sfx_damage_popup.mp3
(Stored with Git LFS)
Binary file not shown.
BIN
Assets/Scripts/Contents/BossRaid/Resources/Audio/sfx_game_over.mp3
(Stored with Git LFS)
Normal file
BIN
Assets/Scripts/Contents/BossRaid/Resources/Audio/sfx_game_over.mp3
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,23 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 27d7dcce9905f6f46b1455f4e5b820dc
|
||||||
|
AudioImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 8
|
||||||
|
defaultSettings:
|
||||||
|
serializedVersion: 2
|
||||||
|
loadType: 0
|
||||||
|
sampleRateSetting: 0
|
||||||
|
sampleRateOverride: 44100
|
||||||
|
compressionFormat: 1
|
||||||
|
quality: 1
|
||||||
|
conversionMode: 0
|
||||||
|
preloadAudioData: 0
|
||||||
|
platformSettingOverrides: {}
|
||||||
|
forceToMono: 0
|
||||||
|
normalize: 1
|
||||||
|
loadInBackground: 0
|
||||||
|
ambisonic: 0
|
||||||
|
3D: 1
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
BIN
Assets/Scripts/Contents/BossRaid/Resources/Audio/sfx_hit_critical.mp3
(Stored with Git LFS)
BIN
Assets/Scripts/Contents/BossRaid/Resources/Audio/sfx_hit_critical.mp3
(Stored with Git LFS)
Binary file not shown.
BIN
Assets/Scripts/Contents/BossRaid/Resources/Audio/sfx_hit_miss.mp3
(Stored with Git LFS)
BIN
Assets/Scripts/Contents/BossRaid/Resources/Audio/sfx_hit_miss.mp3
(Stored with Git LFS)
Binary file not shown.
BIN
Assets/Scripts/Contents/BossRaid/Resources/Audio/sfx_hit_normal.mp3
(Stored with Git LFS)
BIN
Assets/Scripts/Contents/BossRaid/Resources/Audio/sfx_hit_normal.mp3
(Stored with Git LFS)
Binary file not shown.
BIN
Assets/Scripts/Contents/BossRaid/Resources/Audio/sfx_phase_transition.mp3
(Stored with Git LFS)
BIN
Assets/Scripts/Contents/BossRaid/Resources/Audio/sfx_phase_transition.mp3
(Stored with Git LFS)
Binary file not shown.
BIN
Assets/Scripts/Contents/BossRaid/Resources/Audio/sfx_player_death.mp3
(Stored with Git LFS)
Normal file
BIN
Assets/Scripts/Contents/BossRaid/Resources/Audio/sfx_player_death.mp3
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,23 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 914d0a76cfde63d4da4a8671fb6c8b21
|
||||||
|
AudioImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 8
|
||||||
|
defaultSettings:
|
||||||
|
serializedVersion: 2
|
||||||
|
loadType: 0
|
||||||
|
sampleRateSetting: 0
|
||||||
|
sampleRateOverride: 44100
|
||||||
|
compressionFormat: 1
|
||||||
|
quality: 1
|
||||||
|
conversionMode: 0
|
||||||
|
preloadAudioData: 0
|
||||||
|
platformSettingOverrides: {}
|
||||||
|
forceToMono: 0
|
||||||
|
normalize: 1
|
||||||
|
loadInBackground: 0
|
||||||
|
ambisonic: 0
|
||||||
|
3D: 1
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
BIN
Assets/Scripts/Contents/BossRaid/Resources/Audio/sfx_player_hit.mp3
(Stored with Git LFS)
Normal file
BIN
Assets/Scripts/Contents/BossRaid/Resources/Audio/sfx_player_hit.mp3
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,23 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 29176d805e336a34991f09a62a0e77d1
|
||||||
|
AudioImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 8
|
||||||
|
defaultSettings:
|
||||||
|
serializedVersion: 2
|
||||||
|
loadType: 0
|
||||||
|
sampleRateSetting: 0
|
||||||
|
sampleRateOverride: 44100
|
||||||
|
compressionFormat: 1
|
||||||
|
quality: 1
|
||||||
|
conversionMode: 0
|
||||||
|
preloadAudioData: 0
|
||||||
|
platformSettingOverrides: {}
|
||||||
|
forceToMono: 0
|
||||||
|
normalize: 1
|
||||||
|
loadInBackground: 0
|
||||||
|
ambisonic: 0
|
||||||
|
3D: 1
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
BIN
Assets/Scripts/Contents/BossRaid/Resources/BossData.asset
(Stored with Git LFS)
Normal file
BIN
Assets/Scripts/Contents/BossRaid/Resources/BossData.asset
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Assets/Scripts/Contents/BossRaid/Resources/Particles/BreathFX.prefab
(Stored with Git LFS)
Normal file
BIN
Assets/Scripts/Contents/BossRaid/Resources/Particles/BreathFX.prefab
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,7 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: dab8858c439e1ce44b241189a90bfdae
|
||||||
|
PrefabImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
BIN
Assets/Scripts/Contents/BossRaid/Resources/Particles/PlayerHitFX.prefab
(Stored with Git LFS)
Normal file
BIN
Assets/Scripts/Contents/BossRaid/Resources/Particles/PlayerHitFX.prefab
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,7 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: a00fb5f394dc72145bdb0da9fae2e036
|
||||||
|
PrefabImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
BIN
Assets/Scripts/Contents/BossRaid/Resources/Particles/RageBurstFX.prefab
(Stored with Git LFS)
Normal file
BIN
Assets/Scripts/Contents/BossRaid/Resources/Particles/RageBurstFX.prefab
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,7 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 3ce6e1aea4cdaf244b71dbaf1750aad2
|
||||||
|
PrefabImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
BIN
Assets/Scripts/Contents/BossRaid/Resources/Particles/SlamImpactFX.prefab
(Stored with Git LFS)
Normal file
BIN
Assets/Scripts/Contents/BossRaid/Resources/Particles/SlamImpactFX.prefab
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,7 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 95bbbe340f352a044bb8682c9a7ac460
|
||||||
|
PrefabImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
BIN
Assets/Scripts/Contents/BossRaid/Resources/PlayerData.asset
(Stored with Git LFS)
Normal file
BIN
Assets/Scripts/Contents/BossRaid/Resources/PlayerData.asset
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 3c93755ab47a5cf4ba387129fc315eb4
|
||||||
|
NativeFormatImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
mainObjectFileID: 11400000
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
BIN
Assets/Scripts/Contents/BossRaid/Resources/TestBossData.asset
(Stored with Git LFS)
BIN
Assets/Scripts/Contents/BossRaid/Resources/TestBossData.asset
(Stored with Git LFS)
Binary file not shown.
@ -186,7 +186,7 @@ namespace Streamingle.Contents.BossRaid
|
|||||||
_rootRect.anchorMin = new Vector2(1f, 0.5f);
|
_rootRect.anchorMin = new Vector2(1f, 0.5f);
|
||||||
_rootRect.anchorMax = new Vector2(1f, 0.5f);
|
_rootRect.anchorMax = new Vector2(1f, 0.5f);
|
||||||
_rootRect.pivot = new Vector2(1f, 0.5f);
|
_rootRect.pivot = new Vector2(1f, 0.5f);
|
||||||
_rootRect.sizeDelta = new Vector2(160f, 110f);
|
_rootRect.sizeDelta = new Vector2(300f, 200f);
|
||||||
_rootRect.anchoredPosition = new Vector2(OffScreenX, 0f);
|
_rootRect.anchoredPosition = new Vector2(OffScreenX, 0f);
|
||||||
|
|
||||||
// 콤보 숫자
|
// 콤보 숫자
|
||||||
@ -204,6 +204,7 @@ namespace Streamingle.Contents.BossRaid
|
|||||||
_comboText.alignment = TextAnchor.MiddleCenter;
|
_comboText.alignment = TextAnchor.MiddleCenter;
|
||||||
_comboText.fontStyle = FontStyle.Bold;
|
_comboText.fontStyle = FontStyle.Bold;
|
||||||
_comboText.horizontalOverflow = HorizontalWrapMode.Overflow;
|
_comboText.horizontalOverflow = HorizontalWrapMode.Overflow;
|
||||||
|
_comboText.verticalOverflow = VerticalWrapMode.Overflow;
|
||||||
_comboText.raycastTarget = false;
|
_comboText.raycastTarget = false;
|
||||||
if (_font != null) _comboText.font = _font;
|
if (_font != null) _comboText.font = _font;
|
||||||
var outline = comboObj.AddComponent<Outline>();
|
var outline = comboObj.AddComponent<Outline>();
|
||||||
|
|||||||
139
Assets/Scripts/Contents/BossRaid/UI/GameOverScreen.cs
Normal file
139
Assets/Scripts/Contents/BossRaid/UI/GameOverScreen.cs
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
using System.Collections;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.UI;
|
||||||
|
|
||||||
|
namespace Streamingle.Contents.BossRaid
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// GAME OVER 화면. 유저 HP 0 시 표시됩니다.
|
||||||
|
/// </summary>
|
||||||
|
public class GameOverScreen : MonoBehaviour
|
||||||
|
{
|
||||||
|
#region Fields
|
||||||
|
|
||||||
|
[Header("비주얼")]
|
||||||
|
[SerializeField] private Color titleColor = new Color(0.9f, 0.15f, 0.1f);
|
||||||
|
[SerializeField] private Color bgColor = new Color(0f, 0f, 0f, 0.6f);
|
||||||
|
|
||||||
|
private Canvas _canvas;
|
||||||
|
private CanvasGroup _canvasGroup;
|
||||||
|
private Text _titleText;
|
||||||
|
private Coroutine _showCoroutine;
|
||||||
|
private Font _font;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Unity Messages
|
||||||
|
|
||||||
|
private void Awake()
|
||||||
|
{
|
||||||
|
_font = BossRaidFontLoader.Load();
|
||||||
|
CreateUI();
|
||||||
|
_canvasGroup.alpha = 0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Public Methods
|
||||||
|
|
||||||
|
public void Show()
|
||||||
|
{
|
||||||
|
if (_showCoroutine != null) StopCoroutine(_showCoroutine);
|
||||||
|
_showCoroutine = StartCoroutine(ShowCoroutine());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Hide()
|
||||||
|
{
|
||||||
|
if (_showCoroutine != null)
|
||||||
|
{
|
||||||
|
StopCoroutine(_showCoroutine);
|
||||||
|
_showCoroutine = null;
|
||||||
|
}
|
||||||
|
_canvasGroup.alpha = 0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Private Methods
|
||||||
|
|
||||||
|
private IEnumerator ShowCoroutine()
|
||||||
|
{
|
||||||
|
_titleText.text = "";
|
||||||
|
_canvasGroup.alpha = 0f;
|
||||||
|
|
||||||
|
// 페이드 인
|
||||||
|
float elapsed = 0f;
|
||||||
|
while (elapsed < 0.5f)
|
||||||
|
{
|
||||||
|
elapsed += Time.deltaTime;
|
||||||
|
_canvasGroup.alpha = elapsed / 0.5f;
|
||||||
|
yield return null;
|
||||||
|
}
|
||||||
|
_canvasGroup.alpha = 1f;
|
||||||
|
|
||||||
|
// 텍스트 등장 (펀치 스케일)
|
||||||
|
_titleText.text = "GAME OVER";
|
||||||
|
var rect = _titleText.rectTransform;
|
||||||
|
rect.localScale = Vector3.one * 2f;
|
||||||
|
|
||||||
|
elapsed = 0f;
|
||||||
|
while (elapsed < 0.4f)
|
||||||
|
{
|
||||||
|
elapsed += Time.deltaTime;
|
||||||
|
float t = elapsed / 0.4f;
|
||||||
|
float ease = 1f + 2.7f * Mathf.Pow(t - 1f, 3f) + 1.7f * Mathf.Pow(t - 1f, 2f);
|
||||||
|
rect.localScale = Vector3.one * Mathf.LerpUnclamped(2f, 1f, ease);
|
||||||
|
yield return null;
|
||||||
|
}
|
||||||
|
rect.localScale = Vector3.one;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CreateUI()
|
||||||
|
{
|
||||||
|
var canvasObj = new GameObject("BossRaid_GameOver");
|
||||||
|
canvasObj.transform.SetParent(transform);
|
||||||
|
_canvas = canvasObj.AddComponent<Canvas>();
|
||||||
|
_canvas.renderMode = RenderMode.ScreenSpaceOverlay;
|
||||||
|
_canvas.sortingOrder = 201;
|
||||||
|
_canvasGroup = canvasObj.AddComponent<CanvasGroup>();
|
||||||
|
_canvasGroup.interactable = false;
|
||||||
|
_canvasGroup.blocksRaycasts = false;
|
||||||
|
var scaler = canvasObj.AddComponent<CanvasScaler>();
|
||||||
|
scaler.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize;
|
||||||
|
scaler.referenceResolution = new Vector2(1920, 1080);
|
||||||
|
|
||||||
|
// 배경
|
||||||
|
var bgObj = new GameObject("BG");
|
||||||
|
bgObj.transform.SetParent(canvasObj.transform, false);
|
||||||
|
var bgRect = bgObj.AddComponent<RectTransform>();
|
||||||
|
bgRect.anchorMin = Vector2.zero;
|
||||||
|
bgRect.anchorMax = Vector2.one;
|
||||||
|
bgRect.offsetMin = Vector2.zero;
|
||||||
|
bgRect.offsetMax = Vector2.zero;
|
||||||
|
var bgImg = bgObj.AddComponent<Image>();
|
||||||
|
bgImg.color = bgColor;
|
||||||
|
bgImg.raycastTarget = false;
|
||||||
|
|
||||||
|
// 타이틀
|
||||||
|
var titleObj = new GameObject("Title");
|
||||||
|
titleObj.transform.SetParent(canvasObj.transform, false);
|
||||||
|
var titleRect = titleObj.AddComponent<RectTransform>();
|
||||||
|
titleRect.anchorMin = new Vector2(0.1f, 0.3f);
|
||||||
|
titleRect.anchorMax = new Vector2(0.9f, 0.7f);
|
||||||
|
titleRect.offsetMin = Vector2.zero;
|
||||||
|
titleRect.offsetMax = Vector2.zero;
|
||||||
|
_titleText = titleObj.AddComponent<Text>();
|
||||||
|
_titleText.fontSize = 90;
|
||||||
|
_titleText.color = titleColor;
|
||||||
|
_titleText.alignment = TextAnchor.MiddleCenter;
|
||||||
|
_titleText.fontStyle = FontStyle.Bold;
|
||||||
|
_titleText.raycastTarget = false;
|
||||||
|
if (_font != null) _titleText.font = _font;
|
||||||
|
var outline = titleObj.AddComponent<Outline>();
|
||||||
|
outline.effectColor = Color.black;
|
||||||
|
outline.effectDistance = new Vector2(3f, -3f);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 77c10ab592aba794bb52d7cf2c6047f7
|
||||||
166
Assets/Scripts/Contents/BossRaid/UI/PlayerHPBar.cs
Normal file
166
Assets/Scripts/Contents/BossRaid/UI/PlayerHPBar.cs
Normal file
@ -0,0 +1,166 @@
|
|||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.UI;
|
||||||
|
|
||||||
|
namespace Streamingle.Contents.BossRaid
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 유저 HP바. 머리 위 월드스페이스 캔버스로 표시됩니다.
|
||||||
|
/// </summary>
|
||||||
|
public class PlayerHPBar : MonoBehaviour
|
||||||
|
{
|
||||||
|
#region Fields
|
||||||
|
|
||||||
|
[Header("설정")]
|
||||||
|
[SerializeField] private Vector3 offset = new Vector3(0f, 0.3f, 0f);
|
||||||
|
[SerializeField] private float barWidth = 1.2f;
|
||||||
|
[SerializeField] private float barHeight = 0.12f;
|
||||||
|
[SerializeField] private float smoothSpeed = 8f;
|
||||||
|
|
||||||
|
[Header("색상")]
|
||||||
|
[SerializeField] private Color hpColor = new Color(0.2f, 0.85f, 0.3f);
|
||||||
|
[SerializeField] private Color hpColorLow = new Color(0.95f, 0.2f, 0.15f);
|
||||||
|
[SerializeField] private Color bgColor = new Color(0.1f, 0.1f, 0.1f, 0.85f);
|
||||||
|
[SerializeField] private Color frameColor = new Color(0.3f, 0.3f, 0.35f);
|
||||||
|
|
||||||
|
private Canvas _canvas;
|
||||||
|
private Image _hpFill;
|
||||||
|
private RectTransform _fillRect;
|
||||||
|
private Transform _followTarget;
|
||||||
|
private float _targetRatio = 1f;
|
||||||
|
private float _displayRatio = 1f;
|
||||||
|
private bool _isVisible;
|
||||||
|
private Font _font;
|
||||||
|
private Text _nameText;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Unity Messages
|
||||||
|
|
||||||
|
private void LateUpdate()
|
||||||
|
{
|
||||||
|
if (!_isVisible || _followTarget == null) return;
|
||||||
|
|
||||||
|
// 머리 위 따라다님
|
||||||
|
transform.position = _followTarget.position + offset;
|
||||||
|
|
||||||
|
// 카메라를 향하도록
|
||||||
|
if (Camera.main != null)
|
||||||
|
_canvas.transform.rotation = Camera.main.transform.rotation;
|
||||||
|
|
||||||
|
// 부드러운 HP 감소
|
||||||
|
_displayRatio = Mathf.Lerp(_displayRatio, _targetRatio, Time.deltaTime * smoothSpeed);
|
||||||
|
_fillRect.anchorMax = new Vector2(Mathf.Clamp01(_displayRatio), 1f);
|
||||||
|
_hpFill.color = _displayRatio > 0.3f ? hpColor : hpColorLow;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Public Methods
|
||||||
|
|
||||||
|
public void Initialize(Transform headTarget, string playerName = "", Vector3? customOffset = null)
|
||||||
|
{
|
||||||
|
_font = BossRaidFontLoader.Load();
|
||||||
|
_followTarget = headTarget;
|
||||||
|
if (customOffset.HasValue)
|
||||||
|
offset = customOffset.Value;
|
||||||
|
CreateUI();
|
||||||
|
_isVisible = true;
|
||||||
|
|
||||||
|
if (_nameText != null && !string.IsNullOrEmpty(playerName))
|
||||||
|
_nameText.text = playerName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetHP(float ratio)
|
||||||
|
{
|
||||||
|
_targetRatio = Mathf.Clamp01(ratio);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Show()
|
||||||
|
{
|
||||||
|
_isVisible = true;
|
||||||
|
if (_canvas != null) _canvas.gameObject.SetActive(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Hide()
|
||||||
|
{
|
||||||
|
_isVisible = false;
|
||||||
|
if (_canvas != null) _canvas.gameObject.SetActive(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Private Methods
|
||||||
|
|
||||||
|
private void CreateUI()
|
||||||
|
{
|
||||||
|
var canvasObj = new GameObject("PlayerHPBar_Canvas");
|
||||||
|
canvasObj.transform.SetParent(transform);
|
||||||
|
canvasObj.transform.localPosition = Vector3.zero;
|
||||||
|
_canvas = canvasObj.AddComponent<Canvas>();
|
||||||
|
_canvas.renderMode = RenderMode.WorldSpace;
|
||||||
|
_canvas.sortingOrder = 90;
|
||||||
|
|
||||||
|
var rt = canvasObj.GetComponent<RectTransform>();
|
||||||
|
rt.sizeDelta = new Vector2(barWidth, barHeight + 0.15f);
|
||||||
|
rt.localScale = Vector3.one;
|
||||||
|
|
||||||
|
// 프레임
|
||||||
|
var frameObj = new GameObject("Frame");
|
||||||
|
frameObj.transform.SetParent(canvasObj.transform, false);
|
||||||
|
var frameRect = frameObj.AddComponent<RectTransform>();
|
||||||
|
frameRect.anchorMin = new Vector2(0f, 0f);
|
||||||
|
frameRect.anchorMax = new Vector2(1f, 0.7f);
|
||||||
|
frameRect.offsetMin = Vector2.zero;
|
||||||
|
frameRect.offsetMax = Vector2.zero;
|
||||||
|
var frameImg = frameObj.AddComponent<Image>();
|
||||||
|
frameImg.color = frameColor;
|
||||||
|
frameImg.raycastTarget = false;
|
||||||
|
|
||||||
|
// 배경
|
||||||
|
var bgObj = new GameObject("BG");
|
||||||
|
bgObj.transform.SetParent(frameObj.transform, false);
|
||||||
|
var bgRect = bgObj.AddComponent<RectTransform>();
|
||||||
|
bgRect.anchorMin = Vector2.zero;
|
||||||
|
bgRect.anchorMax = Vector2.one;
|
||||||
|
bgRect.offsetMin = new Vector2(0.01f, 0.01f);
|
||||||
|
bgRect.offsetMax = new Vector2(-0.01f, -0.01f);
|
||||||
|
var bgImg = bgObj.AddComponent<Image>();
|
||||||
|
bgImg.color = bgColor;
|
||||||
|
bgImg.raycastTarget = false;
|
||||||
|
|
||||||
|
// HP Fill
|
||||||
|
var fillObj = new GameObject("Fill");
|
||||||
|
fillObj.transform.SetParent(bgObj.transform, false);
|
||||||
|
_fillRect = fillObj.AddComponent<RectTransform>();
|
||||||
|
_fillRect.anchorMin = Vector2.zero;
|
||||||
|
_fillRect.anchorMax = Vector2.one;
|
||||||
|
_fillRect.offsetMin = Vector2.zero;
|
||||||
|
_fillRect.offsetMax = Vector2.zero;
|
||||||
|
_hpFill = fillObj.AddComponent<Image>();
|
||||||
|
_hpFill.color = hpColor;
|
||||||
|
_hpFill.raycastTarget = false;
|
||||||
|
|
||||||
|
// 이름 텍스트 (바 위)
|
||||||
|
var nameObj = new GameObject("Name");
|
||||||
|
nameObj.transform.SetParent(canvasObj.transform, false);
|
||||||
|
var nameRect = nameObj.AddComponent<RectTransform>();
|
||||||
|
nameRect.anchorMin = new Vector2(0f, 0.7f);
|
||||||
|
nameRect.anchorMax = Vector2.one;
|
||||||
|
nameRect.offsetMin = Vector2.zero;
|
||||||
|
nameRect.offsetMax = Vector2.zero;
|
||||||
|
_nameText = nameObj.AddComponent<Text>();
|
||||||
|
_nameText.text = "";
|
||||||
|
_nameText.fontSize = 3;
|
||||||
|
_nameText.color = Color.white;
|
||||||
|
_nameText.alignment = TextAnchor.MiddleCenter;
|
||||||
|
_nameText.raycastTarget = false;
|
||||||
|
if (_font != null) _nameText.font = _font;
|
||||||
|
|
||||||
|
var outline = nameObj.AddComponent<Outline>();
|
||||||
|
outline.effectColor = Color.black;
|
||||||
|
outline.effectDistance = new Vector2(0.3f, -0.3f);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
2
Assets/Scripts/Contents/BossRaid/UI/PlayerHPBar.cs.meta
Normal file
2
Assets/Scripts/Contents/BossRaid/UI/PlayerHPBar.cs.meta
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 6b9275b0b06b5094bb7bedc8038afc2a
|
||||||
121
Assets/Scripts/Contents/BossRaid/Visual/PlayerHitEffect.cs
Normal file
121
Assets/Scripts/Contents/BossRaid/Visual/PlayerHitEffect.cs
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
using System.Collections;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.UI;
|
||||||
|
|
||||||
|
namespace Streamingle.Contents.BossRaid
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 유저 피격 시 빨간 비네트 오버레이 + NiloToon 색상 플래시.
|
||||||
|
/// </summary>
|
||||||
|
public class PlayerHitEffect : MonoBehaviour
|
||||||
|
{
|
||||||
|
#region Fields
|
||||||
|
|
||||||
|
// PlayerData에서 값을 읽되, 없으면 기본값 사용
|
||||||
|
private Color vignetteColor = new Color(1f, 0f, 0f, 0.4f);
|
||||||
|
private float vignetteDuration = 0.4f;
|
||||||
|
private Color hitTintColor = new Color(1f, 0.3f, 0.3f);
|
||||||
|
private float tintDuration = 0.3f;
|
||||||
|
|
||||||
|
private Canvas _canvas;
|
||||||
|
private Image _vignetteImage;
|
||||||
|
private Coroutine _vignetteCoroutine;
|
||||||
|
private Coroutine _tintCoroutine;
|
||||||
|
private PlayerController _player;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Unity Messages
|
||||||
|
|
||||||
|
private void Awake()
|
||||||
|
{
|
||||||
|
CreateVignetteUI();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Public Methods
|
||||||
|
|
||||||
|
public void Play(PlayerController player)
|
||||||
|
{
|
||||||
|
_player = player;
|
||||||
|
|
||||||
|
// PlayerData에서 값 읽기
|
||||||
|
if (player?.Data != null)
|
||||||
|
{
|
||||||
|
vignetteColor = player.Data.vignetteColor;
|
||||||
|
vignetteDuration = player.Data.vignetteDuration;
|
||||||
|
hitTintColor = player.Data.hitTintColor;
|
||||||
|
tintDuration = player.Data.hitTintDuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_vignetteCoroutine != null) StopCoroutine(_vignetteCoroutine);
|
||||||
|
_vignetteCoroutine = StartCoroutine(VignetteCoroutine());
|
||||||
|
|
||||||
|
if (_tintCoroutine != null) StopCoroutine(_tintCoroutine);
|
||||||
|
_tintCoroutine = StartCoroutine(TintCoroutine());
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Private Methods
|
||||||
|
|
||||||
|
private IEnumerator VignetteCoroutine()
|
||||||
|
{
|
||||||
|
_vignetteImage.color = vignetteColor;
|
||||||
|
|
||||||
|
float elapsed = 0f;
|
||||||
|
while (elapsed < vignetteDuration)
|
||||||
|
{
|
||||||
|
elapsed += Time.deltaTime;
|
||||||
|
float t = elapsed / vignetteDuration;
|
||||||
|
var c = vignetteColor;
|
||||||
|
c.a = vignetteColor.a * (1f - t);
|
||||||
|
_vignetteImage.color = c;
|
||||||
|
yield return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
_vignetteImage.color = Color.clear;
|
||||||
|
_vignetteCoroutine = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerator TintCoroutine()
|
||||||
|
{
|
||||||
|
if (_player == null) yield break;
|
||||||
|
|
||||||
|
_player.FlashHitColor(hitTintColor);
|
||||||
|
|
||||||
|
yield return new WaitForSeconds(tintDuration * 0.3f);
|
||||||
|
|
||||||
|
// 부드럽게 원래 색상으로
|
||||||
|
float elapsed = 0f;
|
||||||
|
float fadeDur = tintDuration * 0.7f;
|
||||||
|
while (elapsed < fadeDur)
|
||||||
|
{
|
||||||
|
elapsed += Time.deltaTime;
|
||||||
|
float t = elapsed / fadeDur;
|
||||||
|
Color c = Color.Lerp(hitTintColor, Color.white, t);
|
||||||
|
_player.FlashHitColor(c);
|
||||||
|
yield return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
_player.RestoreColor();
|
||||||
|
_tintCoroutine = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CreateVignetteUI()
|
||||||
|
{
|
||||||
|
var canvasObj = new GameObject("BossRaid_PlayerVignette");
|
||||||
|
canvasObj.transform.SetParent(transform);
|
||||||
|
_canvas = canvasObj.AddComponent<Canvas>();
|
||||||
|
_canvas.renderMode = RenderMode.ScreenSpaceOverlay;
|
||||||
|
_canvas.sortingOrder = 997;
|
||||||
|
|
||||||
|
_vignetteImage = canvasObj.AddComponent<Image>();
|
||||||
|
_vignetteImage.color = Color.clear;
|
||||||
|
_vignetteImage.raycastTarget = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: d0dc1f4dbc9ce184586f621b3705c8bd
|
||||||
@ -32,6 +32,7 @@ namespace Streamingle.Contents.BossRaid
|
|||||||
private BossController _bossController;
|
private BossController _bossController;
|
||||||
private BossRaidSafety _safety;
|
private BossRaidSafety _safety;
|
||||||
private BossRaidAudio _audio;
|
private BossRaidAudio _audio;
|
||||||
|
private PlayerController _playerController;
|
||||||
|
|
||||||
private readonly ConcurrentQueue<Action> _mainThreadActions = new ConcurrentQueue<Action>();
|
private readonly ConcurrentQueue<Action> _mainThreadActions = new ConcurrentQueue<Action>();
|
||||||
|
|
||||||
@ -288,6 +289,7 @@ namespace Streamingle.Contents.BossRaid
|
|||||||
|
|
||||||
CancelInvoke(nameof(CheckBossEvents));
|
CancelInvoke(nameof(CheckBossEvents));
|
||||||
UnsubscribeBossEvents();
|
UnsubscribeBossEvents();
|
||||||
|
UnsubscribePlayerEvents();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CheckBossEvents()
|
private void CheckBossEvents()
|
||||||
@ -303,6 +305,17 @@ namespace Streamingle.Contents.BossRaid
|
|||||||
_bossController.OnPhaseChanged += OnPhaseChanged;
|
_bossController.OnPhaseChanged += OnPhaseChanged;
|
||||||
_bossController.OnDeath += OnBossDeath;
|
_bossController.OnDeath += OnBossDeath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 플레이어 이벤트
|
||||||
|
var newPlayer = _raidManager?.Player;
|
||||||
|
if (newPlayer != null && newPlayer != _playerController)
|
||||||
|
{
|
||||||
|
UnsubscribePlayerEvents();
|
||||||
|
_playerController = newPlayer;
|
||||||
|
_playerController.OnHPChanged += OnPlayerHPChanged;
|
||||||
|
_playerController.OnDamaged += OnPlayerDamaged;
|
||||||
|
_playerController.OnDeath += OnPlayerDeath;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UnsubscribeBossEvents()
|
private void UnsubscribeBossEvents()
|
||||||
@ -317,10 +330,24 @@ namespace Streamingle.Contents.BossRaid
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void UnsubscribePlayerEvents()
|
||||||
|
{
|
||||||
|
if (_playerController != null)
|
||||||
|
{
|
||||||
|
_playerController.OnHPChanged -= OnPlayerHPChanged;
|
||||||
|
_playerController.OnDamaged -= OnPlayerDamaged;
|
||||||
|
_playerController.OnDeath -= OnPlayerDeath;
|
||||||
|
_playerController = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void OnRaidStateChanged(BossRaidManager.RaidState state) => BroadcastState();
|
private void OnRaidStateChanged(BossRaidManager.RaidState state) => BroadcastState();
|
||||||
private void OnHPChanged(int current, int max) => BroadcastState();
|
private void OnHPChanged(int current, int max) => BroadcastState();
|
||||||
private void OnDamaged(int dmg, bool crit, int hp, int max) => BroadcastState();
|
private void OnDamaged(int dmg, bool crit, int hp, int max) => BroadcastState();
|
||||||
private void OnPhaseChanged(int idx, BossData.PhaseData phase) => BroadcastState();
|
private void OnPhaseChanged(int idx, BossData.PhaseData phase) => BroadcastState();
|
||||||
|
private void OnPlayerHPChanged(int current, int max) => BroadcastState();
|
||||||
|
private void OnPlayerDamaged(int dmg) => BroadcastState();
|
||||||
|
private void OnPlayerDeath() => BroadcastState();
|
||||||
private void OnBossDeath() => BroadcastState();
|
private void OnBossDeath() => BroadcastState();
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
@ -345,6 +372,13 @@ namespace Streamingle.Contents.BossRaid
|
|||||||
hpLockRatio = _safety?.HPLockRatio ?? 0f,
|
hpLockRatio = _safety?.HPLockRatio ?? 0f,
|
||||||
bgmVolume = _audio?.BGMVolume ?? 0.5f,
|
bgmVolume = _audio?.BGMVolume ?? 0.5f,
|
||||||
sfxVolume = _audio?.SFXVolume ?? 1f,
|
sfxVolume = _audio?.SFXVolume ?? 1f,
|
||||||
|
// 유저
|
||||||
|
playerHP = _raidManager?.Player?.CurrentHP ?? 0,
|
||||||
|
playerMaxHP = _raidManager?.Player?.MaxHP ?? 0,
|
||||||
|
playerHPRatio = _raidManager?.Player?.HPRatio ?? 0f,
|
||||||
|
playerDead = _raidManager?.Player?.IsDead ?? false,
|
||||||
|
playerGodMode = _raidManager?.Player?.GodMode ?? false,
|
||||||
|
bossAttacking = _raidManager?.Attack?.IsAttacking ?? false,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -414,6 +448,31 @@ namespace Streamingle.Contents.BossRaid
|
|||||||
if (_audio != null) _audio.SFXVolume = sfxVol;
|
if (_audio != null) _audio.SFXVolume = sfxVol;
|
||||||
BroadcastState();
|
BroadcastState();
|
||||||
break;
|
break;
|
||||||
|
// 보스 공격
|
||||||
|
case "boss_breath":
|
||||||
|
_raidManager?.ExecuteBreath();
|
||||||
|
break;
|
||||||
|
case "boss_slam":
|
||||||
|
_raidManager?.ExecuteSlam();
|
||||||
|
break;
|
||||||
|
case "boss_rage_burst":
|
||||||
|
_raidManager?.ExecuteRageBurst();
|
||||||
|
break;
|
||||||
|
// 유저 제어
|
||||||
|
case "set_player_hp":
|
||||||
|
float pRatio = msg["ratio"]?.Value<float>() ?? 1f;
|
||||||
|
_raidManager?.SetPlayerHP(pRatio);
|
||||||
|
BroadcastState();
|
||||||
|
break;
|
||||||
|
case "heal_player":
|
||||||
|
_raidManager?.HealPlayer();
|
||||||
|
BroadcastState();
|
||||||
|
break;
|
||||||
|
case "toggle_god_mode":
|
||||||
|
bool god = msg["value"]?.Value<bool>() ?? false;
|
||||||
|
_raidManager?.SetPlayerGodMode(god);
|
||||||
|
BroadcastState();
|
||||||
|
break;
|
||||||
case "get_state":
|
case "get_state":
|
||||||
BroadcastState();
|
BroadcastState();
|
||||||
break;
|
break;
|
||||||
|
|||||||
BIN
streamingle-urp-analysis.md
(Stored with Git LFS)
Normal file
BIN
streamingle-urp-analysis.md
(Stored with Git LFS)
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user