diff --git a/Assets/Scenes/MovementTest.meta b/Assets/Scenes/MovementTest.meta new file mode 100644 index 0000000..b8bae3b --- /dev/null +++ b/Assets/Scenes/MovementTest.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ab4f84282bf0bb6468d23369c4d7d5cc +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scenes/MovementTest.unity b/Assets/Scenes/MovementTest.unity index 374fe2c..ae90a6f 100644 --- a/Assets/Scenes/MovementTest.unity +++ b/Assets/Scenes/MovementTest.unity @@ -215,6 +215,153 @@ Transform: m_Children: [] m_Father: {fileID: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &99394924 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 99394925} + - component: {fileID: 99394927} + - component: {fileID: 99394926} + - component: {fileID: 99394928} + m_Layer: 0 + m_Name: Square (2) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &99394925 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 99394924} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0.74, y: 2.89, z: 0.09351699} + m_LocalScale: {x: 3.2260692, y: 1.0000845, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1602984459} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!61 &99394926 +BoxCollider2D: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 99394924} + m_Enabled: 1 + m_Density: 1 + m_Material: {fileID: 0} + m_IncludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_ExcludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_LayerOverridePriority: 0 + m_ForceSendLayers: + serializedVersion: 2 + m_Bits: 4294967295 + m_ForceReceiveLayers: + serializedVersion: 2 + m_Bits: 4294967295 + m_ContactCaptureLayers: + serializedVersion: 2 + m_Bits: 4294967295 + m_CallbackLayers: + serializedVersion: 2 + m_Bits: 4294967295 + m_IsTrigger: 0 + m_UsedByEffector: 0 + m_UsedByComposite: 0 + m_Offset: {x: 0, y: 0} + m_SpriteTilingProperty: + border: {x: 0, y: 0, z: 0, w: 0} + pivot: {x: 0.5, y: 0.5} + oldSize: {x: 1, y: 1} + newSize: {x: 1, y: 1} + adaptiveTilingThreshold: 0.5 + drawMode: 0 + adaptiveTiling: 0 + m_AutoTiling: 0 + serializedVersion: 2 + m_Size: {x: 1, y: 1} + m_EdgeRadius: 0 +--- !u!212 &99394927 +SpriteRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 99394924} + m_Enabled: 1 + m_CastShadows: 0 + m_ReceiveShadows: 0 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 0 + m_RayTraceProcedural: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: a97c105638bdf8b4a8650670310a4cd3, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 0 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_Sprite: {fileID: 7482667652216324306, guid: 311925a002f4447b3a28927169b83ea6, type: 3} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_FlipX: 0 + m_FlipY: 0 + m_DrawMode: 0 + m_Size: {x: 1, y: 1} + m_AdaptiveModeThreshold: 0.5 + m_SpriteTileMode: 0 + m_WasSpriteAssigned: 1 + m_MaskInteraction: 0 + m_SpriteSortPoint: 0 +--- !u!114 &99394928 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 99394924} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9809bf1345abc5648af68b3a82653f08, type: 3} + m_Name: + m_EditorClassIdentifier: + m_OverrideArea: 1 + m_Area: 1 + m_IgnoreFromBuild: 0 + m_AffectedAgents: ffffffff --- !u!1 &107616016 GameObject: m_ObjectHideFlags: 0 @@ -233,7 +380,7 @@ GameObject: m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 - m_IsActive: 1 + m_IsActive: 0 --- !u!50 &107616017 Rigidbody2D: serializedVersion: 4 @@ -308,6 +455,127 @@ MonoBehaviour: stepCooldown: 0.2 stepVibrationTime: 0.05 rumble: {fileID: 1744797149} +--- !u!1 &220016280 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 220016284} + - component: {fileID: 220016283} + - component: {fileID: 220016282} + - component: {fileID: 220016281} + m_Layer: 0 + m_Name: Enemy + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &220016281 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 220016280} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6a3ffc4a3af9e0243ac9ee0c995bb82f, type: 3} + m_Name: + m_EditorClassIdentifier: + target: {fileID: 2026065165} +--- !u!195 &220016282 +NavMeshAgent: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 220016280} + m_Enabled: 1 + m_AgentTypeID: 0 + m_Radius: 0.5 + m_Speed: 2 + m_Acceleration: 8 + avoidancePriority: 50 + m_AngularSpeed: 120 + m_StoppingDistance: 0 + m_AutoTraverseOffMeshLink: 1 + m_AutoBraking: 1 + m_AutoRepath: 1 + m_Height: 1 + m_BaseOffset: 0.5 + m_WalkableMask: 4294967295 + m_ObstacleAvoidanceType: 4 +--- !u!212 &220016283 +SpriteRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 220016280} + m_Enabled: 1 + m_CastShadows: 0 + m_ReceiveShadows: 0 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 0 + m_RayTraceProcedural: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: a97c105638bdf8b4a8650670310a4cd3, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 0 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 1 + m_Sprite: {fileID: -2413806693520163455, guid: a86470a33a6bf42c4b3595704624658b, type: 3} + m_Color: {r: 0.6754716, g: 0.23832676, b: 0.23832676, a: 1} + m_FlipX: 0 + m_FlipY: 0 + m_DrawMode: 0 + m_Size: {x: 1, y: 1} + m_AdaptiveModeThreshold: 0.5 + m_SpriteTileMode: 0 + m_WasSpriteAssigned: 1 + m_MaskInteraction: 0 + m_SpriteSortPoint: 0 +--- !u!4 &220016284 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 220016280} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: -10.27, y: 0.64, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &646449334 GameObject: m_ObjectHideFlags: 0 @@ -442,6 +710,107 @@ Transform: - {fileID: 1744797150} m_Father: {fileID: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &852166018 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 852166019} + - component: {fileID: 852166021} + - component: {fileID: 852166022} + m_Layer: 0 + m_Name: Ground + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &852166019 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 852166018} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 1.3329, y: 0.5434, z: 0.09351699} + m_LocalScale: {x: 25.60002, y: 14.79793, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1602984459} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!212 &852166021 +SpriteRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 852166018} + m_Enabled: 1 + m_CastShadows: 0 + m_ReceiveShadows: 0 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 0 + m_RayTraceProcedural: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: a97c105638bdf8b4a8650670310a4cd3, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 0 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: -1 + m_Sprite: {fileID: 7482667652216324306, guid: 311925a002f4447b3a28927169b83ea6, type: 3} + m_Color: {r: 0.21960786, g: 0.21960786, b: 0.21960786, a: 1} + m_FlipX: 0 + m_FlipY: 0 + m_DrawMode: 0 + m_Size: {x: 1, y: 1} + m_AdaptiveModeThreshold: 0.5 + m_SpriteTileMode: 0 + m_WasSpriteAssigned: 1 + m_MaskInteraction: 0 + m_SpriteSortPoint: 0 +--- !u!114 &852166022 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 852166018} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9809bf1345abc5648af68b3a82653f08, type: 3} + m_Name: + m_EditorClassIdentifier: + m_OverrideArea: 0 + m_Area: 0 + m_IgnoreFromBuild: 0 + m_AffectedAgents: ffffffff --- !u!1 &970285067 GameObject: m_ObjectHideFlags: 0 @@ -452,6 +821,7 @@ GameObject: m_Component: - component: {fileID: 970285070} - component: {fileID: 970285069} + - component: {fileID: 970285071} m_Layer: 0 m_Name: Renderer m_TagString: Untagged @@ -499,7 +869,7 @@ SpriteRenderer: m_LightmapParameters: {fileID: 0} m_SortingLayerID: 0 m_SortingLayer: 0 - m_SortingOrder: 0 + m_SortingOrder: 1 m_Sprite: {fileID: -2413806693520163455, guid: a86470a33a6bf42c4b3595704624658b, type: 3} m_Color: {r: 1, g: 1, b: 1, a: 1} m_FlipX: 0 @@ -526,6 +896,561 @@ Transform: m_Children: [] m_Father: {fileID: 2026065165} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!58 &970285071 +CircleCollider2D: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 970285067} + m_Enabled: 1 + m_Density: 1 + m_Material: {fileID: 0} + m_IncludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_ExcludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_LayerOverridePriority: 0 + m_ForceSendLayers: + serializedVersion: 2 + m_Bits: 4294967295 + m_ForceReceiveLayers: + serializedVersion: 2 + m_Bits: 4294967295 + m_ContactCaptureLayers: + serializedVersion: 2 + m_Bits: 4294967295 + m_CallbackLayers: + serializedVersion: 2 + m_Bits: 4294967295 + m_IsTrigger: 0 + m_UsedByEffector: 0 + m_UsedByComposite: 0 + m_Offset: {x: 0, y: 0} + serializedVersion: 2 + m_Radius: 0.5 +--- !u!1 &1156361827 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1156361828} + - component: {fileID: 1156361830} + - component: {fileID: 1156361829} + - component: {fileID: 1156361831} + m_Layer: 0 + m_Name: Square (1) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1156361828 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1156361827} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 6.73, y: -1.66, z: 0.09351699} + m_LocalScale: {x: 1.2368, y: 3.5103, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1602984459} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!61 &1156361829 +BoxCollider2D: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1156361827} + m_Enabled: 1 + m_Density: 1 + m_Material: {fileID: 0} + m_IncludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_ExcludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_LayerOverridePriority: 0 + m_ForceSendLayers: + serializedVersion: 2 + m_Bits: 4294967295 + m_ForceReceiveLayers: + serializedVersion: 2 + m_Bits: 4294967295 + m_ContactCaptureLayers: + serializedVersion: 2 + m_Bits: 4294967295 + m_CallbackLayers: + serializedVersion: 2 + m_Bits: 4294967295 + m_IsTrigger: 0 + m_UsedByEffector: 0 + m_UsedByComposite: 0 + m_Offset: {x: 0, y: 0} + m_SpriteTilingProperty: + border: {x: 0, y: 0, z: 0, w: 0} + pivot: {x: 0.5, y: 0.5} + oldSize: {x: 1, y: 1} + newSize: {x: 1, y: 1} + adaptiveTilingThreshold: 0.5 + drawMode: 0 + adaptiveTiling: 0 + m_AutoTiling: 0 + serializedVersion: 2 + m_Size: {x: 1, y: 1} + m_EdgeRadius: 0 +--- !u!212 &1156361830 +SpriteRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1156361827} + m_Enabled: 1 + m_CastShadows: 0 + m_ReceiveShadows: 0 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 0 + m_RayTraceProcedural: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: a97c105638bdf8b4a8650670310a4cd3, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 0 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_Sprite: {fileID: 7482667652216324306, guid: 311925a002f4447b3a28927169b83ea6, type: 3} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_FlipX: 0 + m_FlipY: 0 + m_DrawMode: 0 + m_Size: {x: 1, y: 1} + m_AdaptiveModeThreshold: 0.5 + m_SpriteTileMode: 0 + m_WasSpriteAssigned: 1 + m_MaskInteraction: 0 + m_SpriteSortPoint: 0 +--- !u!114 &1156361831 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1156361827} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9809bf1345abc5648af68b3a82653f08, type: 3} + m_Name: + m_EditorClassIdentifier: + m_OverrideArea: 1 + m_Area: 1 + m_IgnoreFromBuild: 0 + m_AffectedAgents: ffffffff +--- !u!1 &1194600254 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1194600255} + - component: {fileID: 1194600257} + - component: {fileID: 1194600256} + - component: {fileID: 1194600258} + m_Layer: 0 + m_Name: Square + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1194600255 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1194600254} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: -2.98, y: 0.42, z: 0.09351699} + m_LocalScale: {x: 1.2368, y: 3.5103, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1602984459} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!61 &1194600256 +BoxCollider2D: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1194600254} + m_Enabled: 1 + m_Density: 1 + m_Material: {fileID: 0} + m_IncludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_ExcludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_LayerOverridePriority: 0 + m_ForceSendLayers: + serializedVersion: 2 + m_Bits: 4294967295 + m_ForceReceiveLayers: + serializedVersion: 2 + m_Bits: 4294967295 + m_ContactCaptureLayers: + serializedVersion: 2 + m_Bits: 4294967295 + m_CallbackLayers: + serializedVersion: 2 + m_Bits: 4294967295 + m_IsTrigger: 0 + m_UsedByEffector: 0 + m_UsedByComposite: 0 + m_Offset: {x: 0, y: 0} + m_SpriteTilingProperty: + border: {x: 0, y: 0, z: 0, w: 0} + pivot: {x: 0.5, y: 0.5} + oldSize: {x: 1, y: 1} + newSize: {x: 1, y: 1} + adaptiveTilingThreshold: 0.5 + drawMode: 0 + adaptiveTiling: 0 + m_AutoTiling: 0 + serializedVersion: 2 + m_Size: {x: 1, y: 1} + m_EdgeRadius: 0 +--- !u!212 &1194600257 +SpriteRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1194600254} + m_Enabled: 1 + m_CastShadows: 0 + m_ReceiveShadows: 0 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 0 + m_RayTraceProcedural: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: a97c105638bdf8b4a8650670310a4cd3, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 0 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_Sprite: {fileID: 7482667652216324306, guid: 311925a002f4447b3a28927169b83ea6, type: 3} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_FlipX: 0 + m_FlipY: 0 + m_DrawMode: 0 + m_Size: {x: 1, y: 1} + m_AdaptiveModeThreshold: 0.5 + m_SpriteTileMode: 0 + m_WasSpriteAssigned: 1 + m_MaskInteraction: 0 + m_SpriteSortPoint: 0 +--- !u!114 &1194600258 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1194600254} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9809bf1345abc5648af68b3a82653f08, type: 3} + m_Name: + m_EditorClassIdentifier: + m_OverrideArea: 1 + m_Area: 1 + m_IgnoreFromBuild: 0 + m_AffectedAgents: ffffffff +--- !u!1 &1316213925 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1316213926} + - component: {fileID: 1316213928} + - component: {fileID: 1316213927} + - component: {fileID: 1316213929} + m_Layer: 0 + m_Name: Square (3) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1316213926 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1316213925} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: -1.98, y: -1.4, z: 0.09351699} + m_LocalScale: {x: 3.2260692, y: 1.0000845, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1602984459} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!61 &1316213927 +BoxCollider2D: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1316213925} + m_Enabled: 1 + m_Density: 1 + m_Material: {fileID: 0} + m_IncludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_ExcludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_LayerOverridePriority: 0 + m_ForceSendLayers: + serializedVersion: 2 + m_Bits: 4294967295 + m_ForceReceiveLayers: + serializedVersion: 2 + m_Bits: 4294967295 + m_ContactCaptureLayers: + serializedVersion: 2 + m_Bits: 4294967295 + m_CallbackLayers: + serializedVersion: 2 + m_Bits: 4294967295 + m_IsTrigger: 0 + m_UsedByEffector: 0 + m_UsedByComposite: 0 + m_Offset: {x: 0, y: 0} + m_SpriteTilingProperty: + border: {x: 0, y: 0, z: 0, w: 0} + pivot: {x: 0.5, y: 0.5} + oldSize: {x: 1, y: 1} + newSize: {x: 1, y: 1} + adaptiveTilingThreshold: 0.5 + drawMode: 0 + adaptiveTiling: 0 + m_AutoTiling: 0 + serializedVersion: 2 + m_Size: {x: 1, y: 1} + m_EdgeRadius: 0 +--- !u!212 &1316213928 +SpriteRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1316213925} + m_Enabled: 1 + m_CastShadows: 0 + m_ReceiveShadows: 0 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 0 + m_RayTraceProcedural: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: a97c105638bdf8b4a8650670310a4cd3, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 0 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_Sprite: {fileID: 7482667652216324306, guid: 311925a002f4447b3a28927169b83ea6, type: 3} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_FlipX: 0 + m_FlipY: 0 + m_DrawMode: 0 + m_Size: {x: 1, y: 1} + m_AdaptiveModeThreshold: 0.5 + m_SpriteTileMode: 0 + m_WasSpriteAssigned: 1 + m_MaskInteraction: 0 + m_SpriteSortPoint: 0 +--- !u!114 &1316213929 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1316213925} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9809bf1345abc5648af68b3a82653f08, type: 3} + m_Name: + m_EditorClassIdentifier: + m_OverrideArea: 1 + m_Area: 1 + m_IgnoreFromBuild: 0 + m_AffectedAgents: ffffffff +--- !u!1 &1365819702 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1365819705} + - component: {fileID: 1365819704} + - component: {fileID: 1365819703} + m_Layer: 0 + m_Name: NavMesh + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1365819703 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1365819702} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 70bd44a44cd62c64fbfc1eea95b24880, type: 3} + m_Name: + m_EditorClassIdentifier: + m_OverrideByGrid: 0 + m_UseMeshPrefab: {fileID: 0} + m_CompressBounds: 0 + m_OverrideVector: {x: 1, y: 1, z: 1} +--- !u!114 &1365819704 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1365819702} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: e04976799df50f54ba128eff723155a7, type: 3} + m_Name: + m_EditorClassIdentifier: + m_AgentTypeID: 0 + m_CollectObjects: 0 + m_Size: {x: 10, y: 10, z: 10} + m_Center: {x: 0, y: 2, z: 0} + m_LayerMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_UseGeometry: 0 + m_DefaultArea: 0 + m_IgnoreNavMeshAgent: 1 + m_IgnoreNavMeshObstacle: 1 + m_OverrideTileSize: 0 + m_TileSize: 256 + m_OverrideVoxelSize: 0 + m_VoxelSize: 0.16666667 + m_BuildHeightMesh: 0 + m_HideEditorLogs: 0 + m_NavMeshData: {fileID: 23800000, guid: d308d3c67696b1044b66e5bec5c89bde, type: 2} +--- !u!4 &1365819705 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1365819702} + serializedVersion: 2 + m_LocalRotation: {x: -0.7071068, y: 0, z: 0, w: 0.7071068} + m_LocalPosition: {x: -0.5888119, y: -0.1884947, z: -0.111949444} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &1420709238 GameObject: m_ObjectHideFlags: 0 @@ -607,6 +1532,42 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: d79b9b67e3de5ba4590c4e63726f5c8b, type: 3} m_Name: m_EditorClassIdentifier: +--- !u!1 &1602984458 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1602984459} + m_Layer: 0 + m_Name: Enviorment + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1602984459 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1602984458} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: -1.2670751, y: -0.34023595, z: -0.09351699} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 852166019} + - {fileID: 1194600255} + - {fileID: 1156361828} + - {fileID: 99394925} + - {fileID: 1316213926} + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &1666646756 GameObject: m_ObjectHideFlags: 0 @@ -914,7 +1875,7 @@ Rigidbody2D: m_Interpolate: 0 m_SleepingMode: 1 m_CollisionDetection: 1 - m_Constraints: 0 + m_Constraints: 4 --- !u!114 &2026065163 MonoBehaviour: m_ObjectHideFlags: 0 @@ -971,4 +1932,7 @@ SceneRoots: - {fileID: 107616020} - {fileID: 646449338} - {fileID: 1420709241} + - {fileID: 1602984459} - {fileID: 781349954} + - {fileID: 1365819705} + - {fileID: 220016284} diff --git a/Assets/Scenes/MovementTest/NavMesh-NavMesh.asset b/Assets/Scenes/MovementTest/NavMesh-NavMesh.asset new file mode 100644 index 0000000..78fd7f9 Binary files /dev/null and b/Assets/Scenes/MovementTest/NavMesh-NavMesh.asset differ diff --git a/Assets/Scenes/MovementTest/NavMesh-NavMesh.asset.meta b/Assets/Scenes/MovementTest/NavMesh-NavMesh.asset.meta new file mode 100644 index 0000000..0191fbf --- /dev/null +++ b/Assets/Scenes/MovementTest/NavMesh-NavMesh.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d308d3c67696b1044b66e5bec5c89bde +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 23800000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Enemy.meta b/Assets/Scripts/Enemy.meta new file mode 100644 index 0000000..dfd10a8 --- /dev/null +++ b/Assets/Scripts/Enemy.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2cd36024fd203f84d8cd3c7d4b6b7593 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Enemy/EnemyPathFinding.cs b/Assets/Scripts/Enemy/EnemyPathFinding.cs new file mode 100644 index 0000000..22acd78 --- /dev/null +++ b/Assets/Scripts/Enemy/EnemyPathFinding.cs @@ -0,0 +1,21 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.AI; + +public class EnemyPathFinding : MonoBehaviour +{ + [SerializeField] private Transform target; + + NavMeshAgent agent; + private void Start() + { + agent = GetComponent(); + agent.updateRotation = false; + agent.updateUpAxis = false; + } + private void Update() + { + agent.SetDestination(target.position); + } +} diff --git a/Assets/Scripts/Enemy/EnemyPathFinding.cs.meta b/Assets/Scripts/Enemy/EnemyPathFinding.cs.meta new file mode 100644 index 0000000..b8776b6 --- /dev/null +++ b/Assets/Scripts/Enemy/EnemyPathFinding.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6a3ffc4a3af9e0243ac9ee0c995bb82f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Extensions.meta b/Assets/Scripts/Extensions.meta new file mode 100644 index 0000000..38411e1 --- /dev/null +++ b/Assets/Scripts/Extensions.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 38ce38f74cbf5b84fad41aa34e1af3f2 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/PathFinding.meta b/Assets/Scripts/PathFinding.meta new file mode 100644 index 0000000..68169ce --- /dev/null +++ b/Assets/Scripts/PathFinding.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 15edf91cde5e0974faccaf09491aab0f +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/PathFinding/Gizmos.meta b/Assets/Scripts/PathFinding/Gizmos.meta new file mode 100644 index 0000000..f997dfa --- /dev/null +++ b/Assets/Scripts/PathFinding/Gizmos.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 9f554f0dfb387d647ae9650f24589d6a +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/PathFinding/Gizmos/NavMeshLink Icon.png b/Assets/Scripts/PathFinding/Gizmos/NavMeshLink Icon.png new file mode 100644 index 0000000..f420614 Binary files /dev/null and b/Assets/Scripts/PathFinding/Gizmos/NavMeshLink Icon.png differ diff --git a/Assets/Scripts/PathFinding/Gizmos/NavMeshLink Icon.png.meta b/Assets/Scripts/PathFinding/Gizmos/NavMeshLink Icon.png.meta new file mode 100644 index 0000000..bf97686 --- /dev/null +++ b/Assets/Scripts/PathFinding/Gizmos/NavMeshLink Icon.png.meta @@ -0,0 +1,98 @@ +fileFormatVersion: 2 +guid: 68ad4f5d6fe957c4789aedd21ff67ced +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/PathFinding/Gizmos/NavMeshModifierVolume Icon.png b/Assets/Scripts/PathFinding/Gizmos/NavMeshModifierVolume Icon.png new file mode 100644 index 0000000..48f2efa Binary files /dev/null and b/Assets/Scripts/PathFinding/Gizmos/NavMeshModifierVolume Icon.png differ diff --git a/Assets/Scripts/PathFinding/Gizmos/NavMeshModifierVolume Icon.png.meta b/Assets/Scripts/PathFinding/Gizmos/NavMeshModifierVolume Icon.png.meta new file mode 100644 index 0000000..dd8cb5b --- /dev/null +++ b/Assets/Scripts/PathFinding/Gizmos/NavMeshModifierVolume Icon.png.meta @@ -0,0 +1,98 @@ +fileFormatVersion: 2 +guid: 273c8b5db6e39534781066db3444fe88 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/PathFinding/Gizmos/NavMeshSurface Icon.png b/Assets/Scripts/PathFinding/Gizmos/NavMeshSurface Icon.png new file mode 100644 index 0000000..a289cf6 Binary files /dev/null and b/Assets/Scripts/PathFinding/Gizmos/NavMeshSurface Icon.png differ diff --git a/Assets/Scripts/PathFinding/Gizmos/NavMeshSurface Icon.png.meta b/Assets/Scripts/PathFinding/Gizmos/NavMeshSurface Icon.png.meta new file mode 100644 index 0000000..e99641f --- /dev/null +++ b/Assets/Scripts/PathFinding/Gizmos/NavMeshSurface Icon.png.meta @@ -0,0 +1,98 @@ +fileFormatVersion: 2 +guid: 444810ca896903c41adf617b35274dc4 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/PathFinding/Gizmos/NavMeshSurface2d Icon.png b/Assets/Scripts/PathFinding/Gizmos/NavMeshSurface2d Icon.png new file mode 100644 index 0000000..37124c5 Binary files /dev/null and b/Assets/Scripts/PathFinding/Gizmos/NavMeshSurface2d Icon.png differ diff --git a/Assets/Scripts/PathFinding/Gizmos/NavMeshSurface2d Icon.png.meta b/Assets/Scripts/PathFinding/Gizmos/NavMeshSurface2d Icon.png.meta new file mode 100644 index 0000000..e06ad44 --- /dev/null +++ b/Assets/Scripts/PathFinding/Gizmos/NavMeshSurface2d Icon.png.meta @@ -0,0 +1,98 @@ +fileFormatVersion: 2 +guid: d5b0e13ebe59cd64e9f67284457c6868 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/PathFinding/Gizmos/NavMeshSurfaceGears Icon.png b/Assets/Scripts/PathFinding/Gizmos/NavMeshSurfaceGears Icon.png new file mode 100644 index 0000000..497a19b Binary files /dev/null and b/Assets/Scripts/PathFinding/Gizmos/NavMeshSurfaceGears Icon.png differ diff --git a/Assets/Scripts/PathFinding/Gizmos/NavMeshSurfaceGears Icon.png.meta b/Assets/Scripts/PathFinding/Gizmos/NavMeshSurfaceGears Icon.png.meta new file mode 100644 index 0000000..6e4d104 --- /dev/null +++ b/Assets/Scripts/PathFinding/Gizmos/NavMeshSurfaceGears Icon.png.meta @@ -0,0 +1,98 @@ +fileFormatVersion: 2 +guid: e8142b1daeea8d3419cd0ffbd7b17a37 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/PathFinding/LICENSE b/Assets/Scripts/PathFinding/LICENSE new file mode 100644 index 0000000..ed30590 --- /dev/null +++ b/Assets/Scripts/PathFinding/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019 h8man + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Assets/Scripts/PathFinding/LICENSE.meta b/Assets/Scripts/PathFinding/LICENSE.meta new file mode 100644 index 0000000..122cc1a --- /dev/null +++ b/Assets/Scripts/PathFinding/LICENSE.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 4aafea534cdccb843b27a8b6e839a76f +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/PathFinding/NavMeshComponents.meta b/Assets/Scripts/PathFinding/NavMeshComponents.meta new file mode 100644 index 0000000..3366784 --- /dev/null +++ b/Assets/Scripts/PathFinding/NavMeshComponents.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b9669812fb313c842943ae58d9c50699 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/PathFinding/NavMeshComponents/Editor.meta b/Assets/Scripts/PathFinding/NavMeshComponents/Editor.meta new file mode 100644 index 0000000..3801fb1 --- /dev/null +++ b/Assets/Scripts/PathFinding/NavMeshComponents/Editor.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 455bb0723c59a9145bc3c035376ca788 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/PathFinding/NavMeshComponents/Editor/AgentOverride2dEditor.cs b/Assets/Scripts/PathFinding/NavMeshComponents/Editor/AgentOverride2dEditor.cs new file mode 100644 index 0000000..88c8871 --- /dev/null +++ b/Assets/Scripts/PathFinding/NavMeshComponents/Editor/AgentOverride2dEditor.cs @@ -0,0 +1,35 @@ +using NavMeshPlus.Extensions; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEditor; + +namespace NavMeshPlus.Editors.Extensions +{ + [CanEditMultipleObjects] + [CustomEditor(typeof(AgentOverride2d))] + internal class AgentOverride2dEditor : Editor + { + //SerializedProperty m_OverrideByGrid; + //SerializedProperty m_UseMeshPrefab; + //SerializedProperty m_CompressBounds; + //SerializedProperty m_OverrideVector; + void OnEnable() + { + //m_OverrideByGrid = serializedObject.FindProperty("m_OverrideByGrid"); + //m_UseMeshPrefab = serializedObject.FindProperty("m_UseMeshPrefab"); + //m_CompressBounds = serializedObject.FindProperty("m_CompressBounds"); + //m_OverrideVector = serializedObject.FindProperty("m_OverrideVector"); + } + + public override void OnInspectorGUI() + { + serializedObject.Update(); + + var agent = target as AgentOverride2d; + EditorGUILayout.LabelField("Agent Override", agent.agentOverride?.GetType().Name); + } + } +} diff --git a/Assets/Scripts/PathFinding/NavMeshComponents/Editor/AgentOverride2dEditor.cs.meta b/Assets/Scripts/PathFinding/NavMeshComponents/Editor/AgentOverride2dEditor.cs.meta new file mode 100644 index 0000000..0ce714f --- /dev/null +++ b/Assets/Scripts/PathFinding/NavMeshComponents/Editor/AgentOverride2dEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 86cc6cf350c6f62469395948494f0945 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/PathFinding/NavMeshComponents/Editor/CollectSources2dEditor.cs b/Assets/Scripts/PathFinding/NavMeshComponents/Editor/CollectSources2dEditor.cs new file mode 100644 index 0000000..a7eba15 --- /dev/null +++ b/Assets/Scripts/PathFinding/NavMeshComponents/Editor/CollectSources2dEditor.cs @@ -0,0 +1,73 @@ +using UnityEngine.AI; +using UnityEngine; +using UnityEditor; +using NavMeshPlus.Extensions; + +namespace NavMeshPlus.Editors.Extensions +{ + [CanEditMultipleObjects] + [CustomEditor(typeof(CollectSources2d))] + internal class CollectSources2dEditor: Editor + { + SerializedProperty m_OverrideByGrid; + SerializedProperty m_UseMeshPrefab; + SerializedProperty m_CompressBounds; + SerializedProperty m_OverrideVector; + void OnEnable() + { + m_OverrideByGrid = serializedObject.FindProperty("m_OverrideByGrid"); + m_UseMeshPrefab = serializedObject.FindProperty("m_UseMeshPrefab"); + m_CompressBounds = serializedObject.FindProperty("m_CompressBounds"); + m_OverrideVector = serializedObject.FindProperty("m_OverrideVector"); + } + + public override void OnInspectorGUI() + { + serializedObject.Update(); + + var surf = target as CollectSources2d; + + EditorGUILayout.PropertyField(m_OverrideByGrid); + using (new EditorGUI.DisabledScope(!m_OverrideByGrid.boolValue)) + { + EditorGUI.indentLevel++; + EditorGUILayout.PropertyField(m_UseMeshPrefab); + EditorGUI.indentLevel--; + } + EditorGUILayout.PropertyField(m_CompressBounds); + EditorGUILayout.PropertyField(m_OverrideVector); + + EditorGUILayout.Space(); + + serializedObject.ApplyModifiedProperties(); + + using (new EditorGUI.DisabledScope(Application.isPlaying)) + { + GUILayout.BeginHorizontal(); + if (GUILayout.Button(new GUIContent("Rotate Surface to XY", "Rotates Surface along XY plane to face toward standard 2d camera."))) + { + foreach (CollectSources2d item in targets) + { + item.transform.rotation = Quaternion.Euler(-90f, 0f, 0f); + } + } + if (GUILayout.Button(new GUIContent("Tilt Surface", "If your agent get stuck on vertical movement it may help to solve the issue. This will tilt Surface to -89.98. It may impact baking and navigation."))) + { + foreach (CollectSources2d item in targets) + { + item.transform.rotation = Quaternion.Euler(-89.98f, 0f, 0f); + } + } + GUILayout.EndHorizontal(); + foreach (CollectSources2d navSurface in targets) + { + if (!Mathf.Approximately(navSurface.transform.eulerAngles.x, 270.0198f) && !Mathf.Approximately(navSurface.transform.eulerAngles.x, 270f)) + { + EditorGUILayout.HelpBox("NavMeshSurface is not rotated respectively to (x-90;y0;z0). Apply rotation unless intended.", MessageType.Warning); + } + } + } + } + } + +} diff --git a/Assets/Scripts/PathFinding/NavMeshComponents/Editor/CollectSources2dEditor.cs.meta b/Assets/Scripts/PathFinding/NavMeshComponents/Editor/CollectSources2dEditor.cs.meta new file mode 100644 index 0000000..f1a4a2d --- /dev/null +++ b/Assets/Scripts/PathFinding/NavMeshComponents/Editor/CollectSources2dEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3fc821cbc11a48745bc9edea6bfda007 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/PathFinding/NavMeshComponents/Editor/CollectSourcesCache2dEditor.cs b/Assets/Scripts/PathFinding/NavMeshComponents/Editor/CollectSourcesCache2dEditor.cs new file mode 100644 index 0000000..3396ede --- /dev/null +++ b/Assets/Scripts/PathFinding/NavMeshComponents/Editor/CollectSourcesCache2dEditor.cs @@ -0,0 +1,42 @@ +using UnityEngine.AI; +using UnityEngine; +using UnityEditor; +using NavMeshPlus.Extensions; + +namespace NavMeshPlus.Editors.Extensions +{ + [CanEditMultipleObjects] + [CustomEditor(typeof(CollectSourcesCache2d))] + internal class CollectSourcesCache2dEditor : Editor + { + + public override void OnInspectorGUI() + { + serializedObject.Update(); + + var surf = target as CollectSourcesCache2d; + + serializedObject.ApplyModifiedProperties(); + using (new EditorGUI.DisabledScope(!Application.isPlaying)) + { + GUILayout.BeginHorizontal(); + GUILayout.Label("Sources:"); + if (Application.isPlaying) + { + GUILayout.Label(surf.SourcesCount.ToString()); + GUILayout.Label("Cached:"); + GUILayout.Label(surf.CahcheCount.ToString()); + } + GUILayout.EndHorizontal(); + GUILayout.BeginHorizontal(); + GUILayout.Label("Actions:"); + if (GUILayout.Button("Update Mesh")) + { + surf.UpdateNavMesh(); + } + GUILayout.EndHorizontal(); + } + } + } + +} diff --git a/Assets/Scripts/PathFinding/NavMeshComponents/Editor/CollectSourcesCache2dEditor.cs.meta b/Assets/Scripts/PathFinding/NavMeshComponents/Editor/CollectSourcesCache2dEditor.cs.meta new file mode 100644 index 0000000..66f8061 --- /dev/null +++ b/Assets/Scripts/PathFinding/NavMeshComponents/Editor/CollectSourcesCache2dEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3616009fd1ab770409e0321881372357 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/PathFinding/NavMeshComponents/Editor/NavMeshAgentAttributePropertyDrawer.cs b/Assets/Scripts/PathFinding/NavMeshComponents/Editor/NavMeshAgentAttributePropertyDrawer.cs new file mode 100644 index 0000000..5b933ae --- /dev/null +++ b/Assets/Scripts/PathFinding/NavMeshComponents/Editor/NavMeshAgentAttributePropertyDrawer.cs @@ -0,0 +1,21 @@ +using UnityEditor; +using UnityEngine; +using NavMeshPlus.Extensions; +using NavMeshPlus.Editors.Components; + +//*********************************************************************************** +// Contributed by author jl-randazzo github.com/jl-randazzo +//*********************************************************************************** +namespace NavMeshPlus.Editors.Extensions +{ + [CustomPropertyDrawer(typeof(NavMeshAgentAttribute))] + public class NavMeshAgentAttributePropertyDrawer : PropertyDrawer + { + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + NavMeshComponentsGUIUtility.AgentTypePopup(position, label.text, property); + } + + public override float GetPropertyHeight(SerializedProperty property, GUIContent label) => NavMeshComponentsGUIUtility.IsAgentSelectionValid(property) ? 20 : 40; + } +} diff --git a/Assets/Scripts/PathFinding/NavMeshComponents/Editor/NavMeshAgentAttributePropertyDrawer.cs.meta b/Assets/Scripts/PathFinding/NavMeshComponents/Editor/NavMeshAgentAttributePropertyDrawer.cs.meta new file mode 100644 index 0000000..def39b4 --- /dev/null +++ b/Assets/Scripts/PathFinding/NavMeshComponents/Editor/NavMeshAgentAttributePropertyDrawer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1d43a96ce80684449a8b4eee132e5d47 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/PathFinding/NavMeshComponents/Editor/NavMeshAreaAttributePropertyDrawer.cs b/Assets/Scripts/PathFinding/NavMeshComponents/Editor/NavMeshAreaAttributePropertyDrawer.cs new file mode 100644 index 0000000..6587b92 --- /dev/null +++ b/Assets/Scripts/PathFinding/NavMeshComponents/Editor/NavMeshAreaAttributePropertyDrawer.cs @@ -0,0 +1,21 @@ +using UnityEditor; +using UnityEngine; +using NavMeshPlus.Extensions; +using NavMeshPlus.Editors.Components; + +//*********************************************************************************** +// Contributed by author jl-randazzo github.com/jl-randazzo +//*********************************************************************************** +namespace NavMeshPlus.Editors.Extensions +{ + [CustomPropertyDrawer(typeof(NavMeshAreaAttribute))] + public class NavMeshAreaAttributePropertyDrawer : PropertyDrawer + { + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + NavMeshComponentsGUIUtility.AreaPopup(position, label.text, property); + } + + public override float GetPropertyHeight(SerializedProperty property, GUIContent label) => 20; + } +} diff --git a/Assets/Scripts/PathFinding/NavMeshComponents/Editor/NavMeshAreaAttributePropertyDrawer.cs.meta b/Assets/Scripts/PathFinding/NavMeshComponents/Editor/NavMeshAreaAttributePropertyDrawer.cs.meta new file mode 100644 index 0000000..51960c7 --- /dev/null +++ b/Assets/Scripts/PathFinding/NavMeshComponents/Editor/NavMeshAreaAttributePropertyDrawer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 51136e93cfad4dd7883ae6248247b6a2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: d5b0e13ebe59cd64e9f67284457c6868, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/PathFinding/NavMeshComponents/Editor/NavMeshAssetManager.cs b/Assets/Scripts/PathFinding/NavMeshComponents/Editor/NavMeshAssetManager.cs new file mode 100644 index 0000000..9ebb09b --- /dev/null +++ b/Assets/Scripts/PathFinding/NavMeshComponents/Editor/NavMeshAssetManager.cs @@ -0,0 +1,337 @@ +using System.Collections.Generic; +using System.IO; +using UnityEditor.Experimental.SceneManagement; +using UnityEditor.SceneManagement; +using UnityEngine.AI; +using UnityEngine; +using NavMeshPlus.Extensions; +using UnityEditor; +using NavMeshPlus.Components; + +namespace NavMeshPlus.Editors.Components +{ + public class NavMeshAssetManager : ScriptableSingleton + { + internal struct AsyncBakeOperation + { + public NavMeshSurface surface; + public NavMeshData bakeData; + public AsyncOperation bakeOperation; + } + + List m_BakeOperations = new List(); + internal List GetBakeOperations() { return m_BakeOperations; } + + struct SavedPrefabNavMeshData + { + public NavMeshSurface surface; + public NavMeshData navMeshData; + } + + List m_PrefabNavMeshDataAssets = new List(); + + static string GetAndEnsureTargetPath(NavMeshSurface surface) + { + // Create directory for the asset if it does not exist yet. + var activeScenePath = surface.gameObject.scene.path; + + var targetPath = "Assets"; + if (!string.IsNullOrEmpty(activeScenePath)) + { + targetPath = Path.Combine(Path.GetDirectoryName(activeScenePath), Path.GetFileNameWithoutExtension(activeScenePath)); + } + else + { + var prefabStage = PrefabStageUtility.GetPrefabStage(surface.gameObject); + var isPartOfPrefab = prefabStage != null && prefabStage.IsPartOfPrefabContents(surface.gameObject); + + if (isPartOfPrefab) + { +#if UNITY_2020_1_OR_NEWER + var assetPath = prefabStage.assetPath; +#else + var assetPath = prefabStage.prefabAssetPath; +#endif + if (!string.IsNullOrEmpty(assetPath)) + { + var prefabDirectoryName = Path.GetDirectoryName(assetPath); + if (!string.IsNullOrEmpty(prefabDirectoryName)) + targetPath = prefabDirectoryName; + } + } + } + if (!Directory.Exists(targetPath)) + Directory.CreateDirectory(targetPath); + return targetPath; + } + + static void CreateNavMeshAsset(NavMeshSurface surface) + { + var targetPath = GetAndEnsureTargetPath(surface); + + var combinedAssetPath = Path.Combine(targetPath, "NavMesh-" + surface.name + ".asset"); + combinedAssetPath = AssetDatabase.GenerateUniqueAssetPath(combinedAssetPath); + AssetDatabase.CreateAsset(surface.navMeshData, combinedAssetPath); + } + + NavMeshData GetNavMeshAssetToDelete(NavMeshSurface navSurface) + { + if (PrefabUtility.IsPartOfPrefabInstance(navSurface) && !PrefabUtility.IsPartOfModelPrefab(navSurface)) + { + // Don't allow deleting the asset belonging to the prefab parent + var parentSurface = PrefabUtility.GetCorrespondingObjectFromSource(navSurface) as NavMeshSurface; + if (parentSurface && navSurface.navMeshData == parentSurface.navMeshData) + return null; + } + + // Do not delete the NavMeshData asset referenced from a prefab until the prefab is saved + var prefabStage = PrefabStageUtility.GetPrefabStage(navSurface.gameObject); + var isPartOfPrefab = prefabStage != null && prefabStage.IsPartOfPrefabContents(navSurface.gameObject); + if (isPartOfPrefab && IsCurrentPrefabNavMeshDataStored(navSurface)) + return null; + + return navSurface.navMeshData; + } + + void ClearSurface(NavMeshSurface navSurface) + { + var hasNavMeshData = navSurface.navMeshData != null; + StoreNavMeshDataIfInPrefab(navSurface); + + var assetToDelete = GetNavMeshAssetToDelete(navSurface); + navSurface.RemoveData(); + + if (hasNavMeshData) + { + SetNavMeshData(navSurface, null); + EditorSceneManager.MarkSceneDirty(navSurface.gameObject.scene); + } + + if (assetToDelete) + AssetDatabase.DeleteAsset(AssetDatabase.GetAssetPath(assetToDelete)); + } + + public void StartBakingSurfaces(UnityEngine.Object[] surfaces) + { + // Remove first to avoid double registration of the callback + EditorApplication.update -= UpdateAsyncBuildOperations; + EditorApplication.update += UpdateAsyncBuildOperations; + + foreach (NavMeshSurface surf in surfaces) + { + StoreNavMeshDataIfInPrefab(surf); + + var oper = new AsyncBakeOperation(); + + oper.bakeData = InitializeBakeData(surf); + oper.bakeOperation = surf.UpdateNavMesh(oper.bakeData); + oper.surface = surf; + + m_BakeOperations.Add(oper); + } + } + + static NavMeshData InitializeBakeData(NavMeshSurface surface) + { + var emptySources = new List(); + var emptyBounds = new Bounds(); + return UnityEngine.AI.NavMeshBuilder.BuildNavMeshData(surface.GetBuildSettings(), emptySources, emptyBounds + , surface.transform.position, surface.transform.rotation); + } + + void UpdateAsyncBuildOperations() + { + foreach (var oper in m_BakeOperations) + { + if (oper.surface == null || oper.bakeOperation == null) + continue; + + if (oper.bakeOperation.isDone) + { + var surface = oper.surface; + var delete = GetNavMeshAssetToDelete(surface); + if (delete != null) + AssetDatabase.DeleteAsset(AssetDatabase.GetAssetPath(delete)); + + surface.RemoveData(); + SetNavMeshData(surface, oper.bakeData); + + if (surface.isActiveAndEnabled) + surface.AddData(); + CreateNavMeshAsset(surface); + EditorSceneManager.MarkSceneDirty(surface.gameObject.scene); + } + } + m_BakeOperations.RemoveAll(o => o.bakeOperation == null || o.bakeOperation.isDone); + if (m_BakeOperations.Count == 0) + EditorApplication.update -= UpdateAsyncBuildOperations; + } + + public bool IsSurfaceBaking(NavMeshSurface surface) + { + if (surface == null) + return false; + + foreach (var oper in m_BakeOperations) + { + if (oper.surface == null || oper.bakeOperation == null) + continue; + + if (oper.surface == surface) + return true; + } + + return false; + } + + public void ClearSurfaces(UnityEngine.Object[] surfaces) + { + foreach (NavMeshSurface s in surfaces) + ClearSurface(s); + } + + static void SetNavMeshData(NavMeshSurface navSurface, NavMeshData navMeshData) + { + var so = new SerializedObject(navSurface); + var navMeshDataProperty = so.FindProperty("m_NavMeshData"); + navMeshDataProperty.objectReferenceValue = navMeshData; + so.ApplyModifiedPropertiesWithoutUndo(); + } + + void StoreNavMeshDataIfInPrefab(NavMeshSurface surfaceToStore) + { + var prefabStage = PrefabStageUtility.GetPrefabStage(surfaceToStore.gameObject); + var isPartOfPrefab = prefabStage != null && prefabStage.IsPartOfPrefabContents(surfaceToStore.gameObject); + if (!isPartOfPrefab) + return; + + // check if data has already been stored for this surface + foreach (var storedAssetInfo in m_PrefabNavMeshDataAssets) + if (storedAssetInfo.surface == surfaceToStore) + return; + + if (m_PrefabNavMeshDataAssets.Count == 0) + { + PrefabStage.prefabSaving -= DeleteStoredNavMeshDataAssetsForOwnedSurfaces; + PrefabStage.prefabSaving += DeleteStoredNavMeshDataAssetsForOwnedSurfaces; + + PrefabStage.prefabStageClosing -= ForgetUnsavedNavMeshDataChanges; + PrefabStage.prefabStageClosing += ForgetUnsavedNavMeshDataChanges; + } + + var isDataOwner = true; + if (PrefabUtility.IsPartOfPrefabInstance(surfaceToStore) && !PrefabUtility.IsPartOfModelPrefab(surfaceToStore)) + { + var basePrefabSurface = PrefabUtility.GetCorrespondingObjectFromSource(surfaceToStore) as NavMeshSurface; + isDataOwner = basePrefabSurface == null || surfaceToStore.navMeshData != basePrefabSurface.navMeshData; + } + m_PrefabNavMeshDataAssets.Add(new SavedPrefabNavMeshData { surface = surfaceToStore, navMeshData = isDataOwner ? surfaceToStore.navMeshData : null }); + } + + bool IsCurrentPrefabNavMeshDataStored(NavMeshSurface surface) + { + if (surface == null) + return false; + + foreach (var storedAssetInfo in m_PrefabNavMeshDataAssets) + { + if (storedAssetInfo.surface == surface) + return storedAssetInfo.navMeshData == surface.navMeshData; + } + + return false; + } + + void DeleteStoredNavMeshDataAssetsForOwnedSurfaces(GameObject gameObjectInPrefab) + { + // Debug.LogFormat("DeleteStoredNavMeshDataAsset() when saving prefab {0}", gameObjectInPrefab.name); + + var surfaces = gameObjectInPrefab.GetComponentsInChildren(true); + foreach (var surface in surfaces) + DeleteStoredPrefabNavMeshDataAsset(surface); + } + + void DeleteStoredPrefabNavMeshDataAsset(NavMeshSurface surface) + { + for (var i = m_PrefabNavMeshDataAssets.Count - 1; i >= 0; i--) + { + var storedAssetInfo = m_PrefabNavMeshDataAssets[i]; + if (storedAssetInfo.surface == surface) + { + var storedNavMeshData = storedAssetInfo.navMeshData; + if (storedNavMeshData != null && storedNavMeshData != surface.navMeshData) + { + var assetPath = AssetDatabase.GetAssetPath(storedNavMeshData); + AssetDatabase.DeleteAsset(assetPath); + } + + m_PrefabNavMeshDataAssets.RemoveAt(i); + break; + } + } + + if (m_PrefabNavMeshDataAssets.Count == 0) + { + PrefabStage.prefabSaving -= DeleteStoredNavMeshDataAssetsForOwnedSurfaces; + PrefabStage.prefabStageClosing -= ForgetUnsavedNavMeshDataChanges; + } + } + + void ForgetUnsavedNavMeshDataChanges(PrefabStage prefabStage) + { + // Debug.Log("On prefab closing - forget about this object's surfaces and stop caring about prefab saving"); + + if (prefabStage == null) + return; + + var allSurfacesInPrefab = prefabStage.prefabContentsRoot.GetComponentsInChildren(true); + NavMeshSurface surfaceInPrefab = null; + var index = 0; + do + { + if (allSurfacesInPrefab.Length > 0) + surfaceInPrefab = allSurfacesInPrefab[index]; + + for (var i = m_PrefabNavMeshDataAssets.Count - 1; i >= 0; i--) + { + var storedPrefabInfo = m_PrefabNavMeshDataAssets[i]; + if (storedPrefabInfo.surface == null) + { + // Debug.LogFormat("A surface from the prefab got deleted after it has baked a new NavMesh but it hasn't saved it. Now the unsaved asset gets deleted. ({0})", storedPrefabInfo.navMeshData); + + // surface got deleted, thus delete its initial NavMeshData asset + if (storedPrefabInfo.navMeshData != null) + { + var assetPath = AssetDatabase.GetAssetPath(storedPrefabInfo.navMeshData); + AssetDatabase.DeleteAsset(assetPath); + } + + m_PrefabNavMeshDataAssets.RemoveAt(i); + } + else if (surfaceInPrefab != null && storedPrefabInfo.surface == surfaceInPrefab) + { + //Debug.LogFormat("The surface {0} from the prefab was storing the original navmesh data and now will be forgotten", surfaceInPrefab); + + var baseSurface = PrefabUtility.GetCorrespondingObjectFromSource(surfaceInPrefab) as NavMeshSurface; + if (baseSurface == null || surfaceInPrefab.navMeshData != baseSurface.navMeshData) + { + var assetPath = AssetDatabase.GetAssetPath(surfaceInPrefab.navMeshData); + AssetDatabase.DeleteAsset(assetPath); + + //Debug.LogFormat("The surface {0} from the prefab has baked new NavMeshData but did not save this change so the asset has been now deleted. ({1})", + // surfaceInPrefab, assetPath); + } + + m_PrefabNavMeshDataAssets.RemoveAt(i); + } + } + } while (++index < allSurfacesInPrefab.Length); + + if (m_PrefabNavMeshDataAssets.Count == 0) + { + PrefabStage.prefabSaving -= DeleteStoredNavMeshDataAssetsForOwnedSurfaces; + PrefabStage.prefabStageClosing -= ForgetUnsavedNavMeshDataChanges; + } + } + } +} diff --git a/Assets/Scripts/PathFinding/NavMeshComponents/Editor/NavMeshAssetManager.cs.meta b/Assets/Scripts/PathFinding/NavMeshComponents/Editor/NavMeshAssetManager.cs.meta new file mode 100644 index 0000000..80dd8ef --- /dev/null +++ b/Assets/Scripts/PathFinding/NavMeshComponents/Editor/NavMeshAssetManager.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0d969266144f4fb47be21604dd1e7900 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/PathFinding/NavMeshComponents/Editor/NavMeshComponentsEditor.asmdef b/Assets/Scripts/PathFinding/NavMeshComponents/Editor/NavMeshComponentsEditor.asmdef new file mode 100644 index 0000000..3aa024e --- /dev/null +++ b/Assets/Scripts/PathFinding/NavMeshComponents/Editor/NavMeshComponentsEditor.asmdef @@ -0,0 +1,16 @@ +{ + "name": "NavMeshPlusEditor", + "references": [ + "NavMeshPlus" + ], + "optionalUnityReferences": [], + "includePlatforms": [ + "Editor" + ], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [] +} \ No newline at end of file diff --git a/Assets/Scripts/PathFinding/NavMeshComponents/Editor/NavMeshComponentsEditor.asmdef.meta b/Assets/Scripts/PathFinding/NavMeshComponents/Editor/NavMeshComponentsEditor.asmdef.meta new file mode 100644 index 0000000..d294c82 --- /dev/null +++ b/Assets/Scripts/PathFinding/NavMeshComponents/Editor/NavMeshComponentsEditor.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: a38ed33481bedd74d8c590f5043f49dc +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/PathFinding/NavMeshComponents/Editor/NavMeshComponentsGUIUtility.cs b/Assets/Scripts/PathFinding/NavMeshComponents/Editor/NavMeshComponentsGUIUtility.cs new file mode 100644 index 0000000..1c39735 --- /dev/null +++ b/Assets/Scripts/PathFinding/NavMeshComponents/Editor/NavMeshComponentsGUIUtility.cs @@ -0,0 +1,276 @@ +using UnityEditor; +using UnityEditor.AI; +using UnityEngine; +using UnityEngine.AI; + +namespace NavMeshPlus.Editors.Components +{ + public static class NavMeshComponentsGUIUtility + { + public static void AreaPopup(Rect rect, string labelName, SerializedProperty areaProperty) + { + var areaIndex = -1; + var areaNames = GameObjectUtility.GetNavMeshAreaNames(); + for (var i = 0; i < areaNames.Length; i++) + { + var areaValue = GameObjectUtility.GetNavMeshAreaFromName(areaNames[i]); + if (areaValue == areaProperty.intValue) + areaIndex = i; + } + ArrayUtility.Add(ref areaNames, ""); + ArrayUtility.Add(ref areaNames, "Open Area Settings..."); + + EditorGUI.BeginProperty(rect, GUIContent.none, areaProperty); + + EditorGUI.BeginChangeCheck(); + areaIndex = EditorGUI.Popup(rect, labelName, areaIndex, areaNames); + + if (EditorGUI.EndChangeCheck()) + { + if (areaIndex >= 0 && areaIndex < areaNames.Length - 2) + areaProperty.intValue = GameObjectUtility.GetNavMeshAreaFromName(areaNames[areaIndex]); + else if (areaIndex == areaNames.Length - 1) + NavMeshEditorHelpers.OpenAreaSettings(); + } + + EditorGUI.EndProperty(); + } + + public static bool IsAgentSelectionValid(SerializedProperty agentTypeID) + { + var count = NavMesh.GetSettingsCount(); + for (var i = 0; i < count; i++) + { + var id = NavMesh.GetSettingsByIndex(i).agentTypeID; + var name = NavMesh.GetSettingsNameFromID(id); + if (id == agentTypeID.intValue) + return true; + } + return false; + } + + public static void AgentTypePopup(Rect rect, string labelName, SerializedProperty agentTypeID) + { + var index = -1; + var count = NavMesh.GetSettingsCount(); + var agentTypeNames = new string[count + 2]; + for (var i = 0; i < count; i++) + { + var id = NavMesh.GetSettingsByIndex(i).agentTypeID; + var name = NavMesh.GetSettingsNameFromID(id); + agentTypeNames[i] = name; + if (id == agentTypeID.intValue) + index = i; + } + agentTypeNames[count] = ""; + agentTypeNames[count + 1] = "Open Agent Settings..."; + + bool validAgentType = index != -1; + if (!validAgentType) + { + Rect warningRect = rect; + warningRect.height *= .5f; + warningRect.y += warningRect.height; + EditorGUI.HelpBox(warningRect, "Agent Type invalid.", MessageType.Warning); + + rect.height *= .5f; + } + + EditorGUI.BeginProperty(rect, GUIContent.none, agentTypeID); + + EditorGUI.BeginChangeCheck(); + index = EditorGUI.Popup(rect, labelName, index, agentTypeNames); + if (EditorGUI.EndChangeCheck()) + { + if (index >= 0 && index < count) + { + var id = NavMesh.GetSettingsByIndex(index).agentTypeID; + agentTypeID.intValue = id; + } + else if (index == count + 1) + { + NavMeshEditorHelpers.OpenAgentSettings(-1); + } + } + + EditorGUI.EndProperty(); + } + + // Agent mask is a set (internally array/list) of agentTypeIDs. + // It is used to describe which agents modifiers apply to. + // There is a special case of "None" which is an empty array. + // There is a special case of "All" which is an array of length 1, and value of -1. + public static void AgentMaskPopup(string labelName, SerializedProperty agentMask) + { + // Contents of the dropdown box. + string popupContent = ""; + + if (agentMask.hasMultipleDifferentValues) + popupContent = "\u2014"; + else + popupContent = GetAgentMaskLabelName(agentMask); + + var content = new GUIContent(popupContent); + var popupRect = GUILayoutUtility.GetRect(content, EditorStyles.popup); + + EditorGUI.BeginProperty(popupRect, GUIContent.none, agentMask); + popupRect = EditorGUI.PrefixLabel(popupRect, 0, new GUIContent(labelName)); + bool pressed = GUI.Button(popupRect, content, EditorStyles.popup); + + if (pressed) + { + var show = !agentMask.hasMultipleDifferentValues; + var showNone = show && agentMask.arraySize == 0; + var showAll = show && IsAll(agentMask); + + var menu = new GenericMenu(); + menu.AddItem(new GUIContent("None"), showNone, SetAgentMaskNone, agentMask); + menu.AddItem(new GUIContent("All"), showAll, SetAgentMaskAll, agentMask); + menu.AddSeparator(""); + + var count = NavMesh.GetSettingsCount(); + for (var i = 0; i < count; i++) + { + var id = NavMesh.GetSettingsByIndex(i).agentTypeID; + var sname = NavMesh.GetSettingsNameFromID(id); + + var showSelected = show && AgentMaskHasSelectedAgentTypeID(agentMask, id); + var userData = new object[] { agentMask, id, !showSelected }; + menu.AddItem(new GUIContent(sname), showSelected, ToggleAgentMaskItem, userData); + } + + menu.DropDown(popupRect); + } + + EditorGUI.EndProperty(); + } + + public static GameObject CreateAndSelectGameObject(string suggestedName, GameObject parent) + { + var parentTransform = parent != null ? parent.transform : null; + var uniqueName = GameObjectUtility.GetUniqueNameForSibling(parentTransform, suggestedName); + var child = new GameObject(uniqueName); + + Undo.RegisterCreatedObjectUndo(child, "Create " + uniqueName); + if (parentTransform != null) + Undo.SetTransformParent(child.transform, parentTransform, "Parent " + uniqueName); + + Selection.activeGameObject = child; + + return child; + } + + static bool IsAll(SerializedProperty agentMask) + { + return agentMask.arraySize == 1 && agentMask.GetArrayElementAtIndex(0).intValue == -1; + } + + static void ToggleAgentMaskItem(object userData) + { + var args = (object[])userData; + var agentMask = (SerializedProperty)args[0]; + var agentTypeID = (int)args[1]; + var value = (bool)args[2]; + + ToggleAgentMaskItem(agentMask, agentTypeID, value); + } + + static void ToggleAgentMaskItem(SerializedProperty agentMask, int agentTypeID, bool value) + { + if (agentMask.hasMultipleDifferentValues) + { + agentMask.ClearArray(); + agentMask.serializedObject.ApplyModifiedProperties(); + } + + // Find which index this agent type is in the agentMask array. + int idx = -1; + for (var j = 0; j < agentMask.arraySize; j++) + { + var elem = agentMask.GetArrayElementAtIndex(j); + if (elem.intValue == agentTypeID) + idx = j; + } + + // Handle "All" special case. + if (IsAll(agentMask)) + { + agentMask.DeleteArrayElementAtIndex(0); + } + + // Toggle value. + if (value) + { + if (idx == -1) + { + agentMask.InsertArrayElementAtIndex(agentMask.arraySize); + agentMask.GetArrayElementAtIndex(agentMask.arraySize - 1).intValue = agentTypeID; + } + } + else + { + if (idx != -1) + { + agentMask.DeleteArrayElementAtIndex(idx); + } + } + + agentMask.serializedObject.ApplyModifiedProperties(); + } + + static void SetAgentMaskNone(object data) + { + var agentMask = (SerializedProperty)data; + agentMask.ClearArray(); + agentMask.serializedObject.ApplyModifiedProperties(); + } + + static void SetAgentMaskAll(object data) + { + var agentMask = (SerializedProperty)data; + agentMask.ClearArray(); + agentMask.InsertArrayElementAtIndex(0); + agentMask.GetArrayElementAtIndex(0).intValue = -1; + agentMask.serializedObject.ApplyModifiedProperties(); + } + + static string GetAgentMaskLabelName(SerializedProperty agentMask) + { + if (agentMask.arraySize == 0) + return "None"; + + if (IsAll(agentMask)) + return "All"; + + if (agentMask.arraySize <= 3) + { + var labelName = ""; + for (var j = 0; j < agentMask.arraySize; j++) + { + var elem = agentMask.GetArrayElementAtIndex(j); + var settingsName = NavMesh.GetSettingsNameFromID(elem.intValue); + if (string.IsNullOrEmpty(settingsName)) + continue; + + if (labelName.Length > 0) + labelName += ", "; + labelName += settingsName; + } + return labelName; + } + + return "Mixed..."; + } + + static bool AgentMaskHasSelectedAgentTypeID(SerializedProperty agentMask, int agentTypeID) + { + for (var j = 0; j < agentMask.arraySize; j++) + { + var elem = agentMask.GetArrayElementAtIndex(j); + if (elem.intValue == agentTypeID) + return true; + } + return false; + } + } +} diff --git a/Assets/Scripts/PathFinding/NavMeshComponents/Editor/NavMeshComponentsGUIUtility.cs.meta b/Assets/Scripts/PathFinding/NavMeshComponents/Editor/NavMeshComponentsGUIUtility.cs.meta new file mode 100644 index 0000000..d02f1fa --- /dev/null +++ b/Assets/Scripts/PathFinding/NavMeshComponents/Editor/NavMeshComponentsGUIUtility.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6d05c56cb29ad5240bc671605f95db0c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/PathFinding/NavMeshComponents/Editor/NavMeshLinkEditor.cs b/Assets/Scripts/PathFinding/NavMeshComponents/Editor/NavMeshLinkEditor.cs new file mode 100644 index 0000000..b360fda --- /dev/null +++ b/Assets/Scripts/PathFinding/NavMeshComponents/Editor/NavMeshLinkEditor.cs @@ -0,0 +1,281 @@ +using NavMeshPlus.Components; +using UnityEditor; +using UnityEditor.AI; +using UnityEngine; +using UnityEngine.AI; + +namespace NavMeshPlus.Editors.Components +{ + [CanEditMultipleObjects] + [CustomEditor(typeof(NavMeshLink))] + class NavMeshLinkEditor : Editor + { + SerializedProperty m_AgentTypeID; + SerializedProperty m_Area; + SerializedProperty m_CostModifier; + SerializedProperty m_AutoUpdatePosition; + SerializedProperty m_Bidirectional; + SerializedProperty m_EndPoint; + SerializedProperty m_StartPoint; + SerializedProperty m_Width; + + static int s_SelectedID; + static int s_SelectedPoint = -1; + + static Color s_HandleColor = new Color(255f, 167f, 39f, 210f) / 255; + static Color s_HandleColorDisabled = new Color(255f * 0.75f, 167f * 0.75f, 39f * 0.75f, 100f) / 255; + + void OnEnable() + { + m_AgentTypeID = serializedObject.FindProperty("m_AgentTypeID"); + m_Area = serializedObject.FindProperty("m_Area"); + m_CostModifier = serializedObject.FindProperty("m_CostModifier"); + m_AutoUpdatePosition = serializedObject.FindProperty("m_AutoUpdatePosition"); + m_Bidirectional = serializedObject.FindProperty("m_Bidirectional"); + m_EndPoint = serializedObject.FindProperty("m_EndPoint"); + m_StartPoint = serializedObject.FindProperty("m_StartPoint"); + m_Width = serializedObject.FindProperty("m_Width"); + + s_SelectedID = 0; + s_SelectedPoint = -1; + + NavMeshVisualizationSettings.showNavigation++; + } + + void OnDisable() + { + NavMeshVisualizationSettings.showNavigation--; + } + + static Matrix4x4 UnscaledLocalToWorldMatrix(Transform t) + { + return Matrix4x4.TRS(t.position, t.rotation, Vector3.one); + } + + void AlignTransformToEndPoints(NavMeshLink navLink) + { + var mat = UnscaledLocalToWorldMatrix(navLink.transform); + + var worldStartPt = mat.MultiplyPoint(navLink.startPoint); + var worldEndPt = mat.MultiplyPoint(navLink.endPoint); + + var forward = worldEndPt - worldStartPt; + var up = navLink.transform.up; + + // Flatten + forward -= Vector3.Dot(up, forward) * up; + + var transform = navLink.transform; + transform.rotation = Quaternion.LookRotation(forward, up); + transform.position = (worldEndPt + worldStartPt) * 0.5f; + transform.localScale = Vector3.one; + + navLink.startPoint = transform.InverseTransformPoint(worldStartPt); + navLink.endPoint = transform.InverseTransformPoint(worldEndPt); + } + + public override void OnInspectorGUI() + { + serializedObject.Update(); + + EditorGUILayout.PropertyField(m_AgentTypeID); + EditorGUILayout.Space(); + + EditorGUILayout.PropertyField(m_StartPoint); + EditorGUILayout.PropertyField(m_EndPoint); + + GUILayout.BeginHorizontal(); + GUILayout.Space(EditorGUIUtility.labelWidth); + if (GUILayout.Button("Swap")) + { + foreach (NavMeshLink navLink in targets) + { + var tmp = navLink.startPoint; + navLink.startPoint = navLink.endPoint; + navLink.endPoint = tmp; + } + SceneView.RepaintAll(); + } + if (GUILayout.Button("Align Transform")) + { + foreach (NavMeshLink navLink in targets) + { + Undo.RecordObject(navLink.transform, "Align Transform to End Points"); + Undo.RecordObject(navLink, "Align Transform to End Points"); + AlignTransformToEndPoints(navLink); + } + SceneView.RepaintAll(); + } + GUILayout.EndHorizontal(); + EditorGUILayout.Space(); + + EditorGUILayout.PropertyField(m_Width); + EditorGUILayout.PropertyField(m_CostModifier); + EditorGUILayout.PropertyField(m_AutoUpdatePosition); + EditorGUILayout.PropertyField(m_Bidirectional); + EditorGUILayout.PropertyField(m_Area); + + serializedObject.ApplyModifiedProperties(); + + EditorGUILayout.Space(); + } + + static Vector3 CalcLinkRight(NavMeshLink navLink) + { + var dir = navLink.endPoint - navLink.startPoint; + return (new Vector3(-dir.z, 0.0f, dir.x)).normalized; + } + + static void DrawLink(NavMeshLink navLink) + { + var right = CalcLinkRight(navLink); + var rad = navLink.width * 0.5f; + + Gizmos.DrawLine(navLink.startPoint - right * rad, navLink.startPoint + right * rad); + Gizmos.DrawLine(navLink.endPoint - right * rad, navLink.endPoint + right * rad); + Gizmos.DrawLine(navLink.startPoint - right * rad, navLink.endPoint - right * rad); + Gizmos.DrawLine(navLink.startPoint + right * rad, navLink.endPoint + right * rad); + } + + [DrawGizmo(GizmoType.Selected | GizmoType.Active | GizmoType.Pickable)] + static void RenderBoxGizmo(NavMeshLink navLink, GizmoType gizmoType) + { + if (!EditorApplication.isPlaying) + navLink.UpdateLink(); + + var color = s_HandleColor; + if (!navLink.enabled) + color = s_HandleColorDisabled; + + var oldColor = Gizmos.color; + var oldMatrix = Gizmos.matrix; + + Gizmos.matrix = UnscaledLocalToWorldMatrix(navLink.transform); + + Gizmos.color = color; + DrawLink(navLink); + + Gizmos.matrix = oldMatrix; + Gizmos.color = oldColor; + + Gizmos.DrawIcon(navLink.transform.position, "NavMeshLink Icon", true); + } + + [DrawGizmo(GizmoType.NotInSelectionHierarchy | GizmoType.Pickable)] + static void RenderBoxGizmoNotSelected(NavMeshLink navLink, GizmoType gizmoType) + { + if (NavMeshVisualizationSettings.showNavigation > 0) + { + var color = s_HandleColor; + if (!navLink.enabled) + color = s_HandleColorDisabled; + + var oldColor = Gizmos.color; + var oldMatrix = Gizmos.matrix; + + Gizmos.matrix = UnscaledLocalToWorldMatrix(navLink.transform); + + Gizmos.color = color; + DrawLink(navLink); + + Gizmos.matrix = oldMatrix; + Gizmos.color = oldColor; + } + + Gizmos.DrawIcon(navLink.transform.position, "NavMeshLink Icon", true); + } + + public void OnSceneGUI() + { + var navLink = (NavMeshLink)target; + if (!navLink.enabled) + return; + + var mat = UnscaledLocalToWorldMatrix(navLink.transform); + + var startPt = mat.MultiplyPoint(navLink.startPoint); + var endPt = mat.MultiplyPoint(navLink.endPoint); + var midPt = Vector3.Lerp(startPt, endPt, 0.35f); + var startSize = HandleUtility.GetHandleSize(startPt); + var endSize = HandleUtility.GetHandleSize(endPt); + var midSize = HandleUtility.GetHandleSize(midPt); + + var zup = Quaternion.FromToRotation(Vector3.forward, Vector3.up); + var right = mat.MultiplyVector(CalcLinkRight(navLink)); + + var oldColor = Handles.color; + Handles.color = s_HandleColor; + + Vector3 pos; + + if (navLink.GetInstanceID() == s_SelectedID && s_SelectedPoint == 0) + { + EditorGUI.BeginChangeCheck(); + Handles.CubeHandleCap(0, startPt, zup, 0.1f * startSize, Event.current.type); + pos = Handles.PositionHandle(startPt, navLink.transform.rotation); + if (EditorGUI.EndChangeCheck()) + { + Undo.RecordObject(navLink, "Move link point"); + navLink.startPoint = mat.inverse.MultiplyPoint(pos); + } + } + else + { + if (Handles.Button(startPt, zup, 0.1f * startSize, 0.1f * startSize, Handles.CubeHandleCap)) + { + s_SelectedPoint = 0; + s_SelectedID = navLink.GetInstanceID(); + } + } + + if (navLink.GetInstanceID() == s_SelectedID && s_SelectedPoint == 1) + { + EditorGUI.BeginChangeCheck(); + Handles.CubeHandleCap(0, endPt, zup, 0.1f * startSize, Event.current.type); + pos = Handles.PositionHandle(endPt, navLink.transform.rotation); + if (EditorGUI.EndChangeCheck()) + { + Undo.RecordObject(navLink, "Move link point"); + navLink.endPoint = mat.inverse.MultiplyPoint(pos); + } + } + else + { + if (Handles.Button(endPt, zup, 0.1f * endSize, 0.1f * endSize, Handles.CubeHandleCap)) + { + s_SelectedPoint = 1; + s_SelectedID = navLink.GetInstanceID(); + } + } + + EditorGUI.BeginChangeCheck(); + pos = Handles.Slider(midPt + right * navLink.width * 0.5f, right, midSize * 0.03f, Handles.DotHandleCap, 0); + if (EditorGUI.EndChangeCheck()) + { + Undo.RecordObject(navLink, "Adjust link width"); + navLink.width = Mathf.Max(0.0f, 2.0f * Vector3.Dot(right, (pos - midPt))); + } + + EditorGUI.BeginChangeCheck(); + pos = Handles.Slider(midPt - right * navLink.width * 0.5f, -right, midSize * 0.03f, Handles.DotHandleCap, 0); + if (EditorGUI.EndChangeCheck()) + { + Undo.RecordObject(navLink, "Adjust link width"); + navLink.width = Mathf.Max(0.0f, 2.0f * Vector3.Dot(-right, (pos - midPt))); + } + + Handles.color = oldColor; + } + + [MenuItem("GameObject/Navigation/NavMesh Link", false, 2002)] + static public void CreateNavMeshLink(MenuCommand menuCommand) + { + var parent = menuCommand.context as GameObject; + GameObject go = NavMeshComponentsGUIUtility.CreateAndSelectGameObject("NavMesh Link", parent); + go.AddComponent(); + var view = SceneView.lastActiveSceneView; + if (view != null) + view.MoveToView(go.transform); + } + } +} diff --git a/Assets/Scripts/PathFinding/NavMeshComponents/Editor/NavMeshLinkEditor.cs.meta b/Assets/Scripts/PathFinding/NavMeshComponents/Editor/NavMeshLinkEditor.cs.meta new file mode 100644 index 0000000..e07e698 --- /dev/null +++ b/Assets/Scripts/PathFinding/NavMeshComponents/Editor/NavMeshLinkEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 03832abc07e3394479eec5708b22e984 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/PathFinding/NavMeshComponents/Editor/NavMeshModifierEditor.cs b/Assets/Scripts/PathFinding/NavMeshComponents/Editor/NavMeshModifierEditor.cs new file mode 100644 index 0000000..dfd1f2c --- /dev/null +++ b/Assets/Scripts/PathFinding/NavMeshComponents/Editor/NavMeshModifierEditor.cs @@ -0,0 +1,53 @@ +using NavMeshPlus.Components; +using NavMeshPlus.Extensions; +using UnityEditor; +using UnityEditor.AI; +using UnityEngine.AI; + +namespace NavMeshPlus.Editors.Components +{ + [CanEditMultipleObjects] + [CustomEditor(typeof(NavMeshModifier))] + class NavMeshModifierEditor : Editor + { + SerializedProperty m_AffectedAgents; + SerializedProperty m_Area; + SerializedProperty m_IgnoreFromBuild; + SerializedProperty m_OverrideArea; + + void OnEnable() + { + m_AffectedAgents = serializedObject.FindProperty("m_AffectedAgents"); + m_Area = serializedObject.FindProperty("m_Area"); + m_IgnoreFromBuild = serializedObject.FindProperty("m_IgnoreFromBuild"); + m_OverrideArea = serializedObject.FindProperty("m_OverrideArea"); + + NavMeshVisualizationSettings.showNavigation++; + } + + void OnDisable() + { + NavMeshVisualizationSettings.showNavigation--; + } + + public override void OnInspectorGUI() + { + serializedObject.Update(); + + EditorGUILayout.PropertyField(m_IgnoreFromBuild); + + EditorGUILayout.PropertyField(m_OverrideArea); + if (m_OverrideArea.boolValue) + { + EditorGUI.indentLevel++; + EditorGUILayout.PropertyField(m_Area); + EditorGUI.indentLevel--; + } + + NavMeshComponentsGUIUtility.AgentMaskPopup("Affected Agents", m_AffectedAgents); + EditorGUILayout.Space(); + + serializedObject.ApplyModifiedProperties(); + } + } +} diff --git a/Assets/Scripts/PathFinding/NavMeshComponents/Editor/NavMeshModifierEditor.cs.meta b/Assets/Scripts/PathFinding/NavMeshComponents/Editor/NavMeshModifierEditor.cs.meta new file mode 100644 index 0000000..6eebccb --- /dev/null +++ b/Assets/Scripts/PathFinding/NavMeshComponents/Editor/NavMeshModifierEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b8fce3c13f011874d92d75ca24a90702 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/PathFinding/NavMeshComponents/Editor/NavMeshModifierTilemapEditor.cs b/Assets/Scripts/PathFinding/NavMeshComponents/Editor/NavMeshModifierTilemapEditor.cs new file mode 100644 index 0000000..e07c3d1 --- /dev/null +++ b/Assets/Scripts/PathFinding/NavMeshComponents/Editor/NavMeshModifierTilemapEditor.cs @@ -0,0 +1,158 @@ +using NavMeshPlus.Components; +using NavMeshPlus.Extensions; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; +using UnityEditor; +using UnityEditor.UIElements; +using UnityEditor.AI; +using UnityEngine.AI; +using UnityEngine.Tilemaps; + +//*********************************************************************************** +// Contributed by author jl-randazzo github.com/jl-randazzo +//*********************************************************************************** +namespace NavMeshPlus.Editors.Components +{ + [CanEditMultipleObjects] + [CustomEditor(typeof(NavMeshModifierTilemap))] + class NavMeshModifierTilemapEditor : Editor + { + SerializedProperty m_TileModifiers; + + void OnEnable() + { + m_TileModifiers = serializedObject.FindProperty("m_TileModifiers"); + } + + public override void OnInspectorGUI() + { + NavMeshModifierTilemap modifierTilemap = target as NavMeshModifierTilemap; + + serializedObject.Update(); + EditorGUILayout.PropertyField(m_TileModifiers); + + if (modifierTilemap.HasDuplicateTileModifiers()) + { + EditorGUILayout.HelpBox("There are duplicate Tile entries in the tilemap modifiers! Only the first will be used.", MessageType.Warning); + } + + EditorGUILayout.Space(); + + Tilemap tilemap = modifierTilemap.GetComponent(); + if (tilemap) + { + if (GUILayout.Button("Add Used Tiles")) + { + AddUsedTiles(tilemap, modifierTilemap); + } + } + else + { + EditorGUILayout.HelpBox("Missing required component 'Tilemap'", MessageType.Error); + } + + if (serializedObject.ApplyModifiedProperties()) + { + modifierTilemap.CacheModifiers(); + } + } + + private void AddUsedTiles(Tilemap tilemap, NavMeshModifierTilemap modifierTilemap) + { + Dictionary tileModifiers = modifierTilemap.GetModifierMap(); + + BoundsInt bounds = tilemap.cellBounds; + for (int i = bounds.xMin; i <= bounds.xMax; i++) + { + for (int j = bounds.yMin; j <= bounds.yMax; j++) + { + for (int k = bounds.zMin; k <= bounds.zMax; k++) + { + if (tilemap.GetTile(new Vector3Int(i, j, k)) is TileBase tileBase) + { + if (!tileModifiers.ContainsKey(tileBase)) + { + tileModifiers.Add(tileBase, new NavMeshModifierTilemap.TileModifier()); + + int idx = m_TileModifiers.arraySize; + m_TileModifiers.InsertArrayElementAtIndex(idx); + var newElem = m_TileModifiers.GetArrayElementAtIndex(idx); + var tileProperty = newElem.FindPropertyRelative(nameof(NavMeshModifierTilemap.TileModifier.tile)); + tileProperty.objectReferenceValue = tileBase; + } + } + } + } + } + } + + [CustomPropertyDrawer(typeof(NavMeshModifierTilemap.TileModifier))] + class TileModifierPropertyDrawer : PropertyDrawer + { + private Rect ClaimAdvance(ref Rect position, float height) + { + Rect retVal = position; + retVal.height = height; + position.y += height; + position.height -= height; + return retVal; + } + + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + Rect expandRect = ClaimAdvance(ref position, 20); + property.isExpanded = EditorGUI.Foldout(expandRect, property.isExpanded, label); + if (property.isExpanded) + { + var tileProperty = property.FindPropertyRelative(nameof(NavMeshModifierTilemap.TileModifier.tile)); + Rect tileRect = ClaimAdvance(ref position, 40); + tileRect.width -= 40; + + Rect previewRect = tileRect; + previewRect.width = 40; + previewRect.x += tileRect.width; + tileRect.height /= 2; + + // Adding the tile selector and a preview image. + EditorGUI.PropertyField(tileRect, tileProperty); + TileBase tileBase = tileProperty.objectReferenceValue as TileBase; + TileData tileData = new TileData(); + tileBase?.GetTileData(Vector3Int.zero, null, ref tileData); + if (tileData.sprite) + { + EditorGUI.DrawPreviewTexture(previewRect, tileData.sprite?.texture, null, ScaleMode.ScaleToFit, 0); + } + + Rect toggleRect = ClaimAdvance(ref position, 20); + var overrideAreaProperty = property.FindPropertyRelative(nameof(NavMeshModifierTilemap.TileModifier.overrideArea)); + EditorGUI.PropertyField(toggleRect, overrideAreaProperty); + + if (overrideAreaProperty.boolValue) + { + Rect areaRect = ClaimAdvance(ref position, 20); + var areaProperty = property.FindPropertyRelative(nameof(NavMeshModifierTilemap.TileModifier.area)); + EditorGUI.indentLevel++; + EditorGUI.PropertyField(areaRect, areaProperty); + EditorGUI.indentLevel--; + } + } + } + + public override float GetPropertyHeight(SerializedProperty property, GUIContent label) + { + if (property.isExpanded) + { + var overrideAreaProperty = property.FindPropertyRelative(nameof(NavMeshModifierTilemap.TileModifier.overrideArea)); + if (overrideAreaProperty.boolValue) + { + return 100; + } + return 80; + } + return 20; + + } + } + } +} diff --git a/Assets/Scripts/PathFinding/NavMeshComponents/Editor/NavMeshModifierTilemapEditor.cs.meta b/Assets/Scripts/PathFinding/NavMeshComponents/Editor/NavMeshModifierTilemapEditor.cs.meta new file mode 100644 index 0000000..f4c890a --- /dev/null +++ b/Assets/Scripts/PathFinding/NavMeshComponents/Editor/NavMeshModifierTilemapEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1fa3ed80a7c8401995efba10b64226e9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/PathFinding/NavMeshComponents/Editor/NavMeshModifierVolumeEditor.cs b/Assets/Scripts/PathFinding/NavMeshComponents/Editor/NavMeshModifierVolumeEditor.cs new file mode 100644 index 0000000..66ef21c --- /dev/null +++ b/Assets/Scripts/PathFinding/NavMeshComponents/Editor/NavMeshModifierVolumeEditor.cs @@ -0,0 +1,149 @@ +using UnityEditor.IMGUI.Controls; +using UnityEditorInternal; +using UnityEngine.AI; +using UnityEngine; +using NavMeshPlus.Extensions; +using UnityEditor; +using UnityEditor.AI; +using NavMeshPlus.Components; + +namespace NavMeshPlus.Editors.Components +{ + [CanEditMultipleObjects] + [CustomEditor(typeof(NavMeshModifierVolume))] + class NavMeshModifierVolumeEditor : Editor + { + SerializedProperty m_AffectedAgents; + SerializedProperty m_Area; + SerializedProperty m_Center; + SerializedProperty m_Size; + + static Color s_HandleColor = new Color(187f, 138f, 240f, 210f) / 255; + static Color s_HandleColorDisabled = new Color(187f * 0.75f, 138f * 0.75f, 240f * 0.75f, 100f) / 255; + + BoxBoundsHandle m_BoundsHandle = new BoxBoundsHandle(); + + bool editingCollider + { + get { return EditMode.editMode == EditMode.SceneViewEditMode.Collider && EditMode.IsOwner(this); } + } + + void OnEnable() + { + m_AffectedAgents = serializedObject.FindProperty("m_AffectedAgents"); + m_Area = serializedObject.FindProperty("m_Area"); + m_Center = serializedObject.FindProperty("m_Center"); + m_Size = serializedObject.FindProperty("m_Size"); + + NavMeshVisualizationSettings.showNavigation++; + } + + void OnDisable() + { + NavMeshVisualizationSettings.showNavigation--; + } + + Bounds GetBounds() + { + var navModifier = (NavMeshModifierVolume)target; + return new Bounds(navModifier.transform.position, navModifier.size); + } + + public override void OnInspectorGUI() + { + serializedObject.Update(); + + EditMode.DoEditModeInspectorModeButton(EditMode.SceneViewEditMode.Collider, "Edit Volume", + EditorGUIUtility.IconContent("EditCollider"), GetBounds, this); + + EditorGUILayout.PropertyField(m_Size); + EditorGUILayout.PropertyField(m_Center); + EditorGUILayout.PropertyField(m_Area); + NavMeshComponentsGUIUtility.AgentMaskPopup("Affected Agents", m_AffectedAgents); + EditorGUILayout.Space(); + + serializedObject.ApplyModifiedProperties(); + } + + [DrawGizmo(GizmoType.Selected | GizmoType.Active)] + static void RenderBoxGizmo(NavMeshModifierVolume navModifier, GizmoType gizmoType) + { + var color = navModifier.enabled ? s_HandleColor : s_HandleColorDisabled; + var colorTrans = new Color(color.r * 0.75f, color.g * 0.75f, color.b * 0.75f, color.a * 0.15f); + + var oldColor = Gizmos.color; + var oldMatrix = Gizmos.matrix; + + Gizmos.matrix = navModifier.transform.localToWorldMatrix; + + Gizmos.color = colorTrans; + Gizmos.DrawCube(navModifier.center, navModifier.size); + + Gizmos.color = color; + Gizmos.DrawWireCube(navModifier.center, navModifier.size); + + Gizmos.matrix = oldMatrix; + Gizmos.color = oldColor; + + Gizmos.DrawIcon(navModifier.transform.position, "NavMeshModifierVolume Icon", true); + } + + [DrawGizmo(GizmoType.NotInSelectionHierarchy | GizmoType.Pickable)] + static void RenderBoxGizmoNotSelected(NavMeshModifierVolume navModifier, GizmoType gizmoType) + { + if (NavMeshVisualizationSettings.showNavigation > 0) + { + var color = navModifier.enabled ? s_HandleColor : s_HandleColorDisabled; + var oldColor = Gizmos.color; + var oldMatrix = Gizmos.matrix; + + Gizmos.matrix = navModifier.transform.localToWorldMatrix; + + Gizmos.color = color; + Gizmos.DrawWireCube(navModifier.center, navModifier.size); + + Gizmos.matrix = oldMatrix; + Gizmos.color = oldColor; + } + + Gizmos.DrawIcon(navModifier.transform.position, "NavMeshModifierVolume Icon", true); + } + + void OnSceneGUI() + { + if (!editingCollider) + return; + + var vol = (NavMeshModifierVolume)target; + var color = vol.enabled ? s_HandleColor : s_HandleColorDisabled; + using (new Handles.DrawingScope(color, vol.transform.localToWorldMatrix)) + { + m_BoundsHandle.center = vol.center; + m_BoundsHandle.size = vol.size; + + EditorGUI.BeginChangeCheck(); + m_BoundsHandle.DrawHandle(); + if (EditorGUI.EndChangeCheck()) + { + Undo.RecordObject(vol, "Modified NavMesh Modifier Volume"); + Vector3 center = m_BoundsHandle.center; + Vector3 size = m_BoundsHandle.size; + vol.center = center; + vol.size = size; + EditorUtility.SetDirty(target); + } + } + } + + [MenuItem("GameObject/Navigation/NavMesh Modifier Volume", false, 2001)] + static public void CreateNavMeshModifierVolume(MenuCommand menuCommand) + { + var parent = menuCommand.context as GameObject; + var go = NavMeshComponentsGUIUtility.CreateAndSelectGameObject("NavMesh Modifier Volume", parent); + go.AddComponent(); + var view = SceneView.lastActiveSceneView; + if (view != null) + view.MoveToView(go.transform); + } + } +} diff --git a/Assets/Scripts/PathFinding/NavMeshComponents/Editor/NavMeshModifierVolumeEditor.cs.meta b/Assets/Scripts/PathFinding/NavMeshComponents/Editor/NavMeshModifierVolumeEditor.cs.meta new file mode 100644 index 0000000..c8212e5 --- /dev/null +++ b/Assets/Scripts/PathFinding/NavMeshComponents/Editor/NavMeshModifierVolumeEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5999826ec8e37f74a80d7f6ee2700a3a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/PathFinding/NavMeshComponents/Editor/NavMeshSurfaceEditor.cs b/Assets/Scripts/PathFinding/NavMeshComponents/Editor/NavMeshSurfaceEditor.cs new file mode 100644 index 0000000..f25b216 --- /dev/null +++ b/Assets/Scripts/PathFinding/NavMeshComponents/Editor/NavMeshSurfaceEditor.cs @@ -0,0 +1,399 @@ +#define NAVMESHCOMPONENTS_SHOW_NAVMESHDATA_REF + +using System.Linq; +using UnityEditor.IMGUI.Controls; +using UnityEditorInternal; +using UnityEngine.AI; +using UnityEngine; +using UnityEditor; +using UnityEditor.AI; +using NavMeshPlus.Components; + +namespace NavMeshPlus.Editors.Components +{ + [CanEditMultipleObjects] + [CustomEditor(typeof(NavMeshSurface))] + class NavMeshSurfaceEditor : Editor + { + SerializedProperty m_AgentTypeID; + SerializedProperty m_BuildHeightMesh; + SerializedProperty m_Center; + SerializedProperty m_CollectObjects; + SerializedProperty m_DefaultArea; + SerializedProperty m_LayerMask; + SerializedProperty m_OverrideTileSize; + SerializedProperty m_OverrideVoxelSize; + SerializedProperty m_Size; + SerializedProperty m_TileSize; + SerializedProperty m_UseGeometry; + SerializedProperty m_VoxelSize; + +#if NAVMESHCOMPONENTS_SHOW_NAVMESHDATA_REF + SerializedProperty m_NavMeshData; +#endif + class Styles + { + public readonly GUIContent m_LayerMask = new GUIContent("Include Layers"); + + public readonly GUIContent m_ShowInputGeom = new GUIContent("Show Input Geom"); + public readonly GUIContent m_ShowVoxels = new GUIContent("Show Voxels"); + public readonly GUIContent m_ShowRegions = new GUIContent("Show Regions"); + public readonly GUIContent m_ShowRawContours = new GUIContent("Show Raw Contours"); + public readonly GUIContent m_ShowContours = new GUIContent("Show Contours"); + public readonly GUIContent m_ShowPolyMesh = new GUIContent("Show Poly Mesh"); + public readonly GUIContent m_ShowPolyMeshDetail = new GUIContent("Show Poly Mesh Detail"); + } + + static Styles s_Styles; + + static bool s_ShowDebugOptions; + + static Color s_HandleColor = new Color(127f, 214f, 244f, 100f) / 255; + static Color s_HandleColorSelected = new Color(127f, 214f, 244f, 210f) / 255; + static Color s_HandleColorDisabled = new Color(127f * 0.75f, 214f * 0.75f, 244f * 0.75f, 100f) / 255; + + BoxBoundsHandle m_BoundsHandle = new BoxBoundsHandle(); + + bool editingCollider + { + get { return EditMode.editMode == EditMode.SceneViewEditMode.Collider && EditMode.IsOwner(this); } + } + + void OnEnable() + { + m_AgentTypeID = serializedObject.FindProperty("m_AgentTypeID"); + m_BuildHeightMesh = serializedObject.FindProperty("m_BuildHeightMesh"); + m_Center = serializedObject.FindProperty("m_Center"); + m_CollectObjects = serializedObject.FindProperty("m_CollectObjects"); + m_DefaultArea = serializedObject.FindProperty("m_DefaultArea"); + m_LayerMask = serializedObject.FindProperty("m_LayerMask"); + m_OverrideTileSize = serializedObject.FindProperty("m_OverrideTileSize"); + m_OverrideVoxelSize = serializedObject.FindProperty("m_OverrideVoxelSize"); + m_Size = serializedObject.FindProperty("m_Size"); + m_TileSize = serializedObject.FindProperty("m_TileSize"); + m_UseGeometry = serializedObject.FindProperty("m_UseGeometry"); + m_VoxelSize = serializedObject.FindProperty("m_VoxelSize"); + +#if NAVMESHCOMPONENTS_SHOW_NAVMESHDATA_REF + m_NavMeshData = serializedObject.FindProperty("m_NavMeshData"); +#endif + NavMeshVisualizationSettings.showNavigation++; + } + + void OnDisable() + { + NavMeshVisualizationSettings.showNavigation--; + } + + Bounds GetBounds() + { + var navSurface = (NavMeshSurface)target; + return new Bounds(navSurface.transform.position, navSurface.size); + } + + public override void OnInspectorGUI() + { + if (s_Styles == null) + s_Styles = new Styles(); + + serializedObject.Update(); + + var bs = NavMesh.GetSettingsByID(m_AgentTypeID.intValue); + + if (bs.agentTypeID != -1) + { + // Draw image + const float diagramHeight = 80.0f; + Rect agentDiagramRect = EditorGUILayout.GetControlRect(false, diagramHeight); + NavMeshEditorHelpers.DrawAgentDiagram(agentDiagramRect, bs.agentRadius, bs.agentHeight, bs.agentClimb, bs.agentSlope); + } + + EditorGUILayout.PropertyField(m_AgentTypeID); + EditorGUILayout.Space(); + + EditorGUILayout.PropertyField(m_CollectObjects); + if ((CollectObjects)m_CollectObjects.enumValueIndex == CollectObjects.Volume) + { + EditorGUI.indentLevel++; + + EditMode.DoEditModeInspectorModeButton(EditMode.SceneViewEditMode.Collider, "Edit Volume", + EditorGUIUtility.IconContent("EditCollider"), GetBounds, this); + EditorGUILayout.PropertyField(m_Size); + EditorGUILayout.PropertyField(m_Center); + + EditorGUI.indentLevel--; + } + else + { + if (editingCollider) + EditMode.QuitEditMode(); + } + + EditorGUILayout.PropertyField(m_LayerMask, s_Styles.m_LayerMask); + EditorGUILayout.PropertyField(m_UseGeometry); + + EditorGUILayout.Space(); + + m_OverrideVoxelSize.isExpanded = EditorGUILayout.Foldout(m_OverrideVoxelSize.isExpanded, "Advanced"); + if (m_OverrideVoxelSize.isExpanded) + { + EditorGUI.indentLevel++; + + EditorGUILayout.PropertyField(m_DefaultArea); + + // Override voxel size. + EditorGUILayout.PropertyField(m_OverrideVoxelSize); + + using (new EditorGUI.DisabledScope(!m_OverrideVoxelSize.boolValue || m_OverrideVoxelSize.hasMultipleDifferentValues)) + { + EditorGUI.indentLevel++; + + EditorGUILayout.PropertyField(m_VoxelSize); + + if (!m_OverrideVoxelSize.hasMultipleDifferentValues) + { + if (!m_AgentTypeID.hasMultipleDifferentValues) + { + float voxelsPerRadius = m_VoxelSize.floatValue > 0.0f ? (bs.agentRadius / m_VoxelSize.floatValue) : 0.0f; + EditorGUILayout.LabelField(" ", voxelsPerRadius.ToString("0.00") + " voxels per agent radius", EditorStyles.miniLabel); + } + if (m_OverrideVoxelSize.boolValue) + EditorGUILayout.HelpBox("Voxel size controls how accurately the navigation mesh is generated from the level geometry. A good voxel size is 2-4 voxels per agent radius. Making voxel size smaller will increase build time.", MessageType.None); + } + EditorGUI.indentLevel--; + } + + // Override tile size + EditorGUILayout.PropertyField(m_OverrideTileSize); + + using (new EditorGUI.DisabledScope(!m_OverrideTileSize.boolValue || m_OverrideTileSize.hasMultipleDifferentValues)) + { + EditorGUI.indentLevel++; + + EditorGUILayout.PropertyField(m_TileSize); + + if (!m_TileSize.hasMultipleDifferentValues && !m_VoxelSize.hasMultipleDifferentValues) + { + float tileWorldSize = m_TileSize.intValue * m_VoxelSize.floatValue; + EditorGUILayout.LabelField(" ", tileWorldSize.ToString("0.00") + " world units", EditorStyles.miniLabel); + } + + if (!m_OverrideTileSize.hasMultipleDifferentValues) + { + if (m_OverrideTileSize.boolValue) + EditorGUILayout.HelpBox("Tile size controls the how local the changes to the world are (rebuild or carve). Small tile size allows more local changes, while potentially generating more data overall.", MessageType.None); + } + EditorGUI.indentLevel--; + } + + + // Height mesh + using (new EditorGUI.DisabledScope(true)) + { + EditorGUILayout.PropertyField(m_BuildHeightMesh); + } + + EditorGUILayout.Space(); + EditorGUI.indentLevel--; + } + + EditorGUILayout.Space(); + + serializedObject.ApplyModifiedProperties(); + + var hadError = false; + var multipleTargets = targets.Length > 1; + foreach (NavMeshSurface navSurface in targets) + { + var settings = navSurface.GetBuildSettings(); + // Calculating bounds is potentially expensive when unbounded - so here we just use the center/size. + // It means the validation is not checking vertical voxel limit correctly when the surface is set to something else than "in volume". + var bounds = new Bounds(Vector3.zero, Vector3.zero); + if (navSurface.collectObjects == CollectObjects.Volume) + { + bounds = new Bounds(navSurface.center, navSurface.size); + } + + var errors = settings.ValidationReport(bounds); + if (errors.Length > 0) + { + if (multipleTargets) + EditorGUILayout.LabelField(navSurface.name); + foreach (var err in errors) + { + EditorGUILayout.HelpBox(err, MessageType.Warning); + } + GUILayout.BeginHorizontal(); + GUILayout.Space(EditorGUIUtility.labelWidth); + if (GUILayout.Button("Open Agent Settings...", EditorStyles.miniButton)) + NavMeshEditorHelpers.OpenAgentSettings(navSurface.agentTypeID); + GUILayout.EndHorizontal(); + hadError = true; + } + } + + if (hadError) + EditorGUILayout.Space(); + +#if NAVMESHCOMPONENTS_SHOW_NAVMESHDATA_REF + var nmdRect = EditorGUILayout.GetControlRect(true, EditorGUIUtility.singleLineHeight); + + EditorGUI.BeginProperty(nmdRect, GUIContent.none, m_NavMeshData); + var rectLabel = EditorGUI.PrefixLabel(nmdRect, GUIUtility.GetControlID(FocusType.Passive), new GUIContent(m_NavMeshData.displayName)); + EditorGUI.EndProperty(); + + using (new EditorGUI.DisabledScope(true)) + { + EditorGUI.BeginProperty(nmdRect, GUIContent.none, m_NavMeshData); + EditorGUI.ObjectField(rectLabel, m_NavMeshData, GUIContent.none); + EditorGUI.EndProperty(); + } +#endif + using (new EditorGUI.DisabledScope(Application.isPlaying || m_AgentTypeID.intValue == -1)) + { + GUILayout.BeginHorizontal(); + GUILayout.Space(EditorGUIUtility.labelWidth); + if (GUILayout.Button("Clear")) + { + NavMeshAssetManager.instance.ClearSurfaces(targets); + SceneView.RepaintAll(); + } + + if (GUILayout.Button("Bake")) + { + NavMeshAssetManager.instance.StartBakingSurfaces(targets); + } + + GUILayout.EndHorizontal(); + } + + // Show progress for the selected targets + var bakeOperations = NavMeshAssetManager.instance.GetBakeOperations(); + for (int i = bakeOperations.Count - 1; i >= 0; --i) + { + if (!targets.Contains(bakeOperations[i].surface)) + continue; + + var oper = bakeOperations[i].bakeOperation; + if (oper == null) + continue; + + var p = oper.progress; + if (oper.isDone) + { + SceneView.RepaintAll(); + continue; + } + + GUILayout.BeginHorizontal(); + + if (GUILayout.Button("Cancel", EditorStyles.miniButton)) + { + var bakeData = bakeOperations[i].bakeData; + UnityEngine.AI.NavMeshBuilder.Cancel(bakeData); + bakeOperations.RemoveAt(i); + } + + EditorGUI.ProgressBar(EditorGUILayout.GetControlRect(), p, "Baking: " + (int)(100 * p) + "%"); + if (p <= 1) + Repaint(); + + GUILayout.EndHorizontal(); + } + } + + [DrawGizmo(GizmoType.Selected | GizmoType.Active | GizmoType.Pickable)] + static void RenderBoxGizmoSelected(NavMeshSurface navSurface, GizmoType gizmoType) + { + RenderBoxGizmo(navSurface, gizmoType, true); + } + + [DrawGizmo(GizmoType.NotInSelectionHierarchy | GizmoType.Pickable)] + static void RenderBoxGizmoNotSelected(NavMeshSurface navSurface, GizmoType gizmoType) + { + if (NavMeshVisualizationSettings.showNavigation > 0) + RenderBoxGizmo(navSurface, gizmoType, false); + else + Gizmos.DrawIcon(navSurface.transform.position, "NavMeshSurface Icon", true); + } + + static void RenderBoxGizmo(NavMeshSurface navSurface, GizmoType gizmoType, bool selected) + { + var color = selected ? s_HandleColorSelected : s_HandleColor; + if (!navSurface.enabled) + color = s_HandleColorDisabled; + + var oldColor = Gizmos.color; + var oldMatrix = Gizmos.matrix; + + // Use the unscaled matrix for the NavMeshSurface + var localToWorld = Matrix4x4.TRS(navSurface.transform.position, navSurface.transform.rotation, Vector3.one); + Gizmos.matrix = localToWorld; + + if (navSurface.collectObjects == CollectObjects.Volume) + { + Gizmos.color = color; + Gizmos.DrawWireCube(navSurface.center, navSurface.size); + + if (selected && navSurface.enabled) + { + var colorTrans = new Color(color.r * 0.75f, color.g * 0.75f, color.b * 0.75f, color.a * 0.15f); + Gizmos.color = colorTrans; + Gizmos.DrawCube(navSurface.center, navSurface.size); + } + } + else + { + if (navSurface.navMeshData != null) + { + var bounds = navSurface.navMeshData.sourceBounds; + Gizmos.color = Color.grey; + Gizmos.DrawWireCube(bounds.center, bounds.size); + } + } + + Gizmos.matrix = oldMatrix; + Gizmos.color = oldColor; + + Gizmos.DrawIcon(navSurface.transform.position, "NavMeshSurface Icon", true); + } + + void OnSceneGUI() + { + if (!editingCollider) + return; + + var navSurface = (NavMeshSurface)target; + var color = navSurface.enabled ? s_HandleColor : s_HandleColorDisabled; + var localToWorld = Matrix4x4.TRS(navSurface.transform.position, navSurface.transform.rotation, Vector3.one); + using (new Handles.DrawingScope(color, localToWorld)) + { + m_BoundsHandle.center = navSurface.center; + m_BoundsHandle.size = navSurface.size; + + EditorGUI.BeginChangeCheck(); + m_BoundsHandle.DrawHandle(); + if (EditorGUI.EndChangeCheck()) + { + Undo.RecordObject(navSurface, "Modified NavMesh Surface"); + Vector3 center = m_BoundsHandle.center; + Vector3 size = m_BoundsHandle.size; + navSurface.center = center; + navSurface.size = size; + EditorUtility.SetDirty(target); + } + } + } + + [MenuItem("GameObject/Navigation/NavMesh Surface", false, 2000)] + public static void CreateNavMeshSurface(MenuCommand menuCommand) + { + var parent = menuCommand.context as GameObject; + var go = NavMeshComponentsGUIUtility.CreateAndSelectGameObject("NavMesh Surface", parent); + go.AddComponent(); + var view = SceneView.lastActiveSceneView; + if (view != null) + view.MoveToView(go.transform); + } + } +} diff --git a/Assets/Scripts/PathFinding/NavMeshComponents/Editor/NavMeshSurfaceEditor.cs.meta b/Assets/Scripts/PathFinding/NavMeshComponents/Editor/NavMeshSurfaceEditor.cs.meta new file mode 100644 index 0000000..d3e5f2e --- /dev/null +++ b/Assets/Scripts/PathFinding/NavMeshComponents/Editor/NavMeshSurfaceEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3a7b2ae8284a9b14abd6d688cc877cef +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/PathFinding/NavMeshComponents/Editor/RootSources2dEditor.cs b/Assets/Scripts/PathFinding/NavMeshComponents/Editor/RootSources2dEditor.cs new file mode 100644 index 0000000..5816cb4 --- /dev/null +++ b/Assets/Scripts/PathFinding/NavMeshComponents/Editor/RootSources2dEditor.cs @@ -0,0 +1,39 @@ +using UnityEngine.AI; +using UnityEngine; +using UnityEditor; +using NavMeshPlus.Extensions; +using NavMeshPlus.Components; + +namespace NavMeshPlus.Editors.Extensions +{ + [CanEditMultipleObjects] + [CustomEditor(typeof(RootSources2d))] + internal class RootSources2dEditor: Editor + { + SerializedProperty _rootSources; + void OnEnable() + { + _rootSources = serializedObject.FindProperty("_rootSources"); + } + + public override void OnInspectorGUI() + { + serializedObject.Update(); + + var surf = target as RootSources2d; + EditorGUILayout.HelpBox("Add GameObjects to create NavMesh form it and it's ancestors", MessageType.Info); + + if (surf.NavMeshSurfaceOwner.collectObjects != CollectObjects.Children) + { + EditorGUILayout.Space(); + EditorGUILayout.HelpBox("Root Sources are only suitable for 'CollectObjects - Children'", MessageType.Info); + EditorGUILayout.Space(); + + } + EditorGUILayout.PropertyField(_rootSources); + + serializedObject.ApplyModifiedProperties(); + } + } + +} diff --git a/Assets/Scripts/PathFinding/NavMeshComponents/Editor/RootSources2dEditor.cs.meta b/Assets/Scripts/PathFinding/NavMeshComponents/Editor/RootSources2dEditor.cs.meta new file mode 100644 index 0000000..640fc84 --- /dev/null +++ b/Assets/Scripts/PathFinding/NavMeshComponents/Editor/RootSources2dEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7e3d768af6ee1774cb39815bd8e5b221 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/PathFinding/NavMeshComponents/Scripts.meta b/Assets/Scripts/PathFinding/NavMeshComponents/Scripts.meta new file mode 100644 index 0000000..6d58076 --- /dev/null +++ b/Assets/Scripts/PathFinding/NavMeshComponents/Scripts.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 29f130eb3fdf4574a8a586b2bc99f11a +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/AgentOverride2d.cs b/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/AgentOverride2d.cs new file mode 100644 index 0000000..77ec1c7 --- /dev/null +++ b/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/AgentOverride2d.cs @@ -0,0 +1,36 @@ +using UnityEngine; +using UnityEngine.AI; + +namespace NavMeshPlus.Extensions +{ + public interface IAgentOverride + { + void UpdateAgent(); + } + + public class AgentDefaultOverride : IAgentOverride + { + public void UpdateAgent() + { + } + } + public class AgentOverride2d: MonoBehaviour + { + public NavMeshAgent Agent { get; private set; } + public IAgentOverride agentOverride { get; set; } + private void Awake() + { + Agent = GetComponent(); + } + private void Start() + { + Agent.updateRotation = false; + Agent.updateUpAxis = false; + } + + private void Update() + { + agentOverride?.UpdateAgent(); + } + } +} diff --git a/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/AgentOverride2d.cs.meta b/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/AgentOverride2d.cs.meta new file mode 100644 index 0000000..5d2310f --- /dev/null +++ b/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/AgentOverride2d.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7e39f6090724e4a4a8aadeb042afa2bc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: d5b0e13ebe59cd64e9f67284457c6868, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/AgentRotate2d.cs b/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/AgentRotate2d.cs new file mode 100644 index 0000000..f1f79c0 --- /dev/null +++ b/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/AgentRotate2d.cs @@ -0,0 +1,15 @@ +using UnityEngine; + +namespace NavMeshPlus.Extensions +{ + public class AgentRotate2d: MonoBehaviour + { + private AgentOverride2d override2D; + private void Start() + { + override2D = GetComponent(); + override2D.agentOverride = new RotateAgentInstantly(override2D.Agent, override2D); + } + + } +} diff --git a/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/AgentRotate2d.cs.meta b/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/AgentRotate2d.cs.meta new file mode 100644 index 0000000..7cedfbb --- /dev/null +++ b/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/AgentRotate2d.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8550f034611a06e4f88fc261204d8a7b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: d5b0e13ebe59cd64e9f67284457c6868, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/AgentRotateSmooth2d.cs b/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/AgentRotateSmooth2d.cs new file mode 100644 index 0000000..57aeae7 --- /dev/null +++ b/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/AgentRotateSmooth2d.cs @@ -0,0 +1,16 @@ +using UnityEngine; + +namespace NavMeshPlus.Extensions +{ + class AgentRotateSmooth2d: MonoBehaviour + { + public float angularSpeed; + private AgentOverride2d override2D; + + private void Start() + { + override2D = GetComponent(); + override2D.agentOverride = new RotateAgentSmoothly(override2D.Agent, override2D, angularSpeed); + } + } +} diff --git a/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/AgentRotateSmooth2d.cs.meta b/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/AgentRotateSmooth2d.cs.meta new file mode 100644 index 0000000..ea6efda --- /dev/null +++ b/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/AgentRotateSmooth2d.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8c7f4db162bab4443818dd13bed4b1dc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: d5b0e13ebe59cd64e9f67284457c6868, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/CollectSources2d.cs b/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/CollectSources2d.cs new file mode 100644 index 0000000..1ad5fad --- /dev/null +++ b/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/CollectSources2d.cs @@ -0,0 +1,90 @@ +using NavMeshPlus.Components; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.AI; +using UnityEngine.Tilemaps; + +namespace NavMeshPlus.Extensions +{ + [ExecuteAlways] + [AddComponentMenu("Navigation/Navigation CollectSources2d", 30)] + public class CollectSources2d: NavMeshExtension + { + [SerializeField] + bool m_OverrideByGrid; + public bool overrideByGrid { get { return m_OverrideByGrid; } set { m_OverrideByGrid = value; } } + + [SerializeField] + GameObject m_UseMeshPrefab; + public GameObject useMeshPrefab { get { return m_UseMeshPrefab; } set { m_UseMeshPrefab = value; } } + + [SerializeField] + bool m_CompressBounds; + public bool compressBounds { get { return m_CompressBounds; } set { m_CompressBounds = value; } } + + [SerializeField] + Vector3 m_OverrideVector = Vector3.one; + public Vector3 overrideVector { get { return m_OverrideVector; } set { m_OverrideVector = value; } } + + public override void CalculateWorldBounds(NavMeshSurface surface, List sources, NavMeshBuilderState navNeshState) + { + if (surface.collectObjects != CollectObjects.Volume) + { + navNeshState.worldBounds.Encapsulate(CalculateGridWorldBounds(surface, navNeshState.worldToLocal, navNeshState.worldBounds)); + } + } + + private static Bounds CalculateGridWorldBounds(NavMeshSurface surface, Matrix4x4 worldToLocal, Bounds bounds) + { + var grid = FindObjectOfType(); + var tilemaps = grid?.GetComponentsInChildren(); + if (tilemaps == null || tilemaps.Length < 1) + { + return bounds; + } + foreach (var tilemap in tilemaps) + { + var lbounds = NavMeshSurface.GetWorldBounds(worldToLocal * tilemap.transform.localToWorldMatrix, tilemap.localBounds); + bounds.Encapsulate(lbounds); + if (!surface.hideEditorLogs) + { + Debug.Log($"From Local Bounds [{tilemap.name}]: {tilemap.localBounds}"); + Debug.Log($"To World Bounds: {bounds}"); + } + } + return bounds; + } + + public override void CollectSources(NavMeshSurface surface, List sources, NavMeshBuilderState navNeshState) + { + if (!surface.hideEditorLogs) + { + if (!Mathf.Approximately(transform.eulerAngles.x, 270f)) + { + Debug.LogWarning("NavMeshSurface is not rotated respectively to (x-90;y0;z0). Apply rotation unless intended."); + } + if (Application.isPlaying) + { + if (surface.useGeometry == NavMeshCollectGeometry.PhysicsColliders && Time.frameCount <= 1) + { + Debug.LogWarning("Use Geometry - Physics Colliders option in NavMeshSurface may cause inaccurate mesh bake if executed before Physics update."); + } + } + } + var builder = navNeshState.GetExtraState(); + builder.defaultArea = surface.defaultArea; + builder.layerMask = surface.layerMask; + builder.agentID = surface.agentTypeID; + builder.useMeshPrefab = useMeshPrefab; + builder.overrideByGrid = overrideByGrid; + builder.compressBounds = compressBounds; + builder.overrideVector = overrideVector; + builder.CollectGeometry = surface.useGeometry; + builder.CollectObjects = (CollectObjects)(int)surface.collectObjects; + builder.parent = surface.gameObject; + builder.hideEditorLogs = surface.hideEditorLogs; + builder.SetRoot(navNeshState.roots); + NavMeshBuilder2d.CollectSources(sources, builder); + } + } +} diff --git a/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/CollectSources2d.cs.meta b/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/CollectSources2d.cs.meta new file mode 100644 index 0000000..89f1119 --- /dev/null +++ b/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/CollectSources2d.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 70bd44a44cd62c64fbfc1eea95b24880 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: d5b0e13ebe59cd64e9f67284457c6868, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/CollectSourcesCache2d.cs b/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/CollectSourcesCache2d.cs new file mode 100644 index 0000000..318a420 --- /dev/null +++ b/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/CollectSourcesCache2d.cs @@ -0,0 +1,115 @@ +using NavMeshPlus.Components; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.AI; + +namespace NavMeshPlus.Extensions +{ + [ExecuteAlways] + [AddComponentMenu("Navigation/Navigation CacheSources2d", 30)] + public class CollectSourcesCache2d : NavMeshExtension + { + List _sources; + Dictionary _lookup; + private Bounds _sourcesBounds; + public bool IsDirty { get; protected set; } + + private NavMeshBuilder2dState _state; + + public int SourcesCount => _sources.Count; + public int CahcheCount => _lookup.Count; + + public List Cache { get => _sources; } + + protected override void Awake() + { + _lookup = new Dictionary(); + _sources = new List(); + IsDirty = false; + Order = -1000; + _sourcesBounds = new Bounds(); + base.Awake(); + } + protected override void OnDestroy() + { + _state?.Dispose(); + base.OnDestroy(); + } + + public bool AddSource(GameObject gameObject, NavMeshBuildSource source) + { + var res = _lookup.ContainsKey(gameObject); + if (res) + { + return UpdateSource(gameObject); + } + _sources.Add(source); + _lookup.Add(gameObject, source); + IsDirty = true; + return true; + } + public bool UpdateSource(GameObject gameObject) + { + var res = _lookup.ContainsKey(gameObject); + if(res) + { + IsDirty = true; + var source = _lookup[gameObject]; + var idx = _sources.IndexOf(source); + if (idx >= 0) + { + source.transform = Matrix4x4.TRS(gameObject.transform.position, gameObject.transform.rotation, gameObject.transform.lossyScale); + _sources[idx] = source; + _lookup[gameObject] = source; + } + } + return res; + } + + public bool RemoveSource(GameObject gameObject) + { + var res = _lookup.ContainsKey(gameObject); + if (res) + { + IsDirty = true; + var source = _lookup[gameObject]; + _lookup.Remove(gameObject); + _sources.Remove(source); + } + return res; + } + + public AsyncOperation UpdateNavMesh(NavMeshData data) + { + IsDirty = false; + return NavMeshBuilder.UpdateNavMeshDataAsync(data, NavMeshSurfaceOwner.GetBuildSettings(), _sources, _sourcesBounds); + } + public AsyncOperation UpdateNavMesh() + { + return UpdateNavMesh(NavMeshSurfaceOwner.navMeshData); + } + public override void CollectSources(NavMeshSurface surface, List sources, NavMeshBuilderState navMeshState) + { + _lookup.Clear(); + IsDirty = false; + _state?.Dispose(); + _state = navMeshState.GetExtraState(false); + _state.lookupCallback = LookupCallback; + } + + private void LookupCallback(UnityEngine.Object component, NavMeshBuildSource source) + { + if (component == null) + { + return; + } + _lookup.Add(component, source); + } + + public override void PostCollectSources(NavMeshSurface surface, List sources, NavMeshBuilderState navNeshState) + { + _sourcesBounds = navNeshState.worldBounds; + _sources = sources; + } + } +} diff --git a/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/CollectSourcesCache2d.cs.meta b/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/CollectSourcesCache2d.cs.meta new file mode 100644 index 0000000..852a745 --- /dev/null +++ b/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/CollectSourcesCache2d.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5492b7ed96378624cbcd72212fce093d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: d5b0e13ebe59cd64e9f67284457c6868, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/NavMeshAgentAttribute.cs b/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/NavMeshAgentAttribute.cs new file mode 100644 index 0000000..038e05b --- /dev/null +++ b/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/NavMeshAgentAttribute.cs @@ -0,0 +1,12 @@ +using UnityEngine; + +//*********************************************************************************** +// Contributed by author jl-randazzo github.com/jl-randazzo +//*********************************************************************************** +namespace NavMeshPlus.Extensions +{ + [System.Serializable] + public class NavMeshAgentAttribute : PropertyAttribute + { + } +} diff --git a/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/NavMeshAgentAttribute.cs.meta b/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/NavMeshAgentAttribute.cs.meta new file mode 100644 index 0000000..2a710df --- /dev/null +++ b/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/NavMeshAgentAttribute.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7f3fe2b336bf34749a146f6bf7d462d0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/NavMeshAreaAttribute.cs b/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/NavMeshAreaAttribute.cs new file mode 100644 index 0000000..5868703 --- /dev/null +++ b/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/NavMeshAreaAttribute.cs @@ -0,0 +1,13 @@ +using UnityEngine; + +//*********************************************************************************** +// Contributed by author jl-randazzo github.com/jl-randazzo +//*********************************************************************************** +namespace NavMeshPlus.Extensions +{ + [System.Serializable] + // See also NavMeshAreaAttributePropertyDrawer + public class NavMeshAreaAttribute : PropertyAttribute + { + } +} diff --git a/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/NavMeshAreaAttribute.cs.meta b/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/NavMeshAreaAttribute.cs.meta new file mode 100644 index 0000000..4446803 --- /dev/null +++ b/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/NavMeshAreaAttribute.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ed6d9f7764b9451f97a6658cdc760e00 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: d5b0e13ebe59cd64e9f67284457c6868, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/NavMeshBuilder2d.cs b/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/NavMeshBuilder2d.cs new file mode 100644 index 0000000..a7e4710 --- /dev/null +++ b/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/NavMeshBuilder2d.cs @@ -0,0 +1,393 @@ +using NavMeshPlus.Components; +using System; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.AI; +using UnityEngine.SceneManagement; +using UnityEngine.Tilemaps; +using Object = UnityEngine.Object; + +namespace NavMeshPlus.Extensions +{ + class NavMeshBuilder2dState: IDisposable + { + public Dictionary spriteMeshMap; + public Dictionary coliderMeshMap; + public Action lookupCallback; + public int defaultArea; + public int layerMask; + public int agentID; + public bool overrideByGrid; + public GameObject useMeshPrefab; + public bool compressBounds; + public Vector3 overrideVector; + public NavMeshCollectGeometry CollectGeometry; + public CollectObjects CollectObjects; + public GameObject parent; + public bool hideEditorLogs; + + protected IEnumerable _root; + private bool _disposed; + + public IEnumerable Root => _root ?? GetRoot(); + + public NavMeshBuilder2dState() + { + spriteMeshMap = new Dictionary(); + coliderMeshMap = new Dictionary(); + _root = null; + } + + public Mesh GetMesh(Sprite sprite) + { + Mesh mesh; + if (spriteMeshMap.ContainsKey(sprite)) + { + mesh = spriteMeshMap[sprite]; + } + else + { + mesh = new Mesh(); + NavMeshBuilder2d.sprite2mesh(sprite, mesh); + spriteMeshMap.Add(sprite, mesh); + } + return mesh; + } + + public Mesh GetMesh(Collider2D collider) + { +#if UNITY_2019_3_OR_NEWER + Mesh mesh; + uint hash = collider.GetShapeHash(); + if (coliderMeshMap.ContainsKey(hash)) + { + mesh = coliderMeshMap[hash]; + } + else + { + mesh = collider.CreateMesh(false, false); + coliderMeshMap.Add(hash, mesh); + } + return mesh; +#else + throw new InvalidOperationException("PhysicsColliders supported in Unity 2019.3 and higher."); +#endif + } + public void SetRoot(IEnumerable root) + { + _root = root; + } + public IEnumerable GetRoot() + { + switch (CollectObjects) + { + case CollectObjects.Children: return new[] { parent }; + case CollectObjects.Volume: + case CollectObjects.All: + default: + { + var list = new List(); + var roots = new List(); + for (int i = 0; i < SceneManager.sceneCount; ++i) + { + var s = SceneManager.GetSceneAt(i); + if (!s.isLoaded) continue; + s.GetRootGameObjects(list); + roots.AddRange(list); + } + return roots; + } + } + } + + protected virtual void Dispose(bool disposing) + { + if (_disposed) + { + return; + } + + if (disposing) + { + // TODO: dispose managed state (managed objects). + foreach (var item in spriteMeshMap) + { +#if UNITY_EDITOR + Object.DestroyImmediate(item.Value); +#else + Object.Destroy(item.Value); +#endif + } + foreach (var item in coliderMeshMap) + { +#if UNITY_EDITOR + Object.DestroyImmediate(item.Value); +#else + Object.Destroy(item.Value); +#endif + } + spriteMeshMap.Clear(); + coliderMeshMap.Clear(); + } + + // TODO: free unmanaged resources (unmanaged objects) and override a finalizer below. + // TODO: set large fields to null. + + _disposed = true; + } + + public void Dispose() + { + // Dispose of unmanaged resources. + Dispose(true); + // Suppress finalization. + GC.SuppressFinalize(this); + } + } + + class NavMeshBuilder2d + { + public static void CollectSources(List sources, NavMeshBuilder2dState builder) + { + foreach (var it in builder.Root) + { + CollectSources(it, sources, builder); + } + if (!builder.hideEditorLogs) Debug.Log("Sources " + sources.Count); + } + + public static void CollectSources(GameObject root, List sources, NavMeshBuilder2dState builder) + { + foreach (var modifier in root.GetComponentsInChildren()) + { + if (((0x1 << modifier.gameObject.layer) & builder.layerMask) == 0) + { + continue; + } + if (!modifier.AffectsAgentType(builder.agentID)) + { + continue; + } + int area = builder.defaultArea; + //if it is walkable + if (builder.defaultArea != 1 && !modifier.ignoreFromBuild) + { + AddDefaultWalkableTilemap(sources, builder, modifier); + } + + if (modifier.overrideArea) + { + area = modifier.area; + } + if (!modifier.ignoreFromBuild) + { + CollectSources(sources, builder, modifier, area); + } + } + } + + public static void CollectSources(List sources, NavMeshBuilder2dState builder, NavMeshModifier modifier, int area) + { + if (builder.CollectGeometry == NavMeshCollectGeometry.PhysicsColliders) + { + var collider = modifier.GetComponent(); + if (collider != null) + { + CollectSources(sources, collider, area, builder); + } + } + else + { + var tilemap = modifier.GetComponent(); + if (tilemap != null) + { + CollectTileSources(sources, tilemap, area, builder); + } + var sprite = modifier.GetComponent(); + if (sprite != null) + { + CollectSources(sources, sprite, area, builder); + } + } + } + + private static void AddDefaultWalkableTilemap(List sources, NavMeshBuilder2dState builder, NavMeshModifier modifier) + { + var tilemap = modifier.GetComponent(); + if (tilemap != null) + { + if (builder.compressBounds) + { + tilemap.CompressBounds(); + } + + if (!builder.hideEditorLogs) Debug.Log($"Walkable Bounds [{tilemap.name}]: {tilemap.localBounds}"); + var box = BoxBoundSource(NavMeshSurface.GetWorldBounds(tilemap.transform.localToWorldMatrix, tilemap.localBounds)); + box.area = builder.defaultArea; + sources.Add(box); + } + } + + public static void CollectSources(List sources, SpriteRenderer spriteRenderer, int area, NavMeshBuilder2dState builder) + { + if (spriteRenderer == null || spriteRenderer.sprite == null) + { + return; + } + Mesh mesh; + mesh = builder.GetMesh(spriteRenderer.sprite); + if (mesh == null) + { + if (!builder.hideEditorLogs) Debug.Log($"{spriteRenderer.name} mesh is null"); + return; + } + var src = new NavMeshBuildSource(); + src.shape = NavMeshBuildSourceShape.Mesh; + src.component = spriteRenderer; + src.area = area; + src.transform = Matrix4x4.TRS(Vector3.Scale(spriteRenderer.transform.position, builder.overrideVector), spriteRenderer.transform.rotation, spriteRenderer.transform.lossyScale); + src.sourceObject = mesh; + sources.Add(src); + + builder.lookupCallback?.Invoke(spriteRenderer.gameObject, src); + } + + public static void CollectSources(List sources, Collider2D collider, int area, NavMeshBuilder2dState builder) + { + if (collider.usedByComposite) + { + collider = collider.GetComponent(); + } + + Mesh mesh; + mesh = builder.GetMesh(collider); + if (mesh == null) + { + if (!builder.hideEditorLogs) Debug.Log($"{collider.name} mesh is null"); + return; + } + + var src = new NavMeshBuildSource(); + src.shape = NavMeshBuildSourceShape.Mesh; + src.area = area; + src.component = collider; + src.sourceObject = mesh; + if (collider.attachedRigidbody) + { + src.transform = Matrix4x4.TRS(Vector3.Scale(collider.attachedRigidbody.transform.position, builder.overrideVector), collider.attachedRigidbody.transform.rotation, Vector3.one); + } + else + { + src.transform = Matrix4x4.identity; + } + + sources.Add(src); + + builder.lookupCallback?.Invoke(collider.gameObject, src); + } + + public static void CollectTileSources(List sources, Tilemap tilemap, int area, NavMeshBuilder2dState builder) + { + var bound = tilemap.cellBounds; + + var modifierTilemap = tilemap.GetComponent(); + + var vec3int = new Vector3Int(0, 0, 0); + + var size = new Vector3(tilemap.layoutGrid.cellSize.x, tilemap.layoutGrid.cellSize.y, 0); + Mesh sharedMesh = null; + Quaternion rot = default; + + if (builder.useMeshPrefab != null) + { + sharedMesh = builder.useMeshPrefab.GetComponent().sharedMesh; + size = builder.useMeshPrefab.transform.localScale; + rot = builder.useMeshPrefab.transform.rotation; + } + for (int i = bound.xMin; i < bound.xMax; i++) + { + for (int j = bound.yMin; j < bound.yMax; j++) + { + var src = new NavMeshBuildSource(); + src.area = area; + + vec3int.x = i; + vec3int.y = j; + if (!tilemap.HasTile(vec3int)) + { + continue; + } + + CollectTile(tilemap, builder, vec3int, size, sharedMesh, rot, ref src); + if (modifierTilemap && modifierTilemap.TryGetTileModifier(vec3int, tilemap, out NavMeshModifierTilemap.TileModifier tileModifier)) + { + src.area = tileModifier.overrideArea ? tileModifier.area : area; + } + sources.Add(src); + + builder.lookupCallback?.Invoke(tilemap.GetInstantiatedObject(vec3int), src); + } + } + } + + private static void CollectTile(Tilemap tilemap, NavMeshBuilder2dState builder, Vector3Int vec3int, Vector3 size, Mesh sharedMesh, Quaternion rot, ref NavMeshBuildSource src) + { + if (!builder.overrideByGrid && tilemap.GetColliderType(vec3int) == Tile.ColliderType.Sprite) + { + var sprite = tilemap.GetSprite(vec3int); + if (sprite != null) + { + Mesh mesh = builder.GetMesh(sprite); + src.component = tilemap; + src.transform = GetCellTransformMatrix(tilemap, builder.overrideVector, vec3int); + src.shape = NavMeshBuildSourceShape.Mesh; + src.sourceObject = mesh; + } + } + else if (builder.useMeshPrefab != null || (builder.overrideByGrid && builder.useMeshPrefab != null)) + { + src.transform = Matrix4x4.TRS(Vector3.Scale(tilemap.GetCellCenterWorld(vec3int), builder.overrideVector), rot, size); + src.shape = NavMeshBuildSourceShape.Mesh; + src.sourceObject = sharedMesh; + } + else //default to box + { + src.transform = GetCellTransformMatrix(tilemap, builder.overrideVector, vec3int); + src.shape = NavMeshBuildSourceShape.Box; + src.size = size; + } + } + + public static Matrix4x4 GetCellTransformMatrix(Tilemap tilemap, Vector3 scale, Vector3Int vec3int) + { + return Matrix4x4.TRS(Vector3.Scale(tilemap.GetCellCenterWorld(vec3int), scale) - tilemap.layoutGrid.cellGap, tilemap.transform.rotation, tilemap.transform.lossyScale) * tilemap.orientationMatrix * tilemap.GetTransformMatrix(vec3int); + } + + internal static void sprite2mesh(Sprite sprite, Mesh mesh) + { + Vector3[] vert = new Vector3[sprite.vertices.Length]; + for (int i = 0; i < sprite.vertices.Length; i++) + { + vert[i] = new Vector3(sprite.vertices[i].x, sprite.vertices[i].y, 0); + } + mesh.vertices = vert; + mesh.uv = sprite.uv; + int[] tri = new int[sprite.triangles.Length]; + for (int i = 0; i < sprite.triangles.Length; i++) + { + tri[i] = sprite.triangles[i]; + } + mesh.triangles = tri; + } + + static private NavMeshBuildSource BoxBoundSource(Bounds localBounds) + { + var src = new NavMeshBuildSource(); + src.transform = Matrix4x4.Translate(localBounds.center); + src.shape = NavMeshBuildSourceShape.Box; + src.size = localBounds.size; + src.area = 0; + return src; + } + } +} diff --git a/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/NavMeshBuilder2d.cs.meta b/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/NavMeshBuilder2d.cs.meta new file mode 100644 index 0000000..5d109bb --- /dev/null +++ b/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/NavMeshBuilder2d.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fc6dd3809c1761a4e9a227c70117ed54 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: e8142b1daeea8d3419cd0ffbd7b17a37, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/NavMeshBuilderState.cs b/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/NavMeshBuilderState.cs new file mode 100644 index 0000000..be66cb8 --- /dev/null +++ b/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/NavMeshBuilderState.cs @@ -0,0 +1,109 @@ +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace NavMeshPlus.Extensions +{ + public class NavMeshBuilderState: IDisposable + { + public Matrix4x4 worldToLocal; + public Bounds worldBounds; + public IEnumerable roots; + private CompositeDisposable disposable; + private Dictionary mExtraState; + private bool _disposed; + + public T GetExtraState(bool dispose = true) where T : class, new() + { + if (mExtraState == null) + { + mExtraState = new Dictionary(); + disposable = new CompositeDisposable(); + } + if (!mExtraState.TryGetValue(typeof(T), out System.Object extra)) + { + extra = mExtraState[typeof(T)] = new T(); + if (dispose) + { + disposable.Add(extra); + } + } + + return extra as T; + } + + protected virtual void Dispose(bool disposing) + { + if (_disposed) + { + return; + } + + if (disposing) + { + // TODO: dispose managed state (managed objects). + disposable?.Dispose(); + } + + // TODO: free unmanaged resources (unmanaged objects) and override a finalizer below. + // TODO: set large fields to null. + + _disposed = true; + } + + public void Dispose() + { + // Dispose of unmanaged resources. + Dispose(true); + // Suppress finalization. + GC.SuppressFinalize(this); + } + } + partial class CompositeDisposable: IDisposable + { + private bool _disposed; + private List extraStates = new List(); + + public void Add(IDisposable dispose) + { + extraStates.Add(dispose); + } + public void Add(object dispose) + { + if(dispose is IDisposable) + { + extraStates.Add((IDisposable)dispose); + } + } + protected virtual void Dispose(bool disposing) + { + if (_disposed) + { + return; + } + + if (disposing) + { + // TODO: dispose managed state (managed objects). + foreach (var item in extraStates) + { + item?.Dispose(); + } + extraStates.Clear(); + } + + // TODO: free unmanaged resources (unmanaged objects) and override a finalizer below. + // TODO: set large fields to null. + + _disposed = true; + } + + public void Dispose() + { + // Dispose of unmanaged resources. + Dispose(true); + // Suppress finalization. + GC.SuppressFinalize(this); + } + } +} \ No newline at end of file diff --git a/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/NavMeshBuilderState.cs.meta b/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/NavMeshBuilderState.cs.meta new file mode 100644 index 0000000..32cafaf --- /dev/null +++ b/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/NavMeshBuilderState.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 710022065e740cf40bf86ccac60e3741 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: e8142b1daeea8d3419cd0ffbd7b17a37, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/NavMeshComponents.asmdef b/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/NavMeshComponents.asmdef new file mode 100644 index 0000000..9ad51a6 --- /dev/null +++ b/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/NavMeshComponents.asmdef @@ -0,0 +1,20 @@ +{ + "name": "NavMeshPlus", + "rootNamespace": "", + "references": [], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [ + { + "name": "com.unity.modules.terrain", + "expression": "0", + "define": "IS_TERRAIN_USED" + } + ], + "noEngineReferences": false +} \ No newline at end of file diff --git a/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/NavMeshComponents.asmdef.meta b/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/NavMeshComponents.asmdef.meta new file mode 100644 index 0000000..779f99b --- /dev/null +++ b/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/NavMeshComponents.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 299beb10465c46f41abeaf10478b4727 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/NavMeshExtension.cs b/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/NavMeshExtension.cs new file mode 100644 index 0000000..5459ccd --- /dev/null +++ b/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/NavMeshExtension.cs @@ -0,0 +1,58 @@ +using NavMeshPlus.Components; +using System; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.AI; + +namespace NavMeshPlus.Extensions +{ + public abstract class NavMeshExtension: MonoBehaviour + { + public int Order { get; protected set; } + public virtual void CollectSources(NavMeshSurface surface, List sources, NavMeshBuilderState navNeshState) { } + public virtual void CalculateWorldBounds(NavMeshSurface surface, List sources, NavMeshBuilderState navNeshState) { } + public virtual void PostCollectSources(NavMeshSurface surface, List sources, NavMeshBuilderState navNeshState) { } + public NavMeshSurface NavMeshSurfaceOwner + { + get + { + if (m_navMeshOwner == null) + m_navMeshOwner = GetComponent(); + return m_navMeshOwner; + } + } + NavMeshSurface m_navMeshOwner; + + protected virtual void Awake() + { + ConnectToVcam(true); + } +#if UNITY_EDITOR + [UnityEditor.Callbacks.DidReloadScripts] + static void OnScriptReload() + { + var extensions = Resources.FindObjectsOfTypeAll( + typeof(NavMeshExtension)) as NavMeshExtension[]; + foreach (var e in extensions) + e.ConnectToVcam(true); + } +#endif + protected virtual void OnEnable() { } + protected virtual void OnDestroy() + { + ConnectToVcam(false); + } + protected virtual void ConnectToVcam(bool connect) + { + if (connect && NavMeshSurfaceOwner == null) + Debug.LogError("NevMeshExtension requires a NavMeshSurface component"); + if (NavMeshSurfaceOwner != null) + { + if (connect) + NavMeshSurfaceOwner.NevMeshExtensions.Add(this, Order); + else + NavMeshSurfaceOwner.NevMeshExtensions.Remove(this); + } + } + } +} diff --git a/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/NavMeshExtension.cs.meta b/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/NavMeshExtension.cs.meta new file mode 100644 index 0000000..4194706 --- /dev/null +++ b/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/NavMeshExtension.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0528335b682da1f42901dc790b763830 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: e8142b1daeea8d3419cd0ffbd7b17a37, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/NavMeshExtensionsProvider.cs b/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/NavMeshExtensionsProvider.cs new file mode 100644 index 0000000..29de173 --- /dev/null +++ b/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/NavMeshExtensionsProvider.cs @@ -0,0 +1,57 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + +namespace NavMeshPlus.Extensions +{ + public interface INavMeshExtensionsProvider + { + int Count { get; } + NavMeshExtension this[int index] { get; } + void Add(NavMeshExtension extension, int order); + void Remove(NavMeshExtension extension); + } + internal class NavMeshExtensionMeta + { + public int order; + + public NavMeshExtensionMeta(int order, NavMeshExtension extension) + { + this.order = order; + this.extension = extension; + } + + public NavMeshExtension extension; + } + internal class NavMeshExtensionsProvider : INavMeshExtensionsProvider + { + List _extensions = new List(); + static Comparer Comparer = Comparer.Create((x, y) => x.order > y.order ? 1 : x.order < y.order ? -1 : 0); + public NavMeshExtension this[int index] => _extensions[index].extension; + + public int Count => _extensions.Count; + + public void Add(NavMeshExtension extension, int order) + { + var meta = new NavMeshExtensionMeta(order, extension); + var at = _extensions.BinarySearch(meta, Comparer); + if (at < 0) + { + _extensions.Add(meta); + _extensions.Sort(Comparer); + } + else + { + _extensions.Insert(at, meta); + } + } + + public void Remove(NavMeshExtension extension) + { + _extensions.RemoveAll(x => x.extension = extension); + } + } +} diff --git a/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/NavMeshExtensionsProvider.cs.meta b/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/NavMeshExtensionsProvider.cs.meta new file mode 100644 index 0000000..b999690 --- /dev/null +++ b/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/NavMeshExtensionsProvider.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: dc9c5ff0af7a2f247a2c64921cf9d045 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: e8142b1daeea8d3419cd0ffbd7b17a37, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/NavMeshLink.cs b/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/NavMeshLink.cs new file mode 100644 index 0000000..56ecc93 --- /dev/null +++ b/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/NavMeshLink.cs @@ -0,0 +1,175 @@ +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.AI; +using NavMeshPlus.Extensions; + +namespace NavMeshPlus.Components +{ + [ExecuteInEditMode] + [DefaultExecutionOrder(-101)] + [AddComponentMenu("Navigation/Navigation Link", 33)] + [HelpURL("https://github.com/Unity-Technologies/NavMeshPlus#documentation-draft")] + public class NavMeshLink : MonoBehaviour + { + [SerializeField, NavMeshAgent] + int m_AgentTypeID; + public int agentTypeID { get { return m_AgentTypeID; } set { m_AgentTypeID = value; UpdateLink(); } } + + [SerializeField] + Vector3 m_StartPoint = new Vector3(0.0f, 0.0f, -2.5f); + public Vector3 startPoint { get { return m_StartPoint; } set { m_StartPoint = value; UpdateLink(); } } + + [SerializeField] + Vector3 m_EndPoint = new Vector3(0.0f, 0.0f, 2.5f); + public Vector3 endPoint { get { return m_EndPoint; } set { m_EndPoint = value; UpdateLink(); } } + + [SerializeField] + float m_Width; + public float width { get { return m_Width; } set { m_Width = value; UpdateLink(); } } + + [SerializeField] + int m_CostModifier = -1; + public int costModifier { get { return m_CostModifier; } set { m_CostModifier = value; UpdateLink(); } } + + [SerializeField] + bool m_Bidirectional = true; + public bool bidirectional { get { return m_Bidirectional; } set { m_Bidirectional = value; UpdateLink(); } } + + [SerializeField] + bool m_AutoUpdatePosition; + public bool autoUpdate { get { return m_AutoUpdatePosition; } set { SetAutoUpdate(value); } } + + [SerializeField, NavMeshArea] + int m_Area; + public int area { get { return m_Area; } set { m_Area = value; UpdateLink(); } } + + NavMeshLinkInstance m_LinkInstance = new NavMeshLinkInstance(); + + Vector3 m_LastPosition = Vector3.zero; + Quaternion m_LastRotation = Quaternion.identity; + + static readonly List s_Tracked = new List(); + + void OnEnable() + { + AddLink(); + if (m_AutoUpdatePosition && m_LinkInstance.valid) + AddTracking(this); + } + + void OnDisable() + { + RemoveTracking(this); + m_LinkInstance.Remove(); + } + + public void UpdateLink() + { + m_LinkInstance.Remove(); + AddLink(); + } + + static void AddTracking(NavMeshLink link) + { +#if UNITY_EDITOR + if (s_Tracked.Contains(link)) + { + Debug.LogError("Link is already tracked: " + link); + return; + } +#endif + + if (s_Tracked.Count == 0) + NavMesh.onPreUpdate += UpdateTrackedInstances; + + s_Tracked.Add(link); + } + + static void RemoveTracking(NavMeshLink link) + { + s_Tracked.Remove(link); + + if (s_Tracked.Count == 0) + NavMesh.onPreUpdate -= UpdateTrackedInstances; + } + + void SetAutoUpdate(bool value) + { + if (m_AutoUpdatePosition == value) + return; + m_AutoUpdatePosition = value; + if (value) + AddTracking(this); + else + RemoveTracking(this); + } + + void AddLink() + { +#if UNITY_EDITOR + if (m_LinkInstance.valid) + { + Debug.LogError("Link is already added: " + this); + return; + } +#endif + + var link = new NavMeshLinkData(); + link.startPosition = m_StartPoint; + link.endPosition = m_EndPoint; + link.width = m_Width; + link.costModifier = m_CostModifier; + link.bidirectional = m_Bidirectional; + link.area = m_Area; + link.agentTypeID = m_AgentTypeID; + m_LinkInstance = NavMesh.AddLink(link, transform.position, transform.rotation); + if (m_LinkInstance.valid) + m_LinkInstance.owner = this; + + m_LastPosition = transform.position; + m_LastRotation = transform.rotation; + } + + bool HasTransformChanged() + { + if (m_LastPosition != transform.position) return true; + if (m_LastRotation != transform.rotation) return true; + return false; + } + + void OnDidApplyAnimationProperties() + { + UpdateLink(); + } + + static void UpdateTrackedInstances() + { + foreach (var instance in s_Tracked) + { + if (instance.HasTransformChanged()) + instance.UpdateLink(); + } + } + +#if UNITY_EDITOR + void OnValidate() + { + m_Width = Mathf.Max(0.0f, m_Width); + + if (!m_LinkInstance.valid) + return; + + UpdateLink(); + + if (!m_AutoUpdatePosition) + { + RemoveTracking(this); + } + else if (!s_Tracked.Contains(this)) + { + AddTracking(this); + } + } +#endif + } +} diff --git a/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/NavMeshLink.cs.meta b/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/NavMeshLink.cs.meta new file mode 100644 index 0000000..6ee5ec1 --- /dev/null +++ b/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/NavMeshLink.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9b9acdb93a5f98644a2e18d4884f04e2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 68ad4f5d6fe957c4789aedd21ff67ced, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/NavMeshModifier.cs b/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/NavMeshModifier.cs new file mode 100644 index 0000000..e009bd2 --- /dev/null +++ b/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/NavMeshModifier.cs @@ -0,0 +1,56 @@ +using System.Collections.Generic; +using UnityEngine; +using NavMeshPlus.Extensions; + +namespace NavMeshPlus.Components +{ + [ExecuteInEditMode] + [AddComponentMenu("Navigation/Navigation Modifier", 32)] + [HelpURL("https://github.com/Unity-Technologies/NavMeshComponents#documentation-draft")] + public class NavMeshModifier : MonoBehaviour + { + [SerializeField] + bool m_OverrideArea; + public bool overrideArea { get { return m_OverrideArea; } set { m_OverrideArea = value; } } + + [SerializeField, NavMeshArea] + int m_Area; + public int area { get { return m_Area; } set { m_Area = value; } } + + [SerializeField] + bool m_IgnoreFromBuild; + public bool ignoreFromBuild { get { return m_IgnoreFromBuild; } set { m_IgnoreFromBuild = value; } } + + // List of agent types the modifier is applied for. + // Special values: empty == None, m_AffectedAgents[0] =-1 == All. + [SerializeField] + List m_AffectedAgents = new List(new int[] { -1 }); // Default value is All + + static readonly List s_NavMeshModifiers = new List(); + + public static List activeModifiers + { + get { return s_NavMeshModifiers; } + } + + void OnEnable() + { + if (!s_NavMeshModifiers.Contains(this)) + s_NavMeshModifiers.Add(this); + } + + void OnDisable() + { + s_NavMeshModifiers.Remove(this); + } + + public bool AffectsAgentType(int agentTypeID) + { + if (m_AffectedAgents.Count == 0) + return false; + if (m_AffectedAgents[0] == -1) + return true; + return m_AffectedAgents.IndexOf(agentTypeID) != -1; + } + } +} diff --git a/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/NavMeshModifier.cs.meta b/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/NavMeshModifier.cs.meta new file mode 100644 index 0000000..cf0ebd8 --- /dev/null +++ b/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/NavMeshModifier.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9809bf1345abc5648af68b3a82653f08 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 273c8b5db6e39534781066db3444fe88, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/NavMeshModifierTilemap.cs b/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/NavMeshModifierTilemap.cs new file mode 100644 index 0000000..99b0f4d --- /dev/null +++ b/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/NavMeshModifierTilemap.cs @@ -0,0 +1,69 @@ +using System.Collections.Generic; +using System.Linq; +using UnityEngine; +using NavMeshPlus.Extensions; +using UnityEngine.Tilemaps; + +//*********************************************************************************** +// Contributed by author jl-randazzo github.com/jl-randazzo +//*********************************************************************************** +namespace NavMeshPlus.Components +{ + [AddComponentMenu("Navigation/Navigation Modifier Tilemap", 33)] + [HelpURL("https://github.com/Unity-Technologies/NavMeshComponents#documentation-draft")] + [RequireComponent(typeof(Tilemap))] + [RequireComponent(typeof(NavMeshModifier))] + [DisallowMultipleComponent] + [ExecuteInEditMode] + public class NavMeshModifierTilemap : MonoBehaviour + { + [System.Serializable] + public struct TileModifier + { + public TileBase tile; + public bool overrideArea; + [NavMeshArea] public int area; + } + + private class MatchingTileComparator : IEqualityComparer + { + public static readonly IEqualityComparer Instance = new MatchingTileComparator(); + public bool Equals(TileModifier a, TileModifier b) => a.tile == b.tile; + public int GetHashCode(TileModifier tileModifier) => tileModifier.GetHashCode(); + } + + [SerializeField] + List m_TileModifiers = new List(); + + private Dictionary m_ModifierMap; + + public Dictionary GetModifierMap() => m_TileModifiers.Where(mod => mod.tile != null).Distinct(MatchingTileComparator.Instance).ToDictionary(mod => mod.tile); + + void OnEnable() + { + CacheModifiers(); + } + + public void CacheModifiers() + { + m_ModifierMap = GetModifierMap(); + } + +#if UNITY_EDITOR + public bool HasDuplicateTileModifiers() + { + return m_TileModifiers.Count != m_TileModifiers.Distinct(MatchingTileComparator.Instance).Count(); + } +#endif // UNITY_EDITOR + + public virtual bool TryGetTileModifier(Vector3Int coords, Tilemap tilemap, out TileModifier modifier) + { + if (tilemap.GetTile(coords) is TileBase tileBase) + { + return m_ModifierMap.TryGetValue(tileBase, out modifier); + } + modifier = new TileModifier(); + return false; + } + } +} diff --git a/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/NavMeshModifierTilemap.cs.meta b/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/NavMeshModifierTilemap.cs.meta new file mode 100644 index 0000000..c2f9628 --- /dev/null +++ b/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/NavMeshModifierTilemap.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 709c8d6349be44c68dff3d220992400c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 273c8b5db6e39534781066db3444fe88, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/NavMeshModifierVolume.cs b/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/NavMeshModifierVolume.cs new file mode 100644 index 0000000..1b80168 --- /dev/null +++ b/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/NavMeshModifierVolume.cs @@ -0,0 +1,56 @@ +using System.Collections.Generic; +using UnityEngine; +using NavMeshPlus.Extensions; + +namespace NavMeshPlus.Components +{ + [ExecuteInEditMode] + [AddComponentMenu("Navigation/Navigation ModifierVolume", 31)] + [HelpURL("https://github.com/Unity-Technologies/NavMeshComponents#documentation-draft")] + public class NavMeshModifierVolume : MonoBehaviour + { + [SerializeField] + Vector3 m_Size = new Vector3(4.0f, 3.0f, 4.0f); + public Vector3 size { get { return m_Size; } set { m_Size = value; } } + + [SerializeField] + Vector3 m_Center = new Vector3(0, 1.0f, 0); + public Vector3 center { get { return m_Center; } set { m_Center = value; } } + + [SerializeField, NavMeshArea] + int m_Area; + public int area { get { return m_Area; } set { m_Area = value; } } + + // List of agent types the modifier is applied for. + // Special values: empty == None, m_AffectedAgents[0] =-1 == All. + [SerializeField] + List m_AffectedAgents = new List(new int[] { -1 }); // Default value is All + + static readonly List s_NavMeshModifiers = new List(); + + public static List activeModifiers + { + get { return s_NavMeshModifiers; } + } + + void OnEnable() + { + if (!s_NavMeshModifiers.Contains(this)) + s_NavMeshModifiers.Add(this); + } + + void OnDisable() + { + s_NavMeshModifiers.Remove(this); + } + + public bool AffectsAgentType(int agentTypeID) + { + if (m_AffectedAgents.Count == 0) + return false; + if (m_AffectedAgents[0] == -1) + return true; + return m_AffectedAgents.IndexOf(agentTypeID) != -1; + } + } +} diff --git a/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/NavMeshModifierVolume.cs.meta b/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/NavMeshModifierVolume.cs.meta new file mode 100644 index 0000000..98ec520 --- /dev/null +++ b/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/NavMeshModifierVolume.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7fa0352a4d56abd42ad2fc69deb72448 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 273c8b5db6e39534781066db3444fe88, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/NavMeshSurface.cs b/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/NavMeshSurface.cs new file mode 100644 index 0000000..3eff972 --- /dev/null +++ b/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/NavMeshSurface.cs @@ -0,0 +1,543 @@ +using NavMeshPlus.Extensions; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.AI; +#if UNITY_EDITOR +using UnityEditor; +using UnityEditor.SceneManagement; +#endif + +namespace NavMeshPlus.Components +{ + public enum CollectObjects + { + All = 0, + Volume = 1, + Children = 2, + } + + [ExecuteAlways] + [DefaultExecutionOrder(-102)] + [AddComponentMenu("Navigation/Navigation Surface", 30)] + [HelpURL("https://github.com/Unity-Technologies/NavMeshComponents#documentation-draft")] + public class NavMeshSurface : MonoBehaviour + { + [SerializeField, NavMeshAgent] + int m_AgentTypeID; + public int agentTypeID { get { return m_AgentTypeID; } set { m_AgentTypeID = value; } } + + [SerializeField] + CollectObjects m_CollectObjects = CollectObjects.All; + public CollectObjects collectObjects { get { return m_CollectObjects; } set { m_CollectObjects = value; } } + + [SerializeField] + Vector3 m_Size = new Vector3(10.0f, 10.0f, 10.0f); + public Vector3 size { get { return m_Size; } set { m_Size = value; } } + + [SerializeField] + Vector3 m_Center = new Vector3(0, 2.0f, 0); + public Vector3 center { get { return m_Center; } set { m_Center = value; } } + + [SerializeField] + LayerMask m_LayerMask = ~0; + public LayerMask layerMask { get { return m_LayerMask; } set { m_LayerMask = value; } } + + [SerializeField] + NavMeshCollectGeometry m_UseGeometry = NavMeshCollectGeometry.RenderMeshes; + public NavMeshCollectGeometry useGeometry { get { return m_UseGeometry; } set { m_UseGeometry = value; } } + + [SerializeField, NavMeshArea] + int m_DefaultArea; + public int defaultArea { get { return m_DefaultArea; } set { m_DefaultArea = value; } } + + [SerializeField] + bool m_IgnoreNavMeshAgent = true; + public bool ignoreNavMeshAgent { get { return m_IgnoreNavMeshAgent; } set { m_IgnoreNavMeshAgent = value; } } + + [SerializeField] + bool m_IgnoreNavMeshObstacle = true; + public bool ignoreNavMeshObstacle { get { return m_IgnoreNavMeshObstacle; } set { m_IgnoreNavMeshObstacle = value; } } + + [SerializeField] + bool m_OverrideTileSize; + public bool overrideTileSize { get { return m_OverrideTileSize; } set { m_OverrideTileSize = value; } } + [SerializeField] + int m_TileSize = 256; + public int tileSize { get { return m_TileSize; } set { m_TileSize = value; } } + [SerializeField] + bool m_OverrideVoxelSize; + public bool overrideVoxelSize { get { return m_OverrideVoxelSize; } set { m_OverrideVoxelSize = value; } } + [SerializeField] + float m_VoxelSize; + public float voxelSize { get { return m_VoxelSize; } set { m_VoxelSize = value; } } + + // Currently not supported advanced options + [SerializeField] + bool m_BuildHeightMesh; + public bool buildHeightMesh { get { return m_BuildHeightMesh; } set { m_BuildHeightMesh = value; } } + + [SerializeField] + bool m_HideEditorLogs; + public bool hideEditorLogs { get { return m_HideEditorLogs; } set { m_HideEditorLogs = value; } } + + // Reference to whole scene navmesh data asset. + [UnityEngine.Serialization.FormerlySerializedAs("m_BakedNavMeshData")] + [SerializeField] + NavMeshData m_NavMeshData; + public NavMeshData navMeshData { get { return m_NavMeshData; } set { m_NavMeshData = value; } } + + // Do not serialize - runtime only state. + NavMeshDataInstance m_NavMeshDataInstance; + Vector3 m_LastPosition = Vector3.zero; + Quaternion m_LastRotation = Quaternion.identity; + + static readonly List s_NavMeshSurfaces = new List(); + public INavMeshExtensionsProvider NevMeshExtensions { get; set; } = new NavMeshExtensionsProvider(); + + public static List activeSurfaces + { + get { return s_NavMeshSurfaces; } + } + + void OnEnable() + { + Register(this); + AddData(); + } + + void OnDisable() + { + RemoveData(); + Unregister(this); + } + + public void AddData() + { +#if UNITY_EDITOR + var isInPreviewScene = EditorSceneManager.IsPreviewSceneObject(this); + var isPrefab = isInPreviewScene || EditorUtility.IsPersistent(this); + if (isPrefab) + { + //Debug.LogFormat("NavMeshData from {0}.{1} will not be added to the NavMesh world because the gameObject is a prefab.", + // gameObject.name, name); + return; + } +#endif + if (m_NavMeshDataInstance.valid) + return; + + if (m_NavMeshData != null) + { + m_NavMeshDataInstance = NavMesh.AddNavMeshData(m_NavMeshData, transform.position, transform.rotation); + m_NavMeshDataInstance.owner = this; + } + + m_LastPosition = transform.position; + m_LastRotation = transform.rotation; + } + + public void RemoveData() + { + m_NavMeshDataInstance.Remove(); + m_NavMeshDataInstance = new NavMeshDataInstance(); + } + + public NavMeshBuildSettings GetBuildSettings() + { + var buildSettings = NavMesh.GetSettingsByID(m_AgentTypeID); + if (buildSettings.agentTypeID == -1) + { + if (!m_HideEditorLogs) Debug.LogWarning("No build settings for agent type ID " + agentTypeID, this); + buildSettings.agentTypeID = m_AgentTypeID; + } + + if (overrideTileSize) + { + buildSettings.overrideTileSize = true; + buildSettings.tileSize = tileSize; + } + if (overrideVoxelSize) + { + buildSettings.overrideVoxelSize = true; + buildSettings.voxelSize = voxelSize; + } + return buildSettings; + } + + public void BuildNavMesh() + { + using var builderState = new NavMeshBuilderState() { }; + + var sources = CollectSources(builderState); + + // Use unscaled bounds - this differs in behaviour from e.g. collider components. + // But is similar to reflection probe - and since navmesh data has no scaling support - it is the right choice here. + var sourcesBounds = new Bounds(m_Center, Abs(m_Size)); + if (m_CollectObjects == CollectObjects.All || m_CollectObjects == CollectObjects.Children) + { + sourcesBounds = CalculateWorldBounds(sources); + } + builderState.worldBounds = sourcesBounds; + for (int i = 0; i < NevMeshExtensions.Count; ++i) + { + NevMeshExtensions[i].PostCollectSources(this, sources, builderState); + } + var data = NavMeshBuilder.BuildNavMeshData(GetBuildSettings(), + sources, sourcesBounds, transform.position, transform.rotation); + + if (data != null) + { + data.name = gameObject.name; + RemoveData(); + m_NavMeshData = data; + if (isActiveAndEnabled) + AddData(); + } + } + + // Source: https://github.com/Unity-Technologies/NavMeshComponents/issues/97#issuecomment-528692289 + public AsyncOperation BuildNavMeshAsync() + { + RemoveData(); + m_NavMeshData = new NavMeshData(m_AgentTypeID) + { + name = gameObject.name, + position = transform.position, + rotation = transform.rotation + }; + + if (isActiveAndEnabled) + { + AddData(); + } + + return UpdateNavMesh(m_NavMeshData); + } + + public AsyncOperation UpdateNavMesh(NavMeshData data) + { + using var builderState = new NavMeshBuilderState() { }; + + var sources = CollectSources(builderState); + + // Use unscaled bounds - this differs in behaviour from e.g. collider components. + // But is similar to reflection probe - and since navmesh data has no scaling support - it is the right choice here. + var sourcesBounds = new Bounds(m_Center, Abs(m_Size)); + if (m_CollectObjects == CollectObjects.All || m_CollectObjects == CollectObjects.Children) + { + sourcesBounds = CalculateWorldBounds(sources); + } + builderState.worldBounds = sourcesBounds; + for (int i = 0; i < NevMeshExtensions.Count; ++i) + { + NevMeshExtensions[i].PostCollectSources(this, sources, builderState); + } + return NavMeshBuilder.UpdateNavMeshDataAsync(data, GetBuildSettings(), sources, sourcesBounds); + } + + static void Register(NavMeshSurface surface) + { +#if UNITY_EDITOR + var isInPreviewScene = EditorSceneManager.IsPreviewSceneObject(surface); + var isPrefab = isInPreviewScene || EditorUtility.IsPersistent(surface); + if (isPrefab) + { + //Debug.LogFormat("NavMeshData from {0}.{1} will not be added to the NavMesh world because the gameObject is a prefab.", + // surface.gameObject.name, surface.name); + return; + } +#endif + if (s_NavMeshSurfaces.Count == 0) + NavMesh.onPreUpdate += UpdateActive; + + if (!s_NavMeshSurfaces.Contains(surface)) + s_NavMeshSurfaces.Add(surface); + } + + static void Unregister(NavMeshSurface surface) + { + s_NavMeshSurfaces.Remove(surface); + + if (s_NavMeshSurfaces.Count == 0) + NavMesh.onPreUpdate -= UpdateActive; + } + + static void UpdateActive() + { + for (var i = 0; i < s_NavMeshSurfaces.Count; ++i) + s_NavMeshSurfaces[i].UpdateDataIfTransformChanged(); + } + + void AppendModifierVolumes(ref List sources) + { +#if UNITY_EDITOR + var myStage = StageUtility.GetStageHandle(gameObject); + if (!myStage.IsValid()) + return; +#endif + // Modifiers + List modifiers; + if (m_CollectObjects == CollectObjects.Children) + { + modifiers = new List(GetComponentsInChildren()); + modifiers.RemoveAll(x => !x.isActiveAndEnabled); + } + else + { + modifiers = NavMeshModifierVolume.activeModifiers; + } + + foreach (var m in modifiers) + { + if ((m_LayerMask & (1 << m.gameObject.layer)) == 0) + continue; + if (!m.AffectsAgentType(m_AgentTypeID)) + continue; +#if UNITY_EDITOR + if (!myStage.Contains(m.gameObject)) + continue; +#endif + var mcenter = m.transform.TransformPoint(m.center); + var scale = m.transform.lossyScale; + var msize = new Vector3(m.size.x * Mathf.Abs(scale.x), m.size.y * Mathf.Abs(scale.y), m.size.z * Mathf.Abs(scale.z)); + + var src = new NavMeshBuildSource(); + src.shape = NavMeshBuildSourceShape.ModifierBox; + src.transform = Matrix4x4.TRS(mcenter, m.transform.rotation, Vector3.one); + src.size = msize; + src.area = m.area; + sources.Add(src); + } + } + + List CollectSources(NavMeshBuilderState builderState) + { + var sources = new List(); + var markups = new List(); + + List modifiers; + if (m_CollectObjects == CollectObjects.Children) + { + modifiers = new List(GetComponentsInChildren()); + modifiers.RemoveAll(x => !x.isActiveAndEnabled); + } + else + { + modifiers = NavMeshModifier.activeModifiers; + } + + foreach (var m in modifiers) + { + if ((m_LayerMask & (1 << m.gameObject.layer)) == 0) + continue; + if (!m.AffectsAgentType(m_AgentTypeID)) + continue; + var markup = new NavMeshBuildMarkup(); + markup.root = m.transform; + markup.overrideArea = m.overrideArea; + markup.area = m.area; + markup.ignoreFromBuild = m.ignoreFromBuild; + markups.Add(markup); + } + +#if UNITY_EDITOR + if (!EditorApplication.isPlaying) + { + if (m_CollectObjects == CollectObjects.All) + { + UnityEditor.AI.NavMeshBuilder.CollectSourcesInStage( + null, m_LayerMask, m_UseGeometry, m_DefaultArea, markups, gameObject.scene, sources); + } + else if (m_CollectObjects == CollectObjects.Children) + { + UnityEditor.AI.NavMeshBuilder.CollectSourcesInStage( + transform, m_LayerMask, m_UseGeometry, m_DefaultArea, markups, gameObject.scene, sources); + } + else if (m_CollectObjects == CollectObjects.Volume) + { + Matrix4x4 localToWorld = Matrix4x4.TRS(transform.position, transform.rotation, Vector3.one); + var worldBounds = GetWorldBounds(localToWorld, new Bounds(m_Center, m_Size)); + + UnityEditor.AI.NavMeshBuilder.CollectSourcesInStage( + worldBounds, m_LayerMask, m_UseGeometry, m_DefaultArea, markups, gameObject.scene, sources); + } + for (int i = 0; i < NevMeshExtensions.Count; ++i) + { + NevMeshExtensions[i].CollectSources(this, sources, builderState); + } + } + else +#endif + { + if (m_CollectObjects == CollectObjects.All) + { + NavMeshBuilder.CollectSources(null, m_LayerMask, m_UseGeometry, m_DefaultArea, markups, sources); + } + else if (m_CollectObjects == CollectObjects.Children) + { + NavMeshBuilder.CollectSources(transform, m_LayerMask, m_UseGeometry, m_DefaultArea, markups, sources); + } + else if (m_CollectObjects == CollectObjects.Volume) + { + Matrix4x4 localToWorld = Matrix4x4.TRS(transform.position, transform.rotation, Vector3.one); + var worldBounds = GetWorldBounds(localToWorld, new Bounds(m_Center, m_Size)); + NavMeshBuilder.CollectSources(worldBounds, m_LayerMask, m_UseGeometry, m_DefaultArea, markups, sources); + } + for (int i = 0; i < NevMeshExtensions.Count; ++i) + { + NevMeshExtensions[i].CollectSources(this, sources, builderState); + } + } + + if (m_IgnoreNavMeshAgent) + sources.RemoveAll((x) => (x.component != null && x.component.gameObject.GetComponent() != null)); + + if (m_IgnoreNavMeshObstacle) + sources.RemoveAll((x) => (x.component != null && x.component.gameObject.GetComponent() != null)); + + AppendModifierVolumes(ref sources); + + return sources; + } + + static Vector3 Abs(Vector3 v) + { + return new Vector3(Mathf.Abs(v.x), Mathf.Abs(v.y), Mathf.Abs(v.z)); + } + + public static Bounds GetWorldBounds(Matrix4x4 mat, Bounds bounds) + { + var absAxisX = Abs(mat.MultiplyVector(Vector3.right)); + var absAxisY = Abs(mat.MultiplyVector(Vector3.up)); + var absAxisZ = Abs(mat.MultiplyVector(Vector3.forward)); + var worldPosition = mat.MultiplyPoint(bounds.center); + var worldSize = absAxisX * bounds.size.x + absAxisY * bounds.size.y + absAxisZ * bounds.size.z; + return new Bounds(worldPosition, worldSize); + } + + public Bounds CalculateWorldBounds(List sources) + { + // Use the unscaled matrix for the NavMeshSurface + Matrix4x4 worldToLocal = Matrix4x4.TRS(transform.position, transform.rotation, Vector3.one); + worldToLocal = worldToLocal.inverse; + + var result = new Bounds(); + var builderState = new NavMeshBuilderState() { worldBounds = result, worldToLocal = worldToLocal }; + for (int i = 0; i < NevMeshExtensions.Count; ++i) + { + NevMeshExtensions[i].CalculateWorldBounds(this, sources, builderState); + result.Encapsulate(builderState.worldBounds); + } + foreach (var src in sources) + { + switch (src.shape) + { + case NavMeshBuildSourceShape.Mesh: + { + var m = src.sourceObject as Mesh; + result.Encapsulate(GetWorldBounds(worldToLocal * src.transform, m.bounds)); + break; + } + case NavMeshBuildSourceShape.Terrain: + { +#if IS_TERRAIN_USED + // Terrain pivot is lower/left corner - shift bounds accordingly + var t = src.sourceObject as TerrainData; + result.Encapsulate(GetWorldBounds(worldToLocal * src.transform, new Bounds(0.5f * t.size, t.size))); +#endif + break; + } + case NavMeshBuildSourceShape.Box: + case NavMeshBuildSourceShape.Sphere: + case NavMeshBuildSourceShape.Capsule: + case NavMeshBuildSourceShape.ModifierBox: + result.Encapsulate(GetWorldBounds(worldToLocal * src.transform, new Bounds(Vector3.zero, src.size))); + break; + } + } + // Inflate the bounds a bit to avoid clipping co-planar sources + result.Expand(0.1f); + return result; + } + + bool HasTransformChanged() + { + if (m_LastPosition != transform.position) return true; + if (m_LastRotation != transform.rotation) return true; + return false; + } + + void UpdateDataIfTransformChanged() + { + if (HasTransformChanged()) + { + RemoveData(); + AddData(); + } + } + +#if UNITY_EDITOR + bool UnshareNavMeshAsset() + { + // Nothing to unshare + if (m_NavMeshData == null) + return false; + + // Prefab parent owns the asset reference + var isInPreviewScene = EditorSceneManager.IsPreviewSceneObject(this); + var isPersistentObject = EditorUtility.IsPersistent(this); + if (isInPreviewScene || isPersistentObject) + return false; + + // An instance can share asset reference only with its prefab parent + var prefab = UnityEditor.PrefabUtility.GetCorrespondingObjectFromSource(this) as NavMeshSurface; + if (prefab != null && prefab.navMeshData == navMeshData) + return false; + + // Don't allow referencing an asset that's assigned to another surface + for (var i = 0; i < s_NavMeshSurfaces.Count; ++i) + { + var surface = s_NavMeshSurfaces[i]; + if (surface != this && surface.m_NavMeshData == m_NavMeshData) + return true; + } + + // Asset is not referenced by known surfaces + return false; + } + + void OnValidate() + { + if (UnshareNavMeshAsset()) + { + if (!m_HideEditorLogs) Debug.LogWarning("Duplicating NavMeshSurface does not duplicate the referenced navmesh data", this); + m_NavMeshData = null; + } + + var settings = NavMesh.GetSettingsByID(m_AgentTypeID); + if (settings.agentTypeID != -1) + { + // When unchecking the override control, revert to automatic value. + const float kMinVoxelSize = 0.01f; + if (!m_OverrideVoxelSize) + m_VoxelSize = settings.agentRadius / 3.0f; + if (m_VoxelSize < kMinVoxelSize) + m_VoxelSize = kMinVoxelSize; + + // When unchecking the override control, revert to default value. + const int kMinTileSize = 16; + const int kMaxTileSize = 1024; + const int kDefaultTileSize = 256; + + if (!m_OverrideTileSize) + m_TileSize = kDefaultTileSize; + // Make sure tilesize is in sane range. + if (m_TileSize < kMinTileSize) + m_TileSize = kMinTileSize; + if (m_TileSize > kMaxTileSize) + m_TileSize = kMaxTileSize; + } + } +#endif + } +} diff --git a/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/NavMeshSurface.cs.meta b/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/NavMeshSurface.cs.meta new file mode 100644 index 0000000..dc1d70f --- /dev/null +++ b/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/NavMeshSurface.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e04976799df50f54ba128eff723155a7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 444810ca896903c41adf617b35274dc4, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/RootSources2d.cs b/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/RootSources2d.cs new file mode 100644 index 0000000..d31e62d --- /dev/null +++ b/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/RootSources2d.cs @@ -0,0 +1,32 @@ +using NavMeshPlus.Components; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; +using UnityEngine.AI; + +namespace NavMeshPlus.Extensions +{ + [ExecuteAlways] + [AddComponentMenu("Navigation/Navigation RootSources2d", 30)] + public class RootSources2d: NavMeshExtension + { + [SerializeField] + private List _rootSources; + + public List RootSources { get => _rootSources; set => _rootSources = value; } + + protected override void Awake() + { + Order = -1000; + base.Awake(); + } + + public override void CollectSources(NavMeshSurface surface, List sources, NavMeshBuilderState navNeshState) + { + navNeshState.roots = _rootSources; + } + } +} diff --git a/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/RootSources2d.cs.meta b/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/RootSources2d.cs.meta new file mode 100644 index 0000000..ac2b190 --- /dev/null +++ b/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/RootSources2d.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6fec7b7904f76c4498a68fd145934563 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: d5b0e13ebe59cd64e9f67284457c6868, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/RotateAgentInstantly.cs b/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/RotateAgentInstantly.cs new file mode 100644 index 0000000..d6c4022 --- /dev/null +++ b/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/RotateAgentInstantly.cs @@ -0,0 +1,40 @@ +using UnityEngine; +using UnityEngine.AI; + +//*********************************************************************************** +// Contributed by author @Lazy_Sloth from unity forum (https://forum.unity.com/) +//*********************************************************************************** +namespace NavMeshPlus.Extensions +{ + public class RotateAgentInstantly: IAgentOverride + { + + public RotateAgentInstantly(NavMeshAgent agent, AgentOverride2d owner) + { + this.agent = agent; + this.owner = owner; + } + private NavMeshAgent agent; + private AgentOverride2d owner; + private Vector3 nextWaypoint; + + public void UpdateAgent() + { + if (agent.hasPath && agent.path.corners.Length > 1) + { + if (nextWaypoint != agent.path.corners[1]) + { + RotateToPoint(agent.path.corners[1], agent.transform); + nextWaypoint = agent.path.corners[1]; + } + } + } + + private static void RotateToPoint(Vector3 targetPoint, Transform transform) + { + Vector3 targetVector = targetPoint - transform.position; + float angleDifference = Vector2.SignedAngle(transform.up, targetVector); + transform.rotation = Quaternion.Euler(0, 0, transform.localEulerAngles.z + angleDifference); + } + } +} \ No newline at end of file diff --git a/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/RotateAgentInstantly.cs.meta b/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/RotateAgentInstantly.cs.meta new file mode 100644 index 0000000..abd0ec9 --- /dev/null +++ b/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/RotateAgentInstantly.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5b304bdab91a28c469562d02b8225df3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: e8142b1daeea8d3419cd0ffbd7b17a37, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/RotateAgentSmoothly.cs b/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/RotateAgentSmoothly.cs new file mode 100644 index 0000000..6eeb754 --- /dev/null +++ b/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/RotateAgentSmoothly.cs @@ -0,0 +1,57 @@ +using System.Collections; +using UnityEngine; +using UnityEngine.AI; + +//*********************************************************************************** +// Contributed by author @Lazy_Sloth from unity forum (https://forum.unity.com/) +//*********************************************************************************** +namespace NavMeshPlus.Extensions +{ + public class RotateAgentSmoothly: IAgentOverride + { + public RotateAgentSmoothly(NavMeshAgent agent, AgentOverride2d owner, float rotateSpeed) + { + this.agent = agent; + this.owner = owner; + this.rotateSpeed = rotateSpeed; + } + + private NavMeshAgent agent; + private AgentOverride2d owner; + private Vector2 nextWaypoint; + private float angleDifference; + private float targetAngle; + public float rotateSpeed; + + public void UpdateAgent() + { + if (agent.hasPath && agent.path.corners.Length > 1) + { + if (nextWaypoint != (Vector2)agent.path.corners[1]) + { + owner.StartCoroutine(_RotateCoroutine()); + nextWaypoint = agent.path.corners[1]; + } + } + } + protected IEnumerator _RotateCoroutine() + { + yield return RotateToWaypoints(agent.transform); + } + protected IEnumerator RotateToWaypoints(Transform transform) + { + Vector2 targetVector = agent.path.corners[1] - transform.position; + angleDifference = Vector2.SignedAngle(transform.up, targetVector); + targetAngle = transform.localEulerAngles.z + angleDifference; + + if (targetAngle >= 360) { targetAngle -= 360; } + else if (targetAngle < 0) { targetAngle += 360; } + + while (transform.localEulerAngles.z < targetAngle - 0.1f || transform.localEulerAngles.z > targetAngle + 0.1f) + { + transform.rotation = Quaternion.RotateTowards(transform.rotation, Quaternion.Euler(0, 0, targetAngle), rotateSpeed * Time.deltaTime); + yield return null; + } + } + } +} \ No newline at end of file diff --git a/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/RotateAgentSmoothly.cs.meta b/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/RotateAgentSmoothly.cs.meta new file mode 100644 index 0000000..ec15bde --- /dev/null +++ b/Assets/Scripts/PathFinding/NavMeshComponents/Scripts/RotateAgentSmoothly.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7f8df5c105d35bd4787c3b4ce3e1c56b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: e8142b1daeea8d3419cd0ffbd7b17a37, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/PathFinding/README.md b/Assets/Scripts/PathFinding/README.md new file mode 100644 index 0000000..55d39a6 --- /dev/null +++ b/Assets/Scripts/PathFinding/README.md @@ -0,0 +1,54 @@ + +# NavMeshPlus + +NavMeshComponents.Extensions provides you with ability to create navigation meshes that are generated automatically from your Scene +geometry, which allows characters to move intelligently around the game world. + +![NavMesh](https://github.com/h8man/NavMeshPlus/wiki/images/Tittle-01.png) + +# Unity 2D Pathfinding +This repo is fork of Unity NavMeshComponents enhanced with Extensions system for 2d Pathfinding and more. [[link]](https://github.com/Unity-Technologies/NavMeshComponents) + +#### Wiki [[here]](https://github.com/h8man/NavMeshPlus/wiki) +#### How To [[here]](https://github.com/h8man/NavMeshPlus/wiki/HOW-TO). +#### Demo [[github]](https://github.com/h8man/RedHotSweetPepper ). +#### Discuss [[unityforum]](https://forum.unity.com/threads/2d-navmesh-pathfinding.503596/ ). + +# 2D NavMesh + +In repo you will find implementation of NavMeshSurface and 2d Extensions for tilemap, sprites and collider2d top down games. + +To use it in your project: + +1. Copy repo into your Asset folder (or install as a package). +2. Create Empty Object in scene root. +3. Add "Navigation Surface" component to Empty Object and add NavMeshCollecSources2d component after. +4. Click Rotate Surface to XY (to face surface toward standard 2d camera x-90;y0;z0) +5. Add "Navigation Modifier" component to scene objects obstacles, override the area. +6. In "Navigation Surface" hit Bake. + +How does it works: + +1. It uses [NavMeshSurface](https://docs.unity3d.com/Manual/class-NavMeshSurface.html) as base implementation. +2. Implements world bound calculation. +3. Implements source collector of tiles, sprites and 2d colliders +4. Creates walkable mesh box from world bounds. +5. Convert tiles, sprites and 2d colliders to sources as `NavMeshBuilder` would do. +# Setup + +You can use this in two different ways: downloading this repository or adding it to your project's Package Manager manifest. [Git](https://git-scm.com/) must be installed and added to your path. +Alternatively, you can pick scripts and place in your project's `Assets` folder. + +#### Method 1. Download +Download or clone this repository into your project in the folder `Packages/com.h8man.2d.navmeshplus`. + +#### Method 2. Package Manager Manifest +The following line needs to be added to your `Packages/manifest.json` file in your Unity Project under the `dependencies` section: +``` +"com.h8man.2d.navmeshplus": "https://github.com/h8man/NavMeshPlus.git#master" +``` +#### Method 3. Add Package form git URL +Go to `Package Manager` click `+` and then select `Add Package form git URL` paste url: +``` +https://github.com/h8man/NavMeshPlus.git +``` diff --git a/Assets/Scripts/PathFinding/README.md.meta b/Assets/Scripts/PathFinding/README.md.meta new file mode 100644 index 0000000..f6b8104 --- /dev/null +++ b/Assets/Scripts/PathFinding/README.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 2f77fe52aa3396942bf2eecff964b4d0 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/PathFinding/Unity.meta b/Assets/Scripts/PathFinding/Unity.meta new file mode 100644 index 0000000..0844b4b --- /dev/null +++ b/Assets/Scripts/PathFinding/Unity.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2d085361c3a06be448c4127d3d5e22f4 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/PathFinding/Unity/LICENSE b/Assets/Scripts/PathFinding/Unity/LICENSE new file mode 100644 index 0000000..ea2052f --- /dev/null +++ b/Assets/Scripts/PathFinding/Unity/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2016, Unity Technologies + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/Assets/Scripts/PathFinding/Unity/LICENSE.meta b/Assets/Scripts/PathFinding/Unity/LICENSE.meta new file mode 100644 index 0000000..693f64b --- /dev/null +++ b/Assets/Scripts/PathFinding/Unity/LICENSE.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 4919e823dd64ccf498a5a5e4da60a79e +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/PathFinding/Unity/README.md b/Assets/Scripts/PathFinding/Unity/README.md new file mode 100644 index 0000000..0472ea7 --- /dev/null +++ b/Assets/Scripts/PathFinding/Unity/README.md @@ -0,0 +1,60 @@ +> Please use the branch matching the version of your Unity editor: [master](../../tree/master) for the latest released version, [2018.3](../../tree/2018.3), [2018.2](../../tree/2018.2), [2018.1](../../tree/2018.1), [2017.2](../../tree/2017.2) for up to 2017.4-LTS, [2017.1](../../tree/2017.1), [5.6](../../tree/5.6). + +# Components for Runtime NavMesh Building + +Here we introduce four components for the navigation system: + +* __NavMeshSurface__ – for building and enabling a NavMesh surface for one agent type. +* __NavMeshModifier__ – affects the NavMesh generation of NavMesh area types, based on the transform hierarchy. +* __NavMeshModifierVolume__ – affects the NavMesh generation of NavMesh area types, based on volume. +* __NavMeshLink__ – connects same or different NavMesh surfaces for one agent type. + +These components comprise the high level controls for building and using NavMeshes at runtime as well as edit time. + +Detailed information can be found in the [Documentation](Documentation) section or in the [NavMesh building components](https://docs.unity3d.com/Manual/NavMesh-BuildingComponents.html) section of the Unity Manual. + +# How To Get Started + +Download and install Unity 5.6 or newer. + +Clone or download this repository and open the project in Unity. +Alternatively, you can copy the contents of `Assets/NavMeshComponents` to an existing project. Make sure to select a branch of the repository that matches the Unity version. + +Additional examples are available in the `Assets/Examples` folder. +The examples are provided "as is". They are neither generic nor robust, but serve as inspiration. + +_Note: During the beta cycle features and API are subject to change.\ +**Make sure to backup an existing project before opening it with a beta build.**_ + +# FAQ + +Q: Can I bake a NavMesh at runtime? +A: Yes. + +Q: Can I use NavMesh'es for more than one agent size? +A: Yes. + +Q: Can I put a NavMesh in a prefab? +A: Yes - with some limitations. + +Q: How do I connect two NavMesh surfaces? +A: Use the NavMeshLink to connect the two sides. + +Q: How do I query the NavMesh for one specific size of agent? +A: Use the NavMeshQuery filter when querying the NavMesh. + +Q: What's the deal with the 'DefaultExecutionOrder' attribute? +A: It gives a way of controlling the order of execution of scripts - specifically it allows us to build a NavMesh before the +(native) NavMeshAgent component is enabled. + +Q: What's the use of the new delegate 'NavMesh.onPreUpdate'? +A: It allows you to hook in to controlling the NavMesh data and links set up before the navigation update loop is called on the native side. + +Q: Can I do moving NavMesh platforms? +A: No - new API is required for consistently moving platforms carrying agents. + +Q: Is OffMeshLink now obsolete? +A: No - you can still use OffMeshLink - however you'll find that NavMeshLink is more flexible and have less overhead. + +Q: What happened to HeightMesh and Auto Generated OffMeshLinks? +A: They're not supported in the new NavMesh building feature. HeightMesh will be added at some point. Auto OffMeshLink generation will possibly be replaced with a solution that allows better control of placement. diff --git a/Assets/Scripts/PathFinding/Unity/README.md.meta b/Assets/Scripts/PathFinding/Unity/README.md.meta new file mode 100644 index 0000000..7902f04 --- /dev/null +++ b/Assets/Scripts/PathFinding/Unity/README.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 32745b071c7e5004f946a98ebaf2fc15 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/PathFinding/navmeshplus.pdf b/Assets/Scripts/PathFinding/navmeshplus.pdf new file mode 100644 index 0000000..b76d423 Binary files /dev/null and b/Assets/Scripts/PathFinding/navmeshplus.pdf differ diff --git a/Assets/Scripts/PathFinding/navmeshplus.pdf.meta b/Assets/Scripts/PathFinding/navmeshplus.pdf.meta new file mode 100644 index 0000000..23e5d13 --- /dev/null +++ b/Assets/Scripts/PathFinding/navmeshplus.pdf.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 0d419d21003cd354bb186fc0ad3a84fd +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/PathFinding/package.json b/Assets/Scripts/PathFinding/package.json new file mode 100644 index 0000000..0256e57 --- /dev/null +++ b/Assets/Scripts/PathFinding/package.json @@ -0,0 +1,12 @@ +{ + + "name": "com.h8man.2d.navmeshplus", + "displayName": "NavMeshPlus", + "version": "0.2.18", + "unity": "2019.2", + "description": "NavMesh building components provide you with ability to create navigation meshes that are generated automatically from your Scene geometry, which allows characters to move intelligently around the game world.", + "keywords": ["2d"], + "category": "2D", + "dependencies": { } + +} diff --git a/Assets/Scripts/PathFinding/package.json.meta b/Assets/Scripts/PathFinding/package.json.meta new file mode 100644 index 0000000..791219b --- /dev/null +++ b/Assets/Scripts/PathFinding/package.json.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: a11de58dc8c82df4a8a5db73629430c4 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Rope.meta b/Assets/Scripts/Rope.meta new file mode 100644 index 0000000..90144cc --- /dev/null +++ b/Assets/Scripts/Rope.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d928ffd25dc2dd9429a0e496110c8f60 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/manifest.json b/Packages/manifest.json index 21bbf20..39a06c6 100644 --- a/Packages/manifest.json +++ b/Packages/manifest.json @@ -1,5 +1,6 @@ { "dependencies": { + "com.unity.ai.navigation": "1.1.5", "com.unity.collab-proxy": "2.2.0", "com.unity.feature.2d": "2.0.0", "com.unity.ide.rider": "3.0.27", diff --git a/Packages/packages-lock.json b/Packages/packages-lock.json index ead233e..f1b3bba 100644 --- a/Packages/packages-lock.json +++ b/Packages/packages-lock.json @@ -94,6 +94,15 @@ }, "url": "https://packages.unity.com" }, + "com.unity.ai.navigation": { + "version": "1.1.5", + "depth": 0, + "source": "registry", + "dependencies": { + "com.unity.modules.ai": "1.0.0" + }, + "url": "https://packages.unity.com" + }, "com.unity.burst": { "version": "1.8.11", "depth": 1,