diff --git a/BlueWater/Assets/01.Scenes/02.Combat_2D.unity b/BlueWater/Assets/01.Scenes/02.Combat_2D.unity index 2b846070d..ea8884631 100644 --- a/BlueWater/Assets/01.Scenes/02.Combat_2D.unity +++ b/BlueWater/Assets/01.Scenes/02.Combat_2D.unity @@ -386,6 +386,37 @@ Transform: - {fileID: 1732156238} m_Father: {fileID: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &104997133 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 104997134} + m_Layer: 0 + m_Name: PlayerSpawn + m_TagString: Untagged + m_Icon: {fileID: -964228994112308473, guid: 0000000000000000d000000000000000, type: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &104997134 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 104997133} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: -5} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1915017510} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &121245774 GameObject: m_ObjectHideFlags: 0 @@ -497,7 +528,39 @@ MonoBehaviour: _ConnectionHighLerp: {r: 1, g: 0, b: 0, a: 0.5} _MeshEdgeColor: {r: 0, g: 0, b: 0, a: 0.5} _AreaColors: [] - tagNames: [] + tagNames: + - Basic Ground + - 1 + - 2 + - 3 + - 4 + - 5 + - 6 + - 7 + - 8 + - 9 + - 10 + - 11 + - 12 + - 13 + - 14 + - 15 + - 16 + - 17 + - 18 + - 19 + - 20 + - 21 + - 22 + - 23 + - 24 + - 25 + - 26 + - 27 + - 28 + - 29 + - 30 + - 31 heuristic: 2 heuristicScale: 1 threadCount: 1 @@ -2798,6 +2861,37 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 704479487} m_CullTransparentMesh: 1 +--- !u!1 &729800709 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 729800710} + m_Layer: 0 + m_Name: BossSpawn + m_TagString: Untagged + m_Icon: {fileID: 5132851093641282708, guid: 0000000000000000d000000000000000, type: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &729800710 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 729800709} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 5} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1915017510} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &784283201 GameObject: m_ObjectHideFlags: 0 @@ -3576,80 +3670,6 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 793017943} m_CullTransparentMesh: 0 ---- !u!1001 &818265830 -PrefabInstance: - m_ObjectHideFlags: 0 - serializedVersion: 2 - m_Modification: - serializedVersion: 3 - m_TransformParent: {fileID: 1245399511} - m_Modifications: - - target: {fileID: 1907803032604947452, guid: 4f6f7700d35b9c3499d8ba66f5113e48, - type: 3} - propertyPath: m_Name - value: Slime - objectReference: {fileID: 0} - - target: {fileID: 8090463508496005930, guid: 4f6f7700d35b9c3499d8ba66f5113e48, - type: 3} - propertyPath: m_LocalPosition.x - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 8090463508496005930, guid: 4f6f7700d35b9c3499d8ba66f5113e48, - type: 3} - propertyPath: m_LocalPosition.y - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 8090463508496005930, guid: 4f6f7700d35b9c3499d8ba66f5113e48, - type: 3} - propertyPath: m_LocalPosition.z - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 8090463508496005930, guid: 4f6f7700d35b9c3499d8ba66f5113e48, - type: 3} - propertyPath: m_LocalRotation.w - value: 1 - objectReference: {fileID: 0} - - target: {fileID: 8090463508496005930, guid: 4f6f7700d35b9c3499d8ba66f5113e48, - type: 3} - propertyPath: m_LocalRotation.x - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 8090463508496005930, guid: 4f6f7700d35b9c3499d8ba66f5113e48, - type: 3} - propertyPath: m_LocalRotation.y - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 8090463508496005930, guid: 4f6f7700d35b9c3499d8ba66f5113e48, - type: 3} - propertyPath: m_LocalRotation.z - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 8090463508496005930, guid: 4f6f7700d35b9c3499d8ba66f5113e48, - type: 3} - propertyPath: m_LocalEulerAnglesHint.x - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 8090463508496005930, guid: 4f6f7700d35b9c3499d8ba66f5113e48, - type: 3} - propertyPath: m_LocalEulerAnglesHint.y - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 8090463508496005930, guid: 4f6f7700d35b9c3499d8ba66f5113e48, - type: 3} - propertyPath: m_LocalEulerAnglesHint.z - value: 0 - objectReference: {fileID: 0} - m_RemovedComponents: [] - m_RemovedGameObjects: [] - m_AddedGameObjects: [] - m_AddedComponents: [] - m_SourcePrefab: {fileID: 100100000, guid: 4f6f7700d35b9c3499d8ba66f5113e48, type: 3} ---- !u!4 &818265831 stripped -Transform: - m_CorrespondingSourceObject: {fileID: 8090463508496005930, guid: 4f6f7700d35b9c3499d8ba66f5113e48, - type: 3} - m_PrefabInstance: {fileID: 818265830} - m_PrefabAsset: {fileID: 0} --- !u!1 &823586984 GameObject: m_ObjectHideFlags: 0 @@ -4677,6 +4697,7 @@ RectTransform: - {fileID: 6661296397982603978} - {fileID: 1906451880} - {fileID: 1644675859} + - {fileID: 1703985565} m_Father: {fileID: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} @@ -5168,8 +5189,7 @@ Transform: m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 - m_Children: - - {fileID: 818265831} + m_Children: [] m_Father: {fileID: 1915017510} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &1256709750 @@ -7600,6 +7620,143 @@ Transform: type: 3} m_PrefabInstance: {fileID: 1362034954} m_PrefabAsset: {fileID: 0} +--- !u!1 &1536485950 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1536485951} + - component: {fileID: 1536485953} + - component: {fileID: 1536485952} + m_Layer: 5 + m_Name: Text (TMP) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1536485951 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1536485950} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1703985565} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1536485952 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1536485950} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_text: "\uC2AC\uB77C\uC784" + m_isRightToLeft: 0 + m_fontAsset: {fileID: 11400000, guid: dabfdeb80b25d44b4ace56414d0eb4ad, type: 2} + m_sharedMaterial: {fileID: 5657039867100983486, guid: dabfdeb80b25d44b4ace56414d0eb4ad, + type: 2} + m_fontSharedMaterials: [] + m_fontMaterial: {fileID: 0} + m_fontMaterials: [] + m_fontColor32: + serializedVersion: 2 + rgba: 4281479730 + m_fontColor: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_enableVertexGradient: 0 + m_colorMode: 3 + m_fontColorGradient: + topLeft: {r: 1, g: 1, b: 1, a: 1} + topRight: {r: 1, g: 1, b: 1, a: 1} + bottomLeft: {r: 1, g: 1, b: 1, a: 1} + bottomRight: {r: 1, g: 1, b: 1, a: 1} + m_fontColorGradientPreset: {fileID: 0} + m_spriteAsset: {fileID: 0} + m_tintAllSprites: 0 + m_StyleSheet: {fileID: 0} + m_TextStyleHashCode: -1183493901 + m_overrideHtmlColors: 0 + m_faceColor: + serializedVersion: 2 + rgba: 4294967295 + m_fontSize: 27.6 + m_fontSizeBase: 24 + m_fontWeight: 400 + m_enableAutoSizing: 1 + m_fontSizeMin: 18 + m_fontSizeMax: 72 + m_fontStyle: 0 + m_HorizontalAlignment: 2 + m_VerticalAlignment: 512 + m_textAlignment: 65535 + m_characterSpacing: 0 + m_wordSpacing: 0 + m_lineSpacing: 0 + m_lineSpacingMax: 0 + m_paragraphSpacing: 0 + m_charWidthMaxAdj: 0 + m_TextWrappingMode: 1 + m_wordWrappingRatios: 0.4 + m_overflowMode: 0 + m_linkedTextComponent: {fileID: 0} + parentLinkedComponent: {fileID: 0} + m_enableKerning: 0 + m_ActiveFontFeatures: 6e72656b + m_enableExtraPadding: 0 + checkPaddingRequired: 0 + m_isRichText: 1 + m_EmojiFallbackSupport: 1 + m_parseCtrlCharacters: 1 + m_isOrthographic: 1 + m_isCullingEnabled: 0 + m_horizontalMapping: 0 + m_verticalMapping: 0 + m_uvLineOffset: 0 + m_geometrySortingOrder: 0 + m_IsTextObjectScaleStatic: 0 + m_VertexBufferAutoSizeReduction: 0 + m_useMaxVisibleDescender: 1 + m_pageToDisplay: 1 + m_margin: {x: 0, y: 0, z: 0, w: 0} + m_isUsingLegacyAnimationComponent: 0 + m_isVolumetricText: 0 + m_hasFontAssetChanged: 0 + m_baseMaterial: {fileID: 0} + m_maskOffset: {x: 0, y: 0, z: 0, w: 0} +--- !u!222 &1536485953 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1536485950} + m_CullTransparentMesh: 1 --- !u!1 &1560091181 GameObject: m_ObjectHideFlags: 0 @@ -8013,6 +8170,139 @@ MeshFilter: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1658435463} m_Mesh: {fileID: 10209, guid: 0000000000000000e000000000000000, type: 0} +--- !u!1 &1703985564 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1703985565} + - component: {fileID: 1703985568} + - component: {fileID: 1703985567} + - component: {fileID: 1703985566} + m_Layer: 5 + m_Name: SlimeStageButton + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1703985565 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1703985564} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 1536485951} + m_Father: {fileID: 1033584370} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 1, y: 1} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: -10, y: -10} + m_SizeDelta: {x: 120, y: 40} + m_Pivot: {x: 1, y: 1} +--- !u!114 &1703985566 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1703985564} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 0 + m_WrapAround: 0 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 1703985567} + m_OnClick: + m_PersistentCalls: + m_Calls: + - m_Target: {fileID: 1915017511} + m_TargetAssemblyTypeName: SlimeBossMapController, Assembly-CSharp + m_MethodName: InitBossMap + m_Mode: 1 + m_Arguments: + m_ObjectArgument: {fileID: 0} + m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine + m_IntArgument: 0 + m_FloatArgument: 0 + m_StringArgument: + m_BoolArgument: 0 + m_CallState: 2 +--- !u!114 &1703985567 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1703985564} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1703985568 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1703985564} + m_CullTransparentMesh: 1 --- !u!1 &1715186577 GameObject: m_ObjectHideFlags: 0 @@ -9216,6 +9506,7 @@ GameObject: serializedVersion: 6 m_Component: - component: {fileID: 1915017510} + - component: {fileID: 1915017511} m_Layer: 0 m_Name: SlimeBossMap m_TagString: Untagged @@ -9239,8 +9530,63 @@ Transform: - {fileID: 1994003675} - {fileID: 555715576} - {fileID: 1245399511} + - {fileID: 104997134} + - {fileID: 729800710} m_Father: {fileID: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1915017511 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1915017509} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9d736acd182e9d84484a4ff16ea608c6, type: 3} + m_Name: + m_EditorClassIdentifier: + playerSpawnTransform: {fileID: 104997134} + bossSpawnTransform: {fileID: 729800710} + bossInstantiateTransform: {fileID: 1245399511} + bossPrefab: {fileID: 5876525979198911062, guid: 4f6f7700d35b9c3499d8ba66f5113e48, + type: 3} + slimeStateList: + - k__BackingField: 1 + k__BackingField: 10 + k__BackingField: 100 + k__BackingField: 1 + k__BackingField: 4 + k__BackingField: {x: 1.5, y: 2} + k__BackingField: 1 + - k__BackingField: 2 + k__BackingField: 8 + k__BackingField: 70 + k__BackingField: 1.25 + k__BackingField: 5 + k__BackingField: {x: 1.25, y: 1.75} + k__BackingField: 0 + - k__BackingField: 3 + k__BackingField: 6 + k__BackingField: 50 + k__BackingField: 1.5 + k__BackingField: 6 + k__BackingField: {x: 1, y: 1.5} + k__BackingField: 0 + - k__BackingField: 4 + k__BackingField: 4 + k__BackingField: 30 + k__BackingField: 1.75 + k__BackingField: 7 + k__BackingField: {x: 0.75, y: 1.25} + k__BackingField: 0 + - k__BackingField: 5 + k__BackingField: 2 + k__BackingField: 10 + k__BackingField: 2 + k__BackingField: 8 + k__BackingField: {x: 0.5, y: 1} + k__BackingField: 0 --- !u!1 &1969962453 GameObject: m_ObjectHideFlags: 0 diff --git a/BlueWater/Assets/02.Scripts/Character/CombatPlayer2D/CombatHealth.cs b/BlueWater/Assets/02.Scripts/Character/CombatPlayer2D/CombatHealth.cs index d46058443..55530ca6d 100644 --- a/BlueWater/Assets/02.Scripts/Character/CombatPlayer2D/CombatHealth.cs +++ b/BlueWater/Assets/02.Scripts/Character/CombatPlayer2D/CombatHealth.cs @@ -18,6 +18,9 @@ namespace BlueWaterProject // Interfaces private IDashable iDashable; + // Variables + private WaitForSeconds flashWhiteWaitTime; + // Hashes private static readonly int IsHitHash = Shader.PropertyToID("_IsHit"); @@ -34,6 +37,7 @@ namespace BlueWaterProject OnChangedCurrentHp += heartHpUi.SetCurrentHp; propBlock = new MaterialPropertyBlock(); + flashWhiteWaitTime = new WaitForSeconds(0.05f); SetCurrentHp(maxHp); } @@ -98,10 +102,10 @@ namespace BlueWaterProject spriteRenderer.GetPropertyBlock(propBlock); propBlock.SetInt(IsHitHash, 1); spriteRenderer.SetPropertyBlock(propBlock); - yield return new WaitForSeconds(0.05f); + yield return flashWhiteWaitTime; propBlock.SetInt(IsHitHash, 0); spriteRenderer.SetPropertyBlock(propBlock); - yield return new WaitForSeconds(0.05f); + yield return flashWhiteWaitTime; } } } diff --git a/BlueWater/Assets/02.Scripts/Character/Enemy/Type/FieldBoss/SlimeState.cs b/BlueWater/Assets/02.Scripts/Character/Enemy/Type/FieldBoss/SlimeState.cs new file mode 100644 index 000000000..843d7c4e2 --- /dev/null +++ b/BlueWater/Assets/02.Scripts/Character/Enemy/Type/FieldBoss/SlimeState.cs @@ -0,0 +1,28 @@ +using System; +using UnityEngine; + +// ReSharper disable once CheckNamespace +namespace BlueWaterProject +{ + [Serializable] + public class SlimeState + { + [field: SerializeField] public int Level { get; set; } + [field: SerializeField] public float Size { get; set; } + [field: SerializeField] public float MaxHp { get; set; } + [field: SerializeField] public float Speed { get; set; } + [field: SerializeField] public float Range { get; set; } + [field: SerializeField] public Vector2 RandomCooldown { get; set; } + [field: SerializeField] public bool HasRabbit { get; set; } + + public SlimeState(int level, float size, float maxHp, float speed, Vector2 randomCooldown, bool hasRabbit) + { + Level = level; + Size = size; + MaxHp = maxHp; + Speed = speed; + RandomCooldown = randomCooldown; + HasRabbit = hasRabbit; + } + } +} \ No newline at end of file diff --git a/BlueWater/Assets/02.Scripts/Character/Enemy/Type/FieldBoss/SlimeState.cs.meta b/BlueWater/Assets/02.Scripts/Character/Enemy/Type/FieldBoss/SlimeState.cs.meta new file mode 100644 index 000000000..685e18d14 --- /dev/null +++ b/BlueWater/Assets/02.Scripts/Character/Enemy/Type/FieldBoss/SlimeState.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: a8c2f390530f9ec479693c86e1b3d427 \ No newline at end of file diff --git a/BlueWater/Assets/02.Scripts/Character/Enemy/Type/FieldBoss/Type/TitanSlime.cs b/BlueWater/Assets/02.Scripts/Character/Enemy/Type/FieldBoss/Type/TitanSlime.cs index 8f6045e60..5881f4aef 100644 --- a/BlueWater/Assets/02.Scripts/Character/Enemy/Type/FieldBoss/Type/TitanSlime.cs +++ b/BlueWater/Assets/02.Scripts/Character/Enemy/Type/FieldBoss/Type/TitanSlime.cs @@ -1,19 +1,84 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using BehaviorDesigner.Runtime; using Sirenix.OdinInspector; +using UnityEditor.Animations; using UnityEngine; +using Random = UnityEngine.Random; // ReSharper disable once CheckNamespace namespace BlueWaterProject { - public class TitanSlime : FieldBoss + public enum TitanSlimeAnimationParameter + { + IS_JUMP_SLAM + } + + public enum TitanSlimeAnimationName + { + IDLE, + JUMP_SLAM + } + + public class TitanSlime : MonoBehaviour, IDamageable, IAnimationStateController { /*********************************************************************** * Variables ***********************************************************************/ #region Variables - // 실시간 상태 - [Title("실시간 상태")] - [SerializeField] private bool isMoving; + // 컴포넌트 + [Title("컴포넌트")] + [SerializeField] private Rigidbody rb; + [SerializeField] private Collider col; + [SerializeField] private BehaviorTree behaviorTree; + [SerializeField] private Transform visualLook; + [field: SerializeField] public Animator Anim { get; set; } + [SerializeField] private SpriteRenderer spriteRenderer; + [SerializeField] private AnimatorController slimeController; + [SerializeField] private AnimatorController slimeRabbitController; + + private IAnimationStateController iAnimationStateController; + private SlimeBossMapController mapController; + + // 스탯 + [field: Title("스탯")] + [field: SerializeField] public string BossName { get; private set; } = "거대 슬라임"; + [SerializeField] private SlimeState slimeState; + [SerializeField] private float currentHp; + [SerializeField] private LayerMask targetLayer; + [SerializeField] private LayerMask groundLayer; + public float MaxHp => slimeState.MaxHp; + + // 스킬 + [Title("스킬")] + [SerializeField] private List skillList; + private List instanceSkillList; + + // Variables + private Dictionary animationParameterHashDictionary = new(); + private Dictionary animationNameHashDictionary = new(); + + private MaterialPropertyBlock propBlock; + private WaitForSeconds flashWhiteWaitTime; + private Coroutine flashWhiteCoroutine; + private Coroutine jumpSlamCoroutine; + private Collider[] hitColliders; + + // Shader Hashes + private static readonly int IsHitHash = Shader.PropertyToID("_IsHit"); + + // Parameter hashes + private static readonly int IsJumpSlamHash = Animator.StringToHash("isJumpSlam"); + + // Animation name hashes + private static readonly int IdleHash = Animator.StringToHash("Idle"); + private static readonly int JumpSlamHash = Animator.StringToHash("JumpSlam"); + + // events + public delegate void ChangedCurrentHp(float currentHp); + public event ChangedCurrentHp OnChangedCurrentHp; #endregion @@ -22,9 +87,25 @@ namespace BlueWaterProject ***********************************************************************/ #region Unity Events - private void Update() + private void Awake() { - MoveHandler(); + InitComponent(); + InitDictionary(); + } + + private void Start() + { + mapController = FindAnyObjectByType(); + propBlock = new MaterialPropertyBlock(); + flashWhiteWaitTime = new WaitForSeconds(0.1f); + hitColliders = new Collider[1]; + + StartMove(); + } + + private void OnDestroy() + { + OnChangedCurrentHp -= UiManager.Inst.CombatUi.FieldBossHpSlider.UpdateHpSlider; } #endregion @@ -33,7 +114,49 @@ namespace BlueWaterProject * Init Methods ***********************************************************************/ #region Init Methods + + private void InitComponent() + { + rb = GetComponent(); + col = GetComponent(); + behaviorTree = GetComponent(); + visualLook = transform.Find("VisualLook"); + Anim = visualLook.GetComponent(); + spriteRenderer = visualLook.GetComponent(); + + iAnimationStateController = GetComponent(); + } + private void InitDictionary() + { + animationParameterHashDictionary = new Dictionary(Enum.GetValues(typeof(TitanSlimeAnimationParameter)).Length) + { + { TitanSlimeAnimationParameter.IS_JUMP_SLAM, IsJumpSlamHash }, + }; + + animationNameHashDictionary = new Dictionary(Enum.GetValues(typeof(TitanSlimeAnimationName)).Length) + { + { TitanSlimeAnimationName.IDLE, IdleHash }, + { TitanSlimeAnimationName.JUMP_SLAM, JumpSlamHash }, + }; + } + + public void Init(SlimeState state, bool hasRabbit) + { + slimeState = state; + slimeState.HasRabbit = hasRabbit; + SetCurrentHp(slimeState.MaxHp); + transform.localScale = Vector3.one * slimeState.Size; + if (slimeState.HasRabbit) + { + Anim.runtimeAnimatorController = slimeRabbitController; + OnChangedCurrentHp += UiManager.Inst.CombatUi.FieldBossHpSlider.UpdateHpSlider; + } + else + { + Anim.runtimeAnimatorController = slimeController; + } + } #endregion @@ -41,31 +164,139 @@ namespace BlueWaterProject * Interfaces ***********************************************************************/ #region Interfaces - - public override void Die() + + // IDamageable + public void TakeDamage(float attackerPower, Vector3? attackPos = null) { - isDead = true; + if (currentHp <= 0) return; - if (agent && agent.enabled) + var changeHp = Mathf.Max(currentHp - attackerPower, 0); + SetCurrentHp(changeHp); + + // 죽었는지 체크 + if (changeHp == 0f) { - agent.velocity = Vector3.zero; - agent.isStopped = true; - agent.enabled = false; - } - - if (rb) - { - rb.velocity = Vector3.zero; - rb.isKinematic = true; - } - - if (capsuleCollider && capsuleCollider.enabled) - { - capsuleCollider.isTrigger = true; + Die(); + return; } - animator.SetTrigger("isDead"); - Destroy(gameObject, 2f); + // 공격 당함 + if (spriteRenderer) + { + flashWhiteCoroutine = StartCoroutine(nameof(FlashWhiteCoroutine)); + } + } + + public void Die() + { + if (slimeState.Level <= 4) + { + mapController.SpawnSplitSlimes(transform.position, slimeState.Level + 1, slimeState.HasRabbit); + } + Destroy(gameObject); + } + + public float GetCurrentHp() + { + return currentHp; + } + + public void SetCurrentHp(float value) + { + currentHp = value; + OnChangedCurrentHp?.Invoke(value); + } + + // IAnimationStateController + public void SetAnimationParameter(T parameter, bool value) where T : Enum + { + if (parameter is TitanSlimeAnimationParameter enumParameter) + { + if (animationParameterHashDictionary.TryGetValue(enumParameter, out var hash)) + { + Anim.SetBool(hash, value); + } + else + { + throw new KeyNotFoundException($"The parameter {parameter} was not found in the dictionary."); + } + } + else + { + throw new ArgumentException("Invalid parameter type for SetAnimationParameter"); + } + } + + public void SetAnimationParameter(T parameter, int value) where T : Enum + { + if (parameter is TitanSlimeAnimationParameter enumParameter) + { + if (animationParameterHashDictionary.TryGetValue(enumParameter, out var hash)) + { + Anim.SetInteger(hash, value); + } + else + { + throw new KeyNotFoundException($"The parameter {parameter} was not found in the dictionary."); + } + } + else + { + throw new ArgumentException("Invalid parameter type for SetAnimationParameter"); + } + } + + public void SetAnimationParameter(T parameter, float value) where T : Enum + { + if (parameter is TitanSlimeAnimationParameter enumParameter) + { + if (animationParameterHashDictionary.TryGetValue(enumParameter, out var hash)) + { + Anim.SetFloat(hash, value); + } + else + { + throw new KeyNotFoundException($"The parameter {parameter} was not found in the dictionary."); + } + } + else + { + throw new ArgumentException("Invalid parameter type for SetAnimationParameter"); + } + } + + public void SetAnimationTrigger(T parameter) where T : Enum + { + if (parameter is TitanSlimeAnimationParameter enumParameter) + { + if (animationParameterHashDictionary.TryGetValue(enumParameter, out var hash)) + { + Anim.SetTrigger(hash); + } + else + { + throw new KeyNotFoundException($"The parameter {parameter} was not found in the dictionary."); + } + } + else + { + throw new ArgumentException("Invalid parameter type for SetAnimationParameter"); + } + } + + public bool IsComparingCurrentAnimation(T animationName, int animatorLayer = 0) where T : Enum + { + if (animationName is not TitanSlimeAnimationName enumAnimationName) + { + throw new ArgumentException("Invalid parameter type for SetAnimationParameter"); + } + + if (animationNameHashDictionary.TryGetValue(enumAnimationName, out var hash)) + { + return Anim.GetCurrentAnimatorStateInfo(animatorLayer).shortNameHash == hash; + } + + throw new KeyNotFoundException($"The parameter {animationName} was not found in the dictionary."); } #endregion @@ -74,49 +305,117 @@ namespace BlueWaterProject * Methods ***********************************************************************/ #region Methods - - public override void ActivateSkill(string skillName) - { - IsUsingSkill = true; - - skillDictionary[skillName].SkillInputData.PreviousDirection = PreviousDirection; - skillDictionary[skillName].ActivateSkill( - () => IsUsingSkill = false, - () => PreviousDirection = GetTargetDirection()); - } - - private void MoveHandler() - { - if (agent) - { - //var localVelocity = transform.InverseTransformDirection(agent.velocity); - //var moveDirection = localVelocity.normalized; - - var moveDirection = agent.enabled ? agent.velocity.normalized : rb.velocity.normalized; - - isMoving = moveDirection != Vector3.zero; - animator.SetBool("isMoving", isMoving); - if (isMoving) - { - PreviousDirection = moveDirection; - } - animator.SetFloat("xDirection", PreviousDirection.x); - animator.SetFloat("zDirection", PreviousDirection.z); - - FlipVisualLook(PreviousDirection.x); - } - } - private void FlipVisualLook(float previousDirectionX) + private IEnumerator FlashWhiteCoroutine() { - var localScale = visualLook.localScale; - localScale.x = previousDirectionX switch + spriteRenderer.GetPropertyBlock(propBlock); + propBlock.SetInt(IsHitHash, 1); + spriteRenderer.SetPropertyBlock(propBlock); + yield return flashWhiteWaitTime; + propBlock.SetInt(IsHitHash, 0); + spriteRenderer.SetPropertyBlock(propBlock); + yield return flashWhiteWaitTime; + } + + private void StartMove() + { + StartCoroutine(nameof(StartMoveCoroutine)); + } + + private IEnumerator StartMoveCoroutine() + { + var startPosition = transform.position; + var endPosition = CalculateRandomPosition(startPosition, 2f); + + var elapsedTime = 0f; + while (elapsedTime <= slimeState.Speed) { - > 0.01f => Mathf.Abs(localScale.x), - < -0.01f => -Mathf.Abs(localScale.x), - _ => localScale.x - }; - visualLook.localScale = localScale; + elapsedTime += Time.deltaTime; + transform.position = Vector3.Lerp(startPosition, endPosition, + iAnimationStateController.GetCurrentAnimationNormalizedTime()); + yield return null; + } + + JumpSlam(); + } + + private void JumpSlam() + { + if (currentHp <= 0) return; + + jumpSlamCoroutine = StartCoroutine(nameof(JumpSlamCoroutine)); + } + + private IEnumerator JumpSlamCoroutine() + { + iAnimationStateController.SetAnimationParameter(TitanSlimeAnimationParameter.IS_JUMP_SLAM, true); + + var animationStarted = false; + yield return StartCoroutine(iAnimationStateController.WaitForAnimationToRun(TitanSlimeAnimationName.JUMP_SLAM, + success => animationStarted = success)); + + if (!animationStarted) + { + EndJumpSlam(0); + yield break; + } + + iAnimationStateController.SetCurrentAnimationSpeed(slimeState.Speed); + var startPosition = transform.position; + Vector3 endPosition; + var hitCount = Physics.OverlapSphereNonAlloc(startPosition, slimeState.Range, hitColliders, targetLayer); + if (hitCount >= 1) + { + endPosition = CalculateRandomPosition(hitColliders[0].transform.position, 1f); + } + else + { + endPosition = CalculateRandomPosition(startPosition, 3f); + } + + while (iAnimationStateController.IsComparingCurrentAnimation(TitanSlimeAnimationName.JUMP_SLAM) && + iAnimationStateController.GetCurrentAnimationNormalizedTime() < 1f) + { + transform.position = Vector3.Lerp(startPosition, endPosition, + iAnimationStateController.GetCurrentAnimationNormalizedTime()); + yield return null; + } + + var randomCooldown = Random.Range(slimeState.RandomCooldown.x, slimeState.RandomCooldown.y); + EndJumpSlam(randomCooldown); + } + + private void EndJumpSlam(float cooldown) + { + iAnimationStateController.ResetAnimationSpeed(); + iAnimationStateController.SetAnimationParameter(TitanSlimeAnimationParameter.IS_JUMP_SLAM, false); + + StartCoroutine(Utils.CoolDown(cooldown, JumpSlam)); + } + + private Vector3 CalculateRandomPosition(Vector3 startPosition, float range, int iterationCount = 50) + { + for (var i = 0; i < iterationCount; i++) + { + var randomPosition = startPosition + Random.insideUnitSphere * range; + randomPosition.y = startPosition.y; + + if (!CheckMovablePosition(randomPosition)) continue; + + return randomPosition; + } + + return startPosition; + } + + private bool CheckMovablePosition(Vector3 checkPosition) + { + if (Physics.Raycast(checkPosition, Vector3.down, 1f, groundLayer)) + { + return true; + } + + return false; } #endregion diff --git a/BlueWater/Assets/02.Scripts/SlimeBossMapController.cs b/BlueWater/Assets/02.Scripts/SlimeBossMapController.cs new file mode 100644 index 000000000..e9daa292f --- /dev/null +++ b/BlueWater/Assets/02.Scripts/SlimeBossMapController.cs @@ -0,0 +1,57 @@ +using System.Collections.Generic; +using BlueWaterProject; +using Sirenix.OdinInspector; +using UnityEngine; + +// ReSharper disable once CheckNamespace +public class SlimeBossMapController : MonoBehaviour +{ + // 컴포넌트 + [Title("컴포넌트")] + [SerializeField] private Transform playerSpawnTransform; + [SerializeField] private Transform bossSpawnTransform; + [SerializeField] private Transform bossInstantiateTransform; + [SerializeField] private TitanSlime bossPrefab; + [SerializeField] private List slimeStateList = new(5); + + private List bossInstanceList = new(10); + + public void InitBossMap() + { + AllDestroyInstantiateObject(); + bossInstanceList = new List(10); + + var player = GameObject.FindWithTag("CombatPlayer"); + if (player && playerSpawnTransform) + { + player.transform.position = playerSpawnTransform.position; + } + + InstantiateSlime(bossSpawnTransform.position, 1, true); + } + + private void InstantiateSlime(Vector3 instantiatePosition, int level, bool hasRabbit) + { + var instantiateBoss = Instantiate(bossPrefab, instantiatePosition, Quaternion.identity, bossInstantiateTransform); + var slimeState = slimeStateList.Find((list) => list.Level == level); + instantiateBoss.Init(slimeState, hasRabbit); + + UiManager.Inst.CombatUi.FieldBossHpSlider.SetHpSlider(instantiateBoss.MaxHp, instantiateBoss.BossName); + + bossInstanceList.Add(instantiateBoss.gameObject); + } + + public void SpawnSplitSlimes(Vector3 deathPosition, int nextLevel, bool hasRabbit) + { + InstantiateSlime(deathPosition, nextLevel, hasRabbit); + InstantiateSlime(deathPosition, nextLevel, false); + } + + public void AllDestroyInstantiateObject() + { + foreach (var element in bossInstanceList) + { + Destroy(element); + } + } +} \ No newline at end of file diff --git a/BlueWater/Assets/02.Scripts/SlimeBossMapController.cs.meta b/BlueWater/Assets/02.Scripts/SlimeBossMapController.cs.meta new file mode 100644 index 000000000..5b4df9304 --- /dev/null +++ b/BlueWater/Assets/02.Scripts/SlimeBossMapController.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 9d736acd182e9d84484a4ff16ea608c6 \ No newline at end of file diff --git a/BlueWater/Assets/05.Prefabs/Characters/Enemies/FieldBosses/SlimeRabbit.prefab b/BlueWater/Assets/05.Prefabs/Characters/Enemies/FieldBosses/Slime.prefab similarity index 81% rename from BlueWater/Assets/05.Prefabs/Characters/Enemies/FieldBosses/SlimeRabbit.prefab rename to BlueWater/Assets/05.Prefabs/Characters/Enemies/FieldBosses/Slime.prefab index 4d26081cc..c1231a81c 100644 --- a/BlueWater/Assets/05.Prefabs/Characters/Enemies/FieldBosses/SlimeRabbit.prefab +++ b/BlueWater/Assets/05.Prefabs/Characters/Enemies/FieldBosses/Slime.prefab @@ -14,7 +14,7 @@ GameObject: - component: {fileID: 5660425300834808149} - component: {fileID: 5876525979198911062} m_Layer: 13 - m_Name: SlimeRabbit + m_Name: Slime m_TagString: FieldBoss m_Icon: {fileID: 0} m_NavMeshLayer: 0 @@ -30,8 +30,8 @@ Transform: serializedVersion: 2 m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 + m_LocalScale: {x: 10, y: 10, z: 10} + m_ConstrainProportionsScale: 1 m_Children: - {fileID: 695049024773443745} m_Father: {fileID: 0} @@ -58,10 +58,10 @@ Rigidbody: m_Bits: 0 m_ImplicitCom: 1 m_ImplicitTensor: 1 - m_UseGravity: 1 - m_IsKinematic: 1 + m_UseGravity: 0 + m_IsKinematic: 0 m_Interpolate: 0 - m_Constraints: 112 + m_Constraints: 116 m_CollisionDetection: 0 --- !u!136 &1668494360487994466 CapsuleCollider: @@ -82,10 +82,10 @@ CapsuleCollider: m_ProvidesContacts: 0 m_Enabled: 1 serializedVersion: 2 - m_Radius: 1.5 - m_Height: 3 + m_Radius: 0.25 + m_Height: 0.25 m_Direction: 1 - m_Center: {x: 0, y: 1.5, z: 0} + m_Center: {x: 0, y: 0.25, z: 0} --- !u!114 &5660425300834808149 MonoBehaviour: m_ObjectHideFlags: 0 @@ -105,24 +105,22 @@ MonoBehaviour: logTaskChanges: 0 group: 0 resetValuesOnRestart: 0 - externalBehavior: {fileID: 11400000, guid: d13d572258c1a34448812a8c0c0b54a1, type: 2} + externalBehavior: {fileID: 0} mBehaviorSource: - behaviorName: Rhinoceros + behaviorName: TitanSlime behaviorDescription: mTaskData: types: [] parentIndex: startIndex: variableStartIndex: - JSONSerialization: '{"Variables":[{"Type":"BehaviorDesigner.Runtime.SharedGameObject","Name":"MyObj","IsShared":true,"GameObjectmValue":0},{"Type":"BehaviorDesigner.Runtime.SharedFloat","Name":"CurrentHp","IsShared":true,"PropertyMapping":"BlueWaterProject.Rhinoceros/CurrentHp","PropertyMappingOwner":1,"SinglemValue":0},{"Type":"BehaviorDesigner.Runtime.SharedVector3","Name":"MovePoint","IsShared":true,"Vector3mValue":"(0,0,0)"},{"Type":"BehaviorDesigner.Runtime.SharedFloat","Name":"StoppingDistance","IsShared":true,"SinglemValue":0},{"Type":"BehaviorDesigner.Runtime.SharedBool","Name":"isStartBehavior","IsShared":true,"BooleanmValue":false}]}' + JSONSerialization: '{}' fieldSerializationData: typeName: [] fieldNameHash: startIndex: dataPosition: - unityObjects: - - {fileID: 1907803032604947452} - - {fileID: 1907803032604947452} + unityObjects: [] byteData: byteDataArray: Version: 1.7.7 @@ -140,25 +138,32 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 25f52002aaedd9f47a21029646c1feba, type: 3} m_Name: m_EditorClassIdentifier: - rb: {fileID: 0} - capsuleCollider: {fileID: 0} - agent: {fileID: 0} - behaviorTree: {fileID: 0} - visualLook: {fileID: 0} - animator: {fileID: 0} - spriteRenderer: {fileID: 0} - k__BackingField: TitanSlime - k__BackingField: 500 - moveSpeed: 1 + rb: {fileID: 8142684666082997760} + col: {fileID: 1668494360487994466} + behaviorTree: {fileID: 5660425300834808149} + visualLook: {fileID: 695049024773443745} + k__BackingField: {fileID: 0} + spriteRenderer: {fileID: 8089310337301863899} + slimeController: {fileID: 9100000, guid: 86a4cd4976c230e43ab5f86f49711ee8, type: 2} + slimeRabbitController: {fileID: 9100000, guid: 37338d4da60b9074897d606fa445d255, + type: 2} + k__BackingField: "\uAC70\uB300 \uC2AC\uB77C\uC784" + slimeState: + k__BackingField: 0 + k__BackingField: 0 + k__BackingField: 0 + k__BackingField: 0 + k__BackingField: {x: 0, y: 0} + k__BackingField: 0 + currentHp: 0 + targetRange: 3 targetLayer: serializedVersion: 2 m_Bits: 512 - flashWhiteTime: 0.1 + groundLayer: + serializedVersion: 2 + m_Bits: 8 skillList: [] - k__BackingField: 0 - k__BackingField: {fileID: 0} - k__BackingField: 0 - isMoving: 0 --- !u!1 &5250888242721872286 GameObject: m_ObjectHideFlags: 0 @@ -187,7 +192,7 @@ Transform: serializedVersion: 2 m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 5, y: 5, z: 5} + m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 1 m_Children: [] m_Father: {fileID: 8090463508496005930} diff --git a/BlueWater/Assets/05.Prefabs/Characters/Enemies/FieldBosses/SlimeRabbit.prefab.meta b/BlueWater/Assets/05.Prefabs/Characters/Enemies/FieldBosses/Slime.prefab.meta similarity index 100% rename from BlueWater/Assets/05.Prefabs/Characters/Enemies/FieldBosses/SlimeRabbit.prefab.meta rename to BlueWater/Assets/05.Prefabs/Characters/Enemies/FieldBosses/Slime.prefab.meta