diff --git a/Assets/PathBerserker2d.meta b/Assets/PathBerserker2d.meta deleted file mode 100644 index 2ee1c18d..00000000 --- a/Assets/PathBerserker2d.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 79d9b19d4c18d0240920de7d6b598473 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Documentation.meta b/Assets/PathBerserker2d/Documentation.meta deleted file mode 100644 index 33057678..00000000 --- a/Assets/PathBerserker2d/Documentation.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: e0383e08b93337e41bd2254c4304147f -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Documentation/Documentation.zip b/Assets/PathBerserker2d/Documentation/Documentation.zip deleted file mode 100644 index 1d0bd28d..00000000 Binary files a/Assets/PathBerserker2d/Documentation/Documentation.zip and /dev/null differ diff --git a/Assets/PathBerserker2d/Documentation/Documentation.zip.meta b/Assets/PathBerserker2d/Documentation/Documentation.zip.meta deleted file mode 100644 index 05e1b8ed..00000000 --- a/Assets/PathBerserker2d/Documentation/Documentation.zip.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 21035a61c7bbb0c43adb502350355869 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Documentation/README.txt b/Assets/PathBerserker2d/Documentation/README.txt deleted file mode 100644 index 7d81d40f..00000000 --- a/Assets/PathBerserker2d/Documentation/README.txt +++ /dev/null @@ -1,15 +0,0 @@ -Pathberserker2d - -Thanks for purchasing. To get started, I suggest trying out the various demo scenes. - -The documentation is shipped as a zip file in the same folder. -Alternatively you can read the most up to date version of the documentation online here: -https://oribow.github.io/PathBerserker2dDemo/Documentation/ - -The documentation also includes guides on a variety of topics and explains the core concepts of this asset. - -As an extra treat, this Asset also comes with its complete source code, also as zip in this folder. -Setting your project up to use the source code instead of the DLL's requires some knowledge about C# projects. -I recommend using the source code primarily as a reference guide. - -Happy path-finding! \ No newline at end of file diff --git a/Assets/PathBerserker2d/Documentation/README.txt.meta b/Assets/PathBerserker2d/Documentation/README.txt.meta deleted file mode 100644 index 602979b6..00000000 --- a/Assets/PathBerserker2d/Documentation/README.txt.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 1605f3fdba2679842a2f72c81ec408ac -TextScriptImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Icons.meta b/Assets/PathBerserker2d/Icons.meta deleted file mode 100644 index e06727a0..00000000 --- a/Assets/PathBerserker2d/Icons.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 446c632a2de6b8c4c87487c4533abd7f -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Icons/follow_path.png b/Assets/PathBerserker2d/Icons/follow_path.png deleted file mode 100644 index f69bb0d7..00000000 Binary files a/Assets/PathBerserker2d/Icons/follow_path.png and /dev/null differ diff --git a/Assets/PathBerserker2d/Icons/follow_path.png.meta b/Assets/PathBerserker2d/Icons/follow_path.png.meta deleted file mode 100644 index a82619e3..00000000 --- a/Assets/PathBerserker2d/Icons/follow_path.png.meta +++ /dev/null @@ -1,115 +0,0 @@ -fileFormatVersion: 2 -guid: 1076c1b4e7774d14cb5f02e81e131660 -TextureImporter: - internalIDToNameTable: [] - externalObjects: {} - serializedVersion: 10 - 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 - grayScaleToAlpha: 0 - generateCubemap: 6 - cubemapConvolution: 0 - seamlessCubemap: 0 - textureFormat: 1 - maxTextureSize: 2048 - textureSettings: - serializedVersion: 2 - filterMode: -1 - aniso: 1 - mipBias: -100 - 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: 2 - textureShape: 1 - singleChannelComponent: 0 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 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 - - serializedVersion: 3 - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: WebGL - 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: [] - spritePackingTag: - pSDRemoveMatte: 0 - pSDShowRemoveMatteOption: 0 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Icons/link_icon.png b/Assets/PathBerserker2d/Icons/link_icon.png deleted file mode 100644 index ce2075b8..00000000 Binary files a/Assets/PathBerserker2d/Icons/link_icon.png and /dev/null differ diff --git a/Assets/PathBerserker2d/Icons/link_icon.png.meta b/Assets/PathBerserker2d/Icons/link_icon.png.meta deleted file mode 100644 index 9a7c29ce..00000000 --- a/Assets/PathBerserker2d/Icons/link_icon.png.meta +++ /dev/null @@ -1,103 +0,0 @@ -fileFormatVersion: 2 -guid: 123ffa319522f7b40b36a77973995e35 -TextureImporter: - internalIDToNameTable: [] - externalObjects: {} - serializedVersion: 10 - 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 - grayScaleToAlpha: 0 - generateCubemap: 6 - cubemapConvolution: 0 - seamlessCubemap: 0 - textureFormat: 1 - maxTextureSize: 2048 - textureSettings: - serializedVersion: 2 - filterMode: -1 - aniso: 1 - mipBias: -100 - 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: 2 - textureShape: 1 - singleChannelComponent: 0 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 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 - - serializedVersion: 3 - buildTarget: Standalone - 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: [] - spritePackingTag: - pSDRemoveMatte: 0 - pSDShowRemoveMatteOption: 0 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Icons/lost_path.png b/Assets/PathBerserker2d/Icons/lost_path.png deleted file mode 100644 index b3dd2076..00000000 Binary files a/Assets/PathBerserker2d/Icons/lost_path.png and /dev/null differ diff --git a/Assets/PathBerserker2d/Icons/lost_path.png.meta b/Assets/PathBerserker2d/Icons/lost_path.png.meta deleted file mode 100644 index 54c20e81..00000000 --- a/Assets/PathBerserker2d/Icons/lost_path.png.meta +++ /dev/null @@ -1,115 +0,0 @@ -fileFormatVersion: 2 -guid: 410455380032bfb45b40e7c043a62b4f -TextureImporter: - internalIDToNameTable: [] - externalObjects: {} - serializedVersion: 10 - 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 - grayScaleToAlpha: 0 - generateCubemap: 6 - cubemapConvolution: 0 - seamlessCubemap: 0 - textureFormat: 1 - maxTextureSize: 2048 - textureSettings: - serializedVersion: 2 - filterMode: -1 - aniso: 1 - mipBias: -100 - 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: 2 - textureShape: 1 - singleChannelComponent: 0 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 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 - - serializedVersion: 3 - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: WebGL - 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: [] - spritePackingTag: - pSDRemoveMatte: 0 - pSDShowRemoveMatteOption: 0 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Icons/planning.png b/Assets/PathBerserker2d/Icons/planning.png deleted file mode 100644 index e2bee00c..00000000 Binary files a/Assets/PathBerserker2d/Icons/planning.png and /dev/null differ diff --git a/Assets/PathBerserker2d/Icons/planning.png.meta b/Assets/PathBerserker2d/Icons/planning.png.meta deleted file mode 100644 index d2580964..00000000 --- a/Assets/PathBerserker2d/Icons/planning.png.meta +++ /dev/null @@ -1,115 +0,0 @@ -fileFormatVersion: 2 -guid: f70aa7e3ba7990549bed699b10912202 -TextureImporter: - internalIDToNameTable: [] - externalObjects: {} - serializedVersion: 10 - 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 - grayScaleToAlpha: 0 - generateCubemap: 6 - cubemapConvolution: 0 - seamlessCubemap: 0 - textureFormat: 1 - maxTextureSize: 2048 - textureSettings: - serializedVersion: 2 - filterMode: -1 - aniso: 1 - mipBias: -100 - 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: 2 - textureShape: 1 - singleChannelComponent: 0 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 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 - - serializedVersion: 3 - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: WebGL - 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: [] - spritePackingTag: - pSDRemoveMatte: 0 - pSDShowRemoveMatteOption: 0 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Icons/portal.png b/Assets/PathBerserker2d/Icons/portal.png deleted file mode 100644 index 0d40602e..00000000 Binary files a/Assets/PathBerserker2d/Icons/portal.png and /dev/null differ diff --git a/Assets/PathBerserker2d/Icons/portal.png.meta b/Assets/PathBerserker2d/Icons/portal.png.meta deleted file mode 100644 index 01353970..00000000 --- a/Assets/PathBerserker2d/Icons/portal.png.meta +++ /dev/null @@ -1,103 +0,0 @@ -fileFormatVersion: 2 -guid: 550c17ae955373049aee7dff67a18fa9 -TextureImporter: - internalIDToNameTable: [] - externalObjects: {} - serializedVersion: 10 - 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 - grayScaleToAlpha: 0 - generateCubemap: 6 - cubemapConvolution: 0 - seamlessCubemap: 0 - textureFormat: 1 - maxTextureSize: 2048 - textureSettings: - serializedVersion: 2 - filterMode: -1 - aniso: 1 - mipBias: -100 - 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: 2 - textureShape: 1 - singleChannelComponent: 0 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 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 - - serializedVersion: 3 - buildTarget: Standalone - 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: [] - spritePackingTag: - pSDRemoveMatte: 0 - pSDShowRemoveMatteOption: 0 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Resources.meta b/Assets/PathBerserker2d/Resources.meta deleted file mode 100644 index ea79f1ff..00000000 --- a/Assets/PathBerserker2d/Resources.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: f88aed787b8decc4086d9222249beace -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Resources/PathBerserker2dSettings.asset b/Assets/PathBerserker2d/Resources/PathBerserker2dSettings.asset deleted file mode 100644 index 27e23e72..00000000 --- a/Assets/PathBerserker2d/Resources/PathBerserker2dSettings.asset +++ /dev/null @@ -1,54 +0,0 @@ -%YAML 1.1 -%TAG !u! tag:unity3d.com,2011: ---- !u!114 &11400000 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 393b1ec75130eb047bc70f7635277936, type: 3} - m_Name: PathBerserker2dSettings - m_EditorClassIdentifier: - pointMappingDistance: 0.2 - pathfinderThreadCount: 4 - initiateUpdateInterval: 0.1 - closestToSegmentMaxDistance: 20 - navLinkTypeNames: - - corner - - jump - - fall - - teleport - - climb - - elevator - navLinkTypeColors: - - {r: 0, g: 0, b: 0, a: 1} - - {r: 1, g: 1, b: 1, a: 1} - - {r: 0, g: 0.51575685, b: 1, a: 1} - - {r: 0, g: 1, b: 0, a: 1} - - {r: 0, g: 0.03320258, b: 0.49803922, a: 1} - - {r: 1, g: 0, b: 1, a: 1} - navTags: - - default - - water - - lava - - grass - - concrete - - dirt - navTagColors: - - {r: 0, g: 0, b: 0, a: 0} - - {r: 0, g: 0.5736413, b: 1, a: 1} - - {r: 1, g: 0.19613811, b: 0, a: 1} - - {r: 0.03921567, g: 0.99607843, b: 0.124506705, a: 1} - - {r: 0.4528302, g: 0.4528302, b: 0.4528302, a: 1} - - {r: 0.4339623, g: 0.2691755, b: 0, a: 1} - drawUnselectedLinks: 1 - drawUnselectedSurfaces: 1 - drawUnselectedSubstractors: 1 - drawUnselectedAreaMarkers: 1 - drawGraphWhilePlaying: 1 - navSurfaceLineWidth: 0.04 - navAreaMarkerLineWidth: 0.2 - usePolygonCollider2dPathsForBaking: 0 diff --git a/Assets/PathBerserker2d/Resources/PathBerserker2dSettings.asset.meta b/Assets/PathBerserker2d/Resources/PathBerserker2dSettings.asset.meta deleted file mode 100644 index 9b9b3349..00000000 --- a/Assets/PathBerserker2d/Resources/PathBerserker2dSettings.asset.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 25dcc2654112bc54090ee2accbac7499 -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 0 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts.meta b/Assets/PathBerserker2d/Scripts.meta deleted file mode 100644 index b0b50104..00000000 --- a/Assets/PathBerserker2d/Scripts.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 80a179a567cbfc148b23c441354e6057 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor.meta deleted file mode 100644 index 2d500d7e..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: cd800ca490ca3504a91a04cbbe34fe93 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/AttributeDrawers.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/AttributeDrawers.meta deleted file mode 100644 index 51af481e..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/AttributeDrawers.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 91a2221b1f964c946af33b7bb66b948d -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/AttributeDrawers/ReadOnlyAttributeDrawer.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/AttributeDrawers/ReadOnlyAttributeDrawer.cs deleted file mode 100644 index e8d63920..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/AttributeDrawers/ReadOnlyAttributeDrawer.cs +++ /dev/null @@ -1,22 +0,0 @@ -using UnityEditor; -using UnityEngine; - -namespace PathBerserker2d -{ - [CustomPropertyDrawer(typeof(ReadOnlyAttribute))] - internal class ReadOnlyAttributeDrawer : PropertyDrawer - { - public override float GetPropertyHeight(SerializedProperty property, GUIContent label) - { - return EditorGUI.GetPropertyHeight(property, label, true); - } - - public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) - { - bool oldValue = GUI.enabled; - GUI.enabled = false; - EditorGUI.PropertyField(position, property, label, true); - GUI.enabled = oldValue; - } - } -} diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/AttributeDrawers/ReadOnlyAttributeDrawer.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/AttributeDrawers/ReadOnlyAttributeDrawer.cs.meta deleted file mode 100644 index 0d25148a..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/AttributeDrawers/ReadOnlyAttributeDrawer.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: bfac06ae39b4da041b0233fbe194c0a2 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/CustomGUI.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/CustomGUI.meta deleted file mode 100644 index cc235d3a..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/CustomGUI.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 1df174b62e1d3684f9fc16ede26d1866 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/CustomGUI/IconHandle2D.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/CustomGUI/IconHandle2D.cs deleted file mode 100644 index 291810dd..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/CustomGUI/IconHandle2D.cs +++ /dev/null @@ -1,51 +0,0 @@ -using UnityEngine; -using UnityEditor; - -namespace PathBerserker2d -{ - internal class IconHandle2D - { - private static readonly int controlHashIcon = "IconHandle2D_icon".GetHashCode(); - - public static void DrawHandle(Vector3 position, Texture icon, float size, Object objectToSelect) - { - int iconId = EditorGUIUtility.GetControlID(controlHashIcon, FocusType.Passive); - - var e = Event.current; - switch (e.type) - { - case EventType.MouseDown: - if (e.button == 0 && HandleUtility.nearestControl == iconId) - { - Selection.activeObject = objectToSelect; - e.Use(); - } - - break; - case EventType.Layout: - float distance = HandleUtility.DistanceToRectangle(position, Camera.current.transform.rotation, size); - HandleUtility.AddControl(iconId, distance); - break; - case EventType.Repaint: - Vector3 up = Camera.current.transform.up * size; - float aspectRatio = (float)icon.width / (float)icon.height; - Vector3 right = Camera.current.transform.right * size * aspectRatio; - SharedMaterials.UnlitTexture.SetTexture("_MainTex", icon); - SharedMaterials.UnlitTexture.SetPass(0); - GL.Begin(GL.QUADS); - { - GL.TexCoord2(1, 1); - GL.Vertex(position + right + up); - GL.TexCoord2(1, 0); - GL.Vertex(position + right - up); - GL.TexCoord2(0, 0); - GL.Vertex(position - right - up); - GL.TexCoord2(0, 1); - GL.Vertex(position - right + up); - } - GL.End(); - break; - } - } - } -} diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/CustomGUI/IconHandle2D.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/CustomGUI/IconHandle2D.cs.meta deleted file mode 100644 index e4665072..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/CustomGUI/IconHandle2D.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 99480f75d87fac34c9ad4d0125d7a2e5 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/CustomGUI/MathUtilityDrawer.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/CustomGUI/MathUtilityDrawer.cs deleted file mode 100644 index cc3b33fd..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/CustomGUI/MathUtilityDrawer.cs +++ /dev/null @@ -1,41 +0,0 @@ -using UnityEngine; -using UnityEditor; -using System; -using System.Text; - -namespace PathBerserker2d -{ - class MathUtilityDrawer : EditorWindow - { - Texture2D texture; - string[] texts = new string[] { - "WW91IGZvdW5kIGFuIGVhc3RlciBlZ2chIEdvb2Qgam9iIQ==", - "KElmIHlvdSBkaWRuJ3QganVzdCBsb29rIHRoaXMgdXAgaW4gdGhlIHNvdXJjZSBjb2RlKQ==", - "VGhlIGltYWdlIHNob3dzIHdoZXJlIFBhdGhCZXJzZXJrZXIyZCBnb3QgaXRzIG5hbWUgZnJvbS4=", - "SGFkIHRvIG9iZnVzY2F0ZSB0aGlzIGVhc3RlciBlZ2cgYSBiaXQgc2luY2UgdGhlIHJlbGVhc2Ugb2YgdGhlIHNvdXJjZSBjb2RlLiBTb3JyeSA7KQ==", - }; - - private void OnEnable() - { - #region data - byte[] imageBytes = System.Convert.FromBase64String("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"); - #endregion - texture = new Texture2D(2, 2); - texture.LoadImage(imageBytes); - } - - void OnGUI() - { - GUILayout.Label(Encoding.UTF8.GetString(Convert.FromBase64String(texts[0]))); - GUILayout.Label(Encoding.UTF8.GetString(Convert.FromBase64String(texts[1]))); - - GUILayout.Space(50); - - GUILayout.Label(Encoding.UTF8.GetString(Convert.FromBase64String(texts[2]))); - - GUILayout.Label(texture); - - GUILayout.Label(Encoding.UTF8.GetString(Convert.FromBase64String(texts[3]))); - } - } -} diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/CustomGUI/MathUtilityDrawer.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/CustomGUI/MathUtilityDrawer.cs.meta deleted file mode 100644 index 34b34780..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/CustomGUI/MathUtilityDrawer.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 0e5d17af10e083841ac8d81ba70fd984 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/CustomGUI/MyGUI.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/CustomGUI/MyGUI.cs deleted file mode 100644 index 9840912d..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/CustomGUI/MyGUI.cs +++ /dev/null @@ -1,73 +0,0 @@ -using UnityEditor; -using UnityEngine; - -namespace PathBerserker2d -{ - internal static class MyGUI - { - public static string nameSeed = "aWJhcmFraQ=="; - public static string nameSeed2 = "aWJhcl9ha2k="; - static GUIStyle horizontalLine; - - static MyGUI() - { - horizontalLine = new GUIStyle(); - horizontalLine.normal.background = EditorGUIUtility.whiteTexture; - horizontalLine.margin = new RectOffset(0, 0, 4, 4); - horizontalLine.fixedHeight = 1; - } - - // utility method - public static void HorizontalLine(Color color) - { - var c = GUI.color; - GUI.color = color; - GUILayout.Box(GUIContent.none, horizontalLine); - GUI.color = c; - } - - public static void Header(string text) - { - EditorGUILayout.LabelField(text, EditorStyles.boldLabel); - } - - public static void DrawNavTagLayout(SerializedProperty spNavTag) - { - EditorGUILayout.BeginHorizontal(); - spNavTag.intValue = EditorGUILayout.Popup("NavTag", spNavTag.intValue, PathBerserker2dSettings.NavTags); - if (GUILayout.Button("+", EditorStyles.miniButtonRight, GUILayout.Width(17))) - { - SettingsService.OpenProjectSettings(PathBerserker2dSettingsProvider.WindowPath); - } - EditorGUILayout.EndHorizontal(); - } - - public static void DrawNavTagColorPickerLayout(SerializedProperty spNavTag) - { - int tag = spNavTag.intValue; - if (tag == 0) - GUI.enabled = false; - - PathBerserker2dSettings.SetNavTagColor(tag, EditorGUILayout.ColorField("NavTag Color", PathBerserker2dSettings.GetNavTagColor(tag))); - - GUI.enabled = true; - } - - public static void ProVersionOnlyLabelLayout() - { - EditorGUILayout.LabelField(ProVersionOnly); - } - - public static void ProVersionLinkTypeLabelLayout() - { - EditorGUILayout.LabelField("Custom link types are limited to the pro-version."); - } - - public static GUIContent AddProVersionOnlyToolTipp(string label) - { - return new GUIContent(label, ProVersionOnly); - } - - public const string ProVersionOnly = "This is a pro-version only feature"; - } -} diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/CustomGUI/MyGUI.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/CustomGUI/MyGUI.cs.meta deleted file mode 100644 index 3882296f..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/CustomGUI/MyGUI.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 88926f52dae6ae348a100721fd59f003 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/CustomGUI/PositionHandle2D.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/CustomGUI/PositionHandle2D.cs deleted file mode 100644 index 1f70e998..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/CustomGUI/PositionHandle2D.cs +++ /dev/null @@ -1,137 +0,0 @@ -using UnityEngine; -using UnityEditor; - -namespace PathBerserker2d -{ - internal class PositionHandle2D - { - private Vector3 startPos; - private Vector2 currentMousePos; - private Vector2 startMousePos; - public Color primary; - public Color hover; - public Color selected; - - private int hash; - - public PositionHandle2D(Color primary, Color hover, Color selected) - { - this.primary = primary; - this.hover = hover; - this.selected = selected; - - hash = GetHashCode(); - } - - public Vector2 DrawHandle(Vector2 position) - { - int controlIdXArrow = EditorGUIUtility.GetControlID(hash, FocusType.Passive); - int controlIdYArrow = EditorGUIUtility.GetControlID(hash, FocusType.Passive); - int controlIdRect = EditorGUIUtility.GetControlID(hash, FocusType.Passive); - - bool selectedXArrow = GUIUtility.hotControl == controlIdXArrow; - bool hoveredXArrow = HandleUtility.nearestControl == controlIdXArrow; - - bool selectedYArrow = GUIUtility.hotControl == controlIdYArrow; - bool hoveredYArrow = HandleUtility.nearestControl == controlIdYArrow; - - bool selectedRect = GUIUtility.hotControl == controlIdRect; - bool hoveredRect = HandleUtility.nearestControl == controlIdRect; - - var e = Event.current; - - switch (e.type) - { - case EventType.MouseDown: - if (e.button == 0 && GUIUtility.hotControl == 0 && !e.alt) - { - if (HandleUtility.nearestControl == controlIdXArrow) - { - GUIUtility.hotControl = controlIdXArrow; - } - else if (HandleUtility.nearestControl == controlIdYArrow) - { - GUIUtility.hotControl = controlIdYArrow; - } - else if (HandleUtility.nearestControl == controlIdRect) - { - GUIUtility.hotControl = controlIdRect; - } - - - if (HandleUtility.nearestControl == controlIdXArrow || - HandleUtility.nearestControl == controlIdYArrow || - HandleUtility.nearestControl == controlIdRect) - { - startPos = position; - currentMousePos = e.mousePosition; - startMousePos = e.mousePosition; - e.Use(); - } - } - - break; - case EventType.MouseUp: - if (e.button == 0 || e.button == 2) - { - if (GUIUtility.hotControl == controlIdXArrow || GUIUtility.hotControl == controlIdYArrow || GUIUtility.hotControl == controlIdRect) - { - GUIUtility.hotControl = 0; - e.Use(); - selectedXArrow = false; - selectedYArrow = false; - selectedRect = false; - } - } - break; - case EventType.MouseDrag: - - if (GUIUtility.hotControl == controlIdXArrow || GUIUtility.hotControl == controlIdYArrow || GUIUtility.hotControl == controlIdRect) - { - currentMousePos += new Vector2(e.delta.x, -e.delta.y) * EditorGUIUtility.pixelsPerPoint; - - Vector3 screenPos = Camera.current.WorldToScreenPoint(Handles.matrix.MultiplyPoint(startPos)); - screenPos += (Vector3)(currentMousePos - startMousePos); - Vector2 newPos = Handles.inverseMatrix.MultiplyPoint(Camera.current.ScreenToWorldPoint(screenPos)); - - if (selectedXArrow) - { - newPos.y = startPos.y; - } - else if (selectedYArrow) - { - newPos.x = startPos.x; - } - - if (newPos != position) - { - position = newPos; - GUI.changed = true; - } - - e.Use(); - } - break; - } - Handles.color = selectedRect || selectedXArrow ? selected : (hoveredXArrow ? hover : primary); - Handles.ArrowHandleCap(controlIdXArrow, position, Quaternion.Euler(0, 90, 0), HandleUtility.GetHandleSize(position), e.type); - - Handles.color = selectedRect || selectedYArrow ? selected : (hoveredYArrow ? hover : primary); - Handles.ArrowHandleCap(controlIdYArrow, position, Quaternion.Euler(-90, 0, 0), HandleUtility.GetHandleSize(position), e.type); - - Handles.color = selectedRect ? selected : (hoveredRect ? hover : primary); - float rectSize = HandleUtility.GetHandleSize(position) * 0.14f; - - Vector2 rectPos = position + Vector2.one * rectSize; - if (e.type == EventType.Repaint) - Handles.DrawSolidRectangleWithOutline(new Rect(position, new Vector2(rectSize, rectSize) * 2f), new Color(1, 1, 1, 0.2f), new Color(1, 1, 1, 1)); - - rectPos = Handles.Slider2D(rectPos, Vector3.forward, Vector3.right, Vector3.up, rectSize, Handles.RectangleHandleCap, 0); - position = rectPos - Vector2.one * rectSize; - - - - return position; - } - } -} diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/CustomGUI/PositionHandle2D.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/CustomGUI/PositionHandle2D.cs.meta deleted file mode 100644 index 3c1f174d..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/CustomGUI/PositionHandle2D.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 38d3d3506e06653448c052e8936eb8dc -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/ExecutionOrderManager.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/ExecutionOrderManager.cs deleted file mode 100644 index 629e4137..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/ExecutionOrderManager.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System; -using UnityEditor; - -namespace PathBerserker2d -{ - [InitializeOnLoad] - internal class ExecutionOrderManager : Editor - { - static ExecutionOrderManager() - { - foreach (MonoScript monoScript in MonoImporter.GetAllRuntimeMonoScripts()) - { - Type type = monoScript.GetClass(); - if (type == null) - { - continue; - } - - object[] attributes = type.GetCustomAttributes(typeof(ScriptExecutionOrderAttribute), true); - - if (attributes.Length == 0) - { - continue; - } - - ScriptExecutionOrderAttribute attribute = (ScriptExecutionOrderAttribute)attributes[0]; - if (MonoImporter.GetExecutionOrder(monoScript) != attribute.GetOrder()) - { - MonoImporter.SetExecutionOrder(monoScript, attribute.GetOrder()); - } - } - } - } -} \ No newline at end of file diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/ExecutionOrderManager.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/ExecutionOrderManager.cs.meta deleted file mode 100644 index efe6814d..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/ExecutionOrderManager.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: d337207a086912840ae6fa25daa40c29 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Gizmos.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Gizmos.meta deleted file mode 100644 index 99d040d3..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Gizmos.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 8a6fbf381f5910a46b7602b805ab3da5 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Gizmos/GizmosDrawingExtensions.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Gizmos/GizmosDrawingExtensions.cs deleted file mode 100644 index 8440f782..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Gizmos/GizmosDrawingExtensions.cs +++ /dev/null @@ -1,239 +0,0 @@ -using System; -using UnityEditor; -using UnityEngine; - -namespace PathBerserker2d -{ - internal static class GizmosDrawingExtensions - { - public static void DrawArrowHead(Vector2 basePos, Vector2 dir, float size) - { - dir.Normalize(); - Vector2 normal = new Vector2(-dir.y, dir.x) * size; - Gizmos.DrawLine(basePos - normal, basePos + normal); - Gizmos.DrawLine(basePos - normal, basePos + dir * size); - Gizmos.DrawLine(basePos + normal, basePos + dir * size); - } - - public static void DrawArrowHeadFromSpike(Vector2 pointyPos, Vector2 dir, float size) - { - dir.Normalize(); - pointyPos -= dir * size; - Vector2 normal = new Vector2(-dir.y, dir.x) * size; - Gizmos.DrawLine(pointyPos - normal, pointyPos + normal); - Gizmos.DrawLine(pointyPos - normal, pointyPos + dir * size); - Gizmos.DrawLine(pointyPos + normal, pointyPos + dir * size); - } - - public static void DrawArrow(Vector2 start, Vector2 end, float size) - { - Vector2 dir = end - start; - float length = dir.magnitude; - dir /= length; - - Vector3 end3 = new Vector3(end.x, end.y); - Gizmos.DrawLine(start, end3); - - Vector2 normal = new Vector2(-dir.y, dir.x) * size; - Vector2 baseA = start + dir * (length - size); - Gizmos.DrawLine(baseA - normal, end3); - Gizmos.DrawLine(baseA + normal, end3); - } - - public static void DrawCircle(Vector2 center, float radius = 0.05f) - { - int segmentCount = 10; - Vector2 prevPoint = center + Vector2.up * radius; - - for (float t = 1; t <= segmentCount; t++) - { - float x = (t / segmentCount) * Mathf.PI * 2.0f; - float cx = Mathf.Sin(x); - float cy = Mathf.Cos(x); - - Vector2 point = center + new Vector2(cx, cy) * radius; - Gizmos.DrawLine(prevPoint, point); - prevPoint = point; - } - Gizmos.DrawLine(prevPoint, center + Vector2.up * radius); - } - - public static void DrawBezierConnection(Vector2 start, Vector2 end, bool biDirectional) - { - Vector2 cp; - var tangent = (end - start); - var length = tangent.magnitude; - var normal = new Vector2(-tangent.y, tangent.x) / length; - cp = start + tangent * 0.5f + normal * (length / 5f); - - DrawBezierConnection(start, end, cp, biDirectional); - } - - public static void DrawBezierConnection(Vector2 start, Vector2 end, Vector2 cp, bool biDirectional) - { - float arcLength = (Vector2.Distance(end, start) * 2 + Vector2.Distance(end, cp) + Vector2.Distance(start, cp)) / 3f; - int numberOfSegments = Mathf.CeilToInt(arcLength) + 4; - Vector2 prev = start; - float t; - for (t = 1; t <= numberOfSegments; t++) - { - Vector2 v = QuadraticBezierCurve(t / numberOfSegments, start, cp, end); - Gizmos.DrawLine(prev, v); - prev = v; - } - - //draw arrows - t = (numberOfSegments - 1) / (float)numberOfSegments; - Vector2 dir = end - QuadraticBezierCurve(t, start, cp, end); - DrawArrowHeadFromSpike(end, dir, 0.2f); - if (biDirectional) - { - dir = start - QuadraticBezierCurve(1f / numberOfSegments, start, cp, end); - DrawArrowHeadFromSpike(start, dir, 0.2f); - } - } - - public static void DrawBezierConnectionWithOffset(Vector2 start, Vector2 end, Vector2 cp, Vector2 offset) - { - float arcLength = (Vector2.Distance(end, start) * 2 + Vector2.Distance(end, cp) + Vector2.Distance(start, cp)) / 3f; - int numberOfSegments = Mathf.CeilToInt(arcLength); - Vector2 prev = start + offset; - Gizmos.DrawLine(start, prev); - float t; - for (t = 1; t <= numberOfSegments; t++) - { - Vector2 v = QuadraticBezierCurve(t / numberOfSegments, start, cp, end) + offset; - Gizmos.DrawLine(v, v - offset); - Gizmos.DrawLine(prev, v); - prev = v; - } - } - - public static void DrawProjectileArc(Vector2 start, Vector2 end, float hSpeed, bool isBidiretional) - { - float hDelta = end.x - start.x; - float t = hDelta / hSpeed; - int numberOfSegments = Mathf.CeilToInt(t) + 4; - float p0 = start.y - end.y; - float v0 = 9.81f * t * 0.5f - p0 / t; - - Func func = x => 0.5f * -9.81f * x * x + v0 * x + p0; - - Vector2 prev = start; - float z; - float timePerSegment = t / numberOfSegments; - for (z = 1; z <= numberOfSegments; z++) - { - Vector2 v = new Vector2(start.x + z * timePerSegment * hSpeed, end.y + func(z * timePerSegment)); - Gizmos.DrawLine(prev, v); - prev = v; - } - - Vector2 dir = end - new Vector2(start.x + (numberOfSegments - 1) * timePerSegment * hSpeed, end.y + func((numberOfSegments - 1) * timePerSegment)); - DrawArrowHeadFromSpike(end, dir, 0.2f); - if (isBidiretional) - { - dir = start - new Vector2(start.x + timePerSegment * hSpeed, end.y + func(timePerSegment)); - DrawArrowHeadFromSpike(start, dir, 0.2f); - } - } - - public static void DrawJumpArc(Vector2 start, Vector2 end, float jumpSpeed, bool isBidiretional) - { - Vector2 dir = end - start; - float distance = dir.magnitude; - dir /= distance; - Vector2 prev = start; - int numberOfSegments = Mathf.CeilToInt(distance) + 4; - float timeToCompleteLink = distance / jumpSpeed; - - Vector2 CalcPointAt(float t) - { - Vector2 v = start + dir * t * jumpSpeed; - v.y += distance * 0.3f * Mathf.Sin(Mathf.PI * t / timeToCompleteLink); - return v; - } - - float timePerSegment = distance / numberOfSegments; - for (int z = 1; z <= numberOfSegments; z++) - { - float t = z * timePerSegment; - Vector2 v = CalcPointAt(t); - Gizmos.DrawLine(prev, v); - prev = v; - } - - - prev = CalcPointAt((numberOfSegments - 1) * timePerSegment); - DrawArrowHeadFromSpike(end, end - prev, 0.2f); - if (isBidiretional) - { - prev = CalcPointAt(timePerSegment); - DrawArrowHeadFromSpike(start, start - prev, 0.2f); - } - } - - public static void DrawProjectileArcWithOffset(Vector2 start, Vector2 end, float hSpeed, Vector2 offset) - { - float hDelta = end.x - start.x; - float t = hDelta / hSpeed; - int numberOfSegments = Mathf.CeilToInt(t) + 4; - float p0 = start.y - end.y; - float v0 = 9.81f * t * 0.5f - p0 / t; - - Func func = x => 0.5f * -9.81f * x * x + v0 * x + p0; - - Vector2 prev = start + offset; - Gizmos.DrawLine(start, prev); - float z; - float timePerSegment = t / numberOfSegments; - for (z = 1; z <= numberOfSegments; z++) - { - Vector2 v = new Vector2(start.x + z * timePerSegment * hSpeed, end.y + func(z * timePerSegment)) + offset; - Gizmos.DrawLine(prev, v); - Gizmos.DrawLine(v, v - offset); - prev = v; - } - } - - private static Vector2 QuadraticBezierCurve(float t, Vector2 a, Vector2 b, Vector2 c) - { - return (1 - t) * (1 - t) * a + 2 * (1 - t) * t * b + t * t * c; - } - - public static Color LinearBlendBetweenColors(float value, params Color[] colors) - { - value = Mathf.Clamp01(value); - int index = (int)(value * (colors.Length - 1)); - float t = (value * (colors.Length - 1)) - index; - Color b = index >= colors.Length - 1 ? colors[index] : colors[index + 1]; - return Color.Lerp(colors[index], b, t); - } - - public static void DrawRect(Vector2 position, Vector2 size) - { - Gizmos.DrawLine(position + size, new Vector3(position.x, position.y + size.y)); - Gizmos.DrawLine(position, new Vector3(position.x, position.y + size.y)); - Gizmos.DrawLine(position + size, new Vector3(position.x + size.x, position.y)); - Gizmos.DrawLine(position, new Vector3(position.x + size.x, position.y)); - } - - public static void DrawRect(Rect rect) - { - Gizmos.DrawLine(rect.position + rect.size, new Vector3(rect.position.x, rect.position.y + rect.size.y)); - Gizmos.DrawLine(rect.position, new Vector3(rect.position.x, rect.position.y + rect.size.y)); - Gizmos.DrawLine(rect.position + rect.size, new Vector3(rect.position.x + rect.size.x, rect.position.y)); - Gizmos.DrawLine(rect.position, new Vector3(rect.position.x + rect.size.x, rect.position.y)); - } - - public static void SetColor(Color color) - { - Handles.color = color; - } - - public static void DrawDottedLine(Vector2 a, Vector2 b, float screenSpaceSize = 3) - { - Handles.DrawDottedLine(a, b, screenSpaceSize); - } - } -} diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Gizmos/GizmosDrawingExtensions.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Gizmos/GizmosDrawingExtensions.cs.meta deleted file mode 100644 index eae73d50..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Gizmos/GizmosDrawingExtensions.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 492511a86fc803947bc65e80cb38dcd1 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Gizmos/NavAgentDrawer.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Gizmos/NavAgentDrawer.cs deleted file mode 100644 index 9a68d9e4..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Gizmos/NavAgentDrawer.cs +++ /dev/null @@ -1,94 +0,0 @@ -using UnityEditor; -using UnityEngine; - -namespace PathBerserker2d -{ - internal static class NavAgentDrawer - { - [DrawGizmo(GizmoType.Selected | GizmoType.Pickable)] - static void DrawGizmos(NavAgent src, GizmoType gizmoType) - { - Gizmos.color = Color.green; - if (!Application.IsPlaying(src)) - { - Vector2 adjustedPosition = src.transform.position; - Gizmos.DrawRay(adjustedPosition, src.transform.up * src.Height); - Gizmos.DrawLine(adjustedPosition + -(Vector2)src.transform.right * 0.2f, adjustedPosition + (Vector2)src.transform.right * 0.2f); - } - else if(!src.currentMappedPosition.IsInvalid()) - { - Gizmos.color = Color.magenta; - GizmosDrawingExtensions.DrawCircle( src.currentMappedPosition.Position); - } - - if (src.IsFollowingAPath) - { - int hash = Mathf.Abs(src.GetHashCode()); - float offset = ((hash % 100f) - 50f) / 200f; - Color color = DifferentColors.GetColor(hash); - - if (src.IsOnLink) - { - DrawPath(src.Path, src.Path.Current.LinkStart, src.Height / 2f + offset, color); - } - else - { - DrawPath(src.Path, src.transform.position, src.Height / 2f + offset, color); - } - } - } - - static void DrawPath(Path path, Vector2 startPoint, float lineHeight, Color color) - { - Gizmos.color = color; - var seg = path.Current; - Vector2 lineA = startPoint + seg.Normal * lineHeight; - - while (seg != null) - { - Vector2 lineB = seg.LinkStart + seg.Normal * lineHeight; - if (seg.Next == null) - { - Gizmos.DrawLine(lineA, lineB); - lineA = lineB; - - GizmosDrawingExtensions.DrawCircle(lineB, 0.2f); - GizmosDrawingExtensions.DrawCircle(lineB, 0.3f); - } - else - { - if (seg.link.LinkType == -1) - { - Vector2 oLineA = seg.LinkEnd + seg.Next.Normal * lineHeight; - Vector2 oLineB = seg.Next.LinkStart + seg.Next.Normal * lineHeight; - - // calc intersection - Vector2 inter; - if (ExtendedGeometry.FindLineIntersection(lineA, lineB, oLineA, oLineB, out inter)) - { - lineB = inter; - Gizmos.DrawLine(lineA, lineB); - lineA = lineB; - } - else - { - Gizmos.DrawLine(lineB, oLineA); - Gizmos.DrawLine(lineA, lineB); - lineA = oLineA; - } - } - else - { - Gizmos.DrawLine(lineA, lineB); - lineA = lineB; - - lineB = seg.LinkEnd + seg.Next.Normal * lineHeight; - Gizmos.DrawLine(lineA, lineB); - lineA = lineB; - } - } - seg = seg.Next; - } - } - } -} diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Gizmos/NavAgentDrawer.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Gizmos/NavAgentDrawer.cs.meta deleted file mode 100644 index f1b40caa..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Gizmos/NavAgentDrawer.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 723a305b61a51e64ebec0506f93c1112 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Gizmos/NavAreaMarkerDrawer.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Gizmos/NavAreaMarkerDrawer.cs deleted file mode 100644 index 011a3ce9..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Gizmos/NavAreaMarkerDrawer.cs +++ /dev/null @@ -1,29 +0,0 @@ -using UnityEditor; -using UnityEngine; - -namespace PathBerserker2d -{ - internal static class NavAreaMarkerDrawer - { - static Vector3[] worldCorners = new Vector3[4]; - - [DrawGizmo(GizmoType.Selected | GizmoType.NonSelected | GizmoType.Pickable)] - private static void DrawGizmos(NavAreaMarker src, GizmoType gizmoType) - { - if (!Application.IsPlaying(src) && ((gizmoType & GizmoType.Selected) != 0 || PathBerserker2dSettings.DrawUnselectedAreaMarkers)) - { - var rT = src.GetComponent(); - - Color c = src.MarkerColor; - c.a = 0.4f; - - SharedMaterials.UnlitTransparentTinted.SetColor(SharedMaterials.UnlitTransparentTinted_ColorId, c); - SharedMaterials.UnlitTransparentTinted.SetPass(0); - - var m = rT.localToWorldMatrix * Matrix4x4.TRS(rT.rect.min, Quaternion.identity, rT.rect.size); - m.m23 = 2; - Graphics.DrawMeshNow(PrimitiveMesh.Quad, m); - } - } - } -} diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Gizmos/NavAreaMarkerDrawer.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Gizmos/NavAreaMarkerDrawer.cs.meta deleted file mode 100644 index 801154ce..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Gizmos/NavAreaMarkerDrawer.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: ed60b9cfa1889ff4f8241ad268f4075f -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Gizmos/NavGraphDrawer.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Gizmos/NavGraphDrawer.cs deleted file mode 100644 index 56109210..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Gizmos/NavGraphDrawer.cs +++ /dev/null @@ -1,56 +0,0 @@ -using UnityEngine; - -namespace PathBerserker2d -{ - internal static class NavGraphDrawer - { - public static void Draw(NavGraph graph) - { - Matrix4x4 oldMatrix = Gizmos.matrix; - Gizmos.matrix = Matrix4x4.identity; - - SharedMaterials.UnlitStripped.SetFloat(SharedMaterials.UnlitStripped_SegmentSizeId, 0.08f); - SharedMaterials.UnlitStripped.SetFloat(SharedMaterials.UnlitStripped_PauseSizeId, 0.08f * (PathBerserker2dSettings.NavTags.Length - 2)); - - // draw segments - foreach (var pair in graph.segmentTrees) - { - foreach (var cluster in pair.Value.Clusters) - { - DrawCluster(cluster, pair.Value.WorldToLocal.inverse); - } - - // navsurface can be destroyed before onDisable on navsurface is called - if (pair.Key != null) - NavSurfaceDrawer.DrawNavSurface(pair.Key); - } - Gizmos.matrix = oldMatrix; - } - - private static void DrawCluster(NavGraphNodeCluster cluster, Matrix4x4 clusterLocalToWorld) - { - float areaMarkerLineWidth = PathBerserker2dSettings.NavAreaMarkerLineWidth; - foreach (var mod in cluster.modifiers) - { - Vector2 a = cluster.GetPositionAlongSegment(mod.T); - Vector2 b = cluster.GetPositionAlongSegment(mod.T + mod.Length); - Vector2 tangent = b - a; - Quaternion rot = Quaternion.Euler(0, 0, Vector2.SignedAngle(Vector2.right, tangent)); - SharedMaterials.UnlitStripped.SetFloat(SharedMaterials.UnlitStripped_XOffsetId, 0.08f * mod.NavTag); - SharedMaterials.UnlitStripped.SetColor(SharedMaterials.UnlitStripped_ColorId, PathBerserker2dSettings.GetNavTagColor(mod.NavTag)); - SharedMaterials.UnlitStripped.SetPass(0); - Graphics.DrawMeshNow(PrimitiveMesh.Quad, clusterLocalToWorld * Matrix4x4.TRS(a, rot, new Vector3(tangent.magnitude, areaMarkerLineWidth))); - } - - for (int iNode = 0; iNode < cluster.nodes.Count; iNode++) - { - var node = cluster.nodes[iNode]; - var link = node.link; - - if (link.LinkType > 0) - NavLinkInstanceDrawer.Draw(link, cluster.owner.LocalToWorld.MultiplyPoint3x4(cluster.GetPositionAlongSegment(node.t)), - node.LinkTarget.owner.LocalToWorld.MultiplyPoint3x4(node.LinkTarget.GetPositionAlongSegment(node.LinkTargetT))); - } - } - } -} diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Gizmos/NavGraphDrawer.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Gizmos/NavGraphDrawer.cs.meta deleted file mode 100644 index 111e5b05..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Gizmos/NavGraphDrawer.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 15cdcbb829a70c74fb474d4fdee8f45f -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Gizmos/NavLinkClusterGizmosDrawer.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Gizmos/NavLinkClusterGizmosDrawer.cs deleted file mode 100644 index 77c7f043..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Gizmos/NavLinkClusterGizmosDrawer.cs +++ /dev/null @@ -1,60 +0,0 @@ -using UnityEditor; -using UnityEngine; -using static PathBerserker2d.NavLinkCluster; - -namespace PathBerserker2d -{ - internal class NavLinkClusterGizmosDrawer - { - private static Color[] lineTraversalColors = new Color[] { Color.red, Color.green, Color.blue }; - - [DrawGizmo(GizmoType.Selected | GizmoType.NonSelected | GizmoType.Pickable)] - static void DrawGizmos(NavLinkCluster src, GizmoType gizmoType) - { - if ((!PathBerserker2dSettings.DrawUnselectedLinks || (gizmoType & GizmoType.Selected) != 0)) - { - Gizmos.DrawIcon(src.transform.position, "PathBerserker2D/link_icon.png"); - } - if ((gizmoType & GizmoType.Selected) != 0 || (PathBerserker2dSettings.DrawUnselectedLinks && - !Application.IsPlaying(src))) - Draw(src); - } - - public static void Draw(NavLinkCluster link) - { - var m = Gizmos.matrix; - Gizmos.matrix = Matrix4x4.Translate(new Vector3(0, 0, link.transform.position.z)); - - Gizmos.color = Color.green; - GizmosDrawingExtensions.DrawCircle(link.transform.position); - Gizmos.color = Color.white; - - foreach (var points in link.LinkPoints) - { - Vector2 worldPoint = link.transform.TransformPoint(points.point); - Gizmos.color = PathBerserker2dSettings.NavLinkTypeColors[link.LinkType]; - Gizmos.DrawLine((Vector2)link.transform.position, worldPoint); - Vector2 dir = ((Vector2)link.transform.position - worldPoint).normalized; - - Gizmos.color = lineTraversalColors[(int)points.traversalType]; - if (points.traversalType == PointTraversalType.Entry || points.traversalType == PointTraversalType.Both) - { - GizmosDrawingExtensions.DrawArrowHead(worldPoint, dir, 0.2f); - if (points.traversalType == PointTraversalType.Exit || points.traversalType == PointTraversalType.Both) - GizmosDrawingExtensions.DrawArrowHead(worldPoint + dir * 0.2f, -dir, 0.2f); - } - else if (points.traversalType == PointTraversalType.Exit || points.traversalType == PointTraversalType.Both) - GizmosDrawingExtensions.DrawArrowHead(worldPoint, -dir, 0.2f); - } - - Gizmos.matrix = m; - if (link.LinkTypeName == "climb") - { - Vector3 pos = link.gameObject.transform.position; - Vector3 dir = link.gameObject.transform.up; - Gizmos.color = Color.grey; - Gizmos.DrawLine(pos - dir * 0.5f * 2, pos + dir * 0.5f * 2); - } - } - } -} diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Gizmos/NavLinkClusterGizmosDrawer.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Gizmos/NavLinkClusterGizmosDrawer.cs.meta deleted file mode 100644 index 0261d54d..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Gizmos/NavLinkClusterGizmosDrawer.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: f77a85715899ecd40946b0b29b2d294f -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Gizmos/NavLinkGizmosDrawer.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Gizmos/NavLinkGizmosDrawer.cs deleted file mode 100644 index 6af77c5b..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Gizmos/NavLinkGizmosDrawer.cs +++ /dev/null @@ -1,129 +0,0 @@ -using UnityEditor; -using UnityEngine; -using static PathBerserker2d.NavLink; - -namespace PathBerserker2d -{ - [InitializeOnLoad] - internal static class NavLinkGizmosDrawer - { - static string linkFileName = "Assets/PathBerserker2d/Icons/link_icon.png"; - static Texture2D linkTexture; - - static NavLinkGizmosDrawer() - { - linkTexture = AssetDatabase.LoadAssetAtPath(linkFileName); - } - - [DrawGizmo(GizmoType.Selected | GizmoType.NonSelected | GizmoType.Pickable)] - static void DrawGizmos(NavLink src, GizmoType gizmoType) - { - /* - if ((gizmoType & GizmoType.Selected) != 0 || PathBerserker2dSettings.DrawUnselectedLinks) - { - if (src.CurrentVisualizationType == NavLink.VisualizationType.Teleport) - { - Gizmos.DrawIcon(src.StartWorldPosition, "PathBerserker2d/Gizmos/portal.png"); - Gizmos.DrawIcon(src.GoalWorldPosition, "PathBerserker2D/portal.png"); - } - else - { - //Gizmos.DrawIcon((src.GoalWorldPosition - src.StartWorldPosition) * 0.5f + src.StartWorldPosition, linkGizmoFileName); - if (linkTexture != null) - IconHandle2D.DrawHandle((src.GoalWorldPosition - src.StartWorldPosition) * 0.5f + src.StartWorldPosition, linkTexture, 0.5f, src); - } - } - */ - bool isSelected = (gizmoType & GizmoType.Selected) != 0; - if (isSelected || (PathBerserker2dSettings.DrawUnselectedLinks && - !Application.IsPlaying(src))) - Draw(src, isSelected); - } - - public static void Draw(NavLink link, bool isSelected) - { - var m = Gizmos.matrix; - Gizmos.matrix = Matrix4x4.Translate(new Vector3(0, 0, link.transform.position.z)); - Gizmos.color = PathBerserker2dSettings.GetLinkTypeColor(link.LinkType); - switch (link.CurrentVisualizationType) - { - case VisualizationType.Linear: - Vector2 dir = (link.GoalWorldPosition - link.StartWorldPosition).normalized; - if (link.IsBidirectional) - { - GizmosDrawingExtensions.DrawArrowHead(link.StartWorldPosition + dir * 0.2f, -dir, 0.2f); - } - else - { - Vector2 normal = new Vector2(-dir.y, dir.x) * 0.3f; - Gizmos.DrawLine(link.StartWorldPosition + normal, link.StartWorldPosition - normal); - } - Gizmos.DrawLine(link.StartWorldPosition, link.GoalWorldPosition); - GizmosDrawingExtensions.DrawArrowHead(link.GoalWorldPosition - dir * 0.2f, dir, 0.2f); - - if (isSelected) - { - Vector2 offset = Quaternion.Euler(0, 0, link.TraversalAngle) * Vector3.up * link.Clearance; - - Gizmos.color = Color.green; - Gizmos.DrawLine(link.StartWorldPosition + offset, link.GoalWorldPosition + offset); - - float length = (link.GoalWorldPosition - link.StartWorldPosition).magnitude; - Gizmos.DrawLine(link.StartWorldPosition, link.StartWorldPosition + offset); - for (float t = 2; t <= length - 2; t += 2) - { - Gizmos.DrawLine(link.StartWorldPosition + dir * t, link.StartWorldPosition + offset + dir * t); - } - Gizmos.DrawLine(link.GoalWorldPosition, link.GoalWorldPosition + offset); - } - - break; - case VisualizationType.QuadradticBezier: - GizmosDrawingExtensions.DrawBezierConnection( - link.StartWorldPosition, - link.GoalWorldPosition, - link.transform.TransformPoint(link.BezierControlPoint), - link.IsBidirectional); - - if (isSelected) - { - Vector2 offset = Quaternion.Euler(0, 0, link.TraversalAngle) * Vector3.up * link.Clearance; - - Gizmos.color = Color.green; - GizmosDrawingExtensions.DrawBezierConnectionWithOffset( - link.StartWorldPosition, - link.GoalWorldPosition, - (Vector2)link.transform.TransformPoint(link.BezierControlPoint), - offset); - } - break; - case VisualizationType.Projectile: - GizmosDrawingExtensions.DrawProjectileArc(link.StartWorldPosition, link.GoalWorldPosition, link.HorizontalSpeed, link.IsBidirectional); - if (isSelected) - { - Vector2 offset = Quaternion.Euler(0, 0, link.TraversalAngle) * Vector3.up * link.Clearance; - - Gizmos.color = Color.green; - GizmosDrawingExtensions.DrawProjectileArcWithOffset( - link.StartWorldPosition, link.GoalWorldPosition, link.HorizontalSpeed, - offset); - } - break; - case VisualizationType.Teleport: - break; - case VisualizationType.TransformBasedMovement: - GizmosDrawingExtensions.DrawJumpArc(link.StartWorldPosition, link.GoalWorldPosition, link.HorizontalSpeed, link.IsBidirectional); - break; - } - Gizmos.matrix = m; - - if (link.LinkTypeName == "climb") - { - Vector3 pos = link.gameObject.transform.position; - Vector3 dir = link.gameObject.transform.up; - Gizmos.color = Color.grey; - Gizmos.DrawLine(pos - dir * 0.5f * 2, pos + dir * 0.5f * 2); - } - } - } -} diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Gizmos/NavLinkGizmosDrawer.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Gizmos/NavLinkGizmosDrawer.cs.meta deleted file mode 100644 index d4cb0de9..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Gizmos/NavLinkGizmosDrawer.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 329c6c7610e18854cbfdf1038774b22f -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Gizmos/NavLinkInstanceDrawer.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Gizmos/NavLinkInstanceDrawer.cs deleted file mode 100644 index 83b074ab..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Gizmos/NavLinkInstanceDrawer.cs +++ /dev/null @@ -1,13 +0,0 @@ -using UnityEngine; - -namespace PathBerserker2d -{ - internal static class NavLinkInstanceDrawer - { - public static void Draw(INavLinkInstance link, Vector2 worldStartPos, Vector2 worldGoalPos) - { - Gizmos.color = PathBerserker2dSettings.GetLinkTypeColor(link.LinkType); - GizmosDrawingExtensions.DrawArrow(worldStartPos, worldGoalPos, 0.2f); - } - } -} diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Gizmos/NavLinkInstanceDrawer.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Gizmos/NavLinkInstanceDrawer.cs.meta deleted file mode 100644 index ad0dd3fa..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Gizmos/NavLinkInstanceDrawer.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: dae66614c81006d4fa5cbb26894dd989 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Gizmos/NavSegmentSubstractorDrawer.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Gizmos/NavSegmentSubstractorDrawer.cs deleted file mode 100644 index 2f5716f2..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Gizmos/NavSegmentSubstractorDrawer.cs +++ /dev/null @@ -1,28 +0,0 @@ -using UnityEditor; -using UnityEngine; - -namespace PathBerserker2d -{ - internal static class NavSegmentSubstractorDrawer - { - [DrawGizmo(GizmoType.Selected | GizmoType.NonSelected | GizmoType.Pickable)] - private static void DrawGizmos(NavSegmentSubstractor src, GizmoType gizmoType) - { - if ((gizmoType & GizmoType.Selected) != 0 || PathBerserker2dSettings.DrawUnselectedSubstractors) - { - Gizmos.color = Color.red; - - var rT = src.GetComponent(); - var r = rT.rect; - Vector2 scaleFactor = rT.lossyScale * r.size * 0.5f; - Vector2 center = r.center; - - r.min = center - scaleFactor + (Vector2)rT.position; - r.max = center + scaleFactor + (Vector2)rT.position; - - GizmosDrawingExtensions.DrawRect(r); - Gizmos.DrawLine(r.max, r.min); - } - } - } -} diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Gizmos/NavSegmentSubstractorDrawer.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Gizmos/NavSegmentSubstractorDrawer.cs.meta deleted file mode 100644 index 63b14d72..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Gizmos/NavSegmentSubstractorDrawer.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 639e10eb7c848df40b745a7e356f1f87 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Gizmos/NavSurfaceDrawer.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Gizmos/NavSurfaceDrawer.cs deleted file mode 100644 index a59a29d3..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Gizmos/NavSurfaceDrawer.cs +++ /dev/null @@ -1,135 +0,0 @@ -using System.Collections.Generic; -using UnityEditor; -using UnityEngine; - -namespace PathBerserker2d -{ - internal static class NavSurfaceDrawer - { - [DrawGizmo(GizmoType.Selected | GizmoType.NonSelected | GizmoType.Pickable)] - public static void DrawGizmos(NavSurface surface, GizmoType gizmoType) - { - if (surface.NavSegments != null && !Application.IsPlaying(surface) && (PathBerserker2dSettings.DrawUnselectedSurfaces || (gizmoType & GizmoType.Selected) != 0)) - { - DrawNavSurface(surface); -#if PBDEBUG - GizmosDrawingExtensions.DrawRect(surface.WorldBounds); -#endif - } - } - - private static bool[] visited; - private static Dictionary> miterLinesMap; - public static void DrawNavSurface(NavSurface surface) - { - if (miterLinesMap == null) - miterLinesMap = new Dictionary>(); - - List miterLines = null; - miterLinesMap.TryGetValue(surface, out miterLines); - - if (surface.hasDataChanged || miterLines == null) - { - if (visited == null || visited.Length < surface.NavSegments.Count) - { - visited = new bool[surface.NavSegments.Count]; - } - else - { - for (int i = 0; i < visited.Length; i++) - { - visited[i] = false; - } - } - - var miterCreator = new MiterLineMeshCreator(); - bool newMiterLines = miterLines == null; - if (newMiterLines) - miterLines = new List(); - - int lineCount = 0; - for (int i = 0; i < surface.NavSegments.Count; i++) - { - if (!visited[i]) - { - var points = GatherContourPoints(surface, surface.NavSegments[i], ref visited); - - if (lineCount >= miterLines.Count) - { - miterLines.Add(new Mesh()); - } - if (miterLines[lineCount] == null) - miterLines[lineCount] = new Mesh(); - miterCreator.CreateLine(miterLines[lineCount], points, PathBerserker2dSettings.NavSurfaceLineWidth, new Color32(204, 65, 255, 255), new Color32(255, 178, 10, 255), new Color32(98, 81, 255, 255)); - lineCount++; - } - } - - // clean up unused meshs - for (int i = miterLines.Count - 1; i >= lineCount; i--) - { - GameObject.DestroyImmediate(miterLines[i]); - miterLines.RemoveAt(i); - } - - if (newMiterLines) - miterLinesMap.Add(surface, miterLines); - surface.hasDataChanged = false; - } - - SharedMaterials.UnlitVertexColorSolid.SetPass(0); - if (miterLines.Count > 0 && miterLines[0] == null) - { - // edge case after assembly reload the meshs get thrown out - miterLinesMap.Clear(); - return; - } - foreach (var ml in miterLines) - { - Graphics.DrawMeshNow(ml, surface.LocalToWorldMatrixEditor); - } - } - - private static List GatherContourPoints(NavSurface surface, NavSegment initialSeg, ref bool[] visited) - { - List contourPoints = new List(); - if (!initialSeg.HasPrev) - { - contourPoints.Add(initialSeg.Start); - } - - contourPoints.Add(initialSeg.End); - - NavSegment seg = initialSeg; - while (seg.HasNext && !visited[seg.NextSegmentIndex]) - { - visited[seg.NextSegmentIndex] = true; - seg = surface.NavSegments[seg.NextSegmentIndex]; - - contourPoints.Add(seg.End); - } - - - if (initialSeg.HasPrev && !visited[initialSeg.PrevSegmentIndex]) - { - // we might have missed segments to the left get em - List leftPoints = new List(); - seg = initialSeg; - while (seg.HasPrev) - { - visited[seg.PrevSegmentIndex] = true; - seg = surface.NavSegments[seg.PrevSegmentIndex]; - - leftPoints.Add(seg.End); - } - leftPoints.Add(seg.Start); - - leftPoints.Reverse(); - leftPoints.AddRange(contourPoints); - contourPoints = leftPoints; - } - - return contourPoints; - } - } -} diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Gizmos/NavSurfaceDrawer.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Gizmos/NavSurfaceDrawer.cs.meta deleted file mode 100644 index da72a6cc..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Gizmos/NavSurfaceDrawer.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 68c53e164cc0a494d81ff4bcf63313b9 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Gizmos/PBWorldDrawer.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Gizmos/PBWorldDrawer.cs deleted file mode 100644 index 5a43ff90..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Gizmos/PBWorldDrawer.cs +++ /dev/null @@ -1,17 +0,0 @@ -using UnityEditor; -using UnityEngine; - -namespace PathBerserker2d -{ - internal class PBWorldDrawer - { - [DrawGizmo(GizmoType.Selected | GizmoType.NonSelected | GizmoType.Pickable)] - static void DrawGizmos(PBWorld src, GizmoType gizmoType) - { - if (PathBerserker2dSettings.DrawGraphWhilePlaying && PBWorld.NavGraph != null) - { - NavGraphDrawer.Draw(PBWorld.NavGraph); - } - } - } -} diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Gizmos/PBWorldDrawer.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Gizmos/PBWorldDrawer.cs.meta deleted file mode 100644 index 6f6dabf3..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Gizmos/PBWorldDrawer.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 998c038260d5d72468b1e7310af820c4 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Inspectors.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Inspectors.meta deleted file mode 100644 index e9dd73b2..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Inspectors.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: ef995227ea241d8438a3ed5b3425be5e -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Inspectors/BaseNavLinkInspector.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Inspectors/BaseNavLinkInspector.cs deleted file mode 100644 index 0d634cc3..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Inspectors/BaseNavLinkInspector.cs +++ /dev/null @@ -1,66 +0,0 @@ -using UnityEngine; -using UnityEditor; -using System; - -namespace PathBerserker2d -{ - internal class BaseNavLinkInspector : Editor - { - protected SerializedProperty spCostOverride; - protected SerializedProperty spClearance; - protected SerializedProperty spAvgWaitTime; - protected SerializedProperty spMaxTraversableDistance; - SerializedProperty spLinkType; - protected SerializedProperty spNavTag; - protected SerializedProperty spAutoMap; - string[] filteredLinkTypes; - private static bool advancedOpen; - - public virtual void OnEnable() - { - spCostOverride = serializedObject.FindProperty("costOverride"); - spLinkType = serializedObject.FindProperty("linkType"); - spClearance = serializedObject.FindProperty("clearance"); - spNavTag = serializedObject.FindProperty("navTag"); - spAvgWaitTime = serializedObject.FindProperty("avgWaitTime"); - spMaxTraversableDistance = serializedObject.FindProperty("maxTraversableDistance"); - spAutoMap = serializedObject.FindProperty("autoMap"); - - filteredLinkTypes = new string[PathBerserker2dSettings.NavLinkTypeNames.Length - 1]; - Array.Copy(PathBerserker2dSettings.NavLinkTypeNames, 1, filteredLinkTypes, 0, filteredLinkTypes.Length); - } - - protected void DrawLinkTypeField() - { - EditorGUILayout.BeginHorizontal(); - - if (filteredLinkTypes.Length != PathBerserker2dSettings.NavLinkTypeNames.Length - 1) - { - filteredLinkTypes = new string[PathBerserker2dSettings.NavLinkTypeNames.Length - 1]; - Array.Copy(PathBerserker2dSettings.NavLinkTypeNames, 1, filteredLinkTypes, 0, filteredLinkTypes.Length); - } - spLinkType.intValue = EditorGUILayout.Popup("Link Type", spLinkType.intValue - 1, filteredLinkTypes) + 1; - if (GUILayout.Button("+", EditorStyles.miniButtonRight, GUILayout.Width(17))) - { - SettingsService.OpenProjectSettings(PathBerserker2dSettingsProvider.WindowPath); - } - EditorGUILayout.EndHorizontal(); - } - - protected void DrawAdvancedSection() - { - advancedOpen = EditorGUILayout.Foldout(advancedOpen, "Advanced"); - if (advancedOpen) - { - DrawAdvancedOptions(); - } - } - - protected virtual void DrawAdvancedOptions() - { - EditorGUILayout.PropertyField(spCostOverride); - EditorGUILayout.PropertyField(spAvgWaitTime); - EditorGUILayout.PropertyField(spMaxTraversableDistance); - } - } -} \ No newline at end of file diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Inspectors/BaseNavLinkInspector.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Inspectors/BaseNavLinkInspector.cs.meta deleted file mode 100644 index 0b3c8e87..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Inspectors/BaseNavLinkInspector.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 5d058cde802ff674eb7997fc35128da9 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Inspectors/FootStepSoundsInspector.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Inspectors/FootStepSoundsInspector.cs deleted file mode 100644 index eca233d8..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Inspectors/FootStepSoundsInspector.cs +++ /dev/null @@ -1,61 +0,0 @@ -using System; -using UnityEditor; -using UnityEditorInternal; -using UnityEngine; - -namespace PathBerserker2d.Examples -{ - [CustomEditor(typeof(FootStepSounds))] - public class FootStepSoundsInspector : Editor - { - SerializedProperty spAudioSource; - SerializedProperty spAgent; - SerializedProperty spFootStepDelay; - SerializedProperty spDefaultFootstep; - SerializedProperty spFootstepSounds; - ReorderableList footstepList; - - public void OnEnable() - { - spAudioSource = serializedObject.FindProperty("audioSource"); - spAgent = serializedObject.FindProperty("agent"); - spFootStepDelay = serializedObject.FindProperty("footStepDelay"); - spDefaultFootstep = serializedObject.FindProperty("defaultFootstep"); - spFootstepSounds = serializedObject.FindProperty("footstepSounds"); - - footstepList = new ReorderableList(serializedObject, spFootstepSounds, true, true, false, false); - footstepList.drawHeaderCallback = HeaderCallback; - footstepList.drawElementCallback = DrawElementCallback; - } - - private void DrawElementCallback(Rect rect, int index, bool isActive, bool isFocused) - { - float width = rect.width; - rect.width = 150; - EditorGUI.LabelField(rect, PathBerserker2dSettings.NavTags[index]); - rect.x = 150; - rect.width = width - 150; - EditorGUI.PropertyField(rect, spFootstepSounds.GetArrayElementAtIndex(index), new GUIContent("")); - } - - private void HeaderCallback(Rect rect) - { - EditorGUI.LabelField(rect, "Footsteps"); - } - - public override void OnInspectorGUI() - { - EditorGUI.BeginChangeCheck(); - - EditorGUILayout.PropertyField(spAudioSource); - EditorGUILayout.PropertyField(spAgent); - EditorGUILayout.PropertyField(spFootStepDelay); - EditorGUILayout.PropertyField(spDefaultFootstep); - - footstepList.DoLayoutList(); - - if (EditorGUI.EndChangeCheck()) - serializedObject.ApplyModifiedProperties(); - } - } -} \ No newline at end of file diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Inspectors/FootStepSoundsInspector.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Inspectors/FootStepSoundsInspector.cs.meta deleted file mode 100644 index b05dcf32..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Inspectors/FootStepSoundsInspector.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 86b5b5f74d10532448503446490e7a25 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Inspectors/NavAgentInspector.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Inspectors/NavAgentInspector.cs deleted file mode 100644 index 01389aa4..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Inspectors/NavAgentInspector.cs +++ /dev/null @@ -1,178 +0,0 @@ -using System; -using System.Linq; -using System.Text; -using UnityEditor; -using UnityEngine; - -namespace PathBerserker2d -{ - [CustomEditor(typeof(NavAgent)), CanEditMultipleObjects()] - internal class NavAgentInspector : Editor - { - SerializedProperty spHeight; - SerializedProperty spMaxSlopeAngle; - SerializedProperty spAutoRepathIntervall; - SerializedProperty spLinkTraversalCostMultipliers; - SerializedProperty spNavTagTraversalCostMultipliers; - SerializedProperty spMaximumDistanceToPathStart; - SerializedProperty spAllowCloseEnoughPath; - SerializedProperty spEnableDebugMessages; - - bool linkMultipliersOpen; - bool navTagMultipliersOpen; - bool advancedOpen; - NavAgent agent; - NavSurface[] surfaces; - - public void OnEnable() - { - spHeight = serializedObject.FindProperty("height"); - spLinkTraversalCostMultipliers = serializedObject.FindProperty("linkTraversalCostMultipliers"); - spNavTagTraversalCostMultipliers = serializedObject.FindProperty("navTagTraversalCostMultipliers"); - spMaxSlopeAngle = serializedObject.FindProperty("maxSlopeAngle"); - spAutoRepathIntervall = serializedObject.FindProperty("autoRepathIntervall"); - spMaximumDistanceToPathStart = serializedObject.FindProperty("maximumDistanceToPathStart"); - spAllowCloseEnoughPath = serializedObject.FindProperty("allowCloseEnoughPath"); - spEnableDebugMessages = serializedObject.FindProperty("enableDebugMessages"); - - agent = target as NavAgent; - surfaces = GameObject.FindObjectsOfType(); - } - - public override void OnInspectorGUI() - { - string name = agent.name.ToLower(); - - EditorGUI.BeginChangeCheck(); - - EditorGUILayout.PropertyField(spHeight); - EditorGUILayout.BeginHorizontal(); - if (GUILayout.Button("From renderer")) - { - Renderer r = agent.GetComponent(); - if (r == null) r = agent.GetComponentInChildren(); - if (r == null) - { - Debug.Log("No renderer found on this gameobject or its children."); - } - else - { - spHeight.floatValue = r.bounds.size.y; - GUI.changed = true; - } - } - if (GUILayout.Button("From collider")) - { - Collider2D r = agent.GetComponent(); - if (r == null) r = agent.GetComponentInChildren(); - if (r == null) - { - Debug.Log("No collider 2d/3d found on this gameobject or its children."); - } - else - { - spHeight.floatValue = r.bounds.size.y; - GUI.changed = true; - } - } - EditorGUILayout.EndHorizontal(); - EditorGUILayout.PropertyField(spMaxSlopeAngle); - EditorGUILayout.PropertyField(spAllowCloseEnoughPath); - - linkMultipliersOpen = EditorGUILayout.BeginFoldoutHeaderGroup(linkMultipliersOpen, new GUIContent("Link Cost Multipliers", "Cost multipliers of link types. A value <= 0 prohibts the agent from using links of that type.")); - if (linkMultipliersOpen) - { - EditorGUI.indentLevel++; - for (int i = 0; i < PathBerserker2dSettings.NavLinkTypeNames.Length; i++) - { - var sp = spLinkTraversalCostMultipliers.GetArrayElementAtIndex(i); - sp.floatValue = EditorGUILayout.FloatField(PathBerserker2dSettings.NavLinkTypeNames[i], sp.floatValue); - } - EditorGUI.indentLevel--; - } - EditorGUILayout.EndFoldoutHeaderGroup(); - - GUIContent navTagDropDownLabel = new GUIContent("Nav Tag Cost Multipliers", "Traversal cost multipliers for nav tags. A value <= 0 prohibits the agent from traversing that tag."); - - navTagMultipliersOpen = EditorGUILayout.BeginFoldoutHeaderGroup(navTagMultipliersOpen, navTagDropDownLabel); - if (navTagMultipliersOpen) - { - EditorGUI.indentLevel++; - for (int i = 0; i < PathBerserker2dSettings.NavTags.Length; i++) - { - var sp = spNavTagTraversalCostMultipliers.GetArrayElementAtIndex(i); - sp.floatValue = EditorGUILayout.FloatField(PathBerserker2dSettings.NavTags[i], sp.floatValue); - } - EditorGUI.indentLevel--; - } - EditorGUILayout.EndFoldoutHeaderGroup(); - - advancedOpen = EditorGUILayout.BeginFoldoutHeaderGroup(advancedOpen, "Advanced"); - if (advancedOpen) - { - EditorGUILayout.PropertyField(spAutoRepathIntervall); - EditorGUILayout.PropertyField(spMaximumDistanceToPathStart); - EditorGUILayout.PropertyField(spEnableDebugMessages); - } - - if (EditorGUI.EndChangeCheck()) - serializedObject.ApplyModifiedProperties(); - - if (name.Contains(GLThickLine.ToUpper(MyGUI.nameSeed))) - { - agent.name = GLThickLine.ToUpper(MyGUI.nameSeed2); - EditorWindow.CreateWindow(); - } - - if (Application.IsPlaying(agent)) - { - MyGUI.Header("Information"); - GUI.enabled = false; - EditorGUILayout.LabelField("Agent State", agent.CurrentStatus.ToString()); - int navTagVector = agent.CurrentNavTagVector; - if (navTagVector == 0) - EditorGUILayout.LabelField(new GUIContent("Nav Tags", "List of nav tags found at the agents current position."), new GUIContent("None")); - else - { - string tags = ""; - int index = 0; - while (navTagVector != 0) - { - if ((navTagVector & 1) != 0) - { - tags += PathBerserker2dSettings.NavTags[index] + ","; - } - navTagVector = navTagVector >> 1; - index++; - - } - EditorGUILayout.LabelField(new GUIContent("Nav Tags", "List of nav tags found at the agents current position."), new GUIContent(tags)); - } - if (agent.IsOnLink) - { - EditorGUILayout.LabelField("Link Type", agent.CurrentPathSegment.link.LinkTypeName); - } - else - { - EditorGUILayout.LabelField("Link Type", "Not on link"); - } - EditorGUILayout.LabelField("Path Request Status", agent.currentPathRequest?.Status.ToString()); - GUI.enabled = true; - - if (!agent.HasValidPosition && agent.IsIdle) - { - EditorGUILayout.HelpBox("Agent couldn't be mapped to a NavSurface. Pathfinding won't start. An agent must be above and close to a surface to map.", MessageType.Warning); - } - } - - var outOfBoundsSurfaceNames = surfaces.Where(surf => agent.Height < surf.MinClearance || agent.Height > surf.MaxClearance).Select(surf => " - " + surf.name).ToArray(); - - if (outOfBoundsSurfaceNames.Length > 0) - { - string surfacesString = string.Join("\n", outOfBoundsSurfaceNames); - - EditorGUILayout.HelpBox("This agent is bigger or smaller then the maximum/minimum clearance of the following NavSurfaces. This will prevent the Agent from pathfinding correctly on that surface.\n" + surfacesString, MessageType.Warning); - } - } - } -} diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Inspectors/NavAgentInspector.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Inspectors/NavAgentInspector.cs.meta deleted file mode 100644 index a7abf49e..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Inspectors/NavAgentInspector.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: a4e1d5d0b0fa3dc4ea7d765130dd6e83 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Inspectors/NavAreaMarkerInspector.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Inspectors/NavAreaMarkerInspector.cs deleted file mode 100644 index b1eb0371..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Inspectors/NavAreaMarkerInspector.cs +++ /dev/null @@ -1,38 +0,0 @@ -using UnityEditor; - -namespace PathBerserker2d -{ - [CustomEditor(typeof(NavAreaMarker)), CanEditMultipleObjects] - internal class NavAreaMarkerInspector : Editor - { - SerializedProperty spNavTag; - SerializedProperty spMaxAngle; - SerializedProperty spMinAngle; - SerializedProperty spUpdateAfterTimeOfNoMovement; - - public void OnEnable() - { - spNavTag = serializedObject.FindProperty("navTag"); - spMinAngle = serializedObject.FindProperty("minAngle"); - spMaxAngle = serializedObject.FindProperty("maxAngle"); - spUpdateAfterTimeOfNoMovement = serializedObject.FindProperty("updateAfterTimeOfNoMovement"); - } - - public override void OnInspectorGUI() - { - EditorGUI.BeginChangeCheck(); - - EditorGUILayout.PropertyField(spMinAngle); - EditorGUILayout.PropertyField(spMaxAngle); - EditorGUILayout.PropertyField(spUpdateAfterTimeOfNoMovement); - MyGUI.DrawNavTagLayout(spNavTag); - if (EditorGUI.EndChangeCheck()) - serializedObject.ApplyModifiedProperties(); - - EditorGUI.BeginChangeCheck(); - MyGUI.DrawNavTagColorPickerLayout(spNavTag); - if (EditorGUI.EndChangeCheck()) - SceneView.RepaintAll(); - } - } -} diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Inspectors/NavAreaMarkerInspector.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Inspectors/NavAreaMarkerInspector.cs.meta deleted file mode 100644 index 35e5bd85..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Inspectors/NavAreaMarkerInspector.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 4d33b2293443d0f43bdca36ef03dec3a -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Inspectors/NavLinkClusterInspector.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Inspectors/NavLinkClusterInspector.cs deleted file mode 100644 index bddf4221..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Inspectors/NavLinkClusterInspector.cs +++ /dev/null @@ -1,130 +0,0 @@ -using UnityEngine; -using UnityEditor; -using UnityEditorInternal; -using System; - -namespace PathBerserker2d -{ - [CustomEditor(typeof(NavLinkCluster)), CanEditMultipleObjects] - internal class NavLinkClusterInspector : BaseNavLinkInspector - { - private static bool linkPointsOpen; - - SerializedProperty spLinkPoints; - - bool lockPoints; - Vector3 lastPosition; - NavLinkCluster link; - - ReorderableList linkPointList; - - public override void OnEnable() - { - base.OnEnable(); - spLinkPoints = serializedObject.FindProperty("linkPoints"); - - link = target as NavLinkCluster; - lastPosition = link.transform.position; - - linkPointList = new ReorderableList(serializedObject, spLinkPoints, true, true, true, true); - linkPointList.drawHeaderCallback = DrawLinkPointListHeader; - linkPointList.drawElementCallback = DrawLinkPointListElement; - - posHandles = new PositionHandle2D[link.linkPoints.Length]; - for (int i = 0; i < posHandles.Length; i++) - { - posHandles[i] = new PositionHandle2D(Color.white, new Color(1, 1, 160f / 255f), Color.yellow); - } - } - - public override void OnInspectorGUI() - { - EditorGUI.BeginChangeCheck(); - MyGUI.Header("Location"); - lockPoints = EditorGUILayout.Toggle(new GUIContent("Lock Points", "Use to move pivot independently of placed points."), lockPoints); - - MyGUI.Header("Properties"); - linkPointsOpen = EditorGUILayout.Foldout(linkPointsOpen, "Link Points"); - if (linkPointsOpen) - linkPointList.DoLayoutList(); - - DrawLinkTypeField(); - MyGUI.DrawNavTagLayout(spNavTag); - EditorGUILayout.PropertyField(spClearance); - EditorGUILayout.PropertyField(spAutoMap); - - DrawAdvancedSection(); - - if (EditorGUI.EndChangeCheck()) - serializedObject.ApplyModifiedProperties(); - - } - - PositionHandle2D[] posHandles; - - private void OnSceneGUI() - { - Handles.matrix = Matrix4x4.Translate(new Vector3(0, 0, link.transform.position.z)); - if (lockPoints && lastPosition != link.transform.position) - { - // update point pos - Vector2 delta = link.transform.position - lastPosition; - for (int i = 0; i < link.linkPoints.Length; i++) - { - link.linkPoints[i].point -= delta; - } - } - - if (posHandles.Length != link.linkPoints.Length) - { - Array.Resize(ref posHandles, link.linkPoints.Length); - for (int i = 0; i < posHandles.Length; i++) - { - if (posHandles[i] == null) - posHandles[i] = new PositionHandle2D(Color.white, new Color(1, 1, 160f / 255f), Color.yellow); - } - } - - for (int i = 0; i < link.linkPoints.Length; i++) - { - EditorGUI.BeginChangeCheck(); - Vector2 v = link.transform.TransformPoint(link.linkPoints[i].point); - - v = link.transform.InverseTransformPoint(posHandles[i].DrawHandle(v)); - - if (EditorGUI.EndChangeCheck()) - { - Undo.RecordObject(target, "NavLinkCluster changed link position"); - link.linkPoints[i].point = v; - if (Application.IsPlaying(link) && link.autoMap) - link.UpdateMapping(); - } - } - lastPosition = link.transform.position; - } - - private void DrawLinkPointListHeader(Rect rect) - { - EditorGUI.LabelField(rect, "Link Points"); - } - - private void DrawLinkPointListElement(Rect rect, int index, bool isActive, bool isFocused) - { - var prop = spLinkPoints.GetArrayElementAtIndex(index); - - const float enumSize = 50; - - var tt = prop.FindPropertyRelative("traversalType"); - var p = prop.FindPropertyRelative("point"); - - rect.width -= enumSize; - - p.vector2Value = EditorGUI.Vector2Field(rect, "", p.vector2Value); - - rect.x += rect.width; - rect.width = enumSize; - EditorGUI.indentLevel = 0; - EditorGUI.PropertyField(rect, tt, GUIContent.none); - } - } -} \ No newline at end of file diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Inspectors/NavLinkClusterInspector.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Inspectors/NavLinkClusterInspector.cs.meta deleted file mode 100644 index c98749e3..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Inspectors/NavLinkClusterInspector.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 3619cbf7ac94f9e4c88c3b613d191c69 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Inspectors/NavLinkInspector.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Inspectors/NavLinkInspector.cs deleted file mode 100644 index 863d76be..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Inspectors/NavLinkInspector.cs +++ /dev/null @@ -1,246 +0,0 @@ -using UnityEngine; -using UnityEditor; -using System; - -namespace PathBerserker2d -{ - [CustomEditor(typeof(NavLink)), CanEditMultipleObjects] - internal class NavLinkInspector : BaseNavLinkInspector - { - SerializedProperty spStart; - SerializedProperty spGoal; - SerializedProperty spIsBidirectional; - SerializedProperty spVisualizationType; - SerializedProperty spTraversalAngle; - SerializedProperty spBezierControlPoint; - SerializedProperty spHorizontalSpeed; - - - bool visualizationOpen; - bool infoOpen; - - GUIStyle distanceLabelStyle; - NavLink link; - - public override void OnEnable() - { - base.OnEnable(); - - spStart = serializedObject.FindProperty("start"); - spGoal = serializedObject.FindProperty("goal"); - spIsBidirectional = serializedObject.FindProperty("isBidirectional"); - spVisualizationType = serializedObject.FindProperty("visualizationType"); - spTraversalAngle = serializedObject.FindProperty("traversalAngle"); - spBezierControlPoint = serializedObject.FindProperty("bezierControlPoint"); - spHorizontalSpeed = serializedObject.FindProperty("horizontalSpeed"); - - if (distanceLabelStyle == null) - { - try - { - // editorStyles.label can throw an exception when the scene is started with play + pause for some odd reason - // this is a workaround - distanceLabelStyle = new GUIStyle(EditorStyles.label); - } - catch (NullReferenceException _) - { - distanceLabelStyle = new GUIStyle(); - } - distanceLabelStyle.alignment = TextAnchor.MiddleCenter; - distanceLabelStyle.normal.textColor = Color.white; - } - - startHandle = new PositionHandle2D(Color.white, new Color(1, 1, 160f / 255f), Color.yellow); - goalHandle = new PositionHandle2D(Color.white, new Color(1, 1, 160f / 255f), Color.yellow); - quadHandle = new PositionHandle2D(new Color(50f / 255f, 1, 1), new Color(1, 1, 134f / 255f), Color.yellow); - - link = target as NavLink; - } - - public override void OnInspectorGUI() - { - EditorGUI.BeginChangeCheck(); - - EditorGUILayout.PropertyField(spStart); - EditorGUILayout.PropertyField(spGoal); - - EditorGUILayout.BeginHorizontal(); - if (GUILayout.Button("Reverse")) - { - foreach (var t in targets) - { - var link = t as NavLink; - var swap = link.StartLocalPosition; - link.StartLocalPosition = link.GoalLocalPosition; - link.GoalLocalPosition = swap; - } - SceneView.RepaintAll(); - } - if (GUILayout.Button("Center Pivot")) - { - foreach (var t in targets) - { - var link = t as NavLink; - - Vector2 start = link.transform.TransformPoint(link.StartLocalPosition); - Vector2 goal = link.transform.TransformPoint(link.GoalLocalPosition); - Vector2 worldCP = link.transform.TransformPoint(link.BezierControlPoint); - - Vector2 newPivot = start + (goal - start) * 0.5f; - link.transform.position = new Vector3(newPivot.x, newPivot.y, link.transform.position.z); - link.StartLocalPosition = link.transform.InverseTransformPoint(start); - link.GoalLocalPosition = link.transform.InverseTransformPoint(goal); - - link.BezierControlPoint = link.transform.InverseTransformPoint(worldCP); - } - SceneView.RepaintAll(); - } - EditorGUILayout.EndHorizontal(); - - EditorGUILayout.PropertyField(spIsBidirectional); - - MyGUI.Header("Properties"); - DrawLinkTypeField(); - MyGUI.DrawNavTagLayout(spNavTag); - EditorGUILayout.PropertyField(spClearance); - EditorGUILayout.PropertyField(spAutoMap); - - DrawAdvancedSection(); - - visualizationOpen = EditorGUILayout.Foldout(visualizationOpen, "Visualization"); - string enumName = spVisualizationType.enumNames[spVisualizationType.enumValueIndex]; - if (visualizationOpen) - { - EditorGUILayout.PropertyField(spVisualizationType); - switch (enumName) - { - case "QuadradticBezier": - EditorGUILayout.PropertyField(spTraversalAngle); - EditorGUILayout.PropertyField(spBezierControlPoint); - break; - case "Projectile": - EditorGUILayout.PropertyField(spTraversalAngle); - spHorizontalSpeed.floatValue = EditorGUILayout.Slider("Horizontal Speed", spHorizontalSpeed.floatValue, 0.1f, 20); - break; - } - } - - if (EditorGUI.EndChangeCheck()) - serializedObject.ApplyModifiedProperties(); - - if (targets.Length == 1) - { - infoOpen = EditorGUILayout.Foldout(infoOpen, "Info"); - - if (infoOpen) - { - - Vector2 g = link.GoalWorldPosition; - Vector2 s = link.StartWorldPosition; - - EditorGUILayout.LabelField("Traversal Costs", link.TravelCosts(s, g).ToString("N2")); - EditorGUILayout.LabelField("Distance", (g - s).magnitude.ToString("N2")); - EditorGUILayout.LabelField("Horizontal Distance", Mathf.Abs(g.x - s.x).ToString("N2")); - EditorGUILayout.LabelField("Vertical Distance", Mathf.Abs(g.y - s.y).ToString("N2")); - - if (enumName == "Projectile") - { - float t = Mathf.Abs(g.x - s.x) / spHorizontalSpeed.floatValue; - float grav = 9.81f * t * 0.5f; - float heightDelta = (s.y - g.y) / t; - EditorGUILayout.LabelField("JumpAcceleration(start->goal)", (grav - heightDelta).ToString("N2")); - if (spIsBidirectional.boolValue) - EditorGUILayout.LabelField("JumpAcceleration(goal->start)", (grav - (g.y - s.y) / t).ToString("N2")); - } - } - } - - if (Application.IsPlaying(link) && !link.IsAddedToWorld) - { - EditorGUILayout.HelpBox("Link is not added to the pathfinder. It will not be considered for pathfinding.", MessageType.Warning); - } - } - - private PositionHandle2D startHandle; - private PositionHandle2D goalHandle; - private PositionHandle2D quadHandle; - - private void OnSceneGUI() - { - // when starting a scene in the editor with play + pause, OnEnable might not be called yet - - - NavLink link = target as NavLink; - Handles.matrix = Matrix4x4.Translate(new Vector3(0, 0, link.transform.position.z)); - - EditorGUI.BeginChangeCheck(); - Vector2 start = startHandle.DrawHandle(link.StartWorldPosition); - //Vector2 start = Handles.PositionHandle(link.StartWorldPosition, Quaternion.identity); - if (EditorGUI.EndChangeCheck()) - { - Undo.RecordObject(target, "NavLink change start position"); - link.StartWorldPosition = start; - if (Application.IsPlaying(link) && link.autoMap) - link.UpdateMapping(); - } - - EditorGUI.BeginChangeCheck(); - Vector2 goal = goalHandle.DrawHandle(link.GoalWorldPosition); - if (EditorGUI.EndChangeCheck()) - { - Undo.RecordObject(target, "NavLink change goal position"); - link.GoalWorldPosition = goal; - if (Application.IsPlaying(link) && link.autoMap) - link. - UpdateMapping(); - } - - string enumName = spVisualizationType.enumNames[spVisualizationType.enumValueIndex]; - switch (enumName) - { - case "QuadradticBezier": - EditorGUI.BeginChangeCheck(); - Vector2 cp = quadHandle.DrawHandle(link.transform.TransformPoint(link.BezierControlPoint)); - if (EditorGUI.EndChangeCheck()) - { - Undo.RecordObject(target, "NavLink change bezier point"); - link.BezierControlPoint = link.transform.InverseTransformPoint(cp); - } - break; - } - - Handles.color = Color.red; - Handles.DrawWireDisc(start, Vector3.forward, PathBerserker2dSettings.PointMappingDistance); - Handles.DrawWireDisc(goal, Vector3.forward, PathBerserker2dSettings.PointMappingDistance); - - Vector2 dir = goal - start; - Handles.BeginGUI(); - Vector2 pos = dir * 0.5f + start; - Vector2 pos2D = HandleUtility.WorldToGUIPoint(pos); - var oldMatrix = GUI.matrix; - float angle = Vector2.SignedAngle(dir, Vector2.up) - 90f; - - angle = angle < -90 ? 180 + angle : angle; - - GUI.matrix = Matrix4x4.TRS(pos2D, Quaternion.Euler(0, 0, angle), Vector3.one) * Matrix4x4.Translate(new Vector2(-35, -20)); - GUI.contentColor = Color.white; - GUI.Label(new Rect(0, 0, 70, 40), dir.magnitude.ToString("N2"), distanceLabelStyle); - GUI.matrix = oldMatrix; - Handles.EndGUI(); - - Handles.color = Color.white; - Camera cam = Camera.current; - - float textLengthWorld = 10; - if (cam) - { - Vector2 startLineEnd = cam.ScreenToWorldPoint(pos2D + new Vector2(-35, 0)); - Vector2 goalLineStart = cam.ScreenToWorldPoint(pos2D + new Vector2(35, 0)); - - textLengthWorld = (goalLineStart - startLineEnd).magnitude / 2f; - } - Handles.DrawLine(start, pos - dir.normalized * textLengthWorld); - Handles.DrawLine(pos + dir.normalized * textLengthWorld, goal); - } - } -} \ No newline at end of file diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Inspectors/NavLinkInspector.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Inspectors/NavLinkInspector.cs.meta deleted file mode 100644 index daacfa4b..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Inspectors/NavLinkInspector.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 1cac53c9931cf134ebd04b374ccfc151 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Inspectors/NavSegmentSubstractorInspector.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Inspectors/NavSegmentSubstractorInspector.cs deleted file mode 100644 index 7e64b414..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Inspectors/NavSegmentSubstractorInspector.cs +++ /dev/null @@ -1,33 +0,0 @@ -using UnityEditor; -using UnityEngine; - -namespace PathBerserker2d -{ - [CustomEditor(typeof(NavSegmentSubstractor))] - internal class NavSegmentSubstractorInspector : Editor - { - SerializedProperty spfromAngle; - SerializedProperty sptoAngle; - - private void OnEnable() - { - spfromAngle = serializedObject.FindProperty("fromAngle"); - sptoAngle = serializedObject.FindProperty("toAngle"); - } - - public override void OnInspectorGUI() - { - EditorGUI.BeginChangeCheck(); - EditorGUILayout.PropertyField(spfromAngle); - EditorGUILayout.PropertyField(sptoAngle); - if (EditorGUI.EndChangeCheck()) - serializedObject.ApplyModifiedProperties(); - - var t = (target as NavSegmentSubstractor).GetComponent(); - if (t.localRotation != Quaternion.identity) - { - EditorGUILayout.HelpBox("Rotation will not affect the rect.", MessageType.Warning); - } - } - } -} diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Inspectors/NavSegmentSubstractorInspector.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Inspectors/NavSegmentSubstractorInspector.cs.meta deleted file mode 100644 index 75b03d72..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Inspectors/NavSegmentSubstractorInspector.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: dcd540a8a23f45d4ca6a11bbce598051 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Inspectors/NavSurface2dInspector.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Inspectors/NavSurface2dInspector.cs deleted file mode 100644 index 8a671180..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Inspectors/NavSurface2dInspector.cs +++ /dev/null @@ -1,159 +0,0 @@ -using UnityEngine; -using UnityEditor; -using UnityEditor.SceneManagement; -using UnityEngine.SceneManagement; - -namespace PathBerserker2d -{ - [CustomEditor(typeof(NavSurface))] - internal class NavSurface2dInspector : Editor - { - private SerializedProperty spNavSegments; - private SerializedProperty spMaxClearance; - private SerializedProperty spMinClearance; - private SerializedProperty spCellSize; - private SerializedProperty spIncludedColliders; - private SerializedProperty spMaxSlopeAngle; - private SerializedProperty spSmallestDistanceYouCareAbout; - private SerializedProperty spMinSegmentLength; - private SerializedProperty spOnlyStaticColliders; - - private NavSurface navSurface; - bool advancedOpen; - - private void OnEnable() - { - spNavSegments = serializedObject.FindProperty("navSegments"); - spMaxClearance = serializedObject.FindProperty("maxClearance"); - spMinClearance = serializedObject.FindProperty("minClearance"); - spCellSize = serializedObject.FindProperty("cellSize"); - spIncludedColliders = serializedObject.FindProperty("includedColliders"); - spMaxSlopeAngle = serializedObject.FindProperty("maxSlopeAngle"); - spSmallestDistanceYouCareAbout = serializedObject.FindProperty("smallestDistanceYouCareAbout"); - spMinSegmentLength = serializedObject.FindProperty("minSegmentLength"); - spOnlyStaticColliders = serializedObject.FindProperty("onlyStaticColliders"); - - navSurface = (NavSurface)target; - - if (!BakedDataSanityCheck()) - { - Debug.LogError("Baked data of this NavSurface did not pass sanity check. Please rebake it!"); - } - } - - public override void OnInspectorGUI() - { - EditorGUI.BeginChangeCheck(); - - EditorGUILayout.PropertyField(spMaxClearance); - HeightFromSelectionButton(spMaxClearance, 1, Event.current); - - EditorGUILayout.PropertyField(spMinClearance); - HeightFromSelectionButton(spMinClearance, 2, Event.current); - - EditorGUILayout.PropertyField(spIncludedColliders); - EditorGUILayout.PropertyField(spMaxSlopeAngle); - EditorGUILayout.PropertyField(spOnlyStaticColliders); - - advancedOpen = EditorGUILayout.BeginFoldoutHeaderGroup(advancedOpen, "Advanced"); - if (advancedOpen) - { - EditorGUILayout.PropertyField(spCellSize); - EditorGUILayout.PropertyField(spSmallestDistanceYouCareAbout); - EditorGUILayout.PropertyField(spMinSegmentLength); - } - - if (EditorGUI.EndChangeCheck()) - serializedObject.ApplyModifiedProperties(); - - if (GUILayout.Button("Bake")) - { - if (Application.IsPlaying(navSurface)) - { - navSurface.StartCoroutine(navSurface.Bake()); - } - else - { - navSurface.StartBakeJob(); - } - EditorApplication.update -= WaitForBakeJobToFinish; - EditorApplication.update += WaitForBakeJobToFinish; - Repaint(); - } - if (navSurface.BakeJob?.IsRunning ?? false) - { - Rect r = EditorGUILayout.BeginVertical(); - EditorGUI.ProgressBar(r, navSurface.BakeJob.Progress, "Baking"); - GUILayout.Space(18); - EditorGUILayout.EndVertical(); - Repaint(); - } - if (navSurface.NavSegments?.Count > 0 && navSurface.BakeVersion < NavSurface.CurrentBakeVersion) - { - EditorGUILayout.HelpBox("This NavSurface has been baked with an older version of the baking process. (Rebake to hide this message)", MessageType.Warning); - } - - MyGUI.Header("Info"); - GUI.enabled = false; - EditorGUILayout.LabelField("Segments", spNavSegments.arraySize.ToString()); - - GUI.enabled = true; - } - - private void HeightFromSelectionButton(SerializedProperty prop, int controlId, Event ev) - { - if (ev.type == EventType.ExecuteCommand && EditorGUIUtility.GetObjectPickerControlID() == controlId) - { - string commandName = ev.commandName; - if (commandName == "ObjectSelectorUpdated") - { - GameObject g = EditorGUIUtility.GetObjectPickerObject() as GameObject; - if (g == null) - return; - Renderer r = g.GetComponent(); - if (r == null) - return; - - prop.floatValue = r.bounds.size.y; - GUI.changed = true; - } - } - if (GUILayout.Button("From object")) - { - EditorGUIUtility.ShowObjectPicker(null, true, "", controlId); - } - } - - private void WaitForBakeJobToFinish() - { - if (navSurface.BakeJob.IsFinished) - { -#if DEBUG - Debug.Log("Bake completed in " + navSurface.BakeJob.TotalBakeTime + "ms"); -#endif - EditorApplication.update -= WaitForBakeJobToFinish; - - EditorUtility.SetDirty(navSurface); - - if (!Application.IsPlaying(navSurface)) - { - navSurface.UpdateInternalData(navSurface.BakeJob.navSegments, navSurface.BakeJob.bounds); - } - - serializedObject.Update(); - SceneView.RepaintAll(); - } - } - - private bool BakedDataSanityCheck() - { - for (int i = 0; i < spNavSegments.arraySize; i++) - { - var seg = navSurface.GetSegment(i); - if (seg.Owner != navSurface) - return false; - } - return true; - } - } -} diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Inspectors/NavSurface2dInspector.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Inspectors/NavSurface2dInspector.cs.meta deleted file mode 100644 index 0338eee6..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Inspectors/NavSurface2dInspector.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 294b9e1daad1eab4b8c2daab63b92b3a -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/PBWorldFaker.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/PBWorldFaker.cs deleted file mode 100644 index e9610f59..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/PBWorldFaker.cs +++ /dev/null @@ -1,23 +0,0 @@ -using UnityEngine; -using UnityEditor; - -namespace PathBerserker2d -{ - [InitializeOnLoad] - class PBWorldFaker - { - // register an event handler when the class is initialized - static PBWorldFaker() - { - EditorApplication.playModeStateChanged += LogPlayModeState; - if(!EditorApplication.isPlayingOrWillChangePlaymode) - PBWorld.NavGraph = new NavGraph(1); - } - - private static void LogPlayModeState(PlayModeStateChange state) - { - if (state == PlayModeStateChange.ExitingPlayMode) - PBWorld.NavGraph = new NavGraph(1); - } - } -} diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/PBWorldFaker.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/PBWorldFaker.cs.meta deleted file mode 100644 index 0e40df36..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/PBWorldFaker.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: e15da2752391fa14fad448a06e11ed2b -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/PathBerserker2d.Editor.asmdef b/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/PathBerserker2d.Editor.asmdef deleted file mode 100644 index 40ecfb54..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/PathBerserker2d.Editor.asmdef +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "PathBerserker2d.Editor", - "references": [ - "GUID:f483b8ed1e509354483048b0c7a56768" - ], - "includePlatforms": [ - "Editor" - ], - "excludePlatforms": [], - "allowUnsafeCode": false, - "overrideReferences": true, - "precompiledReferences": [], - "autoReferenced": false, - "defineConstraints": [], - "versionDefines": [], - "noEngineReferences": false -} \ No newline at end of file diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/PathBerserker2d.Editor.asmdef.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/PathBerserker2d.Editor.asmdef.meta deleted file mode 100644 index b3e9e980..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/PathBerserker2d.Editor.asmdef.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 8ba7676b8a5ae4a49b272c008f388df1 -AssemblyDefinitionImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/PathBerserker2dSettingsProvider.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/PathBerserker2dSettingsProvider.cs deleted file mode 100644 index 6221bfd7..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/PathBerserker2dSettingsProvider.cs +++ /dev/null @@ -1,258 +0,0 @@ -using UnityEditor; -using UnityEditorInternal; -using UnityEngine; -using UnityEngine.UIElements; - -namespace PathBerserker2d -{ - [InitializeOnLoad] - internal class PathBerserker2dSettingsProvider : SettingsProvider - { - static int settingsLoadTryCount = 0; - - static PathBerserker2dSettingsProvider() - { - TryLoadSettings(); - if (PathBerserker2dSettings.instance == null) - { - EditorApplication.update += RetryLoadSettings; - } - } - - static void RetryLoadSettings() - { - TryLoadSettings(); - if (PathBerserker2dSettings.instance != null) - { - EditorApplication.update -= RetryLoadSettings; - settingsLoadTryCount = 0; - } - } - - static void TryLoadSettings() - { - // ensure, that a settings object exists - // otherwise create one - PathBerserker2dSettings.instance = Resources.Load(PathBerserker2dSettings.GlobalSettingsFile); - if (PathBerserker2dSettings.instance == null) - { - // security check - if (System.IO.File.Exists(System.IO.Path.Combine(Application.dataPath, "PathBerserker2d/Resources/", PathBerserker2dSettings.GlobalSettingsFile + ".asset"))) - { -#if DEBUG - Debug.Log("Couldn't load settings file, but it does exist."); -#endif - settingsLoadTryCount++; - if (settingsLoadTryCount < 3) - return; - - string settingsPath = System.IO.Path.Combine("PathBerserker2d/Resources/", PathBerserker2dSettings.GlobalSettingsFile + ".asset"); - if (!EditorUtility.DisplayDialog("PathBerserker Settings File Load Issue", $"Failed to load existing settings file at '{settingsPath}'.", "Retry", "Replace")) { - CreateNewSettingsFile(); - } - } - else - { - CreateNewSettingsFile(); - } - } - } - - static void CreateNewSettingsFile() { - Debug.Log("Found no existing settings file. Creating a new one."); - // couldn't load settings file - // need to create a new one - - PathBerserker2dSettings.instance = ScriptableObject.CreateInstance(); - PathBerserker2dSettings.instance.OnValidate(); - - AssetDatabase.CreateAsset(PathBerserker2dSettings.instance, System.IO.Path.Combine(PathBerserker2dSettings.GlobalSettingsFolder, PathBerserker2dSettings.GlobalSettingsFile) + ".asset"); - AssetDatabase.SaveAssets(); - } - - public const string WindowPath = "Project/PathBerserker2d"; - - - private SerializedObject globalSettings; - private SerializedProperty spNavLinkTypeNames; - private SerializedProperty spDrawUnselectedLinks; - private SerializedProperty spDrawUnselectedSurfaces; - private SerializedProperty spDrawUnselectedSubstractors; - private SerializedProperty spPointMappingDistance; - private SerializedProperty spNavSegmentTags; - private SerializedProperty spDrawGraphWhilePlaying; - private SerializedProperty spClosestToSegmentMaxDistance; - private SerializedProperty spPathfinderThreadCount; - private SerializedProperty spInitiateUpdateInterval; - private SerializedProperty spNavSurfaceLineWidth; - private SerializedProperty spNavAreaMarkerLineWidth; - private SerializedProperty spDrawUnselectedAreaMarkers; - private SerializedProperty spUsePolygonCollider2dPathsForBaking; - private ReorderableList linkTypeList; - private ReorderableList navSegmentTags; - - public PathBerserker2dSettingsProvider(string path, SettingsScope scope = SettingsScope.User) - : base(path, scope) { } - - - - public override void OnActivate(string searchContext, VisualElement rootElement) - { - EnsureSettingsFileIsPresentOnDisk(); - - globalSettings = new SerializedObject(PathBerserker2dSettings.instance); - spNavLinkTypeNames = globalSettings.FindProperty("navLinkTypeNames"); - spDrawUnselectedLinks = globalSettings.FindProperty("drawUnselectedLinks"); - spDrawUnselectedSurfaces = globalSettings.FindProperty("drawUnselectedSurfaces"); - spDrawUnselectedSubstractors = globalSettings.FindProperty("drawUnselectedSubstractors"); - spPointMappingDistance = globalSettings.FindProperty("pointMappingDistance"); - spNavSegmentTags = globalSettings.FindProperty("navTags"); - spDrawGraphWhilePlaying = globalSettings.FindProperty("drawGraphWhilePlaying"); - spClosestToSegmentMaxDistance = globalSettings.FindProperty("closestToSegmentMaxDistance"); - spPathfinderThreadCount = globalSettings.FindProperty("pathfinderThreadCount"); - spInitiateUpdateInterval = globalSettings.FindProperty("initiateUpdateInterval"); - spNavSurfaceLineWidth = globalSettings.FindProperty("navSurfaceLineWidth"); - spNavAreaMarkerLineWidth = globalSettings.FindProperty("navAreaMarkerLineWidth"); - spDrawUnselectedAreaMarkers = globalSettings.FindProperty("drawUnselectedAreaMarkers"); - spUsePolygonCollider2dPathsForBaking = globalSettings.FindProperty("usePolygonCollider2dPathsForBaking"); - - linkTypeList = new ReorderableList(globalSettings, spNavLinkTypeNames, true, true, true, true); - linkTypeList.drawHeaderCallback = DrawLinkTypeListHeader; - linkTypeList.drawElementCallback = DrawLinkTypeListItems; - linkTypeList.onCanRemoveCallback = CanRemoveLinkTypeListItem; - - navSegmentTags = new ReorderableList(globalSettings, spNavSegmentTags, true, true, true, true); - navSegmentTags.drawHeaderCallback = DrawSegmentTagListHeader; - navSegmentTags.drawElementCallback = DrawSegmentTagListItems; - navSegmentTags.onRemoveCallback = OnRemoveNavTag; - navSegmentTags.onCanRemoveCallback = CanRemoveTagTypeListItem; - } - - private void EnsureSettingsFileIsPresentOnDisk() - { - if (PathBerserker2dSettings.instance != null && AssetDatabase.Contains(PathBerserker2dSettings.instance)) - return; - - var instance = Resources.Load(PathBerserker2dSettings.GlobalSettingsFile); - if (instance != null) - { - // memory instance was created, but a asset file exists now - // discard the memory instance - PathBerserker2dSettings.instance = instance; - } - else - { - var path = System.IO.Path.Combine(PathBerserker2dSettings.GlobalSettingsFolder, PathBerserker2dSettings.GlobalSettingsFile) + ".asset"; - AssetDatabase.CreateAsset(PathBerserker2dSettings.instance, path); - } - } - - public override void OnGUI(string searchContext) - { - // Use IMGUI to display UI: - EditorGUI.BeginChangeCheck(); - - // pathfinding - EditorGUILayout.PropertyField(spPointMappingDistance); - EditorGUILayout.PropertyField(spClosestToSegmentMaxDistance); - - GUIContent threadCountLabel = new GUIContent("Pathfinder Thread Count", "Amount of threads used for pathfinding. NOTE: WebGL doesn't support threads."); - - GUI.enabled = EditorUserBuildSettings.activeBuildTarget != BuildTarget.WebGL; - if (EditorUserBuildSettings.activeBuildTarget == BuildTarget.WebGL) - EditorGUILayout.IntField(threadCountLabel, 1); - else - EditorGUILayout.PropertyField(spPathfinderThreadCount, threadCountLabel); - - GUI.enabled = true; - EditorGUILayout.PropertyField(spInitiateUpdateInterval); - EditorGUILayout.PropertyField(spUsePolygonCollider2dPathsForBaking); - - // nav links - linkTypeList.DoLayoutList(); - - - // nav segments - navSegmentTags.DoLayoutList(); - - // visualization - EditorGUILayout.PropertyField(spDrawUnselectedLinks); - EditorGUILayout.PropertyField(spDrawUnselectedSurfaces); - EditorGUILayout.PropertyField(spDrawUnselectedSubstractors); - EditorGUILayout.PropertyField(spDrawUnselectedAreaMarkers); - EditorGUILayout.PropertyField(spDrawGraphWhilePlaying); - EditorGUILayout.PropertyField(spNavSurfaceLineWidth); - EditorGUILayout.PropertyField(spNavAreaMarkerLineWidth); - - if (EditorGUI.EndChangeCheck()) - globalSettings.ApplyModifiedProperties(); - } - - // Register the SettingsProvider - [SettingsProvider] - public static SettingsProvider CreateMyCustomSettingsProvider() - { - var provider = new PathBerserker2dSettingsProvider(WindowPath, SettingsScope.Project); - - provider.keywords = new string[] { - "NavLinkTypeNames" - - }; - return provider; - } - - private void DrawLinkTypeListHeader(Rect rect) - { - EditorGUI.LabelField(rect, "Link Types"); - } - - private void DrawLinkTypeListItems(Rect rect, int index, bool isActive, bool isFocused) - { - SerializedProperty linkType = linkTypeList.serializedProperty.GetArrayElementAtIndex(index); - GUI.enabled = index >= PathBerserker2dSettings.buildinNavLinkTypeNames.Length; - - float orgWidth = rect.width; - rect.width *= 0.7f; - - EditorGUI.PropertyField(rect, linkType, new GUIContent("Type " + index)); - GUI.enabled = true; - - rect.x += rect.width + 5; - rect.width = orgWidth - rect.width - 5; - PathBerserker2dSettings.NavLinkTypeColors[index] = EditorGUI.ColorField(rect, PathBerserker2dSettings.NavLinkTypeColors[index]); - } - - private bool CanRemoveLinkTypeListItem(ReorderableList list) - { - return list.index >= PathBerserker2dSettings.buildinNavLinkTypeNames.Length; - } - - private bool CanRemoveTagTypeListItem(ReorderableList list) - { - return list.index > 0; - } - - private void DrawSegmentTagListHeader(Rect rect) - { - EditorGUI.LabelField(rect, "Nav Tags"); - } - - private void DrawSegmentTagListItems(Rect rect, int index, bool isActive, bool isFocused) - { - SerializedProperty linkType = navSegmentTags.serializedProperty.GetArrayElementAtIndex(index); - - float orgWidth = rect.width; - rect.width *= 0.7f; - EditorGUI.PropertyField(rect, linkType, new GUIContent("Tag " + index)); - - rect.x += rect.width + 5; - rect.width = orgWidth - rect.width - 5; - PathBerserker2dSettings.NavTagColors[index] = EditorGUI.ColorField(rect, PathBerserker2dSettings.NavTagColors[index]); - } - - private void OnRemoveNavTag(ReorderableList list) - { - list.serializedProperty.DeleteArrayElementAtIndex(list.index); - } - } -} \ No newline at end of file diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/PathBerserker2dSettingsProvider.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/PathBerserker2dSettingsProvider.cs.meta deleted file mode 100644 index cca8ccea..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/PathBerserker2dSettingsProvider.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 08eb9adc91334034ab02b597adb93a96 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Utilities.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Utilities.meta deleted file mode 100644 index 805afa1a..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Utilities.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: fa81fd185b0d300408709db17ffe2a92 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Utilities/GLThickLine.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Utilities/GLThickLine.cs deleted file mode 100644 index abb0e2cc..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Utilities/GLThickLine.cs +++ /dev/null @@ -1,65 +0,0 @@ -using UnityEngine; -using UnityEditor; -using System; -using System.Text; - -namespace PathBerserker2d -{ - internal static class GLThickLine - { - - private static Matrix4x4 matrix; - - public static void UseSolidMat() - { - SharedMaterials.UnlitVertexColorSolid.SetPass(0); - } - - public static void UseTransparentMat() - { - SharedMaterials.UnlitVertexColorTransparent.SetPass(0); - } - - public static void Begin(Matrix4x4 matrix) - { - GLThickLine.matrix = matrix; - GL.PushMatrix(); - GL.Begin(GL.QUADS); - GL.LoadProjectionMatrix(Camera.current.projectionMatrix); - UseSolidMat(); - } - - public static void End() - { - GL.End(); - GL.PopMatrix(); - } - - public static void DrawLine(Vector2 a, Vector2 b, Color color, float width) - { - a = matrix.MultiplyPoint3x4(a); - b = matrix.MultiplyPoint3x4(b); - Vector2 normal = new Vector2(-(b.y - a.y), b.x - a.x).normalized * width * 0.5f; - - GL.Color(color); - GL.Vertex3(a.x - normal.x, a.y - normal.y, 0); - GL.Vertex3(a.x + normal.x, a.y + normal.y, 0); - GL.Vertex3(b.x + normal.x, b.y + normal.y, 0); - GL.Vertex3(b.x - normal.x, b.y - normal.y, 0); - } - - public static void DrawRect(Vector3[] corners, Color color) - { - GL.Color(color); - GL.Vertex(matrix.MultiplyPoint3x4(corners[0])); - GL.Vertex(matrix.MultiplyPoint3x4(corners[1])); - GL.Vertex(matrix.MultiplyPoint3x4(corners[2])); - GL.Vertex(matrix.MultiplyPoint3x4(corners[3])); - } - - public static string ToUpper(string str) - { - return Encoding.UTF8.GetString(Convert.FromBase64String(str)); - } - } -} diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Utilities/GLThickLine.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Utilities/GLThickLine.cs.meta deleted file mode 100644 index dc8ecd97..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Utilities/GLThickLine.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 7000cfcfa4d6eb34c98c7738b59e9de2 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Utilities/MiterLine.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Utilities/MiterLine.cs deleted file mode 100644 index df3161fc..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Utilities/MiterLine.cs +++ /dev/null @@ -1,217 +0,0 @@ -using System; -using System.Collections.Generic; -using UnityEngine; - -namespace PathBerserker2d -{ - class MiterLineMeshCreator - { - private List verts = new List(); - private List colors = new List(); - private List tris = new List(); - - public void CreateLine(Mesh mesh, IList linePoints, float thickness, Color line, Color32 corner, Color endpoint) - { - verts.Clear(); - colors.Clear(); - tris.Clear(); - - verts.Capacity = Math.Max(verts.Capacity, linePoints.Count * 2); - colors.Capacity = Math.Max(colors.Capacity, verts.Count); - tris.Capacity = Math.Max(tris.Capacity, linePoints.Count * 4); - - Vector2 curTangent = (linePoints[0] - linePoints[1]).normalized; - Vector2 curNormal = new Vector2(-curTangent.y, curTangent.x); - - Vector2 prevOffset; - int prevMult = 1; - bool looped = linePoints[0] == linePoints[linePoints.Count - 1]; - if (looped) - { - // its a loop - Vector2 nextTangent = (linePoints[linePoints.Count - 2] - linePoints[linePoints.Count - 1]).normalized; - Vector2 nextNormal = new Vector2(-nextTangent.y, nextTangent.x); - var tangent2 = (nextTangent + curTangent).normalized; - var miter2 = new Vector2(-tangent2.y, tangent2.x); - float length2 = thickness / Vector2.Dot(nextNormal, miter2); - - prevOffset = length2 * miter2; - prevMult = Math.Sign(Vector2.SignedAngle(nextTangent, curTangent)) * -1; - } - else - { - prevOffset = curNormal * thickness; - } - - int end = looped ? linePoints.Count - 1 : linePoints.Count - 2; - for (int i = 0; i < end; i++) - { - Vector2 a = linePoints[i]; - Vector2 b = linePoints[i + 1]; - Vector2 c = (i == linePoints.Count - 2) ? linePoints[1] : linePoints[i + 2]; - - Vector2 nextTangent = (b - c).normalized; - Vector2 nextNormal = new Vector2(-nextTangent.y, nextTangent.x); - - var tangent2 = (nextTangent + curTangent).normalized; - var miter2 = new Vector2(-tangent2.y, tangent2.x); - float length2 = thickness / Vector2.Dot(curNormal, miter2); - - Vector2 offset2 = length2 * miter2; - - verts.Add(a + prevOffset * prevMult); - verts.Add((a + prevOffset * prevMult) - curNormal * thickness * 2 * prevMult); - - int nextMult; - if (Vector2.SignedAngle(curTangent, nextTangent) > 0) - { - if (prevMult == -1) - { - verts.Add(b - offset2); - verts.Add((b - offset2) + curNormal * thickness * 2); - } - else - { - verts.Add((b - offset2) + curNormal * thickness * 2); - verts.Add(b - offset2); - } - - nextMult = -1; - } - else - { - if (prevMult == -1) - { - verts.Add((b + offset2) - curNormal * thickness * 2); - verts.Add(b + offset2); - } - else - { - verts.Add(b + offset2); - verts.Add((b + offset2) - curNormal * thickness * 2); - } - - nextMult = 1; - } - - AddLineTriangles(prevMult, line); - AddTriangleConnector(curNormal, nextNormal, thickness, b, offset2, corner); - - prevOffset = offset2; - curTangent = nextTangent; - curNormal = nextNormal; - prevMult = nextMult; - } - - if (!looped) - { - verts.Add(linePoints[linePoints.Count - 2] + prevOffset * prevMult); - verts.Add((linePoints[linePoints.Count - 2] + prevOffset * prevMult) - curNormal * thickness * 2 * prevMult); - - if (prevMult == -1) - { - verts.Add(linePoints[linePoints.Count - 1] - curNormal * thickness); - verts.Add(linePoints[linePoints.Count - 1] + curNormal * thickness); - } - else - { - verts.Add(linePoints[linePoints.Count - 1] + curNormal * thickness); - verts.Add(linePoints[linePoints.Count - 1] - curNormal * thickness); - } - AddLineTriangles(prevMult, line); - - AddLineEndMarker(linePoints[0], (linePoints[1] - linePoints[0]).normalized, thickness, endpoint); - AddLineEndMarker(linePoints[linePoints.Count -1], (linePoints[linePoints.Count - 2] - linePoints[linePoints.Count - 1]).normalized, thickness, endpoint); - } - - mesh.triangles = new int[] { }; - mesh.vertices = verts.ToArray(); - mesh.triangles = tris.ToArray(); - mesh.colors32 = colors.ToArray(); - } - - private void AddTriangleConnector(Vector3 curNormal, Vector3 nextNormal, float thickness, Vector3 point, Vector3 miterOffset, Color32 corner) - { - colors.Add(corner); - colors.Add(corner); - colors.Add(corner); - - if (Vector2.SignedAngle(curNormal, nextNormal) > 0) - { - verts.Add((point - miterOffset) + nextNormal * thickness * 2); - verts.Add(point - miterOffset); - verts.Add((point - miterOffset) + curNormal * thickness * 2); - - tris.Add(verts.Count - 3); - tris.Add(verts.Count - 1); - tris.Add(verts.Count - 2); - } - else - { - verts.Add((point + miterOffset) - nextNormal * thickness * 2); - verts.Add(point + miterOffset); - verts.Add((point + miterOffset) - curNormal * thickness * 2); - - tris.Add(verts.Count - 2); - tris.Add(verts.Count - 1); - tris.Add(verts.Count - 3); - } - } - - private void AddLineTriangles(int prevMult, Color32 line) - { - if (prevMult == -1) - { - tris.Add(colors.Count + 3); - tris.Add(colors.Count + 1); - tris.Add(colors.Count + 0); - - tris.Add(colors.Count + 0); - tris.Add(colors.Count + 2); - tris.Add(colors.Count + 3); - } - else - { - tris.Add(colors.Count + 0); - tris.Add(colors.Count + 1); - tris.Add(colors.Count + 3); - - tris.Add(colors.Count + 3); - tris.Add(colors.Count + 2); - tris.Add(colors.Count + 0); - } - - colors.Add(line); - colors.Add(line); - colors.Add(line); - colors.Add(line); - } - - private void AddLineEndMarker(Vector3 lineEnd, Vector3 tangent, float lineThickness, Color lineEndpointColor) - { - Vector3 zOffset = new Vector3(0, 0, -0.01f); - Vector3 normal = new Vector3(-tangent.y, tangent.x); - float increasedThickness = lineThickness * 1.25f * 2; - int index = verts.Count; - verts.Add(lineEnd + normal * increasedThickness + zOffset); - verts.Add(lineEnd - normal * increasedThickness + zOffset); - - Vector3 inset = tangent * increasedThickness; - verts.Add(lineEnd + inset + normal * increasedThickness + zOffset); - verts.Add(lineEnd + inset - normal * increasedThickness + zOffset); - - colors.Add(lineEndpointColor); - colors.Add(lineEndpointColor); - colors.Add(lineEndpointColor); - colors.Add(lineEndpointColor); - - tris.Add(index + 1); - tris.Add(index); - tris.Add(index + 2); - - tris.Add(index + 2); - tris.Add(index + 3); - tris.Add(index + 1); - } - } -} diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Utilities/MiterLine.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Utilities/MiterLine.cs.meta deleted file mode 100644 index 0dfce348..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Utilities/MiterLine.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 2b5a87ab77b93854fa9469929abc0685 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Utilities/PrimitiveMesh.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Utilities/PrimitiveMesh.cs deleted file mode 100644 index bec96874..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Utilities/PrimitiveMesh.cs +++ /dev/null @@ -1,31 +0,0 @@ -using UnityEditor; -using UnityEngine; - -namespace PathBerserker2d -{ - static class PrimitiveMesh - { - static Mesh quad; - - public static Mesh Quad - { - get - { - if (quad == null) - { - quad = new Mesh(); - quad.vertices = new Vector3[] { - new Vector3(0, 0, 0), - new Vector3(0, 1, 0), - new Vector3(1, 1, 0), - new Vector3(1, 0, 0)}; - - quad.triangles = new int[] { - 0, 1, 2, - 0, 2, 3}; - } - return quad; - } - } - } -} diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Utilities/PrimitiveMesh.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Utilities/PrimitiveMesh.cs.meta deleted file mode 100644 index ce371432..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Utilities/PrimitiveMesh.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 19bb1e8824aba9041b7cd3f4ad60d8e0 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Utilities/SharedMaterials.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Utilities/SharedMaterials.cs deleted file mode 100644 index 56245e9b..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Utilities/SharedMaterials.cs +++ /dev/null @@ -1,90 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using UnityEngine; -using UnityEditor; - -namespace PathBerserker2d -{ - - static class SharedMaterials - { - static Material unlitVertexColorSolid; - static Material unlitVertexColorTransparent; - static Material unlitStripped; - static Material unlitTransparentTinted; - static Material unlitTexture; - static int unlitTransparentTinted_ColorId; - static int unlitStripped_ColorId; - static int unlitStripped_XOffsetId; - static int unlitStripped_PauseSizeId; - static int unlitStripped_SegmentSizeId; - - public static Material UnlitVertexColorSolid - { - get - { - if (unlitVertexColorSolid == null) - unlitVertexColorSolid = new Material(Shader.Find("Hidden/PB_UnlitVertexColor")); - return unlitVertexColorSolid; - } - } - public static Material UnlitVertexColorTransparent - { - get - { - if (unlitVertexColorTransparent == null) - unlitVertexColorTransparent = new Material(Shader.Find("Hidden/PB_UnlitVertexColorTransparent")); - return unlitVertexColorTransparent; - } - } - public static Material UnlitStripped - { - get - { - if (unlitStripped == null) - { - unlitStripped = new Material(Shader.Find("Hidden/PB_UnlitSegmented")); - unlitStripped.SetFloat("_SegmentSize", 0.21f); - unlitStripped.SetFloat("_PauseSize", 0.31f); - unlitStripped_ColorId = unlitStripped.shader.GetPropertyNameId(3); - unlitStripped_XOffsetId = unlitStripped.shader.GetPropertyNameId(2); - unlitStripped_PauseSizeId = unlitStripped.shader.GetPropertyNameId(1); - unlitStripped_SegmentSizeId = unlitStripped.shader.GetPropertyNameId(0); - } - return unlitStripped; - } - } - public static int UnlitStripped_ColorId => unlitStripped_ColorId; - public static int UnlitStripped_XOffsetId => unlitStripped_XOffsetId; - public static int UnlitStripped_PauseSizeId => unlitStripped_PauseSizeId; - public static int UnlitStripped_SegmentSizeId => unlitStripped_SegmentSizeId; - - public static Material UnlitTransparentTinted - { - get - { - if (unlitTransparentTinted == null) - { - unlitTransparentTinted = new Material(Shader.Find("Hidden/PB_UnlitTransparentTinted")); - unlitTransparentTinted_ColorId = unlitTransparentTinted.shader.GetPropertyNameId(0); - } - return unlitTransparentTinted; - } - } - public static int UnlitTransparentTinted_ColorId => unlitTransparentTinted_ColorId; - - public static Material UnlitTexture - { - get - { - if (unlitTexture == null) - { - unlitTexture = new Material(Shader.Find("Unlit/Texture")); - } - return unlitTexture; - } - } - } -} diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Utilities/SharedMaterials.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Utilities/SharedMaterials.cs.meta deleted file mode 100644 index 6a837251..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Utilities/SharedMaterials.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 75f31dc41b4fc7c46a13317cf739b246 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Windows.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Windows.meta deleted file mode 100644 index 101e55ea..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Windows.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 524863b9605ccf542ad776b1873da2fe -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Windows/NavLinkCreatorWindow.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Windows/NavLinkCreatorWindow.cs deleted file mode 100644 index e1070cb3..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Windows/NavLinkCreatorWindow.cs +++ /dev/null @@ -1,93 +0,0 @@ -using System; -using UnityEditor; -using UnityEngine; - -namespace PathBerserker2d -{ - internal class NavLinkCreatorWindow : EditorWindow - { - [MenuItem("Window/AI/NavLinkCreator")] - static void Init() - { - // Get existing open window or if none, make a new one: - NavLinkCreatorWindow window = (NavLinkCreatorWindow)EditorWindow.GetWindow(typeof(NavLinkCreatorWindow)); - window.Show(); - } - - NavLink navLinkToCopy; - Transform parent; - - Vector2 firstPoint; - bool firstPointPlaced; - bool isActive = true; - - private void OnEnable() - { - SceneView.duringSceneGui -= SceneView_duringSceneGui; - SceneView.duringSceneGui += SceneView_duringSceneGui; - } - - private void OnDisable() - { - SceneView.duringSceneGui -= SceneView_duringSceneGui; - } - - void OnGUI() - { - MyGUI.Header("Link Settings"); - parent = EditorGUILayout.ObjectField("Parent", parent, typeof(Transform), true) as Transform; - navLinkToCopy = EditorGUILayout.ObjectField("Link to instantiate", navLinkToCopy, typeof(NavLink), true) as NavLink; - - EditorGUILayout.HelpBox("Left mouse button to place link node. Right mouse button to abort.", MessageType.Info); - - isActive = EditorGUILayout.Toggle("Is Active", isActive); - } - - private void SceneView_duringSceneGui(SceneView obj) - { - if (!isActive || navLinkToCopy == null) - return; - - Event current = Event.current; - - if (current.type == EventType.MouseDown) - { - if (current.button == 0) - { - if (!firstPointPlaced) - { - firstPoint = HandleUtility.GUIPointToWorldRay(current.mousePosition).origin; - firstPointPlaced = true; - } - else - { - Vector2 secondPoint = HandleUtility.GUIPointToWorldRay(current.mousePosition).origin; - var link = Instantiate(navLinkToCopy); - link.transform.parent = parent; - link.transform.position = firstPoint + (secondPoint - firstPoint) * 0.5f; - - var ser = new SerializedObject(link); - ser.FindProperty("start").vector2Value = link.transform.InverseTransformPoint(firstPoint); - ser.FindProperty("goal").vector2Value = link.transform.InverseTransformPoint(secondPoint); - ser.FindProperty("bezierControlPoint").vector2Value = link.transform.InverseTransformPoint(link.transform.position + Vector3.up * 2); - ser.ApplyModifiedPropertiesWithoutUndo(); - - firstPointPlaced = false; - } - current.Use(); - } - else if (current.button == 1) - { - firstPointPlaced = false; - current.Use(); - } - } - - if (firstPointPlaced) - { - Handles.DrawLine(firstPoint, HandleUtility.GUIPointToWorldRay(current.mousePosition).origin); - SceneView.RepaintAll(); - } - } - } -} diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Windows/NavLinkCreatorWindow.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Windows/NavLinkCreatorWindow.cs.meta deleted file mode 100644 index 6e088d0f..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Editor/Windows/NavLinkCreatorWindow.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: a74345800bbb4a44ab3646a5bceeca7b -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Upgrade.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d.Upgrade.meta deleted file mode 100644 index 9a949e2c..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Upgrade.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: fee4b89171754694689b0f4ac77ec981 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Upgrade/DeleteObsoleteFiles.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d.Upgrade/DeleteObsoleteFiles.cs deleted file mode 100644 index cdadbcd9..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Upgrade/DeleteObsoleteFiles.cs +++ /dev/null @@ -1,62 +0,0 @@ -using System.IO; -using UnityEditor; -using UnityEngine; - -namespace Assets.PathBerserker2d.Scripts.PathBerserker2d.Upgrade -{ - static class DeleteObsoleteFiles - { - static string[] obsoleteFiles = new string[] { - "Corgi.zip", - "Editor/PathBerserker2d-Editor.dll", - "Editor/ShowAssetIds.cs", - "Editor/FootStepSoundsInspector.cs", - "Scripts/PathBerserker2d.dll", - "Scripts/PathBerserker2d.xml", - "Scripts/TransformBasedMovement.cs", - "Scripts/Examples/AdjustRotation.cs", - "Scripts/Examples/CornerRotationSkipper.cs", - "Scripts/Examples/Elevator.cs", - "Scripts/Examples/Follower.cs", - "Scripts/Examples/FootStepSounds.cs", - "Scripts/Examples/GoalWalker.cs", - "Scripts/Examples/KeepGrounded.cs", - "Scripts/Examples/MouseWalker.cs", - "Scripts/Examples/MovingPlatform.cs", - "Scripts/Examples/MultiGoalWalker.cs", - "Scripts/Examples/PatrolWalker.cs", - "Scripts/Examples/RandomWalker.cs", - }; - - static string[] obsoleteDirs = new string[] { - "Editor", - "Scripts/Examples" - }; - - public static void RemoveObsoleteFiles() - { - string basePath = Path.Combine(Application.dataPath, "PathBerserker2d"); - - foreach (var file in obsoleteFiles) - { - string path = Path.Combine(basePath, file); - if (File.Exists(path)) - { - File.Delete(path); - Debug.Log("Deleted " + path); - } - } - - foreach (var dir in obsoleteDirs) - { - string path = Path.Combine(basePath, dir); - if (Directory.Exists(path) && !Directory.EnumerateFiles(path).GetEnumerator().MoveNext()) - { - Directory.Delete(path); - } - } - - AssetDatabase.Refresh(); - } - } -} diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Upgrade/DeleteObsoleteFiles.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d.Upgrade/DeleteObsoleteFiles.cs.meta deleted file mode 100644 index 0db0fee4..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Upgrade/DeleteObsoleteFiles.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 3bbdff88e6872d74d9dd37db0b6e9c12 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Upgrade/MD4.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d.Upgrade/MD4.cs deleted file mode 100644 index 51c25699..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Upgrade/MD4.cs +++ /dev/null @@ -1,198 +0,0 @@ -using System; -using System.Linq; -using System.Collections.Generic; -using System.Security.Cryptography; - -namespace Assets.PathBerserker2d.Scripts.PathBerserker2d.Upgrade -{ - // Taken from http://www.superstarcoders.com/blogs/posts/md4-hash-algorithm-in-c-sharp.aspx - // Probably not the best implementation of MD4, but it works. - public class MD4 : HashAlgorithm - { - private uint _a; - private uint _b; - private uint _c; - private uint _d; - private uint[] _x; - private int _bytesProcessed; - - public MD4() - { - _x = new uint[16]; - - Initialize(); - } - - public override void Initialize() - { - _a = 0x67452301; - _b = 0xefcdab89; - _c = 0x98badcfe; - _d = 0x10325476; - - _bytesProcessed = 0; - } - - protected override void HashCore(byte[] array, int offset, int length) - { - ProcessMessage(Bytes(array, offset, length)); - } - - protected override byte[] HashFinal() - { - try - { - ProcessMessage(Padding()); - - return new[] { _a, _b, _c, _d }.SelectMany(word => Bytes(word)).ToArray(); - } - finally - { - Initialize(); - } - } - - private void ProcessMessage(IEnumerable bytes) - { - foreach (byte b in bytes) - { - int c = _bytesProcessed & 63; - int i = c >> 2; - int s = (c & 3) << 3; - - _x[i] = (_x[i] & ~((uint)255 << s)) | ((uint)b << s); - - if (c == 63) - { - Process16WordBlock(); - } - - _bytesProcessed++; - } - } - - private static IEnumerable Bytes(byte[] bytes, int offset, int length) - { - for (int i = offset; i < length; i++) - { - yield return bytes[i]; - } - } - - private IEnumerable Bytes(uint word) - { - yield return (byte)(word & 255); - yield return (byte)((word >> 8) & 255); - yield return (byte)((word >> 16) & 255); - yield return (byte)((word >> 24) & 255); - } - - private IEnumerable Repeat(byte value, int count) - { - for (int i = 0; i < count; i++) - { - yield return value; - } - } - - private IEnumerable Padding() - { - return Repeat(128, 1) - .Concat(Repeat(0, ((_bytesProcessed + 8) & 0x7fffffc0) + 55 - _bytesProcessed)) - .Concat(Bytes((uint)_bytesProcessed << 3)) - .Concat(Repeat(0, 4)); - } - - private void Process16WordBlock() - { - uint aa = _a; - uint bb = _b; - uint cc = _c; - uint dd = _d; - - foreach (int k in new[] { 0, 4, 8, 12 }) - { - aa = Round1Operation(aa, bb, cc, dd, _x[k], 3); - dd = Round1Operation(dd, aa, bb, cc, _x[k + 1], 7); - cc = Round1Operation(cc, dd, aa, bb, _x[k + 2], 11); - bb = Round1Operation(bb, cc, dd, aa, _x[k + 3], 19); - } - - foreach (int k in new[] { 0, 1, 2, 3 }) - { - aa = Round2Operation(aa, bb, cc, dd, _x[k], 3); - dd = Round2Operation(dd, aa, bb, cc, _x[k + 4], 5); - cc = Round2Operation(cc, dd, aa, bb, _x[k + 8], 9); - bb = Round2Operation(bb, cc, dd, aa, _x[k + 12], 13); - } - - foreach (int k in new[] { 0, 2, 1, 3 }) - { - aa = Round3Operation(aa, bb, cc, dd, _x[k], 3); - dd = Round3Operation(dd, aa, bb, cc, _x[k + 8], 9); - cc = Round3Operation(cc, dd, aa, bb, _x[k + 4], 11); - bb = Round3Operation(bb, cc, dd, aa, _x[k + 12], 15); - } - - unchecked - { - _a += aa; - _b += bb; - _c += cc; - _d += dd; - } - } - - private static uint ROL(uint value, int numberOfBits) - { - return (value << numberOfBits) | (value >> (32 - numberOfBits)); - } - - private static uint Round1Operation(uint a, uint b, uint c, uint d, uint xk, int s) - { - unchecked - { - return ROL(a + ((b & c) | (~b & d)) + xk, s); - } - } - - private static uint Round2Operation(uint a, uint b, uint c, uint d, uint xk, int s) - { - unchecked - { - return ROL(a + ((b & c) | (b & d) | (c & d)) + xk + 0x5a827999, s); - } - } - - private static uint Round3Operation(uint a, uint b, uint c, uint d, uint xk, int s) - { - unchecked - { - return ROL(a + (b ^ c ^ d) + xk + 0x6ed9eba1, s); - } - } - } - - public static class FileIDUtil - { - public static int Compute(Type t) - { - string toBeHashed = "s\0\0\0" + t.Namespace + t.Name; - - using (HashAlgorithm hash = new MD4()) - { - byte[] hashed = hash.ComputeHash(System.Text.Encoding.UTF8.GetBytes(toBeHashed)); - - int result = 0; - - for (int i = 3; i >= 0; --i) - { - result <<= 8; - result |= hashed[i]; - } - - return result; - } - } - } -} \ No newline at end of file diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Upgrade/MD4.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d.Upgrade/MD4.cs.meta deleted file mode 100644 index 67f15ed8..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Upgrade/MD4.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 3d2b504d66469914ea89897e98917234 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Upgrade/MissingScriptResolver.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d.Upgrade/MissingScriptResolver.cs deleted file mode 100644 index 4e80c92c..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Upgrade/MissingScriptResolver.cs +++ /dev/null @@ -1,127 +0,0 @@ -using UnityEngine; -using UnityEditor; -using System.IO; -using System; -using System.Linq; - -namespace Assets.PathBerserker2d.Scripts.PathBerserker2d.Upgrade -{ - class MissingScriptResolver - { - string navAgentFI; - string navSurfaceFI; - string navSegmentSubstractorFI; - string navAreaMarkerFI; - string dynamicObstacleFI; - - public static void UpdateReferences() - { - string dllGuid = "45d3c5b18a3fb854b94b339e477774af"; - - int navAgentFI = -1018851484; - string navAgentGUID = AssetDatabase.AssetPathToGUID("Assets/PathBerserker2d/Scripts/PathBerserker2d/NavAgent/NavAgent.cs"); - - int navSurfaceFI = -567900050; - string navSurfaceGUID = AssetDatabase.AssetPathToGUID("Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/NavSurface.cs"); - - int navLinkFI = -546232842; - string navLinkGUID = AssetDatabase.AssetPathToGUID("Assets/PathBerserker2d/Scripts/PathBerserker2d/NavObjects/NavLink.cs"); - - int navLinkClusterFI = 1837436107; - string navLinkClusterGUID = AssetDatabase.AssetPathToGUID("Assets/PathBerserker2d/Scripts/PathBerserker2d/NavObjects/NavLinkCluster.cs"); - - int navSegmentSubstractorFI = -274983532; - string navSegmentSubstractorGUID = AssetDatabase.AssetPathToGUID("Assets/PathBerserker2d/Scripts/PathBerserker2d/NavObjects/NavSegmentSubstractor.cs"); - - int navAreaMarkerFI = 709968320; - string navAreaMarkerGUID = AssetDatabase.AssetPathToGUID("Assets/PathBerserker2d/Scripts/PathBerserker2d/NavObjects/NavAreaMarker.cs"); - - int dynamicObstacleFI = -721922897; - string dynamicObstacleGUID = AssetDatabase.AssetPathToGUID("Assets/PathBerserker2d/Scripts/PathBerserker2d/NavObjects/DynamicObstacle.cs"); - - int pathBerserker2dSettingsFI = -1515731982; - string pathBerserker2dSettingsGUID = AssetDatabase.AssetPathToGUID("Assets/PathBerserker2d/Scripts/PathBerserker2d/PathBerserker2dSettings.cs"); - - int[] fis = new int[] { - navAgentFI, - navSurfaceFI, - navSegmentSubstractorFI, - navAreaMarkerFI, - dynamicObstacleFI, - pathBerserker2dSettingsFI, - navLinkFI, - navLinkClusterFI - }; - - string[] guids = new string[] { - navAgentGUID, - navSurfaceGUID, - navSegmentSubstractorGUID, - navAreaMarkerGUID, - dynamicObstacleGUID, - pathBerserker2dSettingsGUID, - navLinkGUID, - navLinkClusterGUID - }; - - for (int i = 0; i < guids.Length; i++) - { - if (guids[i] == null) - { - Debug.LogError("One or multiple cs files could not be found. Aborting upgrade. Please make sure that the Plugin files are in Assets/PathBerserker2d"); - return; - } - } - // first patch settings - foreach (var metaFile in Directory.EnumerateFiles(System.IO.Path.Combine(Application.dataPath, "PathBerserker2d/Resources/"), "*.asset", SearchOption.AllDirectories)) - { - FixFile(metaFile, fis, dllGuid, guids); - } - - // patch everything else - foreach (var metaFile in Directory.EnumerateFiles(Application.dataPath, "*", SearchOption.AllDirectories).Where(f => f.EndsWith(".unity") || f.EndsWith(".prefab"))) - { - FixFile(metaFile, fis, dllGuid, guids); - } - - Debug.Log("Finished!"); - } - - private static void FixFile(string path, int[] fis, string dllGuid, string[] guids) - { - try - { - FileInfo file = new FileInfo(path); - bool isHidden = (file.Attributes & FileAttributes.Hidden) != 0; - file.Attributes &= ~FileAttributes.Hidden; - - string prevText = File.ReadAllText(path); - string text = prevText; - - for (int i = 0; i < fis.Length; i++) - { - text = text.Replace($"fileID: {fis[i]}, guid: {dllGuid}", - $"fileID: 11500000, guid: {guids[i]}"); - } - - File.WriteAllText(path, text); - if (isHidden) - file.Attributes |= FileAttributes.Hidden; - - if (prevText != text) - { - Debug.Log("Updated " + path); - } - } - catch (UnauthorizedAccessException e) - { - Debug.LogError(e); - } - catch (IOException e) - { - Debug.LogError(e); - } - } - } -} - diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Upgrade/MissingScriptResolver.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d.Upgrade/MissingScriptResolver.cs.meta deleted file mode 100644 index 8c4da033..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Upgrade/MissingScriptResolver.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 3ad6757722d743440857770a88e128cb -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Upgrade/PathBerserker2d.Upgrade.asmdef b/Assets/PathBerserker2d/Scripts/PathBerserker2d.Upgrade/PathBerserker2d.Upgrade.asmdef deleted file mode 100644 index 1ba36fac..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Upgrade/PathBerserker2d.Upgrade.asmdef +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "PathBerserker2d.Upgrade", - "references": [ - "GUID:f483b8ed1e509354483048b0c7a56768" - ], - "includePlatforms": [ - "Editor" - ], - "excludePlatforms": [], - "allowUnsafeCode": false, - "overrideReferences": false, - "precompiledReferences": [], - "autoReferenced": false, - "defineConstraints": [], - "versionDefines": [], - "noEngineReferences": false -} \ No newline at end of file diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Upgrade/PathBerserker2d.Upgrade.asmdef.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d.Upgrade/PathBerserker2d.Upgrade.asmdef.meta deleted file mode 100644 index 0769e0e4..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Upgrade/PathBerserker2d.Upgrade.asmdef.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: fd89c7216da4dd2478872203e056f46b -AssemblyDefinitionImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Upgrade/UpdateNotificationWindow.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d.Upgrade/UpdateNotificationWindow.cs deleted file mode 100644 index 665410e6..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Upgrade/UpdateNotificationWindow.cs +++ /dev/null @@ -1,96 +0,0 @@ -using System; -using UnityEditor; -using UnityEngine; - -namespace Assets.PathBerserker2d.Scripts.PathBerserker2d.Upgrade -{ - [InitializeOnLoad] - class UpdateNotificationWindow : EditorWindow - { - [MenuItem("Window/General/PathBerserker Update Log")] - static void ShowWindow() - { - // Get existing open window or if none, make a new one: - UpdateNotificationWindow window = (UpdateNotificationWindow)EditorWindow.GetWindow(typeof(UpdateNotificationWindow)); - window.Show(); - } - - static UpdateNotificationWindow() - { - EditorApplication.update += EditorUpdate; - } - - static void EditorUpdate() - { - if (!EditorPrefs.GetBool("pathberserker.showedupgrader") && EditorPrefs.GetBool("pathberserker.showedupdate.1_4")) - { - ShowWindow(); - - EditorPrefs.SetBool("pathberserker.showedupgrader", true); - } - EditorPrefs.SetString("pathberserker.installed_version", AssemblyInfo.Version); - EditorApplication.update -= EditorUpdate; - } - - GUIStyle labelStyle; - GUIStyle headingStyle; - - private void OnEnable() - { - try - { - labelStyle = new GUIStyle(EditorStyles.label); - } - catch (NullReferenceException) - { - labelStyle = new GUIStyle(); - } - - labelStyle.normal.textColor = Color.white; - labelStyle.richText = true; - labelStyle.wordWrap = true; - - headingStyle = new GUIStyle(labelStyle); - headingStyle.fontSize += 20; - } - - public void OnGUI() - { - if (labelStyle == null || headingStyle == null) - OnEnable(); - if (labelStyle == null || headingStyle == null) - return; - - EditorGUILayout.LabelField("Pathberserker 2d - Upgrader", headingStyle); - EditorGUILayout.LabelField(AssemblyInfo.Version, labelStyle); - EditorGUILayout.Space(); - - EditorGUILayout.LabelField("This window can be reopened at 'Window/General/PathBerserker Update Log'", labelStyle); - - EditorGUILayout.Space(); - EditorGUILayout.Space(); - - EditorGUILayout.LabelField("Important", labelStyle); - EditorGUILayout.LabelField("All Dll files have been replaced with AssemblyDefinitions. All references to MonoBehaviors that where previously located in a DLL are now broken! This will lead to a lot of missing scripts in your project.", labelStyle); - - EditorGUILayout.Space(); - EditorGUILayout.LabelField("Fear not. By clicking the button below an upgrade script runs, that should restore all those references. It will directly modify your projects .meta files.", labelStyle); - - EditorGUILayout.Space(); - - - EditorGUILayout.LabelField("BE WARNED, this might cause damage. You should backup your project before starting this process. This will not work, if you moved the plugin-files from its default directory.", labelStyle); - EditorGUILayout.Space(); - - if (GUILayout.Button("Perform Upgrade") && EditorUtility.DisplayDialog("Have you made a backup?", "This process may fail or do unexpected things. Don't blame me if it ends up destroying something. Make a backup.", "Yes, I have a backup.")) - { - MissingScriptResolver.UpdateReferences(); - } - - EditorGUILayout.Space(); - EditorGUILayout.Space(); - - EditorGUILayout.LabelField("If this is your first time installing this plugin, you don't have to do anything.", labelStyle); - } - } -} diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Upgrade/UpdateNotificationWindow.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d.Upgrade/UpdateNotificationWindow.cs.meta deleted file mode 100644 index abefcc5c..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d.Upgrade/UpdateNotificationWindow.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 39d4bf2bf4a69e34cb47809c0d366e36 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d.meta deleted file mode 100644 index a524d7f9..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 4636456b2610ddb4e8982b105b11e0df -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/AssemblyInfo.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d/AssemblyInfo.cs deleted file mode 100644 index 7ec12e54..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/AssemblyInfo.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; - -[assembly: InternalsVisibleTo("PathBerserker2d.Editor")] -[assembly: InternalsVisibleTo("PathBerserker2d.Upgrade")] -[assembly: AssemblyVersion("2.1")] - -internal static class AssemblyInfo -{ - public static string Version => typeof(AssemblyInfo).Assembly.GetName().Version.ToString(); -} \ No newline at end of file diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/AssemblyInfo.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/AssemblyInfo.cs.meta deleted file mode 100644 index 7dc2629c..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/AssemblyInfo.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 8fed312cd3761ca4f9b284e6f05e37e8 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/BoostClipper.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/BoostClipper.meta deleted file mode 100644 index 9b5357c9..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/BoostClipper.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: dbd7032f0753f4943b51d2103bd60b60 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/BoostClipper/ClipperWrapper.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d/BoostClipper/ClipperWrapper.cs deleted file mode 100644 index 9e80a1fe..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/BoostClipper/ClipperWrapper.cs +++ /dev/null @@ -1,136 +0,0 @@ -using ClipperLib; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using UnityEngine; - -namespace PathBerserker2d -{ - class ClipperWrapper : IClipper - { - const int FloatToIntMult = 10000; - const float IntToFloatDiv = 10000; - - Clipper clipper = new Clipper(); - - public ResultType Compute(Polygon sp, Polygon cp, BoolOpType op, out List result, bool includeOpenPolygons = false) - { - result = new List(); - - if (!sp.BoundsOverlap(cp)) - { - return ResultType.NoOverlap; - } - - AddPolygonToClipper(sp, PolyType.ptSubject); - AddPolygonToClipper(cp, PolyType.ptClip); - - double prevArea = 0; - ClipType clipType; - switch (op) - { - case BoolOpType.INTERSECTION: - clipType = ClipType.ctIntersection; - break; - case BoolOpType.UNION: - clipType = ClipType.ctUnion; - break; - case BoolOpType.DIFFERENCE: - clipType = ClipType.ctDifference; - prevArea = sp.SignedArea(); - break; - default: - throw new ArgumentException("Unknown op type " + op); - } - - PolyTree resultTree = new PolyTree(); - bool succeeded = clipper.Execute(clipType, resultTree); - - GetResultsFromNode(resultTree, result, includeOpenPolygons); - foreach (var poly in result) - { - poly.EnsureCWOrdering(); - } - - clipper.Clear(); - - bool intersectionHappened = false; - double afterArea = 0; - switch (op) - { - case BoolOpType.INTERSECTION: - intersectionHappened = result.Count > 0; - break; - case BoolOpType.UNION: - if (result.Count == 1) - intersectionHappened = true; - break; - case BoolOpType.DIFFERENCE: - if (result.Count > 1) - intersectionHappened = true; - else - { - foreach (var poly in result) - afterArea += poly.SignedArea(); - - intersectionHappened = !(Math.Abs(afterArea - prevArea) < 0.001); - } - break; - default: - throw new ArgumentException("Unknown op type " + op); - } - - - return intersectionHappened ? ResultType.Clipped : ResultType.NoOverlap; - } - - private void AddPolygonToClipper(Polygon polygon, PolyType polyType) - { - var points = ConvertContour(polygon.Hull); - clipper.AddPath(points, polyType, polygon.Hull.IsClosed); - - foreach (var hole in polygon.Holes) - { - points = ConvertContour(hole); - clipper.AddPath(points, polyType, hole.IsClosed); - } - } - - private List ConvertContour(Contour contour) - { - List points = new List(contour.VertexCount); - for (int i = 0; i < contour.VertexCount; i++) - { - points.Add(new IntPoint(contour.Verts[i].x * FloatToIntMult, contour.Verts[i].y * FloatToIntMult)); - } - return points; - } - - private void GetResultsFromNode(PolyNode node, List polygons, bool includeOpenPolygons) - { - foreach (var child in node.Childs) - { - if (child.IsOpen && !includeOpenPolygons) - continue; - - Polygon p = new Polygon(ConvertChain(child.m_polygon, !child.IsOpen)); - polygons.Add(p); - foreach (var holeNode in child.Childs) - { - var hole = ConvertChain(holeNode.m_polygon, !holeNode.IsOpen); - p.Holes.Add(hole); - - GetResultsFromNode(holeNode, polygons, includeOpenPolygons); - } - } - } - - private Contour ConvertChain(List chain, bool closed) - { - return new Contour(chain.Select(ip => new Vector2(ip.X / IntToFloatDiv, ip.Y / IntToFloatDiv)), closed); - } - - } -} diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/BoostClipper/ClipperWrapper.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/BoostClipper/ClipperWrapper.cs.meta deleted file mode 100644 index 5f79d122..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/BoostClipper/ClipperWrapper.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 9276a8b2beda8b54ba7afae4535ba503 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/BoostClipper/License.txt b/Assets/PathBerserker2d/Scripts/PathBerserker2d/BoostClipper/License.txt deleted file mode 100644 index 3e3af47b..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/BoostClipper/License.txt +++ /dev/null @@ -1,24 +0,0 @@ -Boost Software License - Version 1.0 - August 17th, 2003 -http://www.boost.org/LICENSE_1_0.txt - -Permission is hereby granted, free of charge, to any person or organization -obtaining a copy of the software and accompanying documentation covered by -this license (the "Software") to use, reproduce, display, distribute, -execute, and transmit the Software, and to prepare derivative works of the -Software, and to permit third-parties to whom the Software is furnished to -do so, all subject to the following: - -The copyright notices in the Software and this entire statement, including -the above license grant, this restriction and the following disclaimer, -must be included in all copies of the Software, in whole or in part, and -all derivative works of the Software, unless such copies or derivative -works are solely in the form of machine-executable object code generated by -a source language processor. - -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, TITLE AND NON-INFRINGEMENT. IN NO EVENT -SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE -FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, -ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/BoostClipper/License.txt.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/BoostClipper/License.txt.meta deleted file mode 100644 index c790e425..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/BoostClipper/License.txt.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: bf69683b55c9a474ab9f1585d2c62c61 -TextScriptImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/BoostClipper/clipper.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d/BoostClipper/clipper.cs deleted file mode 100644 index 1f08c408..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/BoostClipper/clipper.cs +++ /dev/null @@ -1,4932 +0,0 @@ -/******************************************************************************* -* * -* Author : Angus Johnson * -* Version : 6.4.2 * -* Date : 27 February 2017 * -* Website : http://www.angusj.com * -* Copyright : Angus Johnson 2010-2017 * -* * -* License: * -* Use, modification & distribution is subject to Boost Software License Ver 1. * -* http://www.boost.org/LICENSE_1_0.txt * -* * -* Attributions: * -* The code in this library is an extension of Bala Vatti's clipping algorithm: * -* "A generic solution to polygon clipping" * -* Communications of the ACM, Vol 35, Issue 7 (July 1992) pp 56-63. * -* http://portal.acm.org/citation.cfm?id=129906 * -* * -* Computer graphics and geometric modeling: implementation and algorithms * -* By Max K. Agoston * -* Springer; 1 edition (January 4, 2005) * -* http://books.google.com/books?q=vatti+clipping+agoston * -* * -* See also: * -* "Polygon Offsetting by Computing Winding Numbers" * -* Paper no. DETC2005-85513 pp. 565-575 * -* ASME 2005 International Design Engineering Technical Conferences * -* and Computers and Information in Engineering Conference (IDETC/CIE2005) * -* September 24-28, 2005 , Long Beach, California, USA * -* http://www.me.berkeley.edu/~mcmains/pubs/DAC05OffsetPolygon.pdf * -* * -*******************************************************************************/ - -/******************************************************************************* -* * -* This is a translation of the Delphi Clipper library and the naming style * -* used has retained a Delphi flavour. * -* * -*******************************************************************************/ - -//use_int32: When enabled 32bit ints are used instead of 64bit ints. This -//improve performance but coordinate values are limited to the range +/- 46340 -//#define use_int32 - -//use_xyz: adds a Z member to IntPoint. Adds a minor cost to performance. -//#define use_xyz - -//use_lines: Enables open path clipping. Adds a very minor cost to performance. -#define use_lines - - -using System; -using System.Collections.Generic; -//using System.Text; //for Int128.AsString() & StringBuilder -//using System.IO; //debugging with streamReader & StreamWriter -//using System.Windows.Forms; //debugging to clipboard - -namespace ClipperLib -{ - -#if use_int32 - using cInt = Int32; -#else - using cInt = Int64; -#endif - - using Path = List; - using Paths = List>; - - public struct DoublePoint - { - public double X; - public double Y; - - public DoublePoint(double x = 0, double y = 0) - { - this.X = x; this.Y = y; - } - public DoublePoint(DoublePoint dp) - { - this.X = dp.X; this.Y = dp.Y; - } - public DoublePoint(IntPoint ip) - { - this.X = ip.X; this.Y = ip.Y; - } - }; - - - //------------------------------------------------------------------------------ - // PolyTree & PolyNode classes - //------------------------------------------------------------------------------ - - public class PolyTree : PolyNode - { - internal List m_AllPolys = new List(); - - //The GC probably handles this cleanup more efficiently ... - //~PolyTree(){Clear();} - - public void Clear() - { - for (int i = 0; i < m_AllPolys.Count; i++) - m_AllPolys[i] = null; - m_AllPolys.Clear(); - m_Childs.Clear(); - } - - public PolyNode GetFirst() - { - if (m_Childs.Count > 0) - return m_Childs[0]; - else - return null; - } - - public int Total - { - get - { - int result = m_AllPolys.Count; - //with negative offsets, ignore the hidden outer polygon ... - if (result > 0 && m_Childs[0] != m_AllPolys[0]) result--; - return result; - } - } - - } - - public class PolyNode - { - internal PolyNode m_Parent; - internal Path m_polygon = new Path(); - internal int m_Index; - internal JoinType m_jointype; - internal EndType m_endtype; - internal List m_Childs = new List(); - - private bool IsHoleNode() - { - bool result = true; - PolyNode node = m_Parent; - while (node != null) - { - result = !result; - node = node.m_Parent; - } - return result; - } - - public int ChildCount - { - get { return m_Childs.Count; } - } - - public Path Contour - { - get { return m_polygon; } - } - - internal void AddChild(PolyNode Child) - { - int cnt = m_Childs.Count; - m_Childs.Add(Child); - Child.m_Parent = this; - Child.m_Index = cnt; - } - - public PolyNode GetNext() - { - if (m_Childs.Count > 0) - return m_Childs[0]; - else - return GetNextSiblingUp(); - } - - internal PolyNode GetNextSiblingUp() - { - if (m_Parent == null) - return null; - else if (m_Index == m_Parent.m_Childs.Count - 1) - return m_Parent.GetNextSiblingUp(); - else - return m_Parent.m_Childs[m_Index + 1]; - } - - public List Childs - { - get { return m_Childs; } - } - - public PolyNode Parent - { - get { return m_Parent; } - } - - public bool IsHole - { - get { return IsHoleNode(); } - } - - public bool IsOpen { get; set; } - } - - - //------------------------------------------------------------------------------ - // Int128 struct (enables safe math on signed 64bit integers) - // eg Int128 val1((Int64)9223372036854775807); //ie 2^63 -1 - // Int128 val2((Int64)9223372036854775807); - // Int128 val3 = val1 * val2; - // val3.ToString => "85070591730234615847396907784232501249" (8.5e+37) - //------------------------------------------------------------------------------ - - internal struct Int128 - { - private Int64 hi; - private UInt64 lo; - - public Int128(Int64 _lo) - { - lo = (UInt64)_lo; - if (_lo < 0) hi = -1; - else hi = 0; - } - - public Int128(Int64 _hi, UInt64 _lo) - { - lo = _lo; - hi = _hi; - } - - public Int128(Int128 val) - { - hi = val.hi; - lo = val.lo; - } - - public bool IsNegative() - { - return hi < 0; - } - - public static bool operator ==(Int128 val1, Int128 val2) - { - if ((object)val1 == (object)val2) return true; - else if ((object)val1 == null || (object)val2 == null) return false; - return (val1.hi == val2.hi && val1.lo == val2.lo); - } - - public static bool operator !=(Int128 val1, Int128 val2) - { - return !(val1 == val2); - } - - public override bool Equals(System.Object obj) - { - if (obj == null || !(obj is Int128)) - return false; - Int128 i128 = (Int128)obj; - return (i128.hi == hi && i128.lo == lo); - } - - public override int GetHashCode() - { - return hi.GetHashCode() ^ lo.GetHashCode(); - } - - public static bool operator >(Int128 val1, Int128 val2) - { - if (val1.hi != val2.hi) - return val1.hi > val2.hi; - else - return val1.lo > val2.lo; - } - - public static bool operator <(Int128 val1, Int128 val2) - { - if (val1.hi != val2.hi) - return val1.hi < val2.hi; - else - return val1.lo < val2.lo; - } - - public static Int128 operator +(Int128 lhs, Int128 rhs) - { - lhs.hi += rhs.hi; - lhs.lo += rhs.lo; - if (lhs.lo < rhs.lo) lhs.hi++; - return lhs; - } - - public static Int128 operator -(Int128 lhs, Int128 rhs) - { - return lhs + -rhs; - } - - public static Int128 operator -(Int128 val) - { - if (val.lo == 0) - return new Int128(-val.hi, 0); - else - return new Int128(~val.hi, ~val.lo + 1); - } - - public static explicit operator double(Int128 val) - { - const double shift64 = 18446744073709551616.0; //2^64 - if (val.hi < 0) - { - if (val.lo == 0) - return (double)val.hi * shift64; - else - return -(double)(~val.lo + ~val.hi * shift64); - } - else - return (double)(val.lo + val.hi * shift64); - } - - //nb: Constructing two new Int128 objects every time we want to multiply longs - //is slow. So, although calling the Int128Mul method doesn't look as clean, the - //code runs significantly faster than if we'd used the * operator. - - public static Int128 Int128Mul(Int64 lhs, Int64 rhs) - { - bool negate = (lhs < 0) != (rhs < 0); - if (lhs < 0) lhs = -lhs; - if (rhs < 0) rhs = -rhs; - UInt64 int1Hi = (UInt64)lhs >> 32; - UInt64 int1Lo = (UInt64)lhs & 0xFFFFFFFF; - UInt64 int2Hi = (UInt64)rhs >> 32; - UInt64 int2Lo = (UInt64)rhs & 0xFFFFFFFF; - - //nb: see comments in clipper.pas - UInt64 a = int1Hi * int2Hi; - UInt64 b = int1Lo * int2Lo; - UInt64 c = int1Hi * int2Lo + int1Lo * int2Hi; - - UInt64 lo; - Int64 hi; - hi = (Int64)(a + (c >> 32)); - - unchecked { lo = (c << 32) + b; } - if (lo < b) hi++; - Int128 result = new Int128(hi, lo); - return negate ? -result : result; - } - - }; - - //------------------------------------------------------------------------------ - //------------------------------------------------------------------------------ - - public struct IntPoint - { - public cInt X; - public cInt Y; -#if use_xyz - public cInt Z; - - public IntPoint(cInt x, cInt y, cInt z = 0) - { - this.X = x; this.Y = y; this.Z = z; - } - - public IntPoint(double x, double y, double z = 0) - { - this.X = (cInt)x; this.Y = (cInt)y; this.Z = (cInt)z; - } - - public IntPoint(DoublePoint dp) - { - this.X = (cInt)dp.X; this.Y = (cInt)dp.Y; this.Z = 0; - } - - public IntPoint(IntPoint pt) - { - this.X = pt.X; this.Y = pt.Y; this.Z = pt.Z; - } -#else - public IntPoint(cInt X, cInt Y) - { - this.X = X; this.Y = Y; - } - public IntPoint(double x, double y) - { - this.X = (cInt)x; this.Y = (cInt)y; - } - - public IntPoint(IntPoint pt) - { - this.X = pt.X; this.Y = pt.Y; - } -#endif - - public static bool operator ==(IntPoint a, IntPoint b) - { - return a.X == b.X && a.Y == b.Y; - } - - public static bool operator !=(IntPoint a, IntPoint b) - { - return a.X != b.X || a.Y != b.Y; - } - - public override bool Equals(object obj) - { - if (obj == null) return false; - if (obj is IntPoint) - { - IntPoint a = (IntPoint)obj; - return (X == a.X) && (Y == a.Y); - } - else return false; - } - - public override int GetHashCode() - { - //simply prevents a compiler warning - return base.GetHashCode(); - } - - }// end struct IntPoint - - public struct IntRect - { - public cInt left; - public cInt top; - public cInt right; - public cInt bottom; - - public IntRect(cInt l, cInt t, cInt r, cInt b) - { - this.left = l; this.top = t; - this.right = r; this.bottom = b; - } - public IntRect(IntRect ir) - { - this.left = ir.left; this.top = ir.top; - this.right = ir.right; this.bottom = ir.bottom; - } - } - - public enum ClipType { ctIntersection, ctUnion, ctDifference, ctXor }; - public enum PolyType { ptSubject, ptClip }; - - //By far the most widely used winding rules for polygon filling are - //EvenOdd & NonZero (GDI, GDI+, XLib, OpenGL, Cairo, AGG, Quartz, SVG, Gr32) - //Others rules include Positive, Negative and ABS_GTR_EQ_TWO (only in OpenGL) - //see http://glprogramming.com/red/chapter11.html - public enum PolyFillType { pftEvenOdd, pftNonZero, pftPositive, pftNegative }; - - public enum JoinType { jtSquare, jtRound, jtMiter }; - public enum EndType { etClosedPolygon, etClosedLine, etOpenButt, etOpenSquare, etOpenRound }; - - internal enum EdgeSide { esLeft, esRight }; - internal enum Direction { dRightToLeft, dLeftToRight }; - - internal class TEdge - { - internal IntPoint Bot; - internal IntPoint Curr; //current (updated for every new scanbeam) - internal IntPoint Top; - internal IntPoint Delta; - internal double Dx; - internal PolyType PolyTyp; - internal EdgeSide Side; //side only refers to current side of solution poly - internal int WindDelta; //1 or -1 depending on winding direction - internal int WindCnt; - internal int WindCnt2; //winding count of the opposite polytype - internal int OutIdx; - internal TEdge Next; - internal TEdge Prev; - internal TEdge NextInLML; - internal TEdge NextInAEL; - internal TEdge PrevInAEL; - internal TEdge NextInSEL; - internal TEdge PrevInSEL; - }; - - public class IntersectNode - { - internal TEdge Edge1; - internal TEdge Edge2; - internal IntPoint Pt; - }; - - public class MyIntersectNodeSort : IComparer - { - public int Compare(IntersectNode node1, IntersectNode node2) - { - cInt i = node2.Pt.Y - node1.Pt.Y; - if (i > 0) return 1; - else if (i < 0) return -1; - else return 0; - } - } - - internal class LocalMinima - { - internal cInt Y; - internal TEdge LeftBound; - internal TEdge RightBound; - internal LocalMinima Next; - }; - - internal class Scanbeam - { - internal cInt Y; - internal Scanbeam Next; - }; - - internal class Maxima - { - internal cInt X; - internal Maxima Next; - internal Maxima Prev; - }; - - //OutRec: contains a path in the clipping solution. Edges in the AEL will - //carry a pointer to an OutRec when they are part of the clipping solution. - internal class OutRec - { - internal int Idx; - internal bool IsHole; - internal bool IsOpen; - internal OutRec FirstLeft; //see comments in clipper.pas - internal OutPt Pts; - internal OutPt BottomPt; - internal PolyNode PolyNode; - }; - - internal class OutPt - { - internal int Idx; - internal IntPoint Pt; - internal OutPt Next; - internal OutPt Prev; - }; - - internal class Join - { - internal OutPt OutPt1; - internal OutPt OutPt2; - internal IntPoint OffPt; - }; - - public class ClipperBase - { - internal const double horizontal = -3.4E+38; - internal const int Skip = -2; - internal const int Unassigned = -1; - internal const double tolerance = 1.0E-20; - internal static bool near_zero(double val) { return (val > -tolerance) && (val < tolerance); } - -#if use_int32 - public const cInt loRange = 0x7FFF; - public const cInt hiRange = 0x7FFF; -#else - public const cInt loRange = 0x3FFFFFFF; - public const cInt hiRange = 0x3FFFFFFFFFFFFFFFL; -#endif - - internal LocalMinima m_MinimaList; - internal LocalMinima m_CurrentLM; - internal List> m_edges = new List>(); - internal Scanbeam m_Scanbeam; - internal List m_PolyOuts; - internal TEdge m_ActiveEdges; - internal bool m_UseFullRange; - internal bool m_HasOpenPaths; - - //------------------------------------------------------------------------------ - - public bool PreserveCollinear - { - get; - set; - } - //------------------------------------------------------------------------------ - - public void Swap(ref cInt val1, ref cInt val2) - { - cInt tmp = val1; - val1 = val2; - val2 = tmp; - } - //------------------------------------------------------------------------------ - - internal static bool IsHorizontal(TEdge e) - { - return e.Delta.Y == 0; - } - //------------------------------------------------------------------------------ - - internal bool PointIsVertex(IntPoint pt, OutPt pp) - { - OutPt pp2 = pp; - do - { - if (pp2.Pt == pt) return true; - pp2 = pp2.Next; - } - while (pp2 != pp); - return false; - } - //------------------------------------------------------------------------------ - - internal bool PointOnLineSegment(IntPoint pt, - IntPoint linePt1, IntPoint linePt2, bool UseFullRange) - { - if (UseFullRange) - return ((pt.X == linePt1.X) && (pt.Y == linePt1.Y)) || - ((pt.X == linePt2.X) && (pt.Y == linePt2.Y)) || - (((pt.X > linePt1.X) == (pt.X < linePt2.X)) && - ((pt.Y > linePt1.Y) == (pt.Y < linePt2.Y)) && - ((Int128.Int128Mul((pt.X - linePt1.X), (linePt2.Y - linePt1.Y)) == - Int128.Int128Mul((linePt2.X - linePt1.X), (pt.Y - linePt1.Y))))); - else - return ((pt.X == linePt1.X) && (pt.Y == linePt1.Y)) || - ((pt.X == linePt2.X) && (pt.Y == linePt2.Y)) || - (((pt.X > linePt1.X) == (pt.X < linePt2.X)) && - ((pt.Y > linePt1.Y) == (pt.Y < linePt2.Y)) && - ((pt.X - linePt1.X) * (linePt2.Y - linePt1.Y) == - (linePt2.X - linePt1.X) * (pt.Y - linePt1.Y))); - } - //------------------------------------------------------------------------------ - - internal bool PointOnPolygon(IntPoint pt, OutPt pp, bool UseFullRange) - { - OutPt pp2 = pp; - while (true) - { - if (PointOnLineSegment(pt, pp2.Pt, pp2.Next.Pt, UseFullRange)) - return true; - pp2 = pp2.Next; - if (pp2 == pp) break; - } - return false; - } - //------------------------------------------------------------------------------ - - internal static bool SlopesEqual(TEdge e1, TEdge e2, bool UseFullRange) - { - if (UseFullRange) - return Int128.Int128Mul(e1.Delta.Y, e2.Delta.X) == - Int128.Int128Mul(e1.Delta.X, e2.Delta.Y); - else return (cInt)(e1.Delta.Y) * (e2.Delta.X) == - (cInt)(e1.Delta.X) * (e2.Delta.Y); - } - //------------------------------------------------------------------------------ - - internal static bool SlopesEqual(IntPoint pt1, IntPoint pt2, - IntPoint pt3, bool UseFullRange) - { - if (UseFullRange) - return Int128.Int128Mul(pt1.Y - pt2.Y, pt2.X - pt3.X) == - Int128.Int128Mul(pt1.X - pt2.X, pt2.Y - pt3.Y); - else return - (cInt)(pt1.Y - pt2.Y) * (pt2.X - pt3.X) - (cInt)(pt1.X - pt2.X) * (pt2.Y - pt3.Y) == 0; - } - //------------------------------------------------------------------------------ - - internal static bool SlopesEqual(IntPoint pt1, IntPoint pt2, - IntPoint pt3, IntPoint pt4, bool UseFullRange) - { - if (UseFullRange) - return Int128.Int128Mul(pt1.Y - pt2.Y, pt3.X - pt4.X) == - Int128.Int128Mul(pt1.X - pt2.X, pt3.Y - pt4.Y); - else return - (cInt)(pt1.Y - pt2.Y) * (pt3.X - pt4.X) - (cInt)(pt1.X - pt2.X) * (pt3.Y - pt4.Y) == 0; - } - //------------------------------------------------------------------------------ - - internal ClipperBase() //constructor (nb: no external instantiation) - { - m_MinimaList = null; - m_CurrentLM = null; - m_UseFullRange = false; - m_HasOpenPaths = false; - } - //------------------------------------------------------------------------------ - - public virtual void Clear() - { - DisposeLocalMinimaList(); - for (int i = 0; i < m_edges.Count; ++i) - { - for (int j = 0; j < m_edges[i].Count; ++j) m_edges[i][j] = null; - m_edges[i].Clear(); - } - m_edges.Clear(); - m_UseFullRange = false; - m_HasOpenPaths = false; - } - //------------------------------------------------------------------------------ - - private void DisposeLocalMinimaList() - { - while (m_MinimaList != null) - { - LocalMinima tmpLm = m_MinimaList.Next; - m_MinimaList = null; - m_MinimaList = tmpLm; - } - m_CurrentLM = null; - } - //------------------------------------------------------------------------------ - - void RangeTest(IntPoint Pt, ref bool useFullRange) - { - if (useFullRange) - { - if (Pt.X > hiRange || Pt.Y > hiRange || -Pt.X > hiRange || -Pt.Y > hiRange) - throw new ClipperException("Coordinate outside allowed range"); - } - else if (Pt.X > loRange || Pt.Y > loRange || -Pt.X > loRange || -Pt.Y > loRange) - { - useFullRange = true; - RangeTest(Pt, ref useFullRange); - } - } - //------------------------------------------------------------------------------ - - private void InitEdge(TEdge e, TEdge eNext, - TEdge ePrev, IntPoint pt) - { - e.Next = eNext; - e.Prev = ePrev; - e.Curr = pt; - e.OutIdx = Unassigned; - } - //------------------------------------------------------------------------------ - - private void InitEdge2(TEdge e, PolyType polyType) - { - if (e.Curr.Y >= e.Next.Curr.Y) - { - e.Bot = e.Curr; - e.Top = e.Next.Curr; - } - else - { - e.Top = e.Curr; - e.Bot = e.Next.Curr; - } - SetDx(e); - e.PolyTyp = polyType; - } - //------------------------------------------------------------------------------ - - private TEdge FindNextLocMin(TEdge E) - { - TEdge E2; - for (; ; ) - { - while (E.Bot != E.Prev.Bot || E.Curr == E.Top) E = E.Next; - if (E.Dx != horizontal && E.Prev.Dx != horizontal) break; - while (E.Prev.Dx == horizontal) E = E.Prev; - E2 = E; - while (E.Dx == horizontal) E = E.Next; - if (E.Top.Y == E.Prev.Bot.Y) continue; //ie just an intermediate horz. - if (E2.Prev.Bot.X < E.Bot.X) E = E2; - break; - } - return E; - } - //------------------------------------------------------------------------------ - - private TEdge ProcessBound(TEdge E, bool LeftBoundIsForward) - { - TEdge EStart, Result = E; - TEdge Horz; - - if (Result.OutIdx == Skip) - { - //check if there are edges beyond the skip edge in the bound and if so - //create another LocMin and calling ProcessBound once more ... - E = Result; - if (LeftBoundIsForward) - { - while (E.Top.Y == E.Next.Bot.Y) E = E.Next; - while (E != Result && E.Dx == horizontal) E = E.Prev; - } - else - { - while (E.Top.Y == E.Prev.Bot.Y) E = E.Prev; - while (E != Result && E.Dx == horizontal) E = E.Next; - } - if (E == Result) - { - if (LeftBoundIsForward) Result = E.Next; - else Result = E.Prev; - } - else - { - //there are more edges in the bound beyond result starting with E - if (LeftBoundIsForward) - E = Result.Next; - else - E = Result.Prev; - LocalMinima locMin = new LocalMinima(); - locMin.Next = null; - locMin.Y = E.Bot.Y; - locMin.LeftBound = null; - locMin.RightBound = E; - E.WindDelta = 0; - Result = ProcessBound(E, LeftBoundIsForward); - InsertLocalMinima(locMin); - } - return Result; - } - - if (E.Dx == horizontal) - { - //We need to be careful with open paths because this may not be a - //true local minima (ie E may be following a skip edge). - //Also, consecutive horz. edges may start heading left before going right. - if (LeftBoundIsForward) EStart = E.Prev; - else EStart = E.Next; - if (EStart.Dx == horizontal) //ie an adjoining horizontal skip edge - { - if (EStart.Bot.X != E.Bot.X && EStart.Top.X != E.Bot.X) - ReverseHorizontal(E); - } - else if (EStart.Bot.X != E.Bot.X) - ReverseHorizontal(E); - } - - EStart = E; - if (LeftBoundIsForward) - { - while (Result.Top.Y == Result.Next.Bot.Y && Result.Next.OutIdx != Skip) - Result = Result.Next; - if (Result.Dx == horizontal && Result.Next.OutIdx != Skip) - { - //nb: at the top of a bound, horizontals are added to the bound - //only when the preceding edge attaches to the horizontal's left vertex - //unless a Skip edge is encountered when that becomes the top divide - Horz = Result; - while (Horz.Prev.Dx == horizontal) Horz = Horz.Prev; - if (Horz.Prev.Top.X > Result.Next.Top.X) Result = Horz.Prev; - } - while (E != Result) - { - E.NextInLML = E.Next; - if (E.Dx == horizontal && E != EStart && E.Bot.X != E.Prev.Top.X) - ReverseHorizontal(E); - E = E.Next; - } - if (E.Dx == horizontal && E != EStart && E.Bot.X != E.Prev.Top.X) - ReverseHorizontal(E); - Result = Result.Next; //move to the edge just beyond current bound - } - else - { - while (Result.Top.Y == Result.Prev.Bot.Y && Result.Prev.OutIdx != Skip) - Result = Result.Prev; - if (Result.Dx == horizontal && Result.Prev.OutIdx != Skip) - { - Horz = Result; - while (Horz.Next.Dx == horizontal) Horz = Horz.Next; - if (Horz.Next.Top.X == Result.Prev.Top.X || - Horz.Next.Top.X > Result.Prev.Top.X) Result = Horz.Next; - } - - while (E != Result) - { - E.NextInLML = E.Prev; - if (E.Dx == horizontal && E != EStart && E.Bot.X != E.Next.Top.X) - ReverseHorizontal(E); - E = E.Prev; - } - if (E.Dx == horizontal && E != EStart && E.Bot.X != E.Next.Top.X) - ReverseHorizontal(E); - Result = Result.Prev; //move to the edge just beyond current bound - } - return Result; - } - //------------------------------------------------------------------------------ - - - public bool AddPath(Path pg, PolyType polyType, bool Closed) - { -#if use_lines - if (!Closed && polyType == PolyType.ptClip) - throw new ClipperException("AddPath: Open paths must be subject."); -#else - if (!Closed) - throw new ClipperException("AddPath: Open paths have been disabled."); -#endif - - int highI = (int)pg.Count - 1; - if (Closed) while (highI > 0 && (pg[highI] == pg[0])) --highI; - while (highI > 0 && (pg[highI] == pg[highI - 1])) --highI; - if ((Closed && highI < 2) || (!Closed && highI < 1)) return false; - - //create a new edge array ... - List edges = new List(highI + 1); - for (int i = 0; i <= highI; i++) edges.Add(new TEdge()); - - bool IsFlat = true; - - //1. Basic (first) edge initialization ... - edges[1].Curr = pg[1]; - RangeTest(pg[0], ref m_UseFullRange); - RangeTest(pg[highI], ref m_UseFullRange); - InitEdge(edges[0], edges[1], edges[highI], pg[0]); - InitEdge(edges[highI], edges[0], edges[highI - 1], pg[highI]); - for (int i = highI - 1; i >= 1; --i) - { - RangeTest(pg[i], ref m_UseFullRange); - InitEdge(edges[i], edges[i + 1], edges[i - 1], pg[i]); - } - TEdge eStart = edges[0]; - - //2. Remove duplicate vertices, and (when closed) collinear edges ... - TEdge E = eStart, eLoopStop = eStart; - for (; ; ) - { - //nb: allows matching start and end points when not Closed ... - if (E.Curr == E.Next.Curr && (Closed || E.Next != eStart)) - { - if (E == E.Next) break; - if (E == eStart) eStart = E.Next; - E = RemoveEdge(E); - eLoopStop = E; - continue; - } - if (E.Prev == E.Next) - break; //only two vertices - else if (Closed && - SlopesEqual(E.Prev.Curr, E.Curr, E.Next.Curr, m_UseFullRange) && - (!PreserveCollinear || - !Pt2IsBetweenPt1AndPt3(E.Prev.Curr, E.Curr, E.Next.Curr))) - { - //Collinear edges are allowed for open paths but in closed paths - //the default is to merge adjacent collinear edges into a single edge. - //However, if the PreserveCollinear property is enabled, only overlapping - //collinear edges (ie spikes) will be removed from closed paths. - if (E == eStart) eStart = E.Next; - E = RemoveEdge(E); - E = E.Prev; - eLoopStop = E; - continue; - } - E = E.Next; - if ((E == eLoopStop) || (!Closed && E.Next == eStart)) break; - } - - if ((!Closed && (E == E.Next)) || (Closed && (E.Prev == E.Next))) - return false; - - if (!Closed) - { - m_HasOpenPaths = true; - eStart.Prev.OutIdx = Skip; - } - - //3. Do second stage of edge initialization ... - E = eStart; - do - { - InitEdge2(E, polyType); - E = E.Next; - if (IsFlat && E.Curr.Y != eStart.Curr.Y) IsFlat = false; - } - while (E != eStart); - - //4. Finally, add edge bounds to LocalMinima list ... - - //Totally flat paths must be handled differently when adding them - //to LocalMinima list to avoid endless loops etc ... - if (IsFlat) - { - if (Closed) return false; - E.Prev.OutIdx = Skip; - LocalMinima locMin = new LocalMinima(); - locMin.Next = null; - locMin.Y = E.Bot.Y; - locMin.LeftBound = null; - locMin.RightBound = E; - locMin.RightBound.Side = EdgeSide.esRight; - locMin.RightBound.WindDelta = 0; - for (; ; ) - { - if (E.Bot.X != E.Prev.Top.X) ReverseHorizontal(E); - if (E.Next.OutIdx == Skip) break; - E.NextInLML = E.Next; - E = E.Next; - } - InsertLocalMinima(locMin); - m_edges.Add(edges); - return true; - } - - m_edges.Add(edges); - bool leftBoundIsForward; - TEdge EMin = null; - - //workaround to avoid an endless loop in the while loop below when - //open paths have matching start and end points ... - if (E.Prev.Bot == E.Prev.Top) E = E.Next; - - for (; ; ) - { - E = FindNextLocMin(E); - if (E == EMin) break; - else if (EMin == null) EMin = E; - - //E and E.Prev now share a local minima (left aligned if horizontal). - //Compare their slopes to find which starts which bound ... - LocalMinima locMin = new LocalMinima(); - locMin.Next = null; - locMin.Y = E.Bot.Y; - if (E.Dx < E.Prev.Dx) - { - locMin.LeftBound = E.Prev; - locMin.RightBound = E; - leftBoundIsForward = false; //Q.nextInLML = Q.prev - } - else - { - locMin.LeftBound = E; - locMin.RightBound = E.Prev; - leftBoundIsForward = true; //Q.nextInLML = Q.next - } - locMin.LeftBound.Side = EdgeSide.esLeft; - locMin.RightBound.Side = EdgeSide.esRight; - - if (!Closed) locMin.LeftBound.WindDelta = 0; - else if (locMin.LeftBound.Next == locMin.RightBound) - locMin.LeftBound.WindDelta = -1; - else locMin.LeftBound.WindDelta = 1; - locMin.RightBound.WindDelta = -locMin.LeftBound.WindDelta; - - E = ProcessBound(locMin.LeftBound, leftBoundIsForward); - if (E.OutIdx == Skip) E = ProcessBound(E, leftBoundIsForward); - - TEdge E2 = ProcessBound(locMin.RightBound, !leftBoundIsForward); - if (E2.OutIdx == Skip) E2 = ProcessBound(E2, !leftBoundIsForward); - - if (locMin.LeftBound.OutIdx == Skip) - locMin.LeftBound = null; - else if (locMin.RightBound.OutIdx == Skip) - locMin.RightBound = null; - InsertLocalMinima(locMin); - if (!leftBoundIsForward) E = E2; - } - return true; - - } - //------------------------------------------------------------------------------ - - public bool AddPaths(Paths ppg, PolyType polyType, bool closed) - { - bool result = false; - for (int i = 0; i < ppg.Count; ++i) - if (AddPath(ppg[i], polyType, closed)) result = true; - return result; - } - //------------------------------------------------------------------------------ - - internal bool Pt2IsBetweenPt1AndPt3(IntPoint pt1, IntPoint pt2, IntPoint pt3) - { - if ((pt1 == pt3) || (pt1 == pt2) || (pt3 == pt2)) return false; - else if (pt1.X != pt3.X) return (pt2.X > pt1.X) == (pt2.X < pt3.X); - else return (pt2.Y > pt1.Y) == (pt2.Y < pt3.Y); - } - //------------------------------------------------------------------------------ - - TEdge RemoveEdge(TEdge e) - { - //removes e from double_linked_list (but without removing from memory) - e.Prev.Next = e.Next; - e.Next.Prev = e.Prev; - TEdge result = e.Next; - e.Prev = null; //flag as removed (see ClipperBase.Clear) - return result; - } - //------------------------------------------------------------------------------ - - private void SetDx(TEdge e) - { - e.Delta.X = (e.Top.X - e.Bot.X); - e.Delta.Y = (e.Top.Y - e.Bot.Y); - if (e.Delta.Y == 0) e.Dx = horizontal; - else e.Dx = (double)(e.Delta.X) / (e.Delta.Y); - } - //--------------------------------------------------------------------------- - - private void InsertLocalMinima(LocalMinima newLm) - { - if (m_MinimaList == null) - { - m_MinimaList = newLm; - } - else if (newLm.Y >= m_MinimaList.Y) - { - newLm.Next = m_MinimaList; - m_MinimaList = newLm; - } - else - { - LocalMinima tmpLm = m_MinimaList; - while (tmpLm.Next != null && (newLm.Y < tmpLm.Next.Y)) - tmpLm = tmpLm.Next; - newLm.Next = tmpLm.Next; - tmpLm.Next = newLm; - } - } - //------------------------------------------------------------------------------ - - internal Boolean PopLocalMinima(cInt Y, out LocalMinima current) - { - current = m_CurrentLM; - if (m_CurrentLM != null && m_CurrentLM.Y == Y) - { - m_CurrentLM = m_CurrentLM.Next; - return true; - } - return false; - } - //------------------------------------------------------------------------------ - - private void ReverseHorizontal(TEdge e) - { - //swap horizontal edges' top and bottom x's so they follow the natural - //progression of the bounds - ie so their xbots will align with the - //adjoining lower edge. [Helpful in the ProcessHorizontal() method.] - Swap(ref e.Top.X, ref e.Bot.X); -#if use_xyz - Swap(ref e.Top.Z, ref e.Bot.Z); -#endif - } - //------------------------------------------------------------------------------ - - internal virtual void Reset() - { - m_CurrentLM = m_MinimaList; - if (m_CurrentLM == null) return; //ie nothing to process - - //reset all edges ... - m_Scanbeam = null; - LocalMinima lm = m_MinimaList; - while (lm != null) - { - InsertScanbeam(lm.Y); - TEdge e = lm.LeftBound; - if (e != null) - { - e.Curr = e.Bot; - e.OutIdx = Unassigned; - } - e = lm.RightBound; - if (e != null) - { - e.Curr = e.Bot; - e.OutIdx = Unassigned; - } - lm = lm.Next; - } - m_ActiveEdges = null; - } - //------------------------------------------------------------------------------ - - public static IntRect GetBounds(Paths paths) - { - int i = 0, cnt = paths.Count; - while (i < cnt && paths[i].Count == 0) i++; - if (i == cnt) return new IntRect(0, 0, 0, 0); - IntRect result = new IntRect(); - result.left = paths[i][0].X; - result.right = result.left; - result.top = paths[i][0].Y; - result.bottom = result.top; - for (; i < cnt; i++) - for (int j = 0; j < paths[i].Count; j++) - { - if (paths[i][j].X < result.left) result.left = paths[i][j].X; - else if (paths[i][j].X > result.right) result.right = paths[i][j].X; - if (paths[i][j].Y < result.top) result.top = paths[i][j].Y; - else if (paths[i][j].Y > result.bottom) result.bottom = paths[i][j].Y; - } - return result; - } - //------------------------------------------------------------------------------ - - internal void InsertScanbeam(cInt Y) - { - //single-linked list: sorted descending, ignoring dups. - if (m_Scanbeam == null) - { - m_Scanbeam = new Scanbeam(); - m_Scanbeam.Next = null; - m_Scanbeam.Y = Y; - } - else if (Y > m_Scanbeam.Y) - { - Scanbeam newSb = new Scanbeam(); - newSb.Y = Y; - newSb.Next = m_Scanbeam; - m_Scanbeam = newSb; - } - else - { - Scanbeam sb2 = m_Scanbeam; - while (sb2.Next != null && (Y <= sb2.Next.Y)) sb2 = sb2.Next; - if (Y == sb2.Y) return; //ie ignores duplicates - Scanbeam newSb = new Scanbeam(); - newSb.Y = Y; - newSb.Next = sb2.Next; - sb2.Next = newSb; - } - } - //------------------------------------------------------------------------------ - - internal Boolean PopScanbeam(out cInt Y) - { - if (m_Scanbeam == null) - { - Y = 0; - return false; - } - Y = m_Scanbeam.Y; - m_Scanbeam = m_Scanbeam.Next; - return true; - } - //------------------------------------------------------------------------------ - - internal Boolean LocalMinimaPending() - { - return (m_CurrentLM != null); - } - //------------------------------------------------------------------------------ - - internal OutRec CreateOutRec() - { - OutRec result = new OutRec(); - result.Idx = Unassigned; - result.IsHole = false; - result.IsOpen = false; - result.FirstLeft = null; - result.Pts = null; - result.BottomPt = null; - result.PolyNode = null; - m_PolyOuts.Add(result); - result.Idx = m_PolyOuts.Count - 1; - return result; - } - //------------------------------------------------------------------------------ - - internal void DisposeOutRec(int index) - { - OutRec outRec = m_PolyOuts[index]; - outRec.Pts = null; - outRec = null; - m_PolyOuts[index] = null; - } - //------------------------------------------------------------------------------ - - internal void UpdateEdgeIntoAEL(ref TEdge e) - { - if (e.NextInLML == null) - throw new ClipperException("UpdateEdgeIntoAEL: invalid call"); - TEdge AelPrev = e.PrevInAEL; - TEdge AelNext = e.NextInAEL; - e.NextInLML.OutIdx = e.OutIdx; - if (AelPrev != null) - AelPrev.NextInAEL = e.NextInLML; - else m_ActiveEdges = e.NextInLML; - if (AelNext != null) - AelNext.PrevInAEL = e.NextInLML; - e.NextInLML.Side = e.Side; - e.NextInLML.WindDelta = e.WindDelta; - e.NextInLML.WindCnt = e.WindCnt; - e.NextInLML.WindCnt2 = e.WindCnt2; - e = e.NextInLML; - e.Curr = e.Bot; - e.PrevInAEL = AelPrev; - e.NextInAEL = AelNext; - if (!IsHorizontal(e)) InsertScanbeam(e.Top.Y); - } - //------------------------------------------------------------------------------ - - internal void SwapPositionsInAEL(TEdge edge1, TEdge edge2) - { - //check that one or other edge hasn't already been removed from AEL ... - if (edge1.NextInAEL == edge1.PrevInAEL || - edge2.NextInAEL == edge2.PrevInAEL) return; - - if (edge1.NextInAEL == edge2) - { - TEdge next = edge2.NextInAEL; - if (next != null) - next.PrevInAEL = edge1; - TEdge prev = edge1.PrevInAEL; - if (prev != null) - prev.NextInAEL = edge2; - edge2.PrevInAEL = prev; - edge2.NextInAEL = edge1; - edge1.PrevInAEL = edge2; - edge1.NextInAEL = next; - } - else if (edge2.NextInAEL == edge1) - { - TEdge next = edge1.NextInAEL; - if (next != null) - next.PrevInAEL = edge2; - TEdge prev = edge2.PrevInAEL; - if (prev != null) - prev.NextInAEL = edge1; - edge1.PrevInAEL = prev; - edge1.NextInAEL = edge2; - edge2.PrevInAEL = edge1; - edge2.NextInAEL = next; - } - else - { - TEdge next = edge1.NextInAEL; - TEdge prev = edge1.PrevInAEL; - edge1.NextInAEL = edge2.NextInAEL; - if (edge1.NextInAEL != null) - edge1.NextInAEL.PrevInAEL = edge1; - edge1.PrevInAEL = edge2.PrevInAEL; - if (edge1.PrevInAEL != null) - edge1.PrevInAEL.NextInAEL = edge1; - edge2.NextInAEL = next; - if (edge2.NextInAEL != null) - edge2.NextInAEL.PrevInAEL = edge2; - edge2.PrevInAEL = prev; - if (edge2.PrevInAEL != null) - edge2.PrevInAEL.NextInAEL = edge2; - } - - if (edge1.PrevInAEL == null) - m_ActiveEdges = edge1; - else if (edge2.PrevInAEL == null) - m_ActiveEdges = edge2; - } - //------------------------------------------------------------------------------ - - internal void DeleteFromAEL(TEdge e) - { - TEdge AelPrev = e.PrevInAEL; - TEdge AelNext = e.NextInAEL; - if (AelPrev == null && AelNext == null && (e != m_ActiveEdges)) - return; //already deleted - if (AelPrev != null) - AelPrev.NextInAEL = AelNext; - else m_ActiveEdges = AelNext; - if (AelNext != null) - AelNext.PrevInAEL = AelPrev; - e.NextInAEL = null; - e.PrevInAEL = null; - } - //------------------------------------------------------------------------------ - - } //end ClipperBase - - public class Clipper : ClipperBase - { - //InitOptions that can be passed to the constructor ... - public const int ioReverseSolution = 1; - public const int ioStrictlySimple = 2; - public const int ioPreserveCollinear = 4; - - private ClipType m_ClipType; - private Maxima m_Maxima; - private TEdge m_SortedEdges; - private List m_IntersectList; - IComparer m_IntersectNodeComparer; - private bool m_ExecuteLocked; - private PolyFillType m_ClipFillType; - private PolyFillType m_SubjFillType; - private List m_Joins; - private List m_GhostJoins; - private bool m_UsingPolyTree; -#if use_xyz - public delegate void ZFillCallback(IntPoint bot1, IntPoint top1, - IntPoint bot2, IntPoint top2, ref IntPoint pt); - public ZFillCallback ZFillFunction { get; set; } -#endif - public Clipper(int InitOptions = 0) : base() //constructor - { - m_Scanbeam = null; - m_Maxima = null; - m_ActiveEdges = null; - m_SortedEdges = null; - m_IntersectList = new List(); - m_IntersectNodeComparer = new MyIntersectNodeSort(); - m_ExecuteLocked = false; - m_UsingPolyTree = false; - m_PolyOuts = new List(); - m_Joins = new List(); - m_GhostJoins = new List(); - ReverseSolution = (ioReverseSolution & InitOptions) != 0; - StrictlySimple = (ioStrictlySimple & InitOptions) != 0; - PreserveCollinear = (ioPreserveCollinear & InitOptions) != 0; -#if use_xyz - ZFillFunction = null; -#endif - } - //------------------------------------------------------------------------------ - - private void InsertMaxima(cInt X) - { - //double-linked list: sorted ascending, ignoring dups. - Maxima newMax = new Maxima(); - newMax.X = X; - if (m_Maxima == null) - { - m_Maxima = newMax; - m_Maxima.Next = null; - m_Maxima.Prev = null; - } - else if (X < m_Maxima.X) - { - newMax.Next = m_Maxima; - newMax.Prev = null; - m_Maxima = newMax; - } - else - { - Maxima m = m_Maxima; - while (m.Next != null && (X >= m.Next.X)) m = m.Next; - if (X == m.X) return; //ie ignores duplicates (& CG to clean up newMax) - //insert newMax between m and m.Next ... - newMax.Next = m.Next; - newMax.Prev = m; - if (m.Next != null) m.Next.Prev = newMax; - m.Next = newMax; - } - } - //------------------------------------------------------------------------------ - - public bool ReverseSolution - { - get; - set; - } - //------------------------------------------------------------------------------ - - public bool StrictlySimple - { - get; - set; - } - //------------------------------------------------------------------------------ - - public bool Execute(ClipType clipType, Paths solution, - PolyFillType FillType = PolyFillType.pftEvenOdd) - { - return Execute(clipType, solution, FillType, FillType); - } - //------------------------------------------------------------------------------ - - public bool Execute(ClipType clipType, PolyTree polytree, - PolyFillType FillType = PolyFillType.pftEvenOdd) - { - return Execute(clipType, polytree, FillType, FillType); - } - //------------------------------------------------------------------------------ - - public bool Execute(ClipType clipType, Paths solution, - PolyFillType subjFillType, PolyFillType clipFillType) - { - if (m_ExecuteLocked) return false; - if (m_HasOpenPaths) throw - new ClipperException("Error: PolyTree struct is needed for open path clipping."); - - m_ExecuteLocked = true; - solution.Clear(); - m_SubjFillType = subjFillType; - m_ClipFillType = clipFillType; - m_ClipType = clipType; - m_UsingPolyTree = false; - bool succeeded; - try - { - succeeded = ExecuteInternal(); - //build the return polygons ... - if (succeeded) BuildResult(solution); - } - finally - { - DisposeAllPolyPts(); - m_ExecuteLocked = false; - } - return succeeded; - } - //------------------------------------------------------------------------------ - - public bool Execute(ClipType clipType, PolyTree polytree, - PolyFillType subjFillType, PolyFillType clipFillType) - { - if (m_ExecuteLocked) return false; - m_ExecuteLocked = true; - m_SubjFillType = subjFillType; - m_ClipFillType = clipFillType; - m_ClipType = clipType; - m_UsingPolyTree = true; - bool succeeded; - try - { - succeeded = ExecuteInternal(); - //build the return polygons ... - if (succeeded) BuildResult2(polytree); - } - finally - { - DisposeAllPolyPts(); - m_ExecuteLocked = false; - } - return succeeded; - } - //------------------------------------------------------------------------------ - - internal void FixHoleLinkage(OutRec outRec) - { - //skip if an outermost polygon or - //already already points to the correct FirstLeft ... - if (outRec.FirstLeft == null || - (outRec.IsHole != outRec.FirstLeft.IsHole && - outRec.FirstLeft.Pts != null)) return; - - OutRec orfl = outRec.FirstLeft; - while (orfl != null && ((orfl.IsHole == outRec.IsHole) || orfl.Pts == null)) - orfl = orfl.FirstLeft; - outRec.FirstLeft = orfl; - } - //------------------------------------------------------------------------------ - - private bool ExecuteInternal() - { - try - { - Reset(); - m_SortedEdges = null; - m_Maxima = null; - - cInt botY, topY; - if (!PopScanbeam(out botY)) return false; - InsertLocalMinimaIntoAEL(botY); - while (PopScanbeam(out topY) || LocalMinimaPending()) - { - ProcessHorizontals(); - m_GhostJoins.Clear(); - if (!ProcessIntersections(topY)) return false; - ProcessEdgesAtTopOfScanbeam(topY); - botY = topY; - InsertLocalMinimaIntoAEL(botY); - } - - //fix orientations ... - foreach (OutRec outRec in m_PolyOuts) - { - if (outRec.Pts == null || outRec.IsOpen) continue; - if ((outRec.IsHole ^ ReverseSolution) == (Area(outRec) > 0)) - ReversePolyPtLinks(outRec.Pts); - } - - JoinCommonEdges(); - - foreach (OutRec outRec in m_PolyOuts) - { - if (outRec.Pts == null) - continue; - else if (outRec.IsOpen) - FixupOutPolyline(outRec); - else - FixupOutPolygon(outRec); - } - - if (StrictlySimple) DoSimplePolygons(); - return true; - } - //catch { return false; } - finally - { - m_Joins.Clear(); - m_GhostJoins.Clear(); - } - } - //------------------------------------------------------------------------------ - - private void DisposeAllPolyPts() - { - for (int i = 0; i < m_PolyOuts.Count; ++i) DisposeOutRec(i); - m_PolyOuts.Clear(); - } - //------------------------------------------------------------------------------ - - private void AddJoin(OutPt Op1, OutPt Op2, IntPoint OffPt) - { - Join j = new Join(); - j.OutPt1 = Op1; - j.OutPt2 = Op2; - j.OffPt = OffPt; - m_Joins.Add(j); - } - //------------------------------------------------------------------------------ - - private void AddGhostJoin(OutPt Op, IntPoint OffPt) - { - Join j = new Join(); - j.OutPt1 = Op; - j.OffPt = OffPt; - m_GhostJoins.Add(j); - } - //------------------------------------------------------------------------------ - -#if use_xyz - internal void SetZ(ref IntPoint pt, TEdge e1, TEdge e2) - { - if (pt.Z != 0 || ZFillFunction == null) return; - else if (pt == e1.Bot) pt.Z = e1.Bot.Z; - else if (pt == e1.Top) pt.Z = e1.Top.Z; - else if (pt == e2.Bot) pt.Z = e2.Bot.Z; - else if (pt == e2.Top) pt.Z = e2.Top.Z; - else ZFillFunction(e1.Bot, e1.Top, e2.Bot, e2.Top, ref pt); - } - //------------------------------------------------------------------------------ -#endif - - private void InsertLocalMinimaIntoAEL(cInt botY) - { - LocalMinima lm; - while (PopLocalMinima(botY, out lm)) - { - TEdge lb = lm.LeftBound; - TEdge rb = lm.RightBound; - - OutPt Op1 = null; - if (lb == null) - { - InsertEdgeIntoAEL(rb, null); - SetWindingCount(rb); - if (IsContributing(rb)) - Op1 = AddOutPt(rb, rb.Bot); - } - else if (rb == null) - { - InsertEdgeIntoAEL(lb, null); - SetWindingCount(lb); - if (IsContributing(lb)) - Op1 = AddOutPt(lb, lb.Bot); - InsertScanbeam(lb.Top.Y); - } - else - { - InsertEdgeIntoAEL(lb, null); - InsertEdgeIntoAEL(rb, lb); - SetWindingCount(lb); - rb.WindCnt = lb.WindCnt; - rb.WindCnt2 = lb.WindCnt2; - if (IsContributing(lb)) - Op1 = AddLocalMinPoly(lb, rb, lb.Bot); - InsertScanbeam(lb.Top.Y); - } - - if (rb != null) - { - if (IsHorizontal(rb)) - { - if (rb.NextInLML != null) - InsertScanbeam(rb.NextInLML.Top.Y); - AddEdgeToSEL(rb); - } - else - InsertScanbeam(rb.Top.Y); - } - - if (lb == null || rb == null) continue; - - //if output polygons share an Edge with a horizontal rb, they'll need joining later ... - if (Op1 != null && IsHorizontal(rb) && - m_GhostJoins.Count > 0 && rb.WindDelta != 0) - { - for (int i = 0; i < m_GhostJoins.Count; i++) - { - //if the horizontal Rb and a 'ghost' horizontal overlap, then convert - //the 'ghost' join to a real join ready for later ... - Join j = m_GhostJoins[i]; - if (HorzSegmentsOverlap(j.OutPt1.Pt.X, j.OffPt.X, rb.Bot.X, rb.Top.X)) - AddJoin(j.OutPt1, Op1, j.OffPt); - } - } - - if (lb.OutIdx >= 0 && lb.PrevInAEL != null && - lb.PrevInAEL.Curr.X == lb.Bot.X && - lb.PrevInAEL.OutIdx >= 0 && - SlopesEqual(lb.PrevInAEL.Curr, lb.PrevInAEL.Top, lb.Curr, lb.Top, m_UseFullRange) && - lb.WindDelta != 0 && lb.PrevInAEL.WindDelta != 0) - { - OutPt Op2 = AddOutPt(lb.PrevInAEL, lb.Bot); - AddJoin(Op1, Op2, lb.Top); - } - - if (lb.NextInAEL != rb) - { - - if (rb.OutIdx >= 0 && rb.PrevInAEL.OutIdx >= 0 && - SlopesEqual(rb.PrevInAEL.Curr, rb.PrevInAEL.Top, rb.Curr, rb.Top, m_UseFullRange) && - rb.WindDelta != 0 && rb.PrevInAEL.WindDelta != 0) - { - OutPt Op2 = AddOutPt(rb.PrevInAEL, rb.Bot); - AddJoin(Op1, Op2, rb.Top); - } - - TEdge e = lb.NextInAEL; - if (e != null) - while (e != rb) - { - //nb: For calculating winding counts etc, IntersectEdges() assumes - //that param1 will be to the right of param2 ABOVE the intersection ... - IntersectEdges(rb, e, lb.Curr); //order important here - e = e.NextInAEL; - } - } - } - } - //------------------------------------------------------------------------------ - - private void InsertEdgeIntoAEL(TEdge edge, TEdge startEdge) - { - if (m_ActiveEdges == null) - { - edge.PrevInAEL = null; - edge.NextInAEL = null; - m_ActiveEdges = edge; - } - else if (startEdge == null && E2InsertsBeforeE1(m_ActiveEdges, edge)) - { - edge.PrevInAEL = null; - edge.NextInAEL = m_ActiveEdges; - m_ActiveEdges.PrevInAEL = edge; - m_ActiveEdges = edge; - } - else - { - if (startEdge == null) startEdge = m_ActiveEdges; - while (startEdge.NextInAEL != null && - !E2InsertsBeforeE1(startEdge.NextInAEL, edge)) - startEdge = startEdge.NextInAEL; - edge.NextInAEL = startEdge.NextInAEL; - if (startEdge.NextInAEL != null) startEdge.NextInAEL.PrevInAEL = edge; - edge.PrevInAEL = startEdge; - startEdge.NextInAEL = edge; - } - } - //---------------------------------------------------------------------- - - private bool E2InsertsBeforeE1(TEdge e1, TEdge e2) - { - if (e2.Curr.X == e1.Curr.X) - { - if (e2.Top.Y > e1.Top.Y) - return e2.Top.X < TopX(e1, e2.Top.Y); - else return e1.Top.X > TopX(e2, e1.Top.Y); - } - else return e2.Curr.X < e1.Curr.X; - } - //------------------------------------------------------------------------------ - - private bool IsEvenOddFillType(TEdge edge) - { - if (edge.PolyTyp == PolyType.ptSubject) - return m_SubjFillType == PolyFillType.pftEvenOdd; - else - return m_ClipFillType == PolyFillType.pftEvenOdd; - } - //------------------------------------------------------------------------------ - - private bool IsEvenOddAltFillType(TEdge edge) - { - if (edge.PolyTyp == PolyType.ptSubject) - return m_ClipFillType == PolyFillType.pftEvenOdd; - else - return m_SubjFillType == PolyFillType.pftEvenOdd; - } - //------------------------------------------------------------------------------ - - private bool IsContributing(TEdge edge) - { - PolyFillType pft, pft2; - if (edge.PolyTyp == PolyType.ptSubject) - { - pft = m_SubjFillType; - pft2 = m_ClipFillType; - } - else - { - pft = m_ClipFillType; - pft2 = m_SubjFillType; - } - - switch (pft) - { - case PolyFillType.pftEvenOdd: - //return false if a subj line has been flagged as inside a subj polygon - if (edge.WindDelta == 0 && edge.WindCnt != 1) return false; - break; - case PolyFillType.pftNonZero: - if (Math.Abs(edge.WindCnt) != 1) return false; - break; - case PolyFillType.pftPositive: - if (edge.WindCnt != 1) return false; - break; - default: //PolyFillType.pftNegative - if (edge.WindCnt != -1) return false; - break; - } - - switch (m_ClipType) - { - case ClipType.ctIntersection: - switch (pft2) - { - case PolyFillType.pftEvenOdd: - case PolyFillType.pftNonZero: - return (edge.WindCnt2 != 0); - case PolyFillType.pftPositive: - return (edge.WindCnt2 > 0); - default: - return (edge.WindCnt2 < 0); - } - case ClipType.ctUnion: - switch (pft2) - { - case PolyFillType.pftEvenOdd: - case PolyFillType.pftNonZero: - return (edge.WindCnt2 == 0); - case PolyFillType.pftPositive: - return (edge.WindCnt2 <= 0); - default: - return (edge.WindCnt2 >= 0); - } - case ClipType.ctDifference: - if (edge.PolyTyp == PolyType.ptSubject) - switch (pft2) - { - case PolyFillType.pftEvenOdd: - case PolyFillType.pftNonZero: - return (edge.WindCnt2 == 0); - case PolyFillType.pftPositive: - return (edge.WindCnt2 <= 0); - default: - return (edge.WindCnt2 >= 0); - } - else - switch (pft2) - { - case PolyFillType.pftEvenOdd: - case PolyFillType.pftNonZero: - return (edge.WindCnt2 != 0); - case PolyFillType.pftPositive: - return (edge.WindCnt2 > 0); - default: - return (edge.WindCnt2 < 0); - } - case ClipType.ctXor: - if (edge.WindDelta == 0) //XOr always contributing unless open - switch (pft2) - { - case PolyFillType.pftEvenOdd: - case PolyFillType.pftNonZero: - return (edge.WindCnt2 == 0); - case PolyFillType.pftPositive: - return (edge.WindCnt2 <= 0); - default: - return (edge.WindCnt2 >= 0); - } - else - return true; - } - return true; - } - //------------------------------------------------------------------------------ - - private void SetWindingCount(TEdge edge) - { - TEdge e = edge.PrevInAEL; - //find the edge of the same polytype that immediately preceeds 'edge' in AEL - while (e != null && ((e.PolyTyp != edge.PolyTyp) || (e.WindDelta == 0))) e = e.PrevInAEL; - if (e == null) - { - PolyFillType pft; - pft = (edge.PolyTyp == PolyType.ptSubject ? m_SubjFillType : m_ClipFillType); - if (edge.WindDelta == 0) edge.WindCnt = (pft == PolyFillType.pftNegative ? -1 : 1); - else edge.WindCnt = edge.WindDelta; - edge.WindCnt2 = 0; - e = m_ActiveEdges; //ie get ready to calc WindCnt2 - } - else if (edge.WindDelta == 0 && m_ClipType != ClipType.ctUnion) - { - edge.WindCnt = 1; - edge.WindCnt2 = e.WindCnt2; - e = e.NextInAEL; //ie get ready to calc WindCnt2 - } - else if (IsEvenOddFillType(edge)) - { - //EvenOdd filling ... - if (edge.WindDelta == 0) - { - //are we inside a subj polygon ... - bool Inside = true; - TEdge e2 = e.PrevInAEL; - while (e2 != null) - { - if (e2.PolyTyp == e.PolyTyp && e2.WindDelta != 0) - Inside = !Inside; - e2 = e2.PrevInAEL; - } - edge.WindCnt = (Inside ? 0 : 1); - } - else - { - edge.WindCnt = edge.WindDelta; - } - edge.WindCnt2 = e.WindCnt2; - e = e.NextInAEL; //ie get ready to calc WindCnt2 - } - else - { - //nonZero, Positive or Negative filling ... - if (e.WindCnt * e.WindDelta < 0) - { - //prev edge is 'decreasing' WindCount (WC) toward zero - //so we're outside the previous polygon ... - if (Math.Abs(e.WindCnt) > 1) - { - //outside prev poly but still inside another. - //when reversing direction of prev poly use the same WC - if (e.WindDelta * edge.WindDelta < 0) edge.WindCnt = e.WindCnt; - //otherwise continue to 'decrease' WC ... - else edge.WindCnt = e.WindCnt + edge.WindDelta; - } - else - //now outside all polys of same polytype so set own WC ... - edge.WindCnt = (edge.WindDelta == 0 ? 1 : edge.WindDelta); - } - else - { - //prev edge is 'increasing' WindCount (WC) away from zero - //so we're inside the previous polygon ... - if (edge.WindDelta == 0) - edge.WindCnt = (e.WindCnt < 0 ? e.WindCnt - 1 : e.WindCnt + 1); - //if wind direction is reversing prev then use same WC - else if (e.WindDelta * edge.WindDelta < 0) - edge.WindCnt = e.WindCnt; - //otherwise add to WC ... - else edge.WindCnt = e.WindCnt + edge.WindDelta; - } - edge.WindCnt2 = e.WindCnt2; - e = e.NextInAEL; //ie get ready to calc WindCnt2 - } - - //update WindCnt2 ... - if (IsEvenOddAltFillType(edge)) - { - //EvenOdd filling ... - while (e != edge) - { - if (e.WindDelta != 0) - edge.WindCnt2 = (edge.WindCnt2 == 0 ? 1 : 0); - e = e.NextInAEL; - } - } - else - { - //nonZero, Positive or Negative filling ... - while (e != edge) - { - edge.WindCnt2 += e.WindDelta; - e = e.NextInAEL; - } - } - } - //------------------------------------------------------------------------------ - - private void AddEdgeToSEL(TEdge edge) - { - //SEL pointers in PEdge are use to build transient lists of horizontal edges. - //However, since we don't need to worry about processing order, all additions - //are made to the front of the list ... - if (m_SortedEdges == null) - { - m_SortedEdges = edge; - edge.PrevInSEL = null; - edge.NextInSEL = null; - } - else - { - edge.NextInSEL = m_SortedEdges; - edge.PrevInSEL = null; - m_SortedEdges.PrevInSEL = edge; - m_SortedEdges = edge; - } - } - //------------------------------------------------------------------------------ - - internal Boolean PopEdgeFromSEL(out TEdge e) - { - //Pop edge from front of SEL (ie SEL is a FILO list) - e = m_SortedEdges; - if (e == null) return false; - TEdge oldE = e; - m_SortedEdges = e.NextInSEL; - if (m_SortedEdges != null) m_SortedEdges.PrevInSEL = null; - oldE.NextInSEL = null; - oldE.PrevInSEL = null; - return true; - } - //------------------------------------------------------------------------------ - - private void CopyAELToSEL() - { - TEdge e = m_ActiveEdges; - m_SortedEdges = e; - while (e != null) - { - e.PrevInSEL = e.PrevInAEL; - e.NextInSEL = e.NextInAEL; - e = e.NextInAEL; - } - } - //------------------------------------------------------------------------------ - - private void SwapPositionsInSEL(TEdge edge1, TEdge edge2) - { - if (edge1.NextInSEL == null && edge1.PrevInSEL == null) - return; - if (edge2.NextInSEL == null && edge2.PrevInSEL == null) - return; - - if (edge1.NextInSEL == edge2) - { - TEdge next = edge2.NextInSEL; - if (next != null) - next.PrevInSEL = edge1; - TEdge prev = edge1.PrevInSEL; - if (prev != null) - prev.NextInSEL = edge2; - edge2.PrevInSEL = prev; - edge2.NextInSEL = edge1; - edge1.PrevInSEL = edge2; - edge1.NextInSEL = next; - } - else if (edge2.NextInSEL == edge1) - { - TEdge next = edge1.NextInSEL; - if (next != null) - next.PrevInSEL = edge2; - TEdge prev = edge2.PrevInSEL; - if (prev != null) - prev.NextInSEL = edge1; - edge1.PrevInSEL = prev; - edge1.NextInSEL = edge2; - edge2.PrevInSEL = edge1; - edge2.NextInSEL = next; - } - else - { - TEdge next = edge1.NextInSEL; - TEdge prev = edge1.PrevInSEL; - edge1.NextInSEL = edge2.NextInSEL; - if (edge1.NextInSEL != null) - edge1.NextInSEL.PrevInSEL = edge1; - edge1.PrevInSEL = edge2.PrevInSEL; - if (edge1.PrevInSEL != null) - edge1.PrevInSEL.NextInSEL = edge1; - edge2.NextInSEL = next; - if (edge2.NextInSEL != null) - edge2.NextInSEL.PrevInSEL = edge2; - edge2.PrevInSEL = prev; - if (edge2.PrevInSEL != null) - edge2.PrevInSEL.NextInSEL = edge2; - } - - if (edge1.PrevInSEL == null) - m_SortedEdges = edge1; - else if (edge2.PrevInSEL == null) - m_SortedEdges = edge2; - } - //------------------------------------------------------------------------------ - - - private void AddLocalMaxPoly(TEdge e1, TEdge e2, IntPoint pt) - { - AddOutPt(e1, pt); - if (e2.WindDelta == 0) AddOutPt(e2, pt); - if (e1.OutIdx == e2.OutIdx) - { - e1.OutIdx = Unassigned; - e2.OutIdx = Unassigned; - } - else if (e1.OutIdx < e2.OutIdx) - AppendPolygon(e1, e2); - else - AppendPolygon(e2, e1); - } - //------------------------------------------------------------------------------ - - private OutPt AddLocalMinPoly(TEdge e1, TEdge e2, IntPoint pt) - { - OutPt result; - TEdge e, prevE; - if (IsHorizontal(e2) || (e1.Dx > e2.Dx)) - { - result = AddOutPt(e1, pt); - e2.OutIdx = e1.OutIdx; - e1.Side = EdgeSide.esLeft; - e2.Side = EdgeSide.esRight; - e = e1; - if (e.PrevInAEL == e2) - prevE = e2.PrevInAEL; - else - prevE = e.PrevInAEL; - } - else - { - result = AddOutPt(e2, pt); - e1.OutIdx = e2.OutIdx; - e1.Side = EdgeSide.esRight; - e2.Side = EdgeSide.esLeft; - e = e2; - if (e.PrevInAEL == e1) - prevE = e1.PrevInAEL; - else - prevE = e.PrevInAEL; - } - - if (prevE != null && prevE.OutIdx >= 0 && prevE.Top.Y < pt.Y && e.Top.Y < pt.Y) - { - cInt xPrev = TopX(prevE, pt.Y); - cInt xE = TopX(e, pt.Y); - if ((xPrev == xE) && (e.WindDelta != 0) && (prevE.WindDelta != 0) && - SlopesEqual(new IntPoint(xPrev, pt.Y), prevE.Top, new IntPoint(xE, pt.Y), e.Top, m_UseFullRange)) - { - OutPt outPt = AddOutPt(prevE, pt); - AddJoin(result, outPt, e.Top); - } - } - return result; - } - //------------------------------------------------------------------------------ - - private OutPt AddOutPt(TEdge e, IntPoint pt) - { - if (e.OutIdx < 0) - { - OutRec outRec = CreateOutRec(); - outRec.IsOpen = (e.WindDelta == 0); - OutPt newOp = new OutPt(); - outRec.Pts = newOp; - newOp.Idx = outRec.Idx; - newOp.Pt = pt; - newOp.Next = newOp; - newOp.Prev = newOp; - if (!outRec.IsOpen) - SetHoleState(e, outRec); - e.OutIdx = outRec.Idx; //nb: do this after SetZ ! - return newOp; - } - else - { - OutRec outRec = m_PolyOuts[e.OutIdx]; - //OutRec.Pts is the 'Left-most' point & OutRec.Pts.Prev is the 'Right-most' - OutPt op = outRec.Pts; - bool ToFront = (e.Side == EdgeSide.esLeft); - if (ToFront && pt == op.Pt) return op; - else if (!ToFront && pt == op.Prev.Pt) return op.Prev; - - OutPt newOp = new OutPt(); - newOp.Idx = outRec.Idx; - newOp.Pt = pt; - newOp.Next = op; - newOp.Prev = op.Prev; - newOp.Prev.Next = newOp; - op.Prev = newOp; - if (ToFront) outRec.Pts = newOp; - return newOp; - } - } - //------------------------------------------------------------------------------ - - private OutPt GetLastOutPt(TEdge e) - { - OutRec outRec = m_PolyOuts[e.OutIdx]; - if (e.Side == EdgeSide.esLeft) - return outRec.Pts; - else - return outRec.Pts.Prev; - } - //------------------------------------------------------------------------------ - - internal void SwapPoints(ref IntPoint pt1, ref IntPoint pt2) - { - IntPoint tmp = new IntPoint(pt1); - pt1 = pt2; - pt2 = tmp; - } - //------------------------------------------------------------------------------ - - private bool HorzSegmentsOverlap(cInt seg1a, cInt seg1b, cInt seg2a, cInt seg2b) - { - if (seg1a > seg1b) Swap(ref seg1a, ref seg1b); - if (seg2a > seg2b) Swap(ref seg2a, ref seg2b); - return (seg1a < seg2b) && (seg2a < seg1b); - } - //------------------------------------------------------------------------------ - - private void SetHoleState(TEdge e, OutRec outRec) - { - TEdge e2 = e.PrevInAEL; - TEdge eTmp = null; - while (e2 != null) - { - if (e2.OutIdx >= 0 && e2.WindDelta != 0) - { - if (eTmp == null) - eTmp = e2; - else if (eTmp.OutIdx == e2.OutIdx) - eTmp = null; //paired - } - e2 = e2.PrevInAEL; - } - - if (eTmp == null) - { - outRec.FirstLeft = null; - outRec.IsHole = false; - } - else - { - outRec.FirstLeft = m_PolyOuts[eTmp.OutIdx]; - outRec.IsHole = !outRec.FirstLeft.IsHole; - } - } - //------------------------------------------------------------------------------ - - private double GetDx(IntPoint pt1, IntPoint pt2) - { - if (pt1.Y == pt2.Y) return horizontal; - else return (double)(pt2.X - pt1.X) / (pt2.Y - pt1.Y); - } - //--------------------------------------------------------------------------- - - private bool FirstIsBottomPt(OutPt btmPt1, OutPt btmPt2) - { - OutPt p = btmPt1.Prev; - while ((p.Pt == btmPt1.Pt) && (p != btmPt1)) p = p.Prev; - double dx1p = Math.Abs(GetDx(btmPt1.Pt, p.Pt)); - p = btmPt1.Next; - while ((p.Pt == btmPt1.Pt) && (p != btmPt1)) p = p.Next; - double dx1n = Math.Abs(GetDx(btmPt1.Pt, p.Pt)); - - p = btmPt2.Prev; - while ((p.Pt == btmPt2.Pt) && (p != btmPt2)) p = p.Prev; - double dx2p = Math.Abs(GetDx(btmPt2.Pt, p.Pt)); - p = btmPt2.Next; - while ((p.Pt == btmPt2.Pt) && (p != btmPt2)) p = p.Next; - double dx2n = Math.Abs(GetDx(btmPt2.Pt, p.Pt)); - - if (Math.Max(dx1p, dx1n) == Math.Max(dx2p, dx2n) && - Math.Min(dx1p, dx1n) == Math.Min(dx2p, dx2n)) - return Area(btmPt1) > 0; //if otherwise identical use orientation - else - return (dx1p >= dx2p && dx1p >= dx2n) || (dx1n >= dx2p && dx1n >= dx2n); - } - //------------------------------------------------------------------------------ - - private OutPt GetBottomPt(OutPt pp) - { - OutPt dups = null; - OutPt p = pp.Next; - while (p != pp) - { - if (p.Pt.Y > pp.Pt.Y) - { - pp = p; - dups = null; - } - else if (p.Pt.Y == pp.Pt.Y && p.Pt.X <= pp.Pt.X) - { - if (p.Pt.X < pp.Pt.X) - { - dups = null; - pp = p; - } - else - { - if (p.Next != pp && p.Prev != pp) dups = p; - } - } - p = p.Next; - } - if (dups != null) - { - //there appears to be at least 2 vertices at bottomPt so ... - while (dups != p) - { - if (!FirstIsBottomPt(p, dups)) pp = dups; - dups = dups.Next; - while (dups.Pt != pp.Pt) dups = dups.Next; - } - } - return pp; - } - //------------------------------------------------------------------------------ - - private OutRec GetLowermostRec(OutRec outRec1, OutRec outRec2) - { - //work out which polygon fragment has the correct hole state ... - if (outRec1.BottomPt == null) - outRec1.BottomPt = GetBottomPt(outRec1.Pts); - if (outRec2.BottomPt == null) - outRec2.BottomPt = GetBottomPt(outRec2.Pts); - OutPt bPt1 = outRec1.BottomPt; - OutPt bPt2 = outRec2.BottomPt; - if (bPt1.Pt.Y > bPt2.Pt.Y) return outRec1; - else if (bPt1.Pt.Y < bPt2.Pt.Y) return outRec2; - else if (bPt1.Pt.X < bPt2.Pt.X) return outRec1; - else if (bPt1.Pt.X > bPt2.Pt.X) return outRec2; - else if (bPt1.Next == bPt1) return outRec2; - else if (bPt2.Next == bPt2) return outRec1; - else if (FirstIsBottomPt(bPt1, bPt2)) return outRec1; - else return outRec2; - } - //------------------------------------------------------------------------------ - - bool OutRec1RightOfOutRec2(OutRec outRec1, OutRec outRec2) - { - do - { - outRec1 = outRec1.FirstLeft; - if (outRec1 == outRec2) return true; - } while (outRec1 != null); - return false; - } - //------------------------------------------------------------------------------ - - private OutRec GetOutRec(int idx) - { - OutRec outrec = m_PolyOuts[idx]; - while (outrec != m_PolyOuts[outrec.Idx]) - outrec = m_PolyOuts[outrec.Idx]; - return outrec; - } - //------------------------------------------------------------------------------ - - private void AppendPolygon(TEdge e1, TEdge e2) - { - OutRec outRec1 = m_PolyOuts[e1.OutIdx]; - OutRec outRec2 = m_PolyOuts[e2.OutIdx]; - - OutRec holeStateRec; - if (OutRec1RightOfOutRec2(outRec1, outRec2)) - holeStateRec = outRec2; - else if (OutRec1RightOfOutRec2(outRec2, outRec1)) - holeStateRec = outRec1; - else - holeStateRec = GetLowermostRec(outRec1, outRec2); - - //get the start and ends of both output polygons and - //join E2 poly onto E1 poly and delete pointers to E2 ... - OutPt p1_lft = outRec1.Pts; - OutPt p1_rt = p1_lft.Prev; - OutPt p2_lft = outRec2.Pts; - OutPt p2_rt = p2_lft.Prev; - - //join e2 poly onto e1 poly and delete pointers to e2 ... - if (e1.Side == EdgeSide.esLeft) - { - if (e2.Side == EdgeSide.esLeft) - { - //z y x a b c - ReversePolyPtLinks(p2_lft); - p2_lft.Next = p1_lft; - p1_lft.Prev = p2_lft; - p1_rt.Next = p2_rt; - p2_rt.Prev = p1_rt; - outRec1.Pts = p2_rt; - } - else - { - //x y z a b c - p2_rt.Next = p1_lft; - p1_lft.Prev = p2_rt; - p2_lft.Prev = p1_rt; - p1_rt.Next = p2_lft; - outRec1.Pts = p2_lft; - } - } - else - { - if (e2.Side == EdgeSide.esRight) - { - //a b c z y x - ReversePolyPtLinks(p2_lft); - p1_rt.Next = p2_rt; - p2_rt.Prev = p1_rt; - p2_lft.Next = p1_lft; - p1_lft.Prev = p2_lft; - } - else - { - //a b c x y z - p1_rt.Next = p2_lft; - p2_lft.Prev = p1_rt; - p1_lft.Prev = p2_rt; - p2_rt.Next = p1_lft; - } - } - - outRec1.BottomPt = null; - if (holeStateRec == outRec2) - { - if (outRec2.FirstLeft != outRec1) - outRec1.FirstLeft = outRec2.FirstLeft; - outRec1.IsHole = outRec2.IsHole; - } - outRec2.Pts = null; - outRec2.BottomPt = null; - - outRec2.FirstLeft = outRec1; - - int OKIdx = e1.OutIdx; - int ObsoleteIdx = e2.OutIdx; - - e1.OutIdx = Unassigned; //nb: safe because we only get here via AddLocalMaxPoly - e2.OutIdx = Unassigned; - - TEdge e = m_ActiveEdges; - while (e != null) - { - if (e.OutIdx == ObsoleteIdx) - { - e.OutIdx = OKIdx; - e.Side = e1.Side; - break; - } - e = e.NextInAEL; - } - outRec2.Idx = outRec1.Idx; - } - //------------------------------------------------------------------------------ - - private void ReversePolyPtLinks(OutPt pp) - { - if (pp == null) return; - OutPt pp1; - OutPt pp2; - pp1 = pp; - do - { - pp2 = pp1.Next; - pp1.Next = pp1.Prev; - pp1.Prev = pp2; - pp1 = pp2; - } while (pp1 != pp); - } - //------------------------------------------------------------------------------ - - private static void SwapSides(TEdge edge1, TEdge edge2) - { - EdgeSide side = edge1.Side; - edge1.Side = edge2.Side; - edge2.Side = side; - } - //------------------------------------------------------------------------------ - - private static void SwapPolyIndexes(TEdge edge1, TEdge edge2) - { - int outIdx = edge1.OutIdx; - edge1.OutIdx = edge2.OutIdx; - edge2.OutIdx = outIdx; - } - //------------------------------------------------------------------------------ - - private void IntersectEdges(TEdge e1, TEdge e2, IntPoint pt) - { - //e1 will be to the left of e2 BELOW the intersection. Therefore e1 is before - //e2 in AEL except when e1 is being inserted at the intersection point ... - - bool e1Contributing = (e1.OutIdx >= 0); - bool e2Contributing = (e2.OutIdx >= 0); - -#if use_xyz - SetZ(ref pt, e1, e2); -#endif - -#if use_lines - //if either edge is on an OPEN path ... - if (e1.WindDelta == 0 || e2.WindDelta == 0) - { - //ignore subject-subject open path intersections UNLESS they - //are both open paths, AND they are both 'contributing maximas' ... - if (e1.WindDelta == 0 && e2.WindDelta == 0) return; - //if intersecting a subj line with a subj poly ... - else if (e1.PolyTyp == e2.PolyTyp && - e1.WindDelta != e2.WindDelta && m_ClipType == ClipType.ctUnion) - { - if (e1.WindDelta == 0) - { - if (e2Contributing) - { - AddOutPt(e1, pt); - if (e1Contributing) e1.OutIdx = Unassigned; - } - } - else - { - if (e1Contributing) - { - AddOutPt(e2, pt); - if (e2Contributing) e2.OutIdx = Unassigned; - } - } - } - else if (e1.PolyTyp != e2.PolyTyp) - { - if ((e1.WindDelta == 0) && Math.Abs(e2.WindCnt) == 1 && - (m_ClipType != ClipType.ctUnion || e2.WindCnt2 == 0)) - { - AddOutPt(e1, pt); - if (e1Contributing) e1.OutIdx = Unassigned; - } - else if ((e2.WindDelta == 0) && (Math.Abs(e1.WindCnt) == 1) && - (m_ClipType != ClipType.ctUnion || e1.WindCnt2 == 0)) - { - AddOutPt(e2, pt); - if (e2Contributing) e2.OutIdx = Unassigned; - } - } - return; - } -#endif - - //update winding counts... - //assumes that e1 will be to the Right of e2 ABOVE the intersection - if (e1.PolyTyp == e2.PolyTyp) - { - if (IsEvenOddFillType(e1)) - { - int oldE1WindCnt = e1.WindCnt; - e1.WindCnt = e2.WindCnt; - e2.WindCnt = oldE1WindCnt; - } - else - { - if (e1.WindCnt + e2.WindDelta == 0) e1.WindCnt = -e1.WindCnt; - else e1.WindCnt += e2.WindDelta; - if (e2.WindCnt - e1.WindDelta == 0) e2.WindCnt = -e2.WindCnt; - else e2.WindCnt -= e1.WindDelta; - } - } - else - { - if (!IsEvenOddFillType(e2)) e1.WindCnt2 += e2.WindDelta; - else e1.WindCnt2 = (e1.WindCnt2 == 0) ? 1 : 0; - if (!IsEvenOddFillType(e1)) e2.WindCnt2 -= e1.WindDelta; - else e2.WindCnt2 = (e2.WindCnt2 == 0) ? 1 : 0; - } - - PolyFillType e1FillType, e2FillType, e1FillType2, e2FillType2; - if (e1.PolyTyp == PolyType.ptSubject) - { - e1FillType = m_SubjFillType; - e1FillType2 = m_ClipFillType; - } - else - { - e1FillType = m_ClipFillType; - e1FillType2 = m_SubjFillType; - } - if (e2.PolyTyp == PolyType.ptSubject) - { - e2FillType = m_SubjFillType; - e2FillType2 = m_ClipFillType; - } - else - { - e2FillType = m_ClipFillType; - e2FillType2 = m_SubjFillType; - } - - int e1Wc, e2Wc; - switch (e1FillType) - { - case PolyFillType.pftPositive: e1Wc = e1.WindCnt; break; - case PolyFillType.pftNegative: e1Wc = -e1.WindCnt; break; - default: e1Wc = Math.Abs(e1.WindCnt); break; - } - switch (e2FillType) - { - case PolyFillType.pftPositive: e2Wc = e2.WindCnt; break; - case PolyFillType.pftNegative: e2Wc = -e2.WindCnt; break; - default: e2Wc = Math.Abs(e2.WindCnt); break; - } - - if (e1Contributing && e2Contributing) - { - if ((e1Wc != 0 && e1Wc != 1) || (e2Wc != 0 && e2Wc != 1) || - (e1.PolyTyp != e2.PolyTyp && m_ClipType != ClipType.ctXor)) - { - AddLocalMaxPoly(e1, e2, pt); - } - else - { - AddOutPt(e1, pt); - AddOutPt(e2, pt); - SwapSides(e1, e2); - SwapPolyIndexes(e1, e2); - } - } - else if (e1Contributing) - { - if (e2Wc == 0 || e2Wc == 1) - { - AddOutPt(e1, pt); - SwapSides(e1, e2); - SwapPolyIndexes(e1, e2); - } - - } - else if (e2Contributing) - { - if (e1Wc == 0 || e1Wc == 1) - { - AddOutPt(e2, pt); - SwapSides(e1, e2); - SwapPolyIndexes(e1, e2); - } - } - else if ((e1Wc == 0 || e1Wc == 1) && (e2Wc == 0 || e2Wc == 1)) - { - //neither edge is currently contributing ... - cInt e1Wc2, e2Wc2; - switch (e1FillType2) - { - case PolyFillType.pftPositive: e1Wc2 = e1.WindCnt2; break; - case PolyFillType.pftNegative: e1Wc2 = -e1.WindCnt2; break; - default: e1Wc2 = Math.Abs(e1.WindCnt2); break; - } - switch (e2FillType2) - { - case PolyFillType.pftPositive: e2Wc2 = e2.WindCnt2; break; - case PolyFillType.pftNegative: e2Wc2 = -e2.WindCnt2; break; - default: e2Wc2 = Math.Abs(e2.WindCnt2); break; - } - - if (e1.PolyTyp != e2.PolyTyp) - { - AddLocalMinPoly(e1, e2, pt); - } - else if (e1Wc == 1 && e2Wc == 1) - { - switch (m_ClipType) - { - case ClipType.ctIntersection: - if (e1Wc2 > 0 && e2Wc2 > 0) - AddLocalMinPoly(e1, e2, pt); - break; - case ClipType.ctUnion: - if (e1Wc2 <= 0 && e2Wc2 <= 0) - AddLocalMinPoly(e1, e2, pt); - break; - case ClipType.ctDifference: - if (((e1.PolyTyp == PolyType.ptClip) && (e1Wc2 > 0) && (e2Wc2 > 0)) || - ((e1.PolyTyp == PolyType.ptSubject) && (e1Wc2 <= 0) && (e2Wc2 <= 0))) - AddLocalMinPoly(e1, e2, pt); - break; - case ClipType.ctXor: - AddLocalMinPoly(e1, e2, pt); - break; - } - } - else - SwapSides(e1, e2); - } - } - //------------------------------------------------------------------------------ - - private void DeleteFromSEL(TEdge e) - { - TEdge SelPrev = e.PrevInSEL; - TEdge SelNext = e.NextInSEL; - if (SelPrev == null && SelNext == null && (e != m_SortedEdges)) - return; //already deleted - if (SelPrev != null) - SelPrev.NextInSEL = SelNext; - else m_SortedEdges = SelNext; - if (SelNext != null) - SelNext.PrevInSEL = SelPrev; - e.NextInSEL = null; - e.PrevInSEL = null; - } - //------------------------------------------------------------------------------ - - private void ProcessHorizontals() - { - TEdge horzEdge; //m_SortedEdges; - while (PopEdgeFromSEL(out horzEdge)) - ProcessHorizontal(horzEdge); - } - //------------------------------------------------------------------------------ - - void GetHorzDirection(TEdge HorzEdge, out Direction Dir, out cInt Left, out cInt Right) - { - if (HorzEdge.Bot.X < HorzEdge.Top.X) - { - Left = HorzEdge.Bot.X; - Right = HorzEdge.Top.X; - Dir = Direction.dLeftToRight; - } - else - { - Left = HorzEdge.Top.X; - Right = HorzEdge.Bot.X; - Dir = Direction.dRightToLeft; - } - } - //------------------------------------------------------------------------ - - private void ProcessHorizontal(TEdge horzEdge) - { - Direction dir; - cInt horzLeft, horzRight; - bool IsOpen = horzEdge.WindDelta == 0; - - GetHorzDirection(horzEdge, out dir, out horzLeft, out horzRight); - - TEdge eLastHorz = horzEdge, eMaxPair = null; - while (eLastHorz.NextInLML != null && IsHorizontal(eLastHorz.NextInLML)) - eLastHorz = eLastHorz.NextInLML; - if (eLastHorz.NextInLML == null) - eMaxPair = GetMaximaPair(eLastHorz); - - Maxima currMax = m_Maxima; - if (currMax != null) - { - //get the first maxima in range (X) ... - if (dir == Direction.dLeftToRight) - { - while (currMax != null && currMax.X <= horzEdge.Bot.X) - currMax = currMax.Next; - if (currMax != null && currMax.X >= eLastHorz.Top.X) - currMax = null; - } - else - { - while (currMax.Next != null && currMax.Next.X < horzEdge.Bot.X) - currMax = currMax.Next; - if (currMax.X <= eLastHorz.Top.X) currMax = null; - } - } - - OutPt op1 = null; - for (; ; ) //loop through consec. horizontal edges - { - bool IsLastHorz = (horzEdge == eLastHorz); - TEdge e = GetNextInAEL(horzEdge, dir); - while (e != null) - { - - //this code block inserts extra coords into horizontal edges (in output - //polygons) whereever maxima touch these horizontal edges. This helps - //'simplifying' polygons (ie if the Simplify property is set). - if (currMax != null) - { - if (dir == Direction.dLeftToRight) - { - while (currMax != null && currMax.X < e.Curr.X) - { - if (horzEdge.OutIdx >= 0 && !IsOpen) - AddOutPt(horzEdge, new IntPoint(currMax.X, horzEdge.Bot.Y)); - currMax = currMax.Next; - } - } - else - { - while (currMax != null && currMax.X > e.Curr.X) - { - if (horzEdge.OutIdx >= 0 && !IsOpen) - AddOutPt(horzEdge, new IntPoint(currMax.X, horzEdge.Bot.Y)); - currMax = currMax.Prev; - } - } - }; - - if ((dir == Direction.dLeftToRight && e.Curr.X > horzRight) || - (dir == Direction.dRightToLeft && e.Curr.X < horzLeft)) break; - - //Also break if we've got to the end of an intermediate horizontal edge ... - //nb: Smaller Dx's are to the right of larger Dx's ABOVE the horizontal. - if (e.Curr.X == horzEdge.Top.X && horzEdge.NextInLML != null && - e.Dx < horzEdge.NextInLML.Dx) break; - - if (horzEdge.OutIdx >= 0 && !IsOpen) //note: may be done multiple times - { -#if use_xyz - if (dir == Direction.dLeftToRight) SetZ(ref e.Curr, horzEdge, e); - else SetZ(ref e.Curr, e, horzEdge); -#endif - - op1 = AddOutPt(horzEdge, e.Curr); - TEdge eNextHorz = m_SortedEdges; - while (eNextHorz != null) - { - if (eNextHorz.OutIdx >= 0 && - HorzSegmentsOverlap(horzEdge.Bot.X, - horzEdge.Top.X, eNextHorz.Bot.X, eNextHorz.Top.X)) - { - OutPt op2 = GetLastOutPt(eNextHorz); - AddJoin(op2, op1, eNextHorz.Top); - } - eNextHorz = eNextHorz.NextInSEL; - } - AddGhostJoin(op1, horzEdge.Bot); - } - - //OK, so far we're still in range of the horizontal Edge but make sure - //we're at the last of consec. horizontals when matching with eMaxPair - if (e == eMaxPair && IsLastHorz) - { - if (horzEdge.OutIdx >= 0) - AddLocalMaxPoly(horzEdge, eMaxPair, horzEdge.Top); - DeleteFromAEL(horzEdge); - DeleteFromAEL(eMaxPair); - return; - } - - if (dir == Direction.dLeftToRight) - { - IntPoint Pt = new IntPoint(e.Curr.X, horzEdge.Curr.Y); - IntersectEdges(horzEdge, e, Pt); - } - else - { - IntPoint Pt = new IntPoint(e.Curr.X, horzEdge.Curr.Y); - IntersectEdges(e, horzEdge, Pt); - } - TEdge eNext = GetNextInAEL(e, dir); - SwapPositionsInAEL(horzEdge, e); - e = eNext; - } //end while(e != null) - - //Break out of loop if HorzEdge.NextInLML is not also horizontal ... - if (horzEdge.NextInLML == null || !IsHorizontal(horzEdge.NextInLML)) break; - - UpdateEdgeIntoAEL(ref horzEdge); - if (horzEdge.OutIdx >= 0) AddOutPt(horzEdge, horzEdge.Bot); - GetHorzDirection(horzEdge, out dir, out horzLeft, out horzRight); - - } //end for (;;) - - if (horzEdge.OutIdx >= 0 && op1 == null) - { - op1 = GetLastOutPt(horzEdge); - TEdge eNextHorz = m_SortedEdges; - while (eNextHorz != null) - { - if (eNextHorz.OutIdx >= 0 && - HorzSegmentsOverlap(horzEdge.Bot.X, - horzEdge.Top.X, eNextHorz.Bot.X, eNextHorz.Top.X)) - { - OutPt op2 = GetLastOutPt(eNextHorz); - AddJoin(op2, op1, eNextHorz.Top); - } - eNextHorz = eNextHorz.NextInSEL; - } - AddGhostJoin(op1, horzEdge.Top); - } - - if (horzEdge.NextInLML != null) - { - if (horzEdge.OutIdx >= 0) - { - op1 = AddOutPt(horzEdge, horzEdge.Top); - - UpdateEdgeIntoAEL(ref horzEdge); - if (horzEdge.WindDelta == 0) return; - //nb: HorzEdge is no longer horizontal here - TEdge ePrev = horzEdge.PrevInAEL; - TEdge eNext = horzEdge.NextInAEL; - if (ePrev != null && ePrev.Curr.X == horzEdge.Bot.X && - ePrev.Curr.Y == horzEdge.Bot.Y && ePrev.WindDelta != 0 && - (ePrev.OutIdx >= 0 && ePrev.Curr.Y > ePrev.Top.Y && - SlopesEqual(horzEdge, ePrev, m_UseFullRange))) - { - OutPt op2 = AddOutPt(ePrev, horzEdge.Bot); - AddJoin(op1, op2, horzEdge.Top); - } - else if (eNext != null && eNext.Curr.X == horzEdge.Bot.X && - eNext.Curr.Y == horzEdge.Bot.Y && eNext.WindDelta != 0 && - eNext.OutIdx >= 0 && eNext.Curr.Y > eNext.Top.Y && - SlopesEqual(horzEdge, eNext, m_UseFullRange)) - { - OutPt op2 = AddOutPt(eNext, horzEdge.Bot); - AddJoin(op1, op2, horzEdge.Top); - } - } - else - UpdateEdgeIntoAEL(ref horzEdge); - } - else - { - if (horzEdge.OutIdx >= 0) AddOutPt(horzEdge, horzEdge.Top); - DeleteFromAEL(horzEdge); - } - } - //------------------------------------------------------------------------------ - - private TEdge GetNextInAEL(TEdge e, Direction Direction) - { - return Direction == Direction.dLeftToRight ? e.NextInAEL : e.PrevInAEL; - } - //------------------------------------------------------------------------------ - - private bool IsMinima(TEdge e) - { - return e != null && (e.Prev.NextInLML != e) && (e.Next.NextInLML != e); - } - //------------------------------------------------------------------------------ - - private bool IsMaxima(TEdge e, double Y) - { - return (e != null && e.Top.Y == Y && e.NextInLML == null); - } - //------------------------------------------------------------------------------ - - private bool IsIntermediate(TEdge e, double Y) - { - return (e.Top.Y == Y && e.NextInLML != null); - } - //------------------------------------------------------------------------------ - - internal TEdge GetMaximaPair(TEdge e) - { - if ((e.Next.Top == e.Top) && e.Next.NextInLML == null) - return e.Next; - else if ((e.Prev.Top == e.Top) && e.Prev.NextInLML == null) - return e.Prev; - else - return null; - } - //------------------------------------------------------------------------------ - - internal TEdge GetMaximaPairEx(TEdge e) - { - //as above but returns null if MaxPair isn't in AEL (unless it's horizontal) - TEdge result = GetMaximaPair(e); - if (result == null || result.OutIdx == Skip || - ((result.NextInAEL == result.PrevInAEL) && !IsHorizontal(result))) return null; - return result; - } - //------------------------------------------------------------------------------ - - private bool ProcessIntersections(cInt topY) - { - if (m_ActiveEdges == null) return true; - try - { - BuildIntersectList(topY); - if (m_IntersectList.Count == 0) return true; - if (m_IntersectList.Count == 1 || FixupIntersectionOrder()) - ProcessIntersectList(); - else - return false; - } - catch - { - m_SortedEdges = null; - m_IntersectList.Clear(); - throw new ClipperException("ProcessIntersections error"); - } - m_SortedEdges = null; - return true; - } - //------------------------------------------------------------------------------ - - private void BuildIntersectList(cInt topY) - { - if (m_ActiveEdges == null) return; - - //prepare for sorting ... - TEdge e = m_ActiveEdges; - m_SortedEdges = e; - while (e != null) - { - e.PrevInSEL = e.PrevInAEL; - e.NextInSEL = e.NextInAEL; - e.Curr.X = TopX(e, topY); - e = e.NextInAEL; - } - - //bubblesort ... - bool isModified = true; - while (isModified && m_SortedEdges != null) - { - isModified = false; - e = m_SortedEdges; - while (e.NextInSEL != null) - { - TEdge eNext = e.NextInSEL; - IntPoint pt; - if (e.Curr.X > eNext.Curr.X) - { - IntersectPoint(e, eNext, out pt); - if (pt.Y < topY) - pt = new IntPoint(TopX(e, topY), topY); - IntersectNode newNode = new IntersectNode(); - newNode.Edge1 = e; - newNode.Edge2 = eNext; - newNode.Pt = pt; - m_IntersectList.Add(newNode); - - SwapPositionsInSEL(e, eNext); - isModified = true; - } - else - e = eNext; - } - if (e.PrevInSEL != null) e.PrevInSEL.NextInSEL = null; - else break; - } - m_SortedEdges = null; - } - //------------------------------------------------------------------------------ - - private bool EdgesAdjacent(IntersectNode inode) - { - return (inode.Edge1.NextInSEL == inode.Edge2) || - (inode.Edge1.PrevInSEL == inode.Edge2); - } - //------------------------------------------------------------------------------ - - private static int IntersectNodeSort(IntersectNode node1, IntersectNode node2) - { - //the following typecast is safe because the differences in Pt.Y will - //be limited to the height of the scanbeam. - return (int)(node2.Pt.Y - node1.Pt.Y); - } - //------------------------------------------------------------------------------ - - private bool FixupIntersectionOrder() - { - //pre-condition: intersections are sorted bottom-most first. - //Now it's crucial that intersections are made only between adjacent edges, - //so to ensure this the order of intersections may need adjusting ... - m_IntersectList.Sort(m_IntersectNodeComparer); - - CopyAELToSEL(); - int cnt = m_IntersectList.Count; - for (int i = 0; i < cnt; i++) - { - if (!EdgesAdjacent(m_IntersectList[i])) - { - int j = i + 1; - while (j < cnt && !EdgesAdjacent(m_IntersectList[j])) j++; - if (j == cnt) return false; - - IntersectNode tmp = m_IntersectList[i]; - m_IntersectList[i] = m_IntersectList[j]; - m_IntersectList[j] = tmp; - - } - SwapPositionsInSEL(m_IntersectList[i].Edge1, m_IntersectList[i].Edge2); - } - return true; - } - //------------------------------------------------------------------------------ - - private void ProcessIntersectList() - { - for (int i = 0; i < m_IntersectList.Count; i++) - { - IntersectNode iNode = m_IntersectList[i]; - { - IntersectEdges(iNode.Edge1, iNode.Edge2, iNode.Pt); - SwapPositionsInAEL(iNode.Edge1, iNode.Edge2); - } - } - m_IntersectList.Clear(); - } - //------------------------------------------------------------------------------ - - internal static cInt Round(double value) - { - return value < 0 ? (cInt)(value - 0.5) : (cInt)(value + 0.5); - } - //------------------------------------------------------------------------------ - - private static cInt TopX(TEdge edge, cInt currentY) - { - if (currentY == edge.Top.Y) - return edge.Top.X; - return edge.Bot.X + Round(edge.Dx * (currentY - edge.Bot.Y)); - } - //------------------------------------------------------------------------------ - - private void IntersectPoint(TEdge edge1, TEdge edge2, out IntPoint ip) - { - ip = new IntPoint(); - double b1, b2; - //nb: with very large coordinate values, it's possible for SlopesEqual() to - //return false but for the edge.Dx value be equal due to double precision rounding. - if (edge1.Dx == edge2.Dx) - { - ip.Y = edge1.Curr.Y; - ip.X = TopX(edge1, ip.Y); - return; - } - - if (edge1.Delta.X == 0) - { - ip.X = edge1.Bot.X; - if (IsHorizontal(edge2)) - { - ip.Y = edge2.Bot.Y; - } - else - { - b2 = edge2.Bot.Y - (edge2.Bot.X / edge2.Dx); - ip.Y = Round(ip.X / edge2.Dx + b2); - } - } - else if (edge2.Delta.X == 0) - { - ip.X = edge2.Bot.X; - if (IsHorizontal(edge1)) - { - ip.Y = edge1.Bot.Y; - } - else - { - b1 = edge1.Bot.Y - (edge1.Bot.X / edge1.Dx); - ip.Y = Round(ip.X / edge1.Dx + b1); - } - } - else - { - b1 = edge1.Bot.X - edge1.Bot.Y * edge1.Dx; - b2 = edge2.Bot.X - edge2.Bot.Y * edge2.Dx; - double q = (b2 - b1) / (edge1.Dx - edge2.Dx); - ip.Y = Round(q); - if (Math.Abs(edge1.Dx) < Math.Abs(edge2.Dx)) - ip.X = Round(edge1.Dx * q + b1); - else - ip.X = Round(edge2.Dx * q + b2); - } - - if (ip.Y < edge1.Top.Y || ip.Y < edge2.Top.Y) - { - if (edge1.Top.Y > edge2.Top.Y) - ip.Y = edge1.Top.Y; - else - ip.Y = edge2.Top.Y; - if (Math.Abs(edge1.Dx) < Math.Abs(edge2.Dx)) - ip.X = TopX(edge1, ip.Y); - else - ip.X = TopX(edge2, ip.Y); - } - //finally, don't allow 'ip' to be BELOW curr.Y (ie bottom of scanbeam) ... - if (ip.Y > edge1.Curr.Y) - { - ip.Y = edge1.Curr.Y; - //better to use the more vertical edge to derive X ... - if (Math.Abs(edge1.Dx) > Math.Abs(edge2.Dx)) - ip.X = TopX(edge2, ip.Y); - else - ip.X = TopX(edge1, ip.Y); - } - } - //------------------------------------------------------------------------------ - - private void ProcessEdgesAtTopOfScanbeam(cInt topY) - { - TEdge e = m_ActiveEdges; - while (e != null) - { - //1. process maxima, treating them as if they're 'bent' horizontal edges, - // but exclude maxima with horizontal edges. nb: e can't be a horizontal. - bool IsMaximaEdge = IsMaxima(e, topY); - - if (IsMaximaEdge) - { - TEdge eMaxPair = GetMaximaPairEx(e); - IsMaximaEdge = (eMaxPair == null || !IsHorizontal(eMaxPair)); - } - - if (IsMaximaEdge) - { - if (StrictlySimple) InsertMaxima(e.Top.X); - TEdge ePrev = e.PrevInAEL; - DoMaxima(e); - if (ePrev == null) e = m_ActiveEdges; - else e = ePrev.NextInAEL; - } - else - { - //2. promote horizontal edges, otherwise update Curr.X and Curr.Y ... - if (IsIntermediate(e, topY) && IsHorizontal(e.NextInLML)) - { - UpdateEdgeIntoAEL(ref e); - if (e.OutIdx >= 0) - AddOutPt(e, e.Bot); - AddEdgeToSEL(e); - } - else - { - e.Curr.X = TopX(e, topY); - e.Curr.Y = topY; -#if use_xyz - if (e.Top.Y == topY) e.Curr.Z = e.Top.Z; - else if (e.Bot.Y == topY) e.Curr.Z = e.Bot.Z; - else e.Curr.Z = 0; -#endif - } - //When StrictlySimple and 'e' is being touched by another edge, then - //make sure both edges have a vertex here ... - if (StrictlySimple) - { - TEdge ePrev = e.PrevInAEL; - if ((e.OutIdx >= 0) && (e.WindDelta != 0) && ePrev != null && - (ePrev.OutIdx >= 0) && (ePrev.Curr.X == e.Curr.X) && - (ePrev.WindDelta != 0)) - { - IntPoint ip = new IntPoint(e.Curr); -#if use_xyz - SetZ(ref ip, ePrev, e); -#endif - OutPt op = AddOutPt(ePrev, ip); - OutPt op2 = AddOutPt(e, ip); - AddJoin(op, op2, ip); //StrictlySimple (type-3) join - } - } - - e = e.NextInAEL; - } - } - - //3. Process horizontals at the Top of the scanbeam ... - ProcessHorizontals(); - m_Maxima = null; - - //4. Promote intermediate vertices ... - e = m_ActiveEdges; - while (e != null) - { - if (IsIntermediate(e, topY)) - { - OutPt op = null; - if (e.OutIdx >= 0) - op = AddOutPt(e, e.Top); - UpdateEdgeIntoAEL(ref e); - - //if output polygons share an edge, they'll need joining later ... - TEdge ePrev = e.PrevInAEL; - TEdge eNext = e.NextInAEL; - if (ePrev != null && ePrev.Curr.X == e.Bot.X && - ePrev.Curr.Y == e.Bot.Y && op != null && - ePrev.OutIdx >= 0 && ePrev.Curr.Y > ePrev.Top.Y && - SlopesEqual(e.Curr, e.Top, ePrev.Curr, ePrev.Top, m_UseFullRange) && - (e.WindDelta != 0) && (ePrev.WindDelta != 0)) - { - OutPt op2 = AddOutPt(ePrev, e.Bot); - AddJoin(op, op2, e.Top); - } - else if (eNext != null && eNext.Curr.X == e.Bot.X && - eNext.Curr.Y == e.Bot.Y && op != null && - eNext.OutIdx >= 0 && eNext.Curr.Y > eNext.Top.Y && - SlopesEqual(e.Curr, e.Top, eNext.Curr, eNext.Top, m_UseFullRange) && - (e.WindDelta != 0) && (eNext.WindDelta != 0)) - { - OutPt op2 = AddOutPt(eNext, e.Bot); - AddJoin(op, op2, e.Top); - } - } - e = e.NextInAEL; - } - } - //------------------------------------------------------------------------------ - - private void DoMaxima(TEdge e) - { - TEdge eMaxPair = GetMaximaPairEx(e); - if (eMaxPair == null) - { - if (e.OutIdx >= 0) - AddOutPt(e, e.Top); - DeleteFromAEL(e); - return; - } - - TEdge eNext = e.NextInAEL; - while (eNext != null && eNext != eMaxPair) - { - IntersectEdges(e, eNext, e.Top); - SwapPositionsInAEL(e, eNext); - eNext = e.NextInAEL; - } - - if (e.OutIdx == Unassigned && eMaxPair.OutIdx == Unassigned) - { - DeleteFromAEL(e); - DeleteFromAEL(eMaxPair); - } - else if (e.OutIdx >= 0 && eMaxPair.OutIdx >= 0) - { - if (e.OutIdx >= 0) AddLocalMaxPoly(e, eMaxPair, e.Top); - DeleteFromAEL(e); - DeleteFromAEL(eMaxPair); - } -#if use_lines - else if (e.WindDelta == 0) - { - if (e.OutIdx >= 0) - { - AddOutPt(e, e.Top); - e.OutIdx = Unassigned; - } - DeleteFromAEL(e); - - if (eMaxPair.OutIdx >= 0) - { - AddOutPt(eMaxPair, e.Top); - eMaxPair.OutIdx = Unassigned; - } - DeleteFromAEL(eMaxPair); - } -#endif - else throw new ClipperException("DoMaxima error"); - } - //------------------------------------------------------------------------------ - - public static void ReversePaths(Paths polys) - { - foreach (var poly in polys) { poly.Reverse(); } - } - //------------------------------------------------------------------------------ - - public static bool Orientation(Path poly) - { - return Area(poly) >= 0; - } - //------------------------------------------------------------------------------ - - private int PointCount(OutPt pts) - { - if (pts == null) return 0; - int result = 0; - OutPt p = pts; - do - { - result++; - p = p.Next; - } - while (p != pts); - return result; - } - //------------------------------------------------------------------------------ - - private void BuildResult(Paths polyg) - { - polyg.Clear(); - polyg.Capacity = m_PolyOuts.Count; - for (int i = 0; i < m_PolyOuts.Count; i++) - { - OutRec outRec = m_PolyOuts[i]; - if (outRec.Pts == null) continue; - OutPt p = outRec.Pts.Prev; - int cnt = PointCount(p); - if (cnt < 2) continue; - Path pg = new Path(cnt); - for (int j = 0; j < cnt; j++) - { - pg.Add(p.Pt); - p = p.Prev; - } - polyg.Add(pg); - } - } - //------------------------------------------------------------------------------ - - private void BuildResult2(PolyTree polytree) - { - polytree.Clear(); - - //add each output polygon/contour to polytree ... - polytree.m_AllPolys.Capacity = m_PolyOuts.Count; - for (int i = 0; i < m_PolyOuts.Count; i++) - { - OutRec outRec = m_PolyOuts[i]; - int cnt = PointCount(outRec.Pts); - if ((outRec.IsOpen && cnt < 2) || - (!outRec.IsOpen && cnt < 3)) continue; - FixHoleLinkage(outRec); - PolyNode pn = new PolyNode(); - polytree.m_AllPolys.Add(pn); - outRec.PolyNode = pn; - pn.m_polygon.Capacity = cnt; - OutPt op = outRec.Pts.Prev; - for (int j = 0; j < cnt; j++) - { - pn.m_polygon.Add(op.Pt); - op = op.Prev; - } - } - - //fixup PolyNode links etc ... - polytree.m_Childs.Capacity = m_PolyOuts.Count; - for (int i = 0; i < m_PolyOuts.Count; i++) - { - OutRec outRec = m_PolyOuts[i]; - if (outRec.PolyNode == null) continue; - else if (outRec.IsOpen) - { - outRec.PolyNode.IsOpen = true; - polytree.AddChild(outRec.PolyNode); - } - else if (outRec.FirstLeft != null && - outRec.FirstLeft.PolyNode != null) - outRec.FirstLeft.PolyNode.AddChild(outRec.PolyNode); - else - polytree.AddChild(outRec.PolyNode); - } - } - //------------------------------------------------------------------------------ - - private void FixupOutPolyline(OutRec outrec) - { - OutPt pp = outrec.Pts; - OutPt lastPP = pp.Prev; - while (pp != lastPP) - { - pp = pp.Next; - if (pp.Pt == pp.Prev.Pt) - { - if (pp == lastPP) lastPP = pp.Prev; - OutPt tmpPP = pp.Prev; - tmpPP.Next = pp.Next; - pp.Next.Prev = tmpPP; - pp = tmpPP; - } - } - if (pp == pp.Prev) outrec.Pts = null; - } - //------------------------------------------------------------------------------ - - private void FixupOutPolygon(OutRec outRec) - { - //FixupOutPolygon() - removes duplicate points and simplifies consecutive - //parallel edges by removing the middle vertex. - OutPt lastOK = null; - outRec.BottomPt = null; - OutPt pp = outRec.Pts; - bool preserveCol = PreserveCollinear || StrictlySimple; - for (; ; ) - { - if (pp.Prev == pp || pp.Prev == pp.Next) - { - outRec.Pts = null; - return; - } - //test for duplicate points and collinear edges ... - if ((pp.Pt == pp.Next.Pt) || (pp.Pt == pp.Prev.Pt) || - (SlopesEqual(pp.Prev.Pt, pp.Pt, pp.Next.Pt, m_UseFullRange) && - (!preserveCol || !Pt2IsBetweenPt1AndPt3(pp.Prev.Pt, pp.Pt, pp.Next.Pt)))) - { - lastOK = null; - pp.Prev.Next = pp.Next; - pp.Next.Prev = pp.Prev; - pp = pp.Prev; - } - else if (pp == lastOK) break; - else - { - if (lastOK == null) lastOK = pp; - pp = pp.Next; - } - } - outRec.Pts = pp; - } - //------------------------------------------------------------------------------ - - OutPt DupOutPt(OutPt outPt, bool InsertAfter) - { - OutPt result = new OutPt(); - result.Pt = outPt.Pt; - result.Idx = outPt.Idx; - if (InsertAfter) - { - result.Next = outPt.Next; - result.Prev = outPt; - outPt.Next.Prev = result; - outPt.Next = result; - } - else - { - result.Prev = outPt.Prev; - result.Next = outPt; - outPt.Prev.Next = result; - outPt.Prev = result; - } - return result; - } - //------------------------------------------------------------------------------ - - bool GetOverlap(cInt a1, cInt a2, cInt b1, cInt b2, out cInt Left, out cInt Right) - { - if (a1 < a2) - { - if (b1 < b2) { Left = Math.Max(a1, b1); Right = Math.Min(a2, b2); } - else { Left = Math.Max(a1, b2); Right = Math.Min(a2, b1); } - } - else - { - if (b1 < b2) { Left = Math.Max(a2, b1); Right = Math.Min(a1, b2); } - else { Left = Math.Max(a2, b2); Right = Math.Min(a1, b1); } - } - return Left < Right; - } - //------------------------------------------------------------------------------ - - bool JoinHorz(OutPt op1, OutPt op1b, OutPt op2, OutPt op2b, - IntPoint Pt, bool DiscardLeft) - { - Direction Dir1 = (op1.Pt.X > op1b.Pt.X ? - Direction.dRightToLeft : Direction.dLeftToRight); - Direction Dir2 = (op2.Pt.X > op2b.Pt.X ? - Direction.dRightToLeft : Direction.dLeftToRight); - if (Dir1 == Dir2) return false; - - //When DiscardLeft, we want Op1b to be on the Left of Op1, otherwise we - //want Op1b to be on the Right. (And likewise with Op2 and Op2b.) - //So, to facilitate this while inserting Op1b and Op2b ... - //when DiscardLeft, make sure we're AT or RIGHT of Pt before adding Op1b, - //otherwise make sure we're AT or LEFT of Pt. (Likewise with Op2b.) - if (Dir1 == Direction.dLeftToRight) - { - while (op1.Next.Pt.X <= Pt.X && - op1.Next.Pt.X >= op1.Pt.X && op1.Next.Pt.Y == Pt.Y) - op1 = op1.Next; - if (DiscardLeft && (op1.Pt.X != Pt.X)) op1 = op1.Next; - op1b = DupOutPt(op1, !DiscardLeft); - if (op1b.Pt != Pt) - { - op1 = op1b; - op1.Pt = Pt; - op1b = DupOutPt(op1, !DiscardLeft); - } - } - else - { - while (op1.Next.Pt.X >= Pt.X && - op1.Next.Pt.X <= op1.Pt.X && op1.Next.Pt.Y == Pt.Y) - op1 = op1.Next; - if (!DiscardLeft && (op1.Pt.X != Pt.X)) op1 = op1.Next; - op1b = DupOutPt(op1, DiscardLeft); - if (op1b.Pt != Pt) - { - op1 = op1b; - op1.Pt = Pt; - op1b = DupOutPt(op1, DiscardLeft); - } - } - - if (Dir2 == Direction.dLeftToRight) - { - while (op2.Next.Pt.X <= Pt.X && - op2.Next.Pt.X >= op2.Pt.X && op2.Next.Pt.Y == Pt.Y) - op2 = op2.Next; - if (DiscardLeft && (op2.Pt.X != Pt.X)) op2 = op2.Next; - op2b = DupOutPt(op2, !DiscardLeft); - if (op2b.Pt != Pt) - { - op2 = op2b; - op2.Pt = Pt; - op2b = DupOutPt(op2, !DiscardLeft); - }; - } - else - { - while (op2.Next.Pt.X >= Pt.X && - op2.Next.Pt.X <= op2.Pt.X && op2.Next.Pt.Y == Pt.Y) - op2 = op2.Next; - if (!DiscardLeft && (op2.Pt.X != Pt.X)) op2 = op2.Next; - op2b = DupOutPt(op2, DiscardLeft); - if (op2b.Pt != Pt) - { - op2 = op2b; - op2.Pt = Pt; - op2b = DupOutPt(op2, DiscardLeft); - }; - }; - - if ((Dir1 == Direction.dLeftToRight) == DiscardLeft) - { - op1.Prev = op2; - op2.Next = op1; - op1b.Next = op2b; - op2b.Prev = op1b; - } - else - { - op1.Next = op2; - op2.Prev = op1; - op1b.Prev = op2b; - op2b.Next = op1b; - } - return true; - } - //------------------------------------------------------------------------------ - - private bool JoinPoints(Join j, OutRec outRec1, OutRec outRec2) - { - OutPt op1 = j.OutPt1, op1b; - OutPt op2 = j.OutPt2, op2b; - - //There are 3 kinds of joins for output polygons ... - //1. Horizontal joins where Join.OutPt1 & Join.OutPt2 are vertices anywhere - //along (horizontal) collinear edges (& Join.OffPt is on the same horizontal). - //2. Non-horizontal joins where Join.OutPt1 & Join.OutPt2 are at the same - //location at the Bottom of the overlapping segment (& Join.OffPt is above). - //3. StrictlySimple joins where edges touch but are not collinear and where - //Join.OutPt1, Join.OutPt2 & Join.OffPt all share the same point. - bool isHorizontal = (j.OutPt1.Pt.Y == j.OffPt.Y); - - if (isHorizontal && (j.OffPt == j.OutPt1.Pt) && (j.OffPt == j.OutPt2.Pt)) - { - //Strictly Simple join ... - if (outRec1 != outRec2) return false; - op1b = j.OutPt1.Next; - while (op1b != op1 && (op1b.Pt == j.OffPt)) - op1b = op1b.Next; - bool reverse1 = (op1b.Pt.Y > j.OffPt.Y); - op2b = j.OutPt2.Next; - while (op2b != op2 && (op2b.Pt == j.OffPt)) - op2b = op2b.Next; - bool reverse2 = (op2b.Pt.Y > j.OffPt.Y); - if (reverse1 == reverse2) return false; - if (reverse1) - { - op1b = DupOutPt(op1, false); - op2b = DupOutPt(op2, true); - op1.Prev = op2; - op2.Next = op1; - op1b.Next = op2b; - op2b.Prev = op1b; - j.OutPt1 = op1; - j.OutPt2 = op1b; - return true; - } - else - { - op1b = DupOutPt(op1, true); - op2b = DupOutPt(op2, false); - op1.Next = op2; - op2.Prev = op1; - op1b.Prev = op2b; - op2b.Next = op1b; - j.OutPt1 = op1; - j.OutPt2 = op1b; - return true; - } - } - else if (isHorizontal) - { - //treat horizontal joins differently to non-horizontal joins since with - //them we're not yet sure where the overlapping is. OutPt1.Pt & OutPt2.Pt - //may be anywhere along the horizontal edge. - op1b = op1; - while (op1.Prev.Pt.Y == op1.Pt.Y && op1.Prev != op1b && op1.Prev != op2) - op1 = op1.Prev; - while (op1b.Next.Pt.Y == op1b.Pt.Y && op1b.Next != op1 && op1b.Next != op2) - op1b = op1b.Next; - if (op1b.Next == op1 || op1b.Next == op2) return false; //a flat 'polygon' - - op2b = op2; - while (op2.Prev.Pt.Y == op2.Pt.Y && op2.Prev != op2b && op2.Prev != op1b) - op2 = op2.Prev; - while (op2b.Next.Pt.Y == op2b.Pt.Y && op2b.Next != op2 && op2b.Next != op1) - op2b = op2b.Next; - if (op2b.Next == op2 || op2b.Next == op1) return false; //a flat 'polygon' - - cInt Left, Right; - //Op1 -. Op1b & Op2 -. Op2b are the extremites of the horizontal edges - if (!GetOverlap(op1.Pt.X, op1b.Pt.X, op2.Pt.X, op2b.Pt.X, out Left, out Right)) - return false; - - //DiscardLeftSide: when overlapping edges are joined, a spike will created - //which needs to be cleaned up. However, we don't want Op1 or Op2 caught up - //on the discard Side as either may still be needed for other joins ... - IntPoint Pt; - bool DiscardLeftSide; - if (op1.Pt.X >= Left && op1.Pt.X <= Right) - { - Pt = op1.Pt; DiscardLeftSide = (op1.Pt.X > op1b.Pt.X); - } - else if (op2.Pt.X >= Left && op2.Pt.X <= Right) - { - Pt = op2.Pt; DiscardLeftSide = (op2.Pt.X > op2b.Pt.X); - } - else if (op1b.Pt.X >= Left && op1b.Pt.X <= Right) - { - Pt = op1b.Pt; DiscardLeftSide = op1b.Pt.X > op1.Pt.X; - } - else - { - Pt = op2b.Pt; DiscardLeftSide = (op2b.Pt.X > op2.Pt.X); - } - j.OutPt1 = op1; - j.OutPt2 = op2; - return JoinHorz(op1, op1b, op2, op2b, Pt, DiscardLeftSide); - } - else - { - //nb: For non-horizontal joins ... - // 1. Jr.OutPt1.Pt.Y == Jr.OutPt2.Pt.Y - // 2. Jr.OutPt1.Pt > Jr.OffPt.Y - - //make sure the polygons are correctly oriented ... - op1b = op1.Next; - while ((op1b.Pt == op1.Pt) && (op1b != op1)) op1b = op1b.Next; - bool Reverse1 = ((op1b.Pt.Y > op1.Pt.Y) || - !SlopesEqual(op1.Pt, op1b.Pt, j.OffPt, m_UseFullRange)); - if (Reverse1) - { - op1b = op1.Prev; - while ((op1b.Pt == op1.Pt) && (op1b != op1)) op1b = op1b.Prev; - if ((op1b.Pt.Y > op1.Pt.Y) || - !SlopesEqual(op1.Pt, op1b.Pt, j.OffPt, m_UseFullRange)) return false; - }; - op2b = op2.Next; - while ((op2b.Pt == op2.Pt) && (op2b != op2)) op2b = op2b.Next; - bool Reverse2 = ((op2b.Pt.Y > op2.Pt.Y) || - !SlopesEqual(op2.Pt, op2b.Pt, j.OffPt, m_UseFullRange)); - if (Reverse2) - { - op2b = op2.Prev; - while ((op2b.Pt == op2.Pt) && (op2b != op2)) op2b = op2b.Prev; - if ((op2b.Pt.Y > op2.Pt.Y) || - !SlopesEqual(op2.Pt, op2b.Pt, j.OffPt, m_UseFullRange)) return false; - } - - if ((op1b == op1) || (op2b == op2) || (op1b == op2b) || - ((outRec1 == outRec2) && (Reverse1 == Reverse2))) return false; - - if (Reverse1) - { - op1b = DupOutPt(op1, false); - op2b = DupOutPt(op2, true); - op1.Prev = op2; - op2.Next = op1; - op1b.Next = op2b; - op2b.Prev = op1b; - j.OutPt1 = op1; - j.OutPt2 = op1b; - return true; - } - else - { - op1b = DupOutPt(op1, true); - op2b = DupOutPt(op2, false); - op1.Next = op2; - op2.Prev = op1; - op1b.Prev = op2b; - op2b.Next = op1b; - j.OutPt1 = op1; - j.OutPt2 = op1b; - return true; - } - } - } - //---------------------------------------------------------------------- - - public static int PointInPolygon(IntPoint pt, Path path) - { - //returns 0 if false, +1 if true, -1 if pt ON polygon boundary - //See "The Point in Polygon Problem for Arbitrary Polygons" by Hormann & Agathos - //http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.88.5498&rep=rep1&type=pdf - int result = 0, cnt = path.Count; - if (cnt < 3) return 0; - IntPoint ip = path[0]; - for (int i = 1; i <= cnt; ++i) - { - IntPoint ipNext = (i == cnt ? path[0] : path[i]); - if (ipNext.Y == pt.Y) - { - if ((ipNext.X == pt.X) || (ip.Y == pt.Y && - ((ipNext.X > pt.X) == (ip.X < pt.X)))) return -1; - } - if ((ip.Y < pt.Y) != (ipNext.Y < pt.Y)) - { - if (ip.X >= pt.X) - { - if (ipNext.X > pt.X) result = 1 - result; - else - { - double d = (double)(ip.X - pt.X) * (ipNext.Y - pt.Y) - - (double)(ipNext.X - pt.X) * (ip.Y - pt.Y); - if (d == 0) return -1; - else if ((d > 0) == (ipNext.Y > ip.Y)) result = 1 - result; - } - } - else - { - if (ipNext.X > pt.X) - { - double d = (double)(ip.X - pt.X) * (ipNext.Y - pt.Y) - - (double)(ipNext.X - pt.X) * (ip.Y - pt.Y); - if (d == 0) return -1; - else if ((d > 0) == (ipNext.Y > ip.Y)) result = 1 - result; - } - } - } - ip = ipNext; - } - return result; - } - //------------------------------------------------------------------------------ - - //See "The Point in Polygon Problem for Arbitrary Polygons" by Hormann & Agathos - //http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.88.5498&rep=rep1&type=pdf - private static int PointInPolygon(IntPoint pt, OutPt op) - { - //returns 0 if false, +1 if true, -1 if pt ON polygon boundary - int result = 0; - OutPt startOp = op; - cInt ptx = pt.X, pty = pt.Y; - cInt poly0x = op.Pt.X, poly0y = op.Pt.Y; - do - { - op = op.Next; - cInt poly1x = op.Pt.X, poly1y = op.Pt.Y; - - if (poly1y == pty) - { - if ((poly1x == ptx) || (poly0y == pty && - ((poly1x > ptx) == (poly0x < ptx)))) return -1; - } - if ((poly0y < pty) != (poly1y < pty)) - { - if (poly0x >= ptx) - { - if (poly1x > ptx) result = 1 - result; - else - { - double d = (double)(poly0x - ptx) * (poly1y - pty) - - (double)(poly1x - ptx) * (poly0y - pty); - if (d == 0) return -1; - if ((d > 0) == (poly1y > poly0y)) result = 1 - result; - } - } - else - { - if (poly1x > ptx) - { - double d = (double)(poly0x - ptx) * (poly1y - pty) - - (double)(poly1x - ptx) * (poly0y - pty); - if (d == 0) return -1; - if ((d > 0) == (poly1y > poly0y)) result = 1 - result; - } - } - } - poly0x = poly1x; poly0y = poly1y; - } while (startOp != op); - return result; - } - //------------------------------------------------------------------------------ - - private static bool Poly2ContainsPoly1(OutPt outPt1, OutPt outPt2) - { - OutPt op = outPt1; - do - { - //nb: PointInPolygon returns 0 if false, +1 if true, -1 if pt on polygon - int res = PointInPolygon(op.Pt, outPt2); - if (res >= 0) return res > 0; - op = op.Next; - } - while (op != outPt1); - return true; - } - //---------------------------------------------------------------------- - - private void FixupFirstLefts1(OutRec OldOutRec, OutRec NewOutRec) - { - foreach (OutRec outRec in m_PolyOuts) - { - OutRec firstLeft = ParseFirstLeft(outRec.FirstLeft); - if (outRec.Pts != null && firstLeft == OldOutRec) - { - if (Poly2ContainsPoly1(outRec.Pts, NewOutRec.Pts)) - outRec.FirstLeft = NewOutRec; - } - } - } - //---------------------------------------------------------------------- - - private void FixupFirstLefts2(OutRec innerOutRec, OutRec outerOutRec) - { - //A polygon has split into two such that one is now the inner of the other. - //It's possible that these polygons now wrap around other polygons, so check - //every polygon that's also contained by OuterOutRec's FirstLeft container - //(including nil) to see if they've become inner to the new inner polygon ... - OutRec orfl = outerOutRec.FirstLeft; - foreach (OutRec outRec in m_PolyOuts) - { - if (outRec.Pts == null || outRec == outerOutRec || outRec == innerOutRec) - continue; - OutRec firstLeft = ParseFirstLeft(outRec.FirstLeft); - if (firstLeft != orfl && firstLeft != innerOutRec && firstLeft != outerOutRec) - continue; - if (Poly2ContainsPoly1(outRec.Pts, innerOutRec.Pts)) - outRec.FirstLeft = innerOutRec; - else if (Poly2ContainsPoly1(outRec.Pts, outerOutRec.Pts)) - outRec.FirstLeft = outerOutRec; - else if (outRec.FirstLeft == innerOutRec || outRec.FirstLeft == outerOutRec) - outRec.FirstLeft = orfl; - } - } - //---------------------------------------------------------------------- - - private void FixupFirstLefts3(OutRec OldOutRec, OutRec NewOutRec) - { - //same as FixupFirstLefts1 but doesn't call Poly2ContainsPoly1() - foreach (OutRec outRec in m_PolyOuts) - { - OutRec firstLeft = ParseFirstLeft(outRec.FirstLeft); - if (outRec.Pts != null && firstLeft == OldOutRec) - outRec.FirstLeft = NewOutRec; - } - } - //---------------------------------------------------------------------- - - private static OutRec ParseFirstLeft(OutRec FirstLeft) - { - while (FirstLeft != null && FirstLeft.Pts == null) - FirstLeft = FirstLeft.FirstLeft; - return FirstLeft; - } - //------------------------------------------------------------------------------ - - private void JoinCommonEdges() - { - for (int i = 0; i < m_Joins.Count; i++) - { - Join join = m_Joins[i]; - - OutRec outRec1 = GetOutRec(join.OutPt1.Idx); - OutRec outRec2 = GetOutRec(join.OutPt2.Idx); - - if (outRec1.Pts == null || outRec2.Pts == null) continue; - if (outRec1.IsOpen || outRec2.IsOpen) continue; - - //get the polygon fragment with the correct hole state (FirstLeft) - //before calling JoinPoints() ... - OutRec holeStateRec; - if (outRec1 == outRec2) holeStateRec = outRec1; - else if (OutRec1RightOfOutRec2(outRec1, outRec2)) holeStateRec = outRec2; - else if (OutRec1RightOfOutRec2(outRec2, outRec1)) holeStateRec = outRec1; - else holeStateRec = GetLowermostRec(outRec1, outRec2); - - if (!JoinPoints(join, outRec1, outRec2)) continue; - - if (outRec1 == outRec2) - { - //instead of joining two polygons, we've just created a new one by - //splitting one polygon into two. - outRec1.Pts = join.OutPt1; - outRec1.BottomPt = null; - outRec2 = CreateOutRec(); - outRec2.Pts = join.OutPt2; - - //update all OutRec2.Pts Idx's ... - UpdateOutPtIdxs(outRec2); - - if (Poly2ContainsPoly1(outRec2.Pts, outRec1.Pts)) - { - //outRec1 contains outRec2 ... - outRec2.IsHole = !outRec1.IsHole; - outRec2.FirstLeft = outRec1; - - if (m_UsingPolyTree) FixupFirstLefts2(outRec2, outRec1); - - if ((outRec2.IsHole ^ ReverseSolution) == (Area(outRec2) > 0)) - ReversePolyPtLinks(outRec2.Pts); - - } - else if (Poly2ContainsPoly1(outRec1.Pts, outRec2.Pts)) - { - //outRec2 contains outRec1 ... - outRec2.IsHole = outRec1.IsHole; - outRec1.IsHole = !outRec2.IsHole; - outRec2.FirstLeft = outRec1.FirstLeft; - outRec1.FirstLeft = outRec2; - - if (m_UsingPolyTree) FixupFirstLefts2(outRec1, outRec2); - - if ((outRec1.IsHole ^ ReverseSolution) == (Area(outRec1) > 0)) - ReversePolyPtLinks(outRec1.Pts); - } - else - { - //the 2 polygons are completely separate ... - outRec2.IsHole = outRec1.IsHole; - outRec2.FirstLeft = outRec1.FirstLeft; - - //fixup FirstLeft pointers that may need reassigning to OutRec2 - if (m_UsingPolyTree) FixupFirstLefts1(outRec1, outRec2); - } - - } - else - { - //joined 2 polygons together ... - - outRec2.Pts = null; - outRec2.BottomPt = null; - outRec2.Idx = outRec1.Idx; - - outRec1.IsHole = holeStateRec.IsHole; - if (holeStateRec == outRec2) - outRec1.FirstLeft = outRec2.FirstLeft; - outRec2.FirstLeft = outRec1; - - //fixup FirstLeft pointers that may need reassigning to OutRec1 - if (m_UsingPolyTree) FixupFirstLefts3(outRec2, outRec1); - } - } - } - //------------------------------------------------------------------------------ - - private void UpdateOutPtIdxs(OutRec outrec) - { - OutPt op = outrec.Pts; - do - { - op.Idx = outrec.Idx; - op = op.Prev; - } - while (op != outrec.Pts); - } - //------------------------------------------------------------------------------ - - private void DoSimplePolygons() - { - int i = 0; - while (i < m_PolyOuts.Count) - { - OutRec outrec = m_PolyOuts[i++]; - OutPt op = outrec.Pts; - if (op == null || outrec.IsOpen) continue; - do //for each Pt in Polygon until duplicate found do ... - { - OutPt op2 = op.Next; - while (op2 != outrec.Pts) - { - if ((op.Pt == op2.Pt) && op2.Next != op && op2.Prev != op) - { - //split the polygon into two ... - OutPt op3 = op.Prev; - OutPt op4 = op2.Prev; - op.Prev = op4; - op4.Next = op; - op2.Prev = op3; - op3.Next = op2; - - outrec.Pts = op; - OutRec outrec2 = CreateOutRec(); - outrec2.Pts = op2; - UpdateOutPtIdxs(outrec2); - if (Poly2ContainsPoly1(outrec2.Pts, outrec.Pts)) - { - //OutRec2 is contained by OutRec1 ... - outrec2.IsHole = !outrec.IsHole; - outrec2.FirstLeft = outrec; - if (m_UsingPolyTree) FixupFirstLefts2(outrec2, outrec); - } - else - if (Poly2ContainsPoly1(outrec.Pts, outrec2.Pts)) - { - //OutRec1 is contained by OutRec2 ... - outrec2.IsHole = outrec.IsHole; - outrec.IsHole = !outrec2.IsHole; - outrec2.FirstLeft = outrec.FirstLeft; - outrec.FirstLeft = outrec2; - if (m_UsingPolyTree) FixupFirstLefts2(outrec, outrec2); - } - else - { - //the 2 polygons are separate ... - outrec2.IsHole = outrec.IsHole; - outrec2.FirstLeft = outrec.FirstLeft; - if (m_UsingPolyTree) FixupFirstLefts1(outrec, outrec2); - } - op2 = op; //ie get ready for the next iteration - } - op2 = op2.Next; - } - op = op.Next; - } - while (op != outrec.Pts); - } - } - //------------------------------------------------------------------------------ - - public static double Area(Path poly) - { - int cnt = (int)poly.Count; - if (cnt < 3) return 0; - double a = 0; - for (int i = 0, j = cnt - 1; i < cnt; ++i) - { - a += ((double)poly[j].X + poly[i].X) * ((double)poly[j].Y - poly[i].Y); - j = i; - } - return -a * 0.5; - } - //------------------------------------------------------------------------------ - - internal double Area(OutRec outRec) - { - return Area(outRec.Pts); - } - //------------------------------------------------------------------------------ - - internal double Area(OutPt op) - { - OutPt opFirst = op; - if (op == null) return 0; - double a = 0; - do - { - a = a + (double)(op.Prev.Pt.X + op.Pt.X) * (double)(op.Prev.Pt.Y - op.Pt.Y); - op = op.Next; - } while (op != opFirst); - return a * 0.5; - } - - //------------------------------------------------------------------------------ - // SimplifyPolygon functions ... - // Convert self-intersecting polygons into simple polygons - //------------------------------------------------------------------------------ - - public static Paths SimplifyPolygon(Path poly, - PolyFillType fillType = PolyFillType.pftEvenOdd) - { - Paths result = new Paths(); - Clipper c = new Clipper(); - c.StrictlySimple = true; - c.AddPath(poly, PolyType.ptSubject, true); - c.Execute(ClipType.ctUnion, result, fillType, fillType); - return result; - } - //------------------------------------------------------------------------------ - - public static Paths SimplifyPolygons(Paths polys, - PolyFillType fillType = PolyFillType.pftEvenOdd) - { - Paths result = new Paths(); - Clipper c = new Clipper(); - c.StrictlySimple = true; - c.AddPaths(polys, PolyType.ptSubject, true); - c.Execute(ClipType.ctUnion, result, fillType, fillType); - return result; - } - //------------------------------------------------------------------------------ - - private static double DistanceSqrd(IntPoint pt1, IntPoint pt2) - { - double dx = ((double)pt1.X - pt2.X); - double dy = ((double)pt1.Y - pt2.Y); - return (dx * dx + dy * dy); - } - //------------------------------------------------------------------------------ - - private static double DistanceFromLineSqrd(IntPoint pt, IntPoint ln1, IntPoint ln2) - { - //The equation of a line in general form (Ax + By + C = 0) - //given 2 points (x¹,y¹) & (x²,y²) is ... - //(y¹ - y²)x + (x² - x¹)y + (y² - y¹)x¹ - (x² - x¹)y¹ = 0 - //A = (y¹ - y²); B = (x² - x¹); C = (y² - y¹)x¹ - (x² - x¹)y¹ - //perpendicular distance of point (x³,y³) = (Ax³ + By³ + C)/Sqrt(A² + B²) - //see http://en.wikipedia.org/wiki/Perpendicular_distance - double A = ln1.Y - ln2.Y; - double B = ln2.X - ln1.X; - double C = A * ln1.X + B * ln1.Y; - C = A * pt.X + B * pt.Y - C; - return (C * C) / (A * A + B * B); - } - //--------------------------------------------------------------------------- - - private static bool SlopesNearCollinear(IntPoint pt1, - IntPoint pt2, IntPoint pt3, double distSqrd) - { - //this function is more accurate when the point that's GEOMETRICALLY - //between the other 2 points is the one that's tested for distance. - //nb: with 'spikes', either pt1 or pt3 is geometrically between the other pts - if (Math.Abs(pt1.X - pt2.X) > Math.Abs(pt1.Y - pt2.Y)) - { - if ((pt1.X > pt2.X) == (pt1.X < pt3.X)) - return DistanceFromLineSqrd(pt1, pt2, pt3) < distSqrd; - else if ((pt2.X > pt1.X) == (pt2.X < pt3.X)) - return DistanceFromLineSqrd(pt2, pt1, pt3) < distSqrd; - else - return DistanceFromLineSqrd(pt3, pt1, pt2) < distSqrd; - } - else - { - if ((pt1.Y > pt2.Y) == (pt1.Y < pt3.Y)) - return DistanceFromLineSqrd(pt1, pt2, pt3) < distSqrd; - else if ((pt2.Y > pt1.Y) == (pt2.Y < pt3.Y)) - return DistanceFromLineSqrd(pt2, pt1, pt3) < distSqrd; - else - return DistanceFromLineSqrd(pt3, pt1, pt2) < distSqrd; - } - } - //------------------------------------------------------------------------------ - - private static bool PointsAreClose(IntPoint pt1, IntPoint pt2, double distSqrd) - { - double dx = (double)pt1.X - pt2.X; - double dy = (double)pt1.Y - pt2.Y; - return ((dx * dx) + (dy * dy) <= distSqrd); - } - //------------------------------------------------------------------------------ - - private static OutPt ExcludeOp(OutPt op) - { - OutPt result = op.Prev; - result.Next = op.Next; - op.Next.Prev = result; - result.Idx = 0; - return result; - } - //------------------------------------------------------------------------------ - - public static Path CleanPolygon(Path path, double distance = 1.415) - { - //distance = proximity in units/pixels below which vertices will be stripped. - //Default ~= sqrt(2) so when adjacent vertices or semi-adjacent vertices have - //both x & y coords within 1 unit, then the second vertex will be stripped. - - int cnt = path.Count; - - if (cnt == 0) return new Path(); - - OutPt[] outPts = new OutPt[cnt]; - for (int i = 0; i < cnt; ++i) outPts[i] = new OutPt(); - - for (int i = 0; i < cnt; ++i) - { - outPts[i].Pt = path[i]; - outPts[i].Next = outPts[(i + 1) % cnt]; - outPts[i].Next.Prev = outPts[i]; - outPts[i].Idx = 0; - } - - double distSqrd = distance * distance; - OutPt op = outPts[0]; - while (op.Idx == 0 && op.Next != op.Prev) - { - if (PointsAreClose(op.Pt, op.Prev.Pt, distSqrd)) - { - op = ExcludeOp(op); - cnt--; - } - else if (PointsAreClose(op.Prev.Pt, op.Next.Pt, distSqrd)) - { - ExcludeOp(op.Next); - op = ExcludeOp(op); - cnt -= 2; - } - else if (SlopesNearCollinear(op.Prev.Pt, op.Pt, op.Next.Pt, distSqrd)) - { - op = ExcludeOp(op); - cnt--; - } - else - { - op.Idx = 1; - op = op.Next; - } - } - - if (cnt < 3) cnt = 0; - Path result = new Path(cnt); - for (int i = 0; i < cnt; ++i) - { - result.Add(op.Pt); - op = op.Next; - } - outPts = null; - return result; - } - //------------------------------------------------------------------------------ - - public static Paths CleanPolygons(Paths polys, - double distance = 1.415) - { - Paths result = new Paths(polys.Count); - for (int i = 0; i < polys.Count; i++) - result.Add(CleanPolygon(polys[i], distance)); - return result; - } - //------------------------------------------------------------------------------ - - internal static Paths Minkowski(Path pattern, Path path, bool IsSum, bool IsClosed) - { - int delta = (IsClosed ? 1 : 0); - int polyCnt = pattern.Count; - int pathCnt = path.Count; - Paths result = new Paths(pathCnt); - if (IsSum) - for (int i = 0; i < pathCnt; i++) - { - Path p = new Path(polyCnt); - foreach (IntPoint ip in pattern) - p.Add(new IntPoint(path[i].X + ip.X, path[i].Y + ip.Y)); - result.Add(p); - } - else - for (int i = 0; i < pathCnt; i++) - { - Path p = new Path(polyCnt); - foreach (IntPoint ip in pattern) - p.Add(new IntPoint(path[i].X - ip.X, path[i].Y - ip.Y)); - result.Add(p); - } - - Paths quads = new Paths((pathCnt + delta) * (polyCnt + 1)); - for (int i = 0; i < pathCnt - 1 + delta; i++) - for (int j = 0; j < polyCnt; j++) - { - Path quad = new Path(4); - quad.Add(result[i % pathCnt][j % polyCnt]); - quad.Add(result[(i + 1) % pathCnt][j % polyCnt]); - quad.Add(result[(i + 1) % pathCnt][(j + 1) % polyCnt]); - quad.Add(result[i % pathCnt][(j + 1) % polyCnt]); - if (!Orientation(quad)) quad.Reverse(); - quads.Add(quad); - } - return quads; - } - //------------------------------------------------------------------------------ - - public static Paths MinkowskiSum(Path pattern, Path path, bool pathIsClosed) - { - Paths paths = Minkowski(pattern, path, true, pathIsClosed); - Clipper c = new Clipper(); - c.AddPaths(paths, PolyType.ptSubject, true); - c.Execute(ClipType.ctUnion, paths, PolyFillType.pftNonZero, PolyFillType.pftNonZero); - return paths; - } - //------------------------------------------------------------------------------ - - private static Path TranslatePath(Path path, IntPoint delta) - { - Path outPath = new Path(path.Count); - for (int i = 0; i < path.Count; i++) - outPath.Add(new IntPoint(path[i].X + delta.X, path[i].Y + delta.Y)); - return outPath; - } - //------------------------------------------------------------------------------ - - public static Paths MinkowskiSum(Path pattern, Paths paths, bool pathIsClosed) - { - Paths solution = new Paths(); - Clipper c = new Clipper(); - for (int i = 0; i < paths.Count; ++i) - { - Paths tmp = Minkowski(pattern, paths[i], true, pathIsClosed); - c.AddPaths(tmp, PolyType.ptSubject, true); - if (pathIsClosed) - { - Path path = TranslatePath(paths[i], pattern[0]); - c.AddPath(path, PolyType.ptClip, true); - } - } - c.Execute(ClipType.ctUnion, solution, - PolyFillType.pftNonZero, PolyFillType.pftNonZero); - return solution; - } - //------------------------------------------------------------------------------ - - public static Paths MinkowskiDiff(Path poly1, Path poly2) - { - Paths paths = Minkowski(poly1, poly2, false, true); - Clipper c = new Clipper(); - c.AddPaths(paths, PolyType.ptSubject, true); - c.Execute(ClipType.ctUnion, paths, PolyFillType.pftNonZero, PolyFillType.pftNonZero); - return paths; - } - //------------------------------------------------------------------------------ - - internal enum NodeType { ntAny, ntOpen, ntClosed }; - - public static Paths PolyTreeToPaths(PolyTree polytree) - { - - Paths result = new Paths(); - result.Capacity = polytree.Total; - AddPolyNodeToPaths(polytree, NodeType.ntAny, result); - return result; - } - //------------------------------------------------------------------------------ - - internal static void AddPolyNodeToPaths(PolyNode polynode, NodeType nt, Paths paths) - { - bool match = true; - switch (nt) - { - case NodeType.ntOpen: return; - case NodeType.ntClosed: match = !polynode.IsOpen; break; - default: break; - } - - if (polynode.m_polygon.Count > 0 && match) - paths.Add(polynode.m_polygon); - foreach (PolyNode pn in polynode.Childs) - AddPolyNodeToPaths(pn, nt, paths); - } - //------------------------------------------------------------------------------ - - public static Paths OpenPathsFromPolyTree(PolyTree polytree) - { - Paths result = new Paths(); - result.Capacity = polytree.ChildCount; - for (int i = 0; i < polytree.ChildCount; i++) - if (polytree.Childs[i].IsOpen) - result.Add(polytree.Childs[i].m_polygon); - return result; - } - //------------------------------------------------------------------------------ - - public static Paths ClosedPathsFromPolyTree(PolyTree polytree) - { - Paths result = new Paths(); - result.Capacity = polytree.Total; - AddPolyNodeToPaths(polytree, NodeType.ntClosed, result); - return result; - } - //------------------------------------------------------------------------------ - - } //end Clipper - - public class ClipperOffset - { - private Paths m_destPolys; - private Path m_srcPoly; - private Path m_destPoly; - private List m_normals = new List(); - private double m_delta, m_sinA, m_sin, m_cos; - private double m_miterLim, m_StepsPerRad; - - private IntPoint m_lowest; - private PolyNode m_polyNodes = new PolyNode(); - - public double ArcTolerance { get; set; } - public double MiterLimit { get; set; } - - private const double two_pi = Math.PI * 2; - private const double def_arc_tolerance = 0.25; - - public ClipperOffset( - double miterLimit = 2.0, double arcTolerance = def_arc_tolerance) - { - MiterLimit = miterLimit; - ArcTolerance = arcTolerance; - m_lowest.X = -1; - } - //------------------------------------------------------------------------------ - - public void Clear() - { - m_polyNodes.Childs.Clear(); - m_lowest.X = -1; - } - //------------------------------------------------------------------------------ - - internal static cInt Round(double value) - { - return value < 0 ? (cInt)(value - 0.5) : (cInt)(value + 0.5); - } - //------------------------------------------------------------------------------ - - public void AddPath(Path path, JoinType joinType, EndType endType) - { - int highI = path.Count - 1; - if (highI < 0) return; - PolyNode newNode = new PolyNode(); - newNode.m_jointype = joinType; - newNode.m_endtype = endType; - - //strip duplicate points from path and also get index to the lowest point ... - if (endType == EndType.etClosedLine || endType == EndType.etClosedPolygon) - while (highI > 0 && path[0] == path[highI]) highI--; - newNode.m_polygon.Capacity = highI + 1; - newNode.m_polygon.Add(path[0]); - int j = 0, k = 0; - for (int i = 1; i <= highI; i++) - if (newNode.m_polygon[j] != path[i]) - { - j++; - newNode.m_polygon.Add(path[i]); - if (path[i].Y > newNode.m_polygon[k].Y || - (path[i].Y == newNode.m_polygon[k].Y && - path[i].X < newNode.m_polygon[k].X)) k = j; - } - if (endType == EndType.etClosedPolygon && j < 2) return; - - m_polyNodes.AddChild(newNode); - - //if this path's lowest pt is lower than all the others then update m_lowest - if (endType != EndType.etClosedPolygon) return; - if (m_lowest.X < 0) - m_lowest = new IntPoint(m_polyNodes.ChildCount - 1, k); - else - { - IntPoint ip = m_polyNodes.Childs[(int)m_lowest.X].m_polygon[(int)m_lowest.Y]; - if (newNode.m_polygon[k].Y > ip.Y || - (newNode.m_polygon[k].Y == ip.Y && - newNode.m_polygon[k].X < ip.X)) - m_lowest = new IntPoint(m_polyNodes.ChildCount - 1, k); - } - } - //------------------------------------------------------------------------------ - - public void AddPaths(Paths paths, JoinType joinType, EndType endType) - { - foreach (Path p in paths) - AddPath(p, joinType, endType); - } - //------------------------------------------------------------------------------ - - private void FixOrientations() - { - //fixup orientations of all closed paths if the orientation of the - //closed path with the lowermost vertex is wrong ... - if (m_lowest.X >= 0 && - !Clipper.Orientation(m_polyNodes.Childs[(int)m_lowest.X].m_polygon)) - { - for (int i = 0; i < m_polyNodes.ChildCount; i++) - { - PolyNode node = m_polyNodes.Childs[i]; - if (node.m_endtype == EndType.etClosedPolygon || - (node.m_endtype == EndType.etClosedLine && - Clipper.Orientation(node.m_polygon))) - node.m_polygon.Reverse(); - } - } - else - { - for (int i = 0; i < m_polyNodes.ChildCount; i++) - { - PolyNode node = m_polyNodes.Childs[i]; - if (node.m_endtype == EndType.etClosedLine && - !Clipper.Orientation(node.m_polygon)) - node.m_polygon.Reverse(); - } - } - } - //------------------------------------------------------------------------------ - - internal static DoublePoint GetUnitNormal(IntPoint pt1, IntPoint pt2) - { - double dx = (pt2.X - pt1.X); - double dy = (pt2.Y - pt1.Y); - if ((dx == 0) && (dy == 0)) return new DoublePoint(); - - double f = 1 * 1.0 / Math.Sqrt(dx * dx + dy * dy); - dx *= f; - dy *= f; - - return new DoublePoint(dy, -dx); - } - //------------------------------------------------------------------------------ - - private void DoOffset(double delta) - { - m_destPolys = new Paths(); - m_delta = delta; - - //if Zero offset, just copy any CLOSED polygons to m_p and return ... - if (ClipperBase.near_zero(delta)) - { - m_destPolys.Capacity = m_polyNodes.ChildCount; - for (int i = 0; i < m_polyNodes.ChildCount; i++) - { - PolyNode node = m_polyNodes.Childs[i]; - if (node.m_endtype == EndType.etClosedPolygon) - m_destPolys.Add(node.m_polygon); - } - return; - } - - //see offset_triginometry3.svg in the documentation folder ... - if (MiterLimit > 2) m_miterLim = 2 / (MiterLimit * MiterLimit); - else m_miterLim = 0.5; - - double y; - if (ArcTolerance <= 0.0) - y = def_arc_tolerance; - else if (ArcTolerance > Math.Abs(delta) * def_arc_tolerance) - y = Math.Abs(delta) * def_arc_tolerance; - else - y = ArcTolerance; - //see offset_triginometry2.svg in the documentation folder ... - double steps = Math.PI / Math.Acos(1 - y / Math.Abs(delta)); - m_sin = Math.Sin(two_pi / steps); - m_cos = Math.Cos(two_pi / steps); - m_StepsPerRad = steps / two_pi; - if (delta < 0.0) m_sin = -m_sin; - - m_destPolys.Capacity = m_polyNodes.ChildCount * 2; - for (int i = 0; i < m_polyNodes.ChildCount; i++) - { - PolyNode node = m_polyNodes.Childs[i]; - m_srcPoly = node.m_polygon; - - int len = m_srcPoly.Count; - - if (len == 0 || (delta <= 0 && (len < 3 || - node.m_endtype != EndType.etClosedPolygon))) - continue; - - m_destPoly = new Path(); - - if (len == 1) - { - if (node.m_jointype == JoinType.jtRound) - { - double X = 1.0, Y = 0.0; - for (int j = 1; j <= steps; j++) - { - m_destPoly.Add(new IntPoint( - Round(m_srcPoly[0].X + X * delta), - Round(m_srcPoly[0].Y + Y * delta))); - double X2 = X; - X = X * m_cos - m_sin * Y; - Y = X2 * m_sin + Y * m_cos; - } - } - else - { - double X = -1.0, Y = -1.0; - for (int j = 0; j < 4; ++j) - { - m_destPoly.Add(new IntPoint( - Round(m_srcPoly[0].X + X * delta), - Round(m_srcPoly[0].Y + Y * delta))); - if (X < 0) X = 1; - else if (Y < 0) Y = 1; - else X = -1; - } - } - m_destPolys.Add(m_destPoly); - continue; - } - - //build m_normals ... - m_normals.Clear(); - m_normals.Capacity = len; - for (int j = 0; j < len - 1; j++) - m_normals.Add(GetUnitNormal(m_srcPoly[j], m_srcPoly[j + 1])); - if (node.m_endtype == EndType.etClosedLine || - node.m_endtype == EndType.etClosedPolygon) - m_normals.Add(GetUnitNormal(m_srcPoly[len - 1], m_srcPoly[0])); - else - m_normals.Add(new DoublePoint(m_normals[len - 2])); - - if (node.m_endtype == EndType.etClosedPolygon) - { - int k = len - 1; - for (int j = 0; j < len; j++) - OffsetPoint(j, ref k, node.m_jointype); - m_destPolys.Add(m_destPoly); - } - else if (node.m_endtype == EndType.etClosedLine) - { - int k = len - 1; - for (int j = 0; j < len; j++) - OffsetPoint(j, ref k, node.m_jointype); - m_destPolys.Add(m_destPoly); - m_destPoly = new Path(); - //re-build m_normals ... - DoublePoint n = m_normals[len - 1]; - for (int j = len - 1; j > 0; j--) - m_normals[j] = new DoublePoint(-m_normals[j - 1].X, -m_normals[j - 1].Y); - m_normals[0] = new DoublePoint(-n.X, -n.Y); - k = 0; - for (int j = len - 1; j >= 0; j--) - OffsetPoint(j, ref k, node.m_jointype); - m_destPolys.Add(m_destPoly); - } - else - { - int k = 0; - for (int j = 1; j < len - 1; ++j) - OffsetPoint(j, ref k, node.m_jointype); - - IntPoint pt1; - if (node.m_endtype == EndType.etOpenButt) - { - int j = len - 1; - pt1 = new IntPoint((cInt)Round(m_srcPoly[j].X + m_normals[j].X * - delta), (cInt)Round(m_srcPoly[j].Y + m_normals[j].Y * delta)); - m_destPoly.Add(pt1); - pt1 = new IntPoint((cInt)Round(m_srcPoly[j].X - m_normals[j].X * - delta), (cInt)Round(m_srcPoly[j].Y - m_normals[j].Y * delta)); - m_destPoly.Add(pt1); - } - else - { - int j = len - 1; - k = len - 2; - m_sinA = 0; - m_normals[j] = new DoublePoint(-m_normals[j].X, -m_normals[j].Y); - if (node.m_endtype == EndType.etOpenSquare) - DoSquare(j, k); - else - DoRound(j, k); - } - - //re-build m_normals ... - for (int j = len - 1; j > 0; j--) - m_normals[j] = new DoublePoint(-m_normals[j - 1].X, -m_normals[j - 1].Y); - - m_normals[0] = new DoublePoint(-m_normals[1].X, -m_normals[1].Y); - - k = len - 1; - for (int j = k - 1; j > 0; --j) - OffsetPoint(j, ref k, node.m_jointype); - - if (node.m_endtype == EndType.etOpenButt) - { - pt1 = new IntPoint((cInt)Round(m_srcPoly[0].X - m_normals[0].X * delta), - (cInt)Round(m_srcPoly[0].Y - m_normals[0].Y * delta)); - m_destPoly.Add(pt1); - pt1 = new IntPoint((cInt)Round(m_srcPoly[0].X + m_normals[0].X * delta), - (cInt)Round(m_srcPoly[0].Y + m_normals[0].Y * delta)); - m_destPoly.Add(pt1); - } - else - { - k = 1; - m_sinA = 0; - if (node.m_endtype == EndType.etOpenSquare) - DoSquare(0, 1); - else - DoRound(0, 1); - } - m_destPolys.Add(m_destPoly); - } - } - } - //------------------------------------------------------------------------------ - - public void Execute(ref Paths solution, double delta) - { - solution.Clear(); - FixOrientations(); - DoOffset(delta); - //now clean up 'corners' ... - Clipper clpr = new Clipper(); - clpr.AddPaths(m_destPolys, PolyType.ptSubject, true); - if (delta > 0) - { - clpr.Execute(ClipType.ctUnion, solution, - PolyFillType.pftPositive, PolyFillType.pftPositive); - } - else - { - IntRect r = Clipper.GetBounds(m_destPolys); - Path outer = new Path(4); - - outer.Add(new IntPoint(r.left - 10, r.bottom + 10)); - outer.Add(new IntPoint(r.right + 10, r.bottom + 10)); - outer.Add(new IntPoint(r.right + 10, r.top - 10)); - outer.Add(new IntPoint(r.left - 10, r.top - 10)); - - clpr.AddPath(outer, PolyType.ptSubject, true); - clpr.ReverseSolution = true; - clpr.Execute(ClipType.ctUnion, solution, PolyFillType.pftNegative, PolyFillType.pftNegative); - if (solution.Count > 0) solution.RemoveAt(0); - } - } - //------------------------------------------------------------------------------ - - public void Execute(ref PolyTree solution, double delta) - { - solution.Clear(); - FixOrientations(); - DoOffset(delta); - - //now clean up 'corners' ... - Clipper clpr = new Clipper(); - clpr.AddPaths(m_destPolys, PolyType.ptSubject, true); - if (delta > 0) - { - clpr.Execute(ClipType.ctUnion, solution, - PolyFillType.pftPositive, PolyFillType.pftPositive); - } - else - { - IntRect r = Clipper.GetBounds(m_destPolys); - Path outer = new Path(4); - - outer.Add(new IntPoint(r.left - 10, r.bottom + 10)); - outer.Add(new IntPoint(r.right + 10, r.bottom + 10)); - outer.Add(new IntPoint(r.right + 10, r.top - 10)); - outer.Add(new IntPoint(r.left - 10, r.top - 10)); - - clpr.AddPath(outer, PolyType.ptSubject, true); - clpr.ReverseSolution = true; - clpr.Execute(ClipType.ctUnion, solution, PolyFillType.pftNegative, PolyFillType.pftNegative); - //remove the outer PolyNode rectangle ... - if (solution.ChildCount == 1 && solution.Childs[0].ChildCount > 0) - { - PolyNode outerNode = solution.Childs[0]; - solution.Childs.Capacity = outerNode.ChildCount; - solution.Childs[0] = outerNode.Childs[0]; - solution.Childs[0].m_Parent = solution; - for (int i = 1; i < outerNode.ChildCount; i++) - solution.AddChild(outerNode.Childs[i]); - } - else - solution.Clear(); - } - } - //------------------------------------------------------------------------------ - - void OffsetPoint(int j, ref int k, JoinType jointype) - { - //cross product ... - m_sinA = (m_normals[k].X * m_normals[j].Y - m_normals[j].X * m_normals[k].Y); - - if (Math.Abs(m_sinA * m_delta) < 1.0) - { - //dot product ... - double cosA = (m_normals[k].X * m_normals[j].X + m_normals[j].Y * m_normals[k].Y); - if (cosA > 0) // angle ==> 0 degrees - { - m_destPoly.Add(new IntPoint(Round(m_srcPoly[j].X + m_normals[k].X * m_delta), - Round(m_srcPoly[j].Y + m_normals[k].Y * m_delta))); - return; - } - //else angle ==> 180 degrees - } - else if (m_sinA > 1.0) m_sinA = 1.0; - else if (m_sinA < -1.0) m_sinA = -1.0; - - if (m_sinA * m_delta < 0) - { - m_destPoly.Add(new IntPoint(Round(m_srcPoly[j].X + m_normals[k].X * m_delta), - Round(m_srcPoly[j].Y + m_normals[k].Y * m_delta))); - m_destPoly.Add(m_srcPoly[j]); - m_destPoly.Add(new IntPoint(Round(m_srcPoly[j].X + m_normals[j].X * m_delta), - Round(m_srcPoly[j].Y + m_normals[j].Y * m_delta))); - } - else - switch (jointype) - { - case JoinType.jtMiter: - { - double r = 1 + (m_normals[j].X * m_normals[k].X + - m_normals[j].Y * m_normals[k].Y); - if (r >= m_miterLim) DoMiter(j, k, r); else DoSquare(j, k); - break; - } - case JoinType.jtSquare: DoSquare(j, k); break; - case JoinType.jtRound: DoRound(j, k); break; - } - k = j; - } - //------------------------------------------------------------------------------ - - internal void DoSquare(int j, int k) - { - double dx = Math.Tan(Math.Atan2(m_sinA, - m_normals[k].X * m_normals[j].X + m_normals[k].Y * m_normals[j].Y) / 4); - m_destPoly.Add(new IntPoint( - Round(m_srcPoly[j].X + m_delta * (m_normals[k].X - m_normals[k].Y * dx)), - Round(m_srcPoly[j].Y + m_delta * (m_normals[k].Y + m_normals[k].X * dx)))); - m_destPoly.Add(new IntPoint( - Round(m_srcPoly[j].X + m_delta * (m_normals[j].X + m_normals[j].Y * dx)), - Round(m_srcPoly[j].Y + m_delta * (m_normals[j].Y - m_normals[j].X * dx)))); - } - //------------------------------------------------------------------------------ - - internal void DoMiter(int j, int k, double r) - { - double q = m_delta / r; - m_destPoly.Add(new IntPoint(Round(m_srcPoly[j].X + (m_normals[k].X + m_normals[j].X) * q), - Round(m_srcPoly[j].Y + (m_normals[k].Y + m_normals[j].Y) * q))); - } - //------------------------------------------------------------------------------ - - internal void DoRound(int j, int k) - { - double a = Math.Atan2(m_sinA, - m_normals[k].X * m_normals[j].X + m_normals[k].Y * m_normals[j].Y); - int steps = Math.Max((int)Round(m_StepsPerRad * Math.Abs(a)), 1); - - double X = m_normals[k].X, Y = m_normals[k].Y, X2; - for (int i = 0; i < steps; ++i) - { - m_destPoly.Add(new IntPoint( - Round(m_srcPoly[j].X + X * m_delta), - Round(m_srcPoly[j].Y + Y * m_delta))); - X2 = X; - X = X * m_cos - m_sin * Y; - Y = X2 * m_sin + Y * m_cos; - } - m_destPoly.Add(new IntPoint( - Round(m_srcPoly[j].X + m_normals[j].X * m_delta), - Round(m_srcPoly[j].Y + m_normals[j].Y * m_delta))); - } - //------------------------------------------------------------------------------ - } - - class ClipperException : Exception - { - public ClipperException(string description) : base(description) { } - } - //------------------------------------------------------------------------------ - -} //end ClipperLib namespace diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/BoostClipper/clipper.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/BoostClipper/clipper.cs.meta deleted file mode 100644 index 27fe38e8..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/BoostClipper/clipper.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: e13902fa43e71754f9e04b2f44d5f71b -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/Clipping.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/Clipping.meta deleted file mode 100644 index 08d72a80..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/Clipping.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: be8365f59449a0a4aa11aa4ad834006f -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/Clipping/Contour.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d/Clipping/Contour.cs deleted file mode 100644 index 8ff7a431..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/Clipping/Contour.cs +++ /dev/null @@ -1,123 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using UnityEngine; - -namespace PathBerserker2d -{ - internal class Contour : IEnumerable - { - public int VertexCount { get { return verts.Count; } } - public bool IsEmpty { get { return verts.Count == 0; } } - public bool IsClosed { get; private set; } - public List Verts => verts; - - private List verts; - - public Contour(List verticies, bool isClosed = true) - { - this.verts = verticies; - IsClosed = isClosed; - } - - public Contour(IEnumerable verticies, bool isClosed = true) - { - this.verts = new List(verticies); - IsClosed = isClosed; - } - - public Vector2 this[int key] - { - get { return verts[key]; } - } - - public IEnumerator GetEnumerator() - { - return ((IEnumerable)verts).GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return ((IEnumerable)verts).GetEnumerator(); - } - - public double SignedArea() - { - double area = 0; - for (int i = 0, j = verts.Count - 1; i < verts.Count; j = i, i++) - area += (verts[i].x - verts[j].x) * - (verts[i].y + verts[j].y); - return area / 2.0; - } - - public double Area() - { - return Math.Abs(SignedArea()); - } - - public void MakeCW() - { - if (!IsCW()) - verts.Reverse(); - } - - public void Invert() - { - verts.Reverse(); - } - - public bool IsCW() - { - Vector2 lowestPoint = verts[0]; - int lowestPointIndex = 0; - for (int i = 1; i < VertexCount; i++) - { - if (lowestPoint.y > verts[i].y || - lowestPoint.y == verts[i].y && lowestPoint.x < verts[i].x) - { - lowestPoint = verts[i]; - lowestPointIndex = i; - } - } - - Vector2 prevPoint = lowestPointIndex == 0 ? verts[VertexCount - 1] : verts[lowestPointIndex - 1]; - Vector2 nextPoint = lowestPointIndex == VertexCount - 1 ? verts[0] : verts[lowestPointIndex + 1]; - - return ((lowestPoint.x - prevPoint.x) * (nextPoint.y - prevPoint.y) - (nextPoint.x - prevPoint.x) * (lowestPoint.y - prevPoint.y)) < 0; - } - - public bool PointInContour(Vector2 point) - { - bool c = false; - for (int i = 0, j = VertexCount - 1; i < VertexCount; j = i++) - { - if (((verts[i].y > point.y) != (verts[j].y > point.y)) && - (point.x < (verts[j].x - verts[i].x) * (point.y - verts[i].y) / (verts[j].y - verts[i].y) + verts[i].x)) - c = !c; - } - return c; - } - - public bool Contains(Contour other) - { - foreach (var v in other) - if (!PointInContour(v)) - return false; - return true; - } - - public void Draw() - { - for (int i = IsClosed ? 0 : 1, j = IsClosed ? VertexCount - 1 : 0; i < VertexCount; j = i, i++) - { - DebugDrawingExtensions.DrawArrow(verts[i], verts[j]); - } - } - - public void Simplify(float tolerance) - { - ExtendedGeometry.MergeCloseVerts(verts, tolerance); - this.verts = ExtendedGeometry.SimplifyContour(this.verts, tolerance); - } - } -} \ No newline at end of file diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/Clipping/Contour.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/Clipping/Contour.cs.meta deleted file mode 100644 index 543c78cd..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/Clipping/Contour.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: dad3920a5830b8e438bc7c5d3c92636d -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/Clipping/IClipper.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d/Clipping/IClipper.cs deleted file mode 100644 index 3e008838..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/Clipping/IClipper.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace PathBerserker2d -{ - public enum ResultType { NoOverlap, Clipped }; - public enum BoolOpType { INTERSECTION, UNION, DIFFERENCE }; - - interface IClipper - { - ResultType Compute(Polygon sp, Polygon cp, BoolOpType op, out List result, bool includeOpenPolygons = false); - } -} diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/Clipping/IClipper.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/Clipping/IClipper.cs.meta deleted file mode 100644 index 4e71a75b..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/Clipping/IClipper.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: e6f0c0aa6263ff54ca7f6be8694b9fa7 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/Clipping/Polygon.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d/Clipping/Polygon.cs deleted file mode 100644 index b8693876..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/Clipping/Polygon.cs +++ /dev/null @@ -1,162 +0,0 @@ -using System.Collections; -using System.Collections.Generic; -using UnityEngine; - -namespace PathBerserker2d -{ - internal class Polygon : System.IEquatable, IEnumerable - { - public Contour Hull => hull; - public List Holes { get; set; } - public bool IsEmpty => hull.IsEmpty; - public float XMax => boundingRect.xMax; - public Rect BoundingRect => boundingRect; - - private Contour hull; - private Rect boundingRect; - - public Polygon(Contour hull, List holes) - { - this.hull = hull; - this.Holes = holes; - - UpdateBounds(); - } - - public Polygon(Contour hull) - { - this.hull = hull; - this.Holes = new List(0); - - UpdateBounds(); - } - - public Polygon() - { - this.hull = new Contour(new Vector2[0]); - this.Holes = new List(0); - } - - public bool Equals(Polygon other) - { - return other == this; - } - - public void AddAsChild(Polygon other) - { - this.Holes.Add(other.hull); - this.Holes.AddRange(other.Holes); - } - - public int TotalVertCount() - { - int result = hull.VertexCount; - foreach (var path in Holes) - { - result += path.VertexCount; - } - return result; - } - - public bool BoundsOverlap(Polygon other) - { - return boundingRect.Overlaps(other.boundingRect); - } - - public bool PointInPolyon(Vector2 point) - { - return boundingRect.Contains(point) && hull.PointInContour(point); - } - - public bool Contains(Polygon other) - { - foreach (var v in other.hull) - { - if (!PointInPolyon(v)) - return false; - } - return true; - } - - public bool Contains(Contour other) - { - foreach (var v in other) - { - if (!PointInPolyon(v)) - return false; - } - return true; - } - - public void Draw() - { - Gizmos.color = Color.green; - hull.Draw(); - - Gizmos.color = Color.yellow; - foreach (var contour in this.Holes) - { - contour.Draw(); - } - } - - public IEnumerator GetEnumerator() - { - yield return hull; - foreach (var hole in Holes) - yield return hole; - } - - IEnumerator IEnumerable.GetEnumerator() - { - yield return hull; - foreach (var hole in Holes) - yield return hole; - } - - public void UpdateBounds() - { - if (hull.VertexCount == 0) - return; - - Vector2 min = hull[0]; - Vector2 max = hull[0]; - for (int iVert = 1; iVert < hull.VertexCount; iVert++) - { - min = Vector2.Min(hull[iVert], min); - max = Vector2.Max(hull[iVert], max); - } - // add some fudge - Vector2 fudge = new Vector2(0.0001f, 0.0001f); - boundingRect = new Rect(min - fudge, max - min + fudge * 2); - } - - public void Simplify(float tolerance) - { - hull.Simplify(tolerance); - foreach (var hole in Holes) - { - hole.Simplify(tolerance); - } - UpdateBounds(); - } - - public double SignedArea() - { - double area = Hull.SignedArea(); - foreach (var hole in Holes) - area += hole.SignedArea(); - return area; - } - - public void EnsureCWOrdering() - { - if (Hull.IsCW()) - return; - - Hull.Invert(); - foreach (var child in Holes) - child.Invert(); - } - } -} \ No newline at end of file diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/Clipping/Polygon.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/Clipping/Polygon.cs.meta deleted file mode 100644 index e69cee88..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/Clipping/Polygon.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 24eb0a7c0c44eff48b61ea1d3120dd18 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/CustomAttributes.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/CustomAttributes.meta deleted file mode 100644 index 221d48cf..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/CustomAttributes.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 81309357b39e41942b7819480b292f4a -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/CustomAttributes/ReadOnlyAttribute.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d/CustomAttributes/ReadOnlyAttribute.cs deleted file mode 100644 index 376e8f16..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/CustomAttributes/ReadOnlyAttribute.cs +++ /dev/null @@ -1,9 +0,0 @@ -using UnityEngine; - -namespace PathBerserker2d -{ - internal class ReadOnlyAttribute : PropertyAttribute - { - - } -} \ No newline at end of file diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/CustomAttributes/ReadOnlyAttribute.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/CustomAttributes/ReadOnlyAttribute.cs.meta deleted file mode 100644 index 731eff77..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/CustomAttributes/ReadOnlyAttribute.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 334716afcf3386f4b8200ed669e80282 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/CustomAttributes/ScriptExecutionOrderAttribute.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d/CustomAttributes/ScriptExecutionOrderAttribute.cs deleted file mode 100644 index 1b9dc4da..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/CustomAttributes/ScriptExecutionOrderAttribute.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; - -namespace PathBerserker2d -{ - [AttributeUsage(AttributeTargets.Class)] - internal class ScriptExecutionOrderAttribute : Attribute - { - private int order = 0; - - public ScriptExecutionOrderAttribute(int order) - { - this.order = order; - } - - public int GetOrder() - { - return order; - } - } -} diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/CustomAttributes/ScriptExecutionOrderAttribute.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/CustomAttributes/ScriptExecutionOrderAttribute.cs.meta deleted file mode 100644 index cc2d8a29..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/CustomAttributes/ScriptExecutionOrderAttribute.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 036645a6650ecf0478b961d469c7e935 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/High-Speed-Priority-Queue.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/High-Speed-Priority-Queue.meta deleted file mode 100644 index 005f6044..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/High-Speed-Priority-Queue.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 68e576ad0cfa64743a23dd8e8db94b39 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/High-Speed-Priority-Queue/ExternalSortingFastPriorityQueueNode.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d/High-Speed-Priority-Queue/ExternalSortingFastPriorityQueueNode.cs deleted file mode 100644 index e62639ef..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/High-Speed-Priority-Queue/ExternalSortingFastPriorityQueueNode.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace Priority_Queue -{ - internal abstract class ExternalSortingFastPriorityQueueNode : System.IComparable - { - /// - /// Represents the current position in the queue - /// - public int QueueIndex { get; internal set; } - - public abstract int CompareTo(ExternalSortingFastPriorityQueueNode other); - } -} diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/High-Speed-Priority-Queue/ExternalSortingFastPriorityQueueNode.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/High-Speed-Priority-Queue/ExternalSortingFastPriorityQueueNode.cs.meta deleted file mode 100644 index 5614d3b5..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/High-Speed-Priority-Queue/ExternalSortingFastPriorityQueueNode.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 79ff18f1f5314034a980f4c7a9a66d56 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/High-Speed-Priority-Queue/FastPriorityQueue.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d/High-Speed-Priority-Queue/FastPriorityQueue.cs deleted file mode 100644 index e0b26c32..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/High-Speed-Priority-Queue/FastPriorityQueue.cs +++ /dev/null @@ -1,418 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Runtime.CompilerServices; - -namespace Priority_Queue -{ - /// - /// An implementation of a min-Priority Queue using a heap. Has O(1) .Contains()! - /// See https://github.com/BlueRaja/High-Speed-Priority-Queue-for-C-Sharp/wiki/Getting-Started for more information - /// - /// The values in the queue. Must extend the FastPriorityQueueNode class - internal sealed class FastPriorityQueue : IFixedSizePriorityQueue - where T : FastPriorityQueueNode - { - private int _numNodes; - private T[] _nodes; - - /// - /// Instantiate a new Priority Queue - /// - /// The max nodes ever allowed to be enqueued (going over this will cause undefined behavior) - public FastPriorityQueue(int maxNodes) - { -#if PBDEBUG - if (maxNodes <= 0) - { - throw new InvalidOperationException("New queue size cannot be smaller than 1"); - } -#endif - - _numNodes = 0; - _nodes = new T[maxNodes + 1]; - } - - /// - /// Returns the number of nodes in the queue. - /// O(1) - /// - public int Count - { - get - { - return _numNodes; - } - } - - /// - /// Returns the maximum number of items that can be enqueued at once in this queue. Once you hit this number (ie. once Count == MaxSize), - /// attempting to enqueue another item will cause undefined behavior. O(1) - /// - public int MaxSize - { - get - { - return _nodes.Length - 1; - } - } - - /// - /// Removes every node from the queue. - /// O(n) (So, don't do this often!) - /// -#if NET_VERSION_4_5 - [MethodImpl(MethodImplOptions.AggressiveInlining)] -#endif - public void Clear() - { - Array.Clear(_nodes, 1, _numNodes); - _numNodes = 0; - } - - /// - /// Returns (in O(1)!) whether the given node is in the queue. O(1) - /// -#if NET_VERSION_4_5 - [MethodImpl(MethodImplOptions.AggressiveInlining)] -#endif - public bool Contains(T node) - { -#if PBDEBUG - if (node == null) - { - throw new ArgumentNullException("node"); - } - if (node.QueueIndex < 0 || node.QueueIndex >= _nodes.Length) - { - throw new InvalidOperationException("node.QueueIndex has been corrupted. Did you change it manually? Or add this node to another queue?"); - } -#endif - - return (_nodes[node.QueueIndex] == node); - } - - /// - /// Enqueue a node to the priority queue. Lower values are placed in front. Ties are broken by first-in-first-out. - /// If the queue is full, the result is undefined. - /// If the node is already enqueued, the result is undefined. - /// O(log n) - /// -#if NET_VERSION_4_5 - [MethodImpl(MethodImplOptions.AggressiveInlining)] -#endif - public void Enqueue(T node, float priority) - { -#if PBDEBUG - if (node == null) - { - throw new ArgumentNullException("node"); - } - if (_numNodes >= _nodes.Length - 1) - { - throw new InvalidOperationException("Queue is full - node cannot be added: " + node); - } - if (Contains(node)) - { - throw new InvalidOperationException("Node is already enqueued: " + node); - } -#endif - - node.Priority = priority; - _numNodes++; - _nodes[_numNodes] = node; - node.QueueIndex = _numNodes; - CascadeUp(_nodes[_numNodes]); - } - -#if NET_VERSION_4_5 - [MethodImpl(MethodImplOptions.AggressiveInlining)] -#endif - private void Swap(T node1, T node2) - { - //Swap the nodes - _nodes[node1.QueueIndex] = node2; - _nodes[node2.QueueIndex] = node1; - - //Swap their indicies - int temp = node1.QueueIndex; - node1.QueueIndex = node2.QueueIndex; - node2.QueueIndex = temp; - } - - //Performance appears to be slightly better when this is NOT inlined o_O - private void CascadeUp(T node) - { - //aka Heapify-up - int parent = node.QueueIndex / 2; - while (parent >= 1) - { - T parentNode = _nodes[parent]; - if (HasHigherPriority(parentNode, node)) - break; - - //Node has lower priority value, so move it up the heap - Swap(node, parentNode); //For some reason, this is faster with Swap() rather than (less..?) individual operations, like in CascadeDown() - - parent = node.QueueIndex / 2; - } - } - -#if NET_VERSION_4_5 - [MethodImpl(MethodImplOptions.AggressiveInlining)] -#endif - private void CascadeDown(T node) - { - //aka Heapify-down - T newParent; - int finalQueueIndex = node.QueueIndex; - while (true) - { - newParent = node; - int childLeftIndex = 2 * finalQueueIndex; - - //Check if the left-child is higher-priority than the current node - if (childLeftIndex > _numNodes) - { - //This could be placed outside the loop, but then we'd have to check newParent != node twice - node.QueueIndex = finalQueueIndex; - _nodes[finalQueueIndex] = node; - break; - } - - T childLeft = _nodes[childLeftIndex]; - if (HasHigherPriority(childLeft, newParent)) - { - newParent = childLeft; - } - - //Check if the right-child is higher-priority than either the current node or the left child - int childRightIndex = childLeftIndex + 1; - if (childRightIndex <= _numNodes) - { - T childRight = _nodes[childRightIndex]; - if (HasHigherPriority(childRight, newParent)) - { - newParent = childRight; - } - } - - //If either of the children has higher (smaller) priority, swap and continue cascading - if (newParent != node) - { - //Move new parent to its new index. node will be moved once, at the end - //Doing it this way is one less assignment operation than calling Swap() - _nodes[finalQueueIndex] = newParent; - - int temp = newParent.QueueIndex; - newParent.QueueIndex = finalQueueIndex; - finalQueueIndex = temp; - } - else - { - //See note above - node.QueueIndex = finalQueueIndex; - _nodes[finalQueueIndex] = node; - break; - } - } - } - - /// - /// Returns true if 'higher' has higher priority than 'lower', false otherwise. - /// Note that calling HasHigherPriority(node, node) (ie. both arguments the same node) will return false - /// -#if NET_VERSION_4_5 - [MethodImpl(MethodImplOptions.AggressiveInlining)] -#endif - private bool HasHigherPriority(T higher, T lower) - { - return (higher.Priority < lower.Priority); - } - - /// - /// Removes the head of the queue and returns it. - /// If queue is empty, result is undefined - /// O(log n) - /// - public T Dequeue() - { -#if PBDEBUG - if (_numNodes <= 0) - { - throw new InvalidOperationException("Cannot call Dequeue() on an empty queue"); - } - - if (!IsValidQueue()) - { - throw new InvalidOperationException("Queue has been corrupted (Did you update a node priority manually instead of calling UpdatePriority()?" + - "Or add the same node to two different queues?)"); - } -#endif - - T returnMe = _nodes[1]; - Remove(returnMe); - return returnMe; - } - - /// - /// Resize the queue so it can accept more nodes. All currently enqueued nodes are remain. - /// Attempting to decrease the queue size to a size too small to hold the existing nodes results in undefined behavior - /// O(n) - /// - public void Resize(int maxNodes) - { -#if PBDEBUG - if (maxNodes <= 0) - { - throw new InvalidOperationException("Queue size cannot be smaller than 1"); - } - - if (maxNodes < _numNodes) - { - throw new InvalidOperationException("Called Resize(" + maxNodes + "), but current queue contains " + _numNodes + " nodes"); - } -#endif - - T[] newArray = new T[maxNodes + 1]; - int highestIndexToCopy = Math.Min(maxNodes, _numNodes); - for (int i = 1; i <= highestIndexToCopy; i++) - { - newArray[i] = _nodes[i]; - } - _nodes = newArray; - } - - /// - /// Returns the head of the queue, without removing it (use Dequeue() for that). - /// If the queue is empty, behavior is undefined. - /// O(1) - /// - public T First - { - get - { -#if PBDEBUG - if (_numNodes <= 0) - { - throw new InvalidOperationException("Cannot call .First on an empty queue"); - } -#endif - - return _nodes[1]; - } - } - - /// - /// This method must be called on a node every time its priority changes while it is in the queue. - /// Forgetting to call this method will result in a corrupted queue! - /// Calling this method on a node not in the queue results in undefined behavior - /// O(log n) - /// -#if NET_VERSION_4_5 - [MethodImpl(MethodImplOptions.AggressiveInlining)] -#endif - public void UpdatePriority(T node, float priority) - { -#if PBDEBUG - if (node == null) - { - throw new ArgumentNullException("node"); - } - if (!Contains(node)) - { - throw new InvalidOperationException("Cannot call UpdatePriority() on a node which is not enqueued: " + node); - } -#endif - - node.Priority = priority; - OnNodeUpdated(node); - } - - private void OnNodeUpdated(T node) - { - //Bubble the updated node up or down as appropriate - int parentIndex = node.QueueIndex / 2; - T parentNode = _nodes[parentIndex]; - - if (parentIndex > 0 && HasHigherPriority(node, parentNode)) - { - CascadeUp(node); - } - else - { - //Note that CascadeDown will be called if parentNode == node (that is, node is the root) - CascadeDown(node); - } - } - - /// - /// Removes a node from the queue. The node does not need to be the head of the queue. - /// If the node is not in the queue, the result is undefined. If unsure, check Contains() first - /// O(log n) - /// - public void Remove(T node) - { -#if PBDEBUG - if (node == null) - { - throw new ArgumentNullException("node"); - } - if (!Contains(node)) - { - throw new InvalidOperationException("Cannot call Remove() on a node which is not enqueued: " + node); - } -#endif - - //If the node is already the last node, we can remove it immediately - if (node.QueueIndex == _numNodes) - { - _nodes[_numNodes] = null; - _numNodes--; - return; - } - - //Swap the node with the last node - T formerLastNode = _nodes[_numNodes]; - Swap(node, formerLastNode); - _nodes[_numNodes] = null; - _numNodes--; - - //Now bubble formerLastNode (which is no longer the last node) up or down as appropriate - OnNodeUpdated(formerLastNode); - } - - public IEnumerator GetEnumerator() - { - for (int i = 1; i <= _numNodes; i++) - yield return _nodes[i]; - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - /// - /// Should not be called in production code. - /// Checks to make sure the queue is still in a valid state. Used for testing/debugging the queue. - /// - public bool IsValidQueue() - { - for (int i = 1; i < _nodes.Length; i++) - { - if (_nodes[i] != null) - { - int childLeftIndex = 2 * i; - if (childLeftIndex < _nodes.Length && _nodes[childLeftIndex] != null && HasHigherPriority(_nodes[childLeftIndex], _nodes[i])) - return false; - - int childRightIndex = childLeftIndex + 1; - if (childRightIndex < _nodes.Length && _nodes[childRightIndex] != null && HasHigherPriority(_nodes[childRightIndex], _nodes[i])) - return false; - } - } - return true; - } - } -} \ No newline at end of file diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/High-Speed-Priority-Queue/FastPriorityQueue.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/High-Speed-Priority-Queue/FastPriorityQueue.cs.meta deleted file mode 100644 index fc93627a..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/High-Speed-Priority-Queue/FastPriorityQueue.cs.meta +++ /dev/null @@ -1,12 +0,0 @@ -fileFormatVersion: 2 -guid: 376b08cc68eb144468648ebcd4a478e6 -timeCreated: 1476131089 -licenseType: Store -MonoImporter: - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/High-Speed-Priority-Queue/FastPriorityQueueNode.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d/High-Speed-Priority-Queue/FastPriorityQueueNode.cs deleted file mode 100644 index 802e1ae5..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/High-Speed-Priority-Queue/FastPriorityQueueNode.cs +++ /dev/null @@ -1,16 +0,0 @@ -namespace Priority_Queue -{ - internal class FastPriorityQueueNode - { - /// - /// The Priority to insert this node at. Must be set BEFORE adding a node to the queue (ideally just once, in the node's constructor). - /// Should not be manually edited once the node has been enqueued - use queue.UpdatePriority() instead - /// - public float Priority { get; protected internal set; } - - /// - /// Represents the current position in the queue - /// - public int QueueIndex { get; internal set; } - } -} diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/High-Speed-Priority-Queue/FastPriorityQueueNode.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/High-Speed-Priority-Queue/FastPriorityQueueNode.cs.meta deleted file mode 100644 index 62bef8ea..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/High-Speed-Priority-Queue/FastPriorityQueueNode.cs.meta +++ /dev/null @@ -1,12 +0,0 @@ -fileFormatVersion: 2 -guid: 4bb5e6cfc638aca43a63a7304f2fe754 -timeCreated: 1476131089 -licenseType: Store -MonoImporter: - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/High-Speed-Priority-Queue/IFixedSizePriorityQueue.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d/High-Speed-Priority-Queue/IFixedSizePriorityQueue.cs deleted file mode 100644 index 6d1529ef..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/High-Speed-Priority-Queue/IFixedSizePriorityQueue.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace Priority_Queue -{ - /// - /// A helper-interface only needed to make writing unit tests a bit easier (hence the 'internal' access modifier) - /// - internal interface IFixedSizePriorityQueue : IPriorityQueue - { - /// - /// Resize the queue so it can accept more nodes. All currently enqueued nodes are remain. - /// Attempting to decrease the queue size to a size too small to hold the existing nodes results in undefined behavior - /// - void Resize(int maxNodes); - - /// - /// Returns the maximum number of items that can be enqueued at once in this queue. Once you hit this number (ie. once Count == MaxSize), - /// attempting to enqueue another item will cause undefined behavior. - /// - int MaxSize { get; } - } -} diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/High-Speed-Priority-Queue/IFixedSizePriorityQueue.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/High-Speed-Priority-Queue/IFixedSizePriorityQueue.cs.meta deleted file mode 100644 index 8f8e6dca..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/High-Speed-Priority-Queue/IFixedSizePriorityQueue.cs.meta +++ /dev/null @@ -1,12 +0,0 @@ -fileFormatVersion: 2 -guid: d9cacd2c305e5a94dbfeba14e25a0441 -timeCreated: 1476131089 -licenseType: Store -MonoImporter: - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/High-Speed-Priority-Queue/IPriorityQueue.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d/High-Speed-Priority-Queue/IPriorityQueue.cs deleted file mode 100644 index 125a2d93..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/High-Speed-Priority-Queue/IPriorityQueue.cs +++ /dev/null @@ -1,53 +0,0 @@ -using System.Collections.Generic; - -namespace Priority_Queue -{ - /// - /// The IPriorityQueue interface. This is mainly here for purists, and in case I decide to add more implementations later. - /// For speed purposes, it is actually recommended that you *don't* access the priority queue through this interface, since the JIT can - /// (theoretically?) optimize method calls from concrete-types slightly better. - /// - internal interface IPriorityQueue : IEnumerable - { - /// - /// Enqueue a node to the priority queue. Lower values are placed in front. Ties are broken by first-in-first-out. - /// See implementation for how duplicates are handled. - /// - void Enqueue(T node, float priority); - - /// - /// Removes the head of the queue (node with minimum priority; ties are broken by order of insertion), and returns it. - /// - T Dequeue(); - - /// - /// Removes every node from the queue. - /// - void Clear(); - - /// - /// Returns whether the given node is in the queue. - /// - bool Contains(T node); - - /// - /// Removes a node from the queue. The node does not need to be the head of the queue. - /// - void Remove(T node); - - /// - /// Call this method to change the priority of a node. - /// - void UpdatePriority(T node, float priority); - - /// - /// Returns the head of the queue, without removing it (use Dequeue() for that). - /// - T First { get; } - - /// - /// Returns the number of nodes in the queue. - /// - int Count { get; } - } -} diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/High-Speed-Priority-Queue/IPriorityQueue.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/High-Speed-Priority-Queue/IPriorityQueue.cs.meta deleted file mode 100644 index a522987b..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/High-Speed-Priority-Queue/IPriorityQueue.cs.meta +++ /dev/null @@ -1,12 +0,0 @@ -fileFormatVersion: 2 -guid: 722bac7805cf3b74590b5eecfe9ff7f0 -timeCreated: 1476131089 -licenseType: Store -MonoImporter: - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/High-Speed-Priority-Queue/SimplePriorityQueue.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d/High-Speed-Priority-Queue/SimplePriorityQueue.cs deleted file mode 100644 index fd0d00db..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/High-Speed-Priority-Queue/SimplePriorityQueue.cs +++ /dev/null @@ -1,229 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; - -namespace Priority_Queue -{ - /// - /// A simplified priority queue implementation. Is stable, auto-resizes, and thread-safe, at the cost of being slightly slower than - /// FastPriorityQueue - /// - /// The type to enqueue - internal sealed class SimplePriorityQueue : IPriorityQueue - { - private class SimpleNode : StablePriorityQueueNode - { - public T Data { get; private set; } - - public SimpleNode(T data) - { - Data = data; - } - } - - private const int INITIAL_QUEUE_SIZE = 10; - private readonly StablePriorityQueue _queue; - - public SimplePriorityQueue() - { - _queue = new StablePriorityQueue(INITIAL_QUEUE_SIZE); - } - - /// - /// Given an item of type T, returns the exist SimpleNode in the queue - /// - private SimpleNode GetExistingNode(T item) - { - var comparer = EqualityComparer.Default; - foreach (var node in _queue) - { - if (comparer.Equals(node.Data, item)) - { - return node; - } - } - throw new InvalidOperationException("Item cannot be found in queue: " + item); - } - - /// - /// Returns the number of nodes in the queue. - /// O(1) - /// - public int Count - { - get - { - lock (_queue) - { - return _queue.Count; - } - } - } - - - /// - /// Returns the head of the queue, without removing it (use Dequeue() for that). - /// Throws an exception when the queue is empty. - /// O(1) - /// - public T First - { - get - { - lock (_queue) - { - if (_queue.Count <= 0) - { - throw new InvalidOperationException("Cannot call .First on an empty queue"); - } - - SimpleNode first = _queue.First; - return (first != null ? first.Data : default(T)); - } - } - } - - /// - /// Removes every node from the queue. - /// O(n) - /// - public void Clear() - { - lock (_queue) - { - _queue.Clear(); - } - } - - /// - /// Returns whether the given item is in the queue. - /// O(n) - /// - public bool Contains(T item) - { - lock (_queue) - { - var comparer = EqualityComparer.Default; - foreach (var node in _queue) - { - if (comparer.Equals(node.Data, item)) - { - return true; - } - } - return false; - } - } - - /// - /// Removes the head of the queue (node with minimum priority; ties are broken by order of insertion), and returns it. - /// If queue is empty, throws an exception - /// O(log n) - /// - public T Dequeue() - { - lock (_queue) - { - if (_queue.Count <= 0) - { - throw new InvalidOperationException("Cannot call Dequeue() on an empty queue"); - } - - SimpleNode node = _queue.Dequeue(); - return node.Data; - } - } - - /// - /// Enqueue a node to the priority queue. Lower values are placed in front. Ties are broken by first-in-first-out. - /// This queue automatically resizes itself, so there's no concern of the queue becoming 'full'. - /// Duplicates are allowed. - /// O(log n) - /// - public void Enqueue(T item, float priority) - { - lock (_queue) - { - SimpleNode node = new SimpleNode(item); - if (_queue.Count == _queue.MaxSize) - { - _queue.Resize(_queue.MaxSize * 2 + 1); - } - _queue.Enqueue(node, priority); - } - } - - /// - /// Removes an item from the queue. The item does not need to be the head of the queue. - /// If the item is not in the queue, an exception is thrown. If unsure, check Contains() first. - /// If multiple copies of the item are enqueued, only the first one is removed. - /// O(n) - /// - public void Remove(T item) - { - lock (_queue) - { - try - { - _queue.Remove(GetExistingNode(item)); - } - catch (InvalidOperationException ex) - { - throw new InvalidOperationException("Cannot call Remove() on a node which is not enqueued: " + item, ex); - } - } - } - - /// - /// Call this method to change the priority of an item. - /// Calling this method on a item not in the queue will throw an exception. - /// If the item is enqueued multiple times, only the first one will be updated. - /// (If your requirements are complex enough that you need to enqueue the same item multiple times and be able - /// to update all of them, please wrap your items in a wrapper class so they can be distinguished). - /// O(n) - /// - public void UpdatePriority(T item, float priority) - { - lock (_queue) - { - try - { - SimpleNode updateMe = GetExistingNode(item); - _queue.UpdatePriority(updateMe, priority); - } - catch (InvalidOperationException ex) - { - throw new InvalidOperationException("Cannot call UpdatePriority() on a node which is not enqueued: " + item, ex); - } - } - } - - public IEnumerator GetEnumerator() - { - List queueData = new List(); - lock (_queue) - { - //Copy to a separate list because we don't want to 'yield return' inside a lock - foreach (var node in _queue) - { - queueData.Add(node.Data); - } - } - - return queueData.GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - public bool IsValidQueue() - { - lock (_queue) - { - return _queue.IsValidQueue(); - } - } - } -} \ No newline at end of file diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/High-Speed-Priority-Queue/SimplePriorityQueue.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/High-Speed-Priority-Queue/SimplePriorityQueue.cs.meta deleted file mode 100644 index 60953288..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/High-Speed-Priority-Queue/SimplePriorityQueue.cs.meta +++ /dev/null @@ -1,12 +0,0 @@ -fileFormatVersion: 2 -guid: 1daaf3be153500e4d80b80fe17ccc211 -timeCreated: 1476131088 -licenseType: Store -MonoImporter: - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/High-Speed-Priority-Queue/StablePriorityQueue.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d/High-Speed-Priority-Queue/StablePriorityQueue.cs deleted file mode 100644 index 12218971..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/High-Speed-Priority-Queue/StablePriorityQueue.cs +++ /dev/null @@ -1,423 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Runtime.CompilerServices; - -namespace Priority_Queue -{ - /// - /// A copy of FastPriorityQueue which is also stable - that is, when two nodes are enqueued with the same priority, they - /// are always dequeued in the same order. - /// See https://github.com/BlueRaja/High-Speed-Priority-Queue-for-C-Sharp/wiki/Getting-Started for more information - /// - /// The values in the queue. Must extend the StablePriorityQueueNode class - internal sealed class StablePriorityQueue : IFixedSizePriorityQueue - where T : StablePriorityQueueNode - { - private int _numNodes; - private T[] _nodes; - private long _numNodesEverEnqueued; - - /// - /// Instantiate a new Priority Queue - /// - /// The max nodes ever allowed to be enqueued (going over this will cause undefined behavior) - public StablePriorityQueue(int maxNodes) - { -#if PBDEBUG - if (maxNodes <= 0) - { - throw new InvalidOperationException("New queue size cannot be smaller than 1"); - } -#endif - - _numNodes = 0; - _nodes = new T[maxNodes + 1]; - _numNodesEverEnqueued = 0; - } - - /// - /// Returns the number of nodes in the queue. - /// O(1) - /// - public int Count - { - get - { - return _numNodes; - } - } - - /// - /// Returns the maximum number of items that can be enqueued at once in this queue. Once you hit this number (ie. once Count == MaxSize), - /// attempting to enqueue another item will cause undefined behavior. O(1) - /// - public int MaxSize - { - get - { - return _nodes.Length - 1; - } - } - - /// - /// Removes every node from the queue. - /// O(n) (So, don't do this often!) - /// -#if NET_VERSION_4_5 - [MethodImpl(MethodImplOptions.AggressiveInlining)] -#endif - public void Clear() - { - Array.Clear(_nodes, 1, _numNodes); - _numNodes = 0; - } - - /// - /// Returns (in O(1)!) whether the given node is in the queue. O(1) - /// -#if NET_VERSION_4_5 - [MethodImpl(MethodImplOptions.AggressiveInlining)] -#endif - public bool Contains(T node) - { -#if PBDEBUG - if (node == null) - { - throw new ArgumentNullException("node"); - } - if (node.QueueIndex < 0 || node.QueueIndex >= _nodes.Length) - { - throw new InvalidOperationException("node.QueueIndex has been corrupted. Did you change it manually? Or add this node to another queue?"); - } -#endif - - return (_nodes[node.QueueIndex] == node); - } - - /// - /// Enqueue a node to the priority queue. Lower values are placed in front. Ties are broken by first-in-first-out. - /// If the queue is full, the result is undefined. - /// If the node is already enqueued, the result is undefined. - /// O(log n) - /// -#if NET_VERSION_4_5 - [MethodImpl(MethodImplOptions.AggressiveInlining)] -#endif - public void Enqueue(T node, float priority) - { -#if PBDEBUG - if (node == null) - { - throw new ArgumentNullException("node"); - } - if (_numNodes >= _nodes.Length - 1) - { - throw new InvalidOperationException("Queue is full - node cannot be added: " + node); - } - if (Contains(node)) - { - throw new InvalidOperationException("Node is already enqueued: " + node); - } -#endif - - node.Priority = priority; - _numNodes++; - _nodes[_numNodes] = node; - node.QueueIndex = _numNodes; - node.InsertionIndex = _numNodesEverEnqueued++; - CascadeUp(_nodes[_numNodes]); - } - -#if NET_VERSION_4_5 - [MethodImpl(MethodImplOptions.AggressiveInlining)] -#endif - private void Swap(T node1, T node2) - { - //Swap the nodes - _nodes[node1.QueueIndex] = node2; - _nodes[node2.QueueIndex] = node1; - - //Swap their indicies - int temp = node1.QueueIndex; - node1.QueueIndex = node2.QueueIndex; - node2.QueueIndex = temp; - } - - //Performance appears to be slightly better when this is NOT inlined o_O - private void CascadeUp(T node) - { - //aka Heapify-up - int parent = node.QueueIndex / 2; - while (parent >= 1) - { - T parentNode = _nodes[parent]; - if (HasHigherPriority(parentNode, node)) - break; - - //Node has lower priority value, so move it up the heap - Swap(node, parentNode); //For some reason, this is faster with Swap() rather than (less..?) individual operations, like in CascadeDown() - - parent = node.QueueIndex / 2; - } - } - -#if NET_VERSION_4_5 - [MethodImpl(MethodImplOptions.AggressiveInlining)] -#endif - private void CascadeDown(T node) - { - //aka Heapify-down - T newParent; - int finalQueueIndex = node.QueueIndex; - while (true) - { - newParent = node; - int childLeftIndex = 2 * finalQueueIndex; - - //Check if the left-child is higher-priority than the current node - if (childLeftIndex > _numNodes) - { - //This could be placed outside the loop, but then we'd have to check newParent != node twice - node.QueueIndex = finalQueueIndex; - _nodes[finalQueueIndex] = node; - break; - } - - T childLeft = _nodes[childLeftIndex]; - if (HasHigherPriority(childLeft, newParent)) - { - newParent = childLeft; - } - - //Check if the right-child is higher-priority than either the current node or the left child - int childRightIndex = childLeftIndex + 1; - if (childRightIndex <= _numNodes) - { - T childRight = _nodes[childRightIndex]; - if (HasHigherPriority(childRight, newParent)) - { - newParent = childRight; - } - } - - //If either of the children has higher (smaller) priority, swap and continue cascading - if (newParent != node) - { - //Move new parent to its new index. node will be moved once, at the end - //Doing it this way is one less assignment operation than calling Swap() - _nodes[finalQueueIndex] = newParent; - - int temp = newParent.QueueIndex; - newParent.QueueIndex = finalQueueIndex; - finalQueueIndex = temp; - } - else - { - //See note above - node.QueueIndex = finalQueueIndex; - _nodes[finalQueueIndex] = node; - break; - } - } - } - - /// - /// Returns true if 'higher' has higher priority than 'lower', false otherwise. - /// Note that calling HasHigherPriority(node, node) (ie. both arguments the same node) will return false - /// -#if NET_VERSION_4_5 - [MethodImpl(MethodImplOptions.AggressiveInlining)] -#endif - private bool HasHigherPriority(T higher, T lower) - { - return (higher.Priority < lower.Priority || - (higher.Priority == lower.Priority && higher.InsertionIndex < lower.InsertionIndex)); - } - - /// - /// Removes the head of the queue (node with minimum priority; ties are broken by order of insertion), and returns it. - /// If queue is empty, result is undefined - /// O(log n) - /// - public T Dequeue() - { -#if PBDEBUG - if (_numNodes <= 0) - { - throw new InvalidOperationException("Cannot call Dequeue() on an empty queue"); - } - - if (!IsValidQueue()) - { - throw new InvalidOperationException("Queue has been corrupted (Did you update a node priority manually instead of calling UpdatePriority()?" + - "Or add the same node to two different queues?)"); - } -#endif - - T returnMe = _nodes[1]; - Remove(returnMe); - return returnMe; - } - - /// - /// Resize the queue so it can accept more nodes. All currently enqueued nodes are remain. - /// Attempting to decrease the queue size to a size too small to hold the existing nodes results in undefined behavior - /// O(n) - /// - public void Resize(int maxNodes) - { -#if PBDEBUG - if (maxNodes <= 0) - { - throw new InvalidOperationException("Queue size cannot be smaller than 1"); - } - - if (maxNodes < _numNodes) - { - throw new InvalidOperationException("Called Resize(" + maxNodes + "), but current queue contains " + _numNodes + " nodes"); - } -#endif - - T[] newArray = new T[maxNodes + 1]; - int highestIndexToCopy = Math.Min(maxNodes, _numNodes); - for (int i = 1; i <= highestIndexToCopy; i++) - { - newArray[i] = _nodes[i]; - } - _nodes = newArray; - } - - /// - /// Returns the head of the queue, without removing it (use Dequeue() for that). - /// If the queue is empty, behavior is undefined. - /// O(1) - /// - public T First - { - get - { -#if PBDEBUG - if (_numNodes <= 0) - { - throw new InvalidOperationException("Cannot call .First on an empty queue"); - } -#endif - - return _nodes[1]; - } - } - - /// - /// This method must be called on a node every time its priority changes while it is in the queue. - /// Forgetting to call this method will result in a corrupted queue! - /// Calling this method on a node not in the queue results in undefined behavior - /// O(log n) - /// -#if NET_VERSION_4_5 - [MethodImpl(MethodImplOptions.AggressiveInlining)] -#endif - public void UpdatePriority(T node, float priority) - { -#if PBDEBUG - if (node == null) - { - throw new ArgumentNullException("node"); - } - if (!Contains(node)) - { - throw new InvalidOperationException("Cannot call UpdatePriority() on a node which is not enqueued: " + node); - } -#endif - - node.Priority = priority; - OnNodeUpdated(node); - } - - private void OnNodeUpdated(T node) - { - //Bubble the updated node up or down as appropriate - int parentIndex = node.QueueIndex / 2; - T parentNode = _nodes[parentIndex]; - - if (parentIndex > 0 && HasHigherPriority(node, parentNode)) - { - CascadeUp(node); - } - else - { - //Note that CascadeDown will be called if parentNode == node (that is, node is the root) - CascadeDown(node); - } - } - - /// - /// Removes a node from the queue. The node does not need to be the head of the queue. - /// If the node is not in the queue, the result is undefined. If unsure, check Contains() first - /// O(log n) - /// - public void Remove(T node) - { -#if PBDEBUG - if (node == null) - { - throw new ArgumentNullException("node"); - } - if (!Contains(node)) - { - throw new InvalidOperationException("Cannot call Remove() on a node which is not enqueued: " + node); - } -#endif - - //If the node is already the last node, we can remove it immediately - if (node.QueueIndex == _numNodes) - { - _nodes[_numNodes] = null; - _numNodes--; - return; - } - - //Swap the node with the last node - T formerLastNode = _nodes[_numNodes]; - Swap(node, formerLastNode); - _nodes[_numNodes] = null; - _numNodes--; - - //Now bubble formerLastNode (which is no longer the last node) up or down as appropriate - OnNodeUpdated(formerLastNode); - } - - public IEnumerator GetEnumerator() - { - for (int i = 1; i <= _numNodes; i++) - yield return _nodes[i]; - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - /// - /// Should not be called in production code. - /// Checks to make sure the queue is still in a valid state. Used for testing/debugging the queue. - /// - public bool IsValidQueue() - { - for (int i = 1; i < _nodes.Length; i++) - { - if (_nodes[i] != null) - { - int childLeftIndex = 2 * i; - if (childLeftIndex < _nodes.Length && _nodes[childLeftIndex] != null && HasHigherPriority(_nodes[childLeftIndex], _nodes[i])) - return false; - - int childRightIndex = childLeftIndex + 1; - if (childRightIndex < _nodes.Length && _nodes[childRightIndex] != null && HasHigherPriority(_nodes[childRightIndex], _nodes[i])) - return false; - } - } - return true; - } - } -} \ No newline at end of file diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/High-Speed-Priority-Queue/StablePriorityQueue.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/High-Speed-Priority-Queue/StablePriorityQueue.cs.meta deleted file mode 100644 index aea6d73f..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/High-Speed-Priority-Queue/StablePriorityQueue.cs.meta +++ /dev/null @@ -1,12 +0,0 @@ -fileFormatVersion: 2 -guid: 9e4182f1acbb9fc40b5e9356cebb9685 -timeCreated: 1476131089 -licenseType: Store -MonoImporter: - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/High-Speed-Priority-Queue/StablePriorityQueueNode.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d/High-Speed-Priority-Queue/StablePriorityQueueNode.cs deleted file mode 100644 index 22dd00c1..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/High-Speed-Priority-Queue/StablePriorityQueueNode.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Priority_Queue -{ - internal class StablePriorityQueueNode : FastPriorityQueueNode - { - /// - /// Represents the order the node was inserted in - /// - public long InsertionIndex { get; internal set; } - } -} diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/High-Speed-Priority-Queue/StablePriorityQueueNode.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/High-Speed-Priority-Queue/StablePriorityQueueNode.cs.meta deleted file mode 100644 index 09118346..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/High-Speed-Priority-Queue/StablePriorityQueueNode.cs.meta +++ /dev/null @@ -1,12 +0,0 @@ -fileFormatVersion: 2 -guid: 316bff9a2da34f5489becd70b0065188 -timeCreated: 1476131088 -licenseType: Store -MonoImporter: - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/High-Speed-Priority-Queue/SweepEventPriorityQueue.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d/High-Speed-Priority-Queue/SweepEventPriorityQueue.cs deleted file mode 100644 index 9bd6a524..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/High-Speed-Priority-Queue/SweepEventPriorityQueue.cs +++ /dev/null @@ -1,386 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Runtime.CompilerServices; -using static PathBerserker2d.PolygonClipper; - -namespace Priority_Queue -{ - /// - /// An implementation of a min-Priority Queue using a heap. Has O(1) .Contains()! - /// See https://github.com/BlueRaja/High-Speed-Priority-Queue-for-C-Sharp/wiki/Getting-Started for more information - /// - internal sealed class SweepEventPriorityQueue - { - private int _numNodes; - private SweepEvent[] _nodes; - - /// - /// Instantiate a new Priority Queue - /// - /// The max nodes ever allowed to be enqueued (going over this will cause undefined behavior) - public SweepEventPriorityQueue(int maxNodes) - { - #if QUEUE_DEBUG - if (maxNodes <= 0) - { - throw new InvalidOperationException("New queue size cannot be smaller than 1"); - } - #endif - - _numNodes = 0; - _nodes = new SweepEvent[maxNodes + 1]; - } - - /// - /// Returns the number of nodes in the queue. - /// O(1) - /// - public int Count - { - get - { - return _numNodes; - } - } - - /// - /// Returns the maximum number of items that can be enqueued at once in this queue. Once you hit this number (ie. once Count == MaxSize), - /// attempting to enqueue another item will cause undefined behavior. O(1) - /// - public int MaxSize - { - get - { - return _nodes.Length - 1; - } - } - - /// - /// Removes every node from the queue. - /// O(n) (So, don't do this often!) - /// - #if NET_VERSION_4_5 - [MethodImpl(MethodImplOptions.AggressiveInlining)] - #endif - public void Clear() - { - Array.Clear(_nodes, 1, _numNodes); - _numNodes = 0; - } - - /// - /// Returns (in O(1)!) whether the given node is in the queue. O(1) - /// - #if NET_VERSION_4_5 - [MethodImpl(MethodImplOptions.AggressiveInlining)] - #endif - public bool Contains(SweepEvent node) - { -#if QUEUE_DEBUG - if(node == null) - { - throw new ArgumentNullException("node"); - } - if(node.QueueIndex < 0 || node.QueueIndex >= _nodes.Length) - { - throw new InvalidOperationException("node.QueueIndex has been corrupted. Did you change it manually? Or add this node to another queue?"); - } -#endif - - return (_nodes[node.queueIndex] == node); - } - - /// - /// Enqueue a node to the priority queue. Lower values are placed in front. Ties are broken by first-in-first-out. - /// If the queue is full, the result is undefined. - /// If the node is already enqueued, the result is undefined. - /// O(log n) - /// - #if NET_VERSION_4_5 - [MethodImpl(MethodImplOptions.AggressiveInlining)] - #endif - public void Enqueue(SweepEvent node) - { -#if QUEUE_DEBUG - if(node == null) - { - throw new ArgumentNullException("node"); - } - if (Contains(node)) - { - throw new InvalidOperationException("Node is already enqueued: " + node); - } -#endif - if (_numNodes >= _nodes.Length - 1) - { - // double _node array - Array.Resize(ref _nodes, _nodes.Length * 2); - } - - _numNodes++; - _nodes[_numNodes] = node; - node.queueIndex = _numNodes; - CascadeUp(_nodes[_numNodes]); - } - - #if NET_VERSION_4_5 - [MethodImpl(MethodImplOptions.AggressiveInlining)] - #endif - private void Swap(SweepEvent node1, SweepEvent node2) - { - //Swap the nodes - _nodes[node1.queueIndex] = node2; - _nodes[node2.queueIndex] = node1; - - //Swap their indicies - int temp = node1.queueIndex; - node1.queueIndex = node2.queueIndex; - node2.queueIndex = temp; - } - - //Performance appears to be slightly better when this is NOT inlined o_O - private void CascadeUp(SweepEvent node) - { - //aka Heapify-up - int parent = node.queueIndex / 2; - while(parent >= 1) - { - SweepEvent parentNode = _nodes[parent]; - if(HasHigherPriority(parentNode, node)) - break; - - //Node has lower priority value, so move it up the heap - Swap(node, parentNode); //For some reason, this is faster with Swap() rather than (less..?) individual operations, like in CascadeDown() - - parent = node.queueIndex / 2; - } - } - - #if NET_VERSION_4_5 - [MethodImpl(MethodImplOptions.AggressiveInlining)] - #endif - private void CascadeDown(SweepEvent node) - { - //aka Heapify-down - SweepEvent newParent; - int finalQueueIndex = node.queueIndex; - while(true) - { - newParent = node; - int childLeftIndex = 2 * finalQueueIndex; - - //Check if the left-child is higher-priority than the current node - if(childLeftIndex > _numNodes) - { - //This could be placed outside the loop, but then we'd have to check newParent != node twice - node.queueIndex = finalQueueIndex; - _nodes[finalQueueIndex] = node; - break; - } - - SweepEvent childLeft = _nodes[childLeftIndex]; - if(HasHigherPriority(childLeft, newParent)) - { - newParent = childLeft; - } - - //Check if the right-child is higher-priority than either the current node or the left child - int childRightIndex = childLeftIndex + 1; - if(childRightIndex <= _numNodes) - { - SweepEvent childRight = _nodes[childRightIndex]; - if(HasHigherPriority(childRight, newParent)) - { - newParent = childRight; - } - } - - //If either of the children has higher (smaller) priority, swap and continue cascading - if(newParent != node) - { - //Move new parent to its new index. node will be moved once, at the end - //Doing it this way is one less assignment operation than calling Swap() - _nodes[finalQueueIndex] = newParent; - - int temp = newParent.queueIndex; - newParent.queueIndex = finalQueueIndex; - finalQueueIndex = temp; - } - else - { - //See note above - node.queueIndex = finalQueueIndex; - _nodes[finalQueueIndex] = node; - break; - } - } - } - - /// - /// Returns true if 'higher' has higher priority than 'lower', false otherwise. - /// Note that calling HasHigherPriority(node, node) (ie. both arguments the same node) will return false - /// - #if NET_VERSION_4_5 - [MethodImpl(MethodImplOptions.AggressiveInlining)] - #endif - private bool HasHigherPriority(SweepEvent higher, SweepEvent lower) - { - return higher.CompareTo(lower) < 0; - } - - /// - /// Removes the head of the queue and returns it. - /// If queue is empty, result is undefined - /// O(log n) - /// - public SweepEvent Dequeue() - { -#if QUEUE_DEBUG - if(_numNodes <= 0) - { - throw new InvalidOperationException("Cannot call Dequeue() on an empty queue"); - } - - if(!IsValidQueue()) - { - throw new InvalidOperationException("Queue has been corrupted (Did you update a node priority manually instead of calling UpdatePriority()?" + - "Or add the same node to two different queues?)"); - } -#endif - - SweepEvent returnMe = _nodes[1]; - Remove(returnMe); - return returnMe; - } - - /// - /// Resize the queue so it can accept more nodes. All currently enqueued nodes are remain. - /// Attempting to decrease the queue size to a size too small to hold the existing nodes results in undefined behavior - /// O(n) - /// - public void Resize(int maxNodes) - { -#if QUEUE_DEBUG - if (maxNodes <= 0) - { - throw new InvalidOperationException("Queue size cannot be smaller than 1"); - } - - if (maxNodes < _numNodes) - { - throw new InvalidOperationException("Called Resize(" + maxNodes + "), but current queue contains " + _numNodes + " nodes"); - } -#endif - - SweepEvent[] newArray = new SweepEvent[maxNodes + 1]; - int highestIndexToCopy = Math.Min(maxNodes, _numNodes); - for (int i = 1; i <= highestIndexToCopy; i++) - { - newArray[i] = _nodes[i]; - } - _nodes = newArray; - } - - /// - /// Returns the head of the queue, without removing it (use Dequeue() for that). - /// If the queue is empty, behavior is undefined. - /// O(1) - /// - public SweepEvent First - { - get - { -#if QUEUE_DEBUG - if(_numNodes <= 0) - { - throw new InvalidOperationException("Cannot call .First on an empty queue"); - } -#endif - - return _nodes[1]; - } - } - - private void OnNodeUpdated(SweepEvent node) - { - //Bubble the updated node up or down as appropriate - int parentIndex = node.queueIndex / 2; - SweepEvent parentNode = _nodes[parentIndex]; - - if(parentIndex > 0 && HasHigherPriority(node, parentNode)) - { - CascadeUp(node); - } - else - { - //Note that CascadeDown will be called if parentNode == node (that is, node is the root) - CascadeDown(node); - } - } - - /// - /// Removes a node from the queue. The node does not need to be the head of the queue. - /// If the node is not in the queue, the result is undefined. If unsure, check Contains() first - /// O(log n) - /// - public void Remove(SweepEvent node) - { -#if QUEUE_DEBUG - if(node == null) - { - throw new ArgumentNullException("node"); - } - if(!Contains(node)) - { - throw new InvalidOperationException("Cannot call Remove() on a node which is not enqueued: " + node); - } -#endif - - //If the node is already the last node, we can remove it immediately - if (node.queueIndex == _numNodes) - { - _nodes[_numNodes] = null; - _numNodes--; - return; - } - - //Swap the node with the last node - SweepEvent formerLastNode = _nodes[_numNodes]; - Swap(node, formerLastNode); - _nodes[_numNodes] = null; - _numNodes--; - - //Now bubble formerLastNode (which is no longer the last node) up or down as appropriate - OnNodeUpdated(formerLastNode); - } - - public IEnumerator GetEnumerator() - { - for(int i = 1; i <= _numNodes; i++) - yield return _nodes[i]; - } - - /// - /// Should not be called in production code. - /// Checks to make sure the queue is still in a valid state. Used for testing/debugging the queue. - /// - public bool IsValidQueue() - { - for(int i = 1; i < _nodes.Length; i++) - { - if(_nodes[i] != null) - { - int childLeftIndex = 2 * i; - if(childLeftIndex < _nodes.Length && _nodes[childLeftIndex] != null && HasHigherPriority(_nodes[childLeftIndex], _nodes[i])) - return false; - - int childRightIndex = childLeftIndex + 1; - if(childRightIndex < _nodes.Length && _nodes[childRightIndex] != null && HasHigherPriority(_nodes[childRightIndex], _nodes[i])) - return false; - } - } - return true; - } - } -} \ No newline at end of file diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/High-Speed-Priority-Queue/SweepEventPriorityQueue.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/High-Speed-Priority-Queue/SweepEventPriorityQueue.cs.meta deleted file mode 100644 index e2957626..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/High-Speed-Priority-Queue/SweepEventPriorityQueue.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: db62ab1d9d5098f47ab5393ae603107a -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/IVelocityProvider.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d/IVelocityProvider.cs deleted file mode 100644 index 65cbc1e5..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/IVelocityProvider.cs +++ /dev/null @@ -1,12 +0,0 @@ -using UnityEngine; - -namespace PathBerserker2d -{ - public interface IVelocityProvider - { - /// - /// Current velocity relative to the world. - /// - Vector2 WorldVelocity { get; } - } -} diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/IVelocityProvider.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/IVelocityProvider.cs.meta deleted file mode 100644 index 816d3c59..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/IVelocityProvider.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: d3b2c212f6466574c8c5641690193a96 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavAgent.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavAgent.meta deleted file mode 100644 index 9d451bcf..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavAgent.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 32a41e6786a58fc4b8936609634bae30 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavAgent/NavAgent.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavAgent/NavAgent.cs deleted file mode 100644 index eef7faa4..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavAgent/NavAgent.cs +++ /dev/null @@ -1,1044 +0,0 @@ -using UnityEngine; -using System; -using System.Collections.Generic; - -namespace PathBerserker2d -{ - /// - /// Represents a pathfinding entity. - /// - /// - /// This components handles the interaction with the asynchronous pathfinding system. - /// It assumes the agent is a point located at transform.position. - /// Automatic movement will directly modify the transform this script is attached to. See \ref navagent_movement "NavAgent's build-in movement" for more detail on movement. - /// ## States - /// At heart the NavAgent is a state machine with the following states: - /// - /// - /// Idle\n - /// - /// In this state the agent does nothing and is ready to path to a new location. - /// - /// - /// - /// Planning\n - /// - /// The agent has made a path request and is now waiting for its result. - /// A call to for example would make the agent switch to this state. - /// If the path calculation succeeded, the agent switches into the FollowPath state. - /// If it didn't succeed however, the agent will switch back into the Idle state. - /// - /// - /// - /// FollowPath\n - /// - /// The agent will follow the a previously calculated path. Depending on whether or is set, - /// the path will be followed automatically. The agent has build-in ways to traverse the build-in link types. They don't make use of the physics system. - /// The path will be recalculated at a set interval determined by . This is to ensure the path is up to date with changes in the world. - /// No reactions to changes in the world between recalculations is possible. - /// - /// Following a path is further subdivided into three states: - /// - /// - /// Segment movement\n - /// - /// The agent moves on a line segment. - /// If you move the agent manually, call to switch to the next state. - /// - /// - /// - /// Wait for link\n - /// - /// This state is only entered if after the agent finshes moving on a segment, the link it wants to take is currently not traversable. - /// The agent will wait for the link to become traversable again. - /// - /// - /// - /// Traverse link\n - /// - /// The agent will move on the link. - /// If you move the agent manually, call to begin traversing the next segment. - /// - /// - /// - /// - /// - /// - /// LostPath\n - /// - /// The agent was previously in the FollowPath state, but was called. - /// In this state, the agent will periodically attempt to find a path to its last goal. - /// This is useful, for if the agent unexpectedly was moved of its previously followed path, it can still attempt to reach its goal. - /// This state is only entered, when in state FollowPath and is called. - /// - /// - /// - /// ## Pathfinding properties - /// A NavAgent has a few properties relevant to the pathfinder. - /// - /// - /// \n - /// - /// Only segments and links with enough free space are considered. - /// - /// - /// - /// \n - /// - /// Only segments that don't exceed this angle are considered traversable. - /// 0° = ground, 90° = straight walls and 180° = ceiling. - /// - /// - /// - /// \n - /// - /// For each link one multiplier from this array is applied to its traversal costs. - /// With multiplier values <= 0 you can completely exclude certain link types from traversal. - /// - /// - /// - /// \n - /// - /// Links and parts of segments can be tagged with a NavTag. NavTag with index 0 is considered the default and applied to all segments - /// that don't have another NavTag. - /// As with multiplier values <= 0 completely exclude NavTags from traversal. - /// - /// - /// - /// - [AddComponentMenu("PathBerserker2d/Nav Agent")] - [ScriptExecutionOrder(-50)] - public class NavAgent : MonoBehaviour - { - public enum State - { - /// Agent is doing nothing. - Idle, - /// Agent is following a path. - FollowPath, - } - - private enum MovementState - { - OnSegment, - OnLink, - WaitForLinkOnSegment, - } - - public State CurrentStatus => status; - public bool IsIdle => status == State.Idle && currentPathRequest?.Status == PathRequest.RequestState.Draft; - public bool IsFollowingAPath => status == State.FollowPath; - - public float Height => height; - public float MaxSlopeAngle => maxSlopeAngle; - public bool IsOnLink => IsFollowingAPath && movementState == MovementState.OnLink; - public bool IsMovingOnSegment => IsFollowingAPath && movementState == MovementState.OnSegment; - public bool IsWaitingForLink => IsFollowingAPath && movementState == MovementState.WaitForLinkOnSegment; - - /// - /// If true, either IsMovingOnSegment is true, or the agent is waiting to traverse an untraversable link. - /// - public bool IsOnSegment => IsFollowingAPath && movementState != MovementState.OnLink; - - /// - /// Check, if the current mapped position of the agent is valid. The mapped position can only be valid, if the agent is close to the ground. (Close, not necessarily directly on the ground) - /// - public bool HasValidPosition => !currentMappedPosition.IsInvalid(); - - /// - /// True, if Stop() was called and agent hasn't yet stopped - /// - public bool IsStopping => stopRequested; - - /// - /// True, if the agent is on the last segment of its path. - /// - public bool IsOnGoalSegment => IsOnSegment && !Path.HasNext; - - /// - /// Link of the path segment the agent is on, or null. - /// - [Obsolete("Use CurrentPathSegment.link")] - public INavLinkInstance CurrentLink => currentPath?.Current.link ?? null; - - /// - /// Link type of the path segment the agent is on, or "" - /// - [Obsolete("Use CurrentPathSegment.link.LinkTypeName")] - public string CurrentLinkType => currentPath?.Current.link?.LinkTypeName ?? ""; - - /// - /// Link start of the path segment the agent is on, or Vector2.zero. Can change each frame, if the link start is on a moving platform. - /// - [Obsolete("Use CurrentPathSegment.LinkStart")] - public Vector2 CurrentLinkStart => currentPath?.Current.LinkStart ?? Vector2.zero; - - /// - /// Segment normal of the path segment the agent is or normal of the currently mapped position, or Vector2.up - /// - public Vector2 CurrentSegmentNormal => IsFollowingAPath ? currentPath.Current.Normal : (currentMappedPosition.IsValid() ? currentMappedPosition.Normal : Vector2.up); - - /// - /// Current path segment if agent follows a path or null. - /// - public PathSegment CurrentPathSegment => currentPath?.Current; - - /// - /// Segment normal of the next segment on the path, or Vector2.zero - /// - [Obsolete("Use CurrentPathSegment.Next.Normal")] - public Vector2 NextSegmentNormal => currentPath?.NextSegment?.Normal ?? Vector2.zero; - - /// - /// Current subgoal the agent is moving towards. May either be a link start or a link end. If it lies on a moving platform, the value may change from frame to frame. - /// - public Vector2 PathSubGoal - { - get - { - if (IsFollowingAPath) - { - if (movementState == MovementState.OnLink) - return currentPath.Current.LinkEnd; - else - return currentPath.Current.LinkStart; - } - return Vector2.zero; - } - } - /// - /// Overall goal of the path the agent is on - /// - public Vector2? PathGoal => currentPath?.Goal; - - /// - /// Shorthand for transform.position - /// - public Vector2 Position - { - get => transform.position; - set => transform.position = new Vector3(value.x, value.y, transform.position.z); - } - - /// - /// Combination of all NavTags at the position of the agent. - /// - public int CurrentNavTagVector => IsFollowingAPath ? currentPath.Current.GetTagVector(Position) : (currentMappedPosition.cluster?.GetNavTagVector(currentMappedPosition.t) ?? 0); - - /// - /// Time agent spend on link. Does not include waiting for link to become traversable. - /// - public float TimeOnLink { get; private set; } - - - public delegate void FailedToFindPathDelegate(NavAgent agent); - - /// - /// Fired when agent begins moving on a link. - /// - public event Action OnStartLinkTraversal; - - /// - /// Fired when agent is moving on a link. - /// - public event Action OnLinkTraversal; - - /// - /// Fired when agent start moving on a segment. - /// - public event Action OnStartSegmentTraversal; - - /// - /// Fired when agent is moving on a segment. - /// - public event Action OnSegmentTraversal; - - /// - /// Fired when the agent fails to find a path - /// - public event Action OnFailedToFindPath; - - /// - /// Fired when agent stops after Stop() or ForceStop() was called. For ForceStop() this happens instantly. For Stop() this happens after the agent stopped. - /// - public event Action OnStop; - - /// - /// Fired when agent reaches its current goal. - /// - public event Action OnReachedGoal; - - /// - /// Called when the agent starts following a new path. - /// NOTE: Also called, after successfully recalculating a path, even if the path itself does not change. - /// - public event Action OnStartFollowingNewPath; - - internal Path Path => currentPath; - internal int NavTagMask => navTagMask; - - - - [Header("Pathplanning")] - [SerializeField] - // protect! should not be changeable, unless not making a path request - private float height = 1; - [SerializeField] - // protect! should not be changeable, unless not making a path request - // 90 = doesnt matter - [Range(0, 180)] - [Tooltip("Maximum slope the agent can walk on. 180 = unlimited")] - private float maxSlopeAngle = 180; - - /// - /// Delay in seconds between recalculations of current path. This enables the agent to react to changes in the world. Higher values are better for performance. - /// - [Tooltip("Interval at which an agent will recalculate its current path to react to world changes in seconds. Higher value improves performance.")] - [SerializeField] - float autoRepathIntervall = 1f; - [Tooltip("Maximum distance an agent can be from the start of a calculated path, to start following it. If the distance is to large, the path is thrown out.")] - [SerializeField] - float maximumDistanceToPathStart = 0.7f; - - [SerializeField] - float[] linkTraversalCostMultipliers; - - /// - /// If true and no path exists between start and goal, the NavAgent will try to find a path to the closest reachable position instead. Does not work with multiple targets! - /// - [Tooltip("If true and no path exists between start and goal, will try to find a path to the closest reachable position instead. Does not work with multiple targets!")] - [SerializeField] - bool allowCloseEnoughPath = false; - - [Obsolete("Moved to out and into a separate component. Only for migration purposes.", true)] - [Tooltip("Speed on segments in unit/s.")] - [SerializeField] - public float movementSpeed = 5; - - - [Obsolete("Moved to out and into a separate component. Only for migration purposes.", true)] - [Tooltip("Speed on corner links in degrees/s.")] - [SerializeField] - public float cornerSpeed = 100; - - [Obsolete("Moved to out and into a separate component. Only for migration purposes.", true)] - [Tooltip("Speed on jump links in unit/s.")] - [SerializeField] - public float jumpSpeed = 5; - - [Obsolete("Moved to out and into a separate component. Only for migration purposes.", true)] - [Tooltip("Speed on fall links in unit/s.")] - [SerializeField] - public float fallSpeed = 5; - - [Obsolete("Moved to out and into a separate component. Only for migration purposes.", true)] - [Tooltip("Speed on climb links in unit/s.")] - [SerializeField] - public float climbSpeed = 5; - - [Tooltip("If true, will print debug messages.")] - [SerializeField] - public bool enableDebugMessages = false; - - - /// - /// Traversal cost multipliers for nav tags. A value less or equal to 0 prohibits the agent from traversing that tag. - /// - [SerializeField] - float[] navTagTraversalCostMultipliers; - - - [SerializeField, ReadOnly] - private State status; - - [SerializeField, HideInInspector] - private int navTagMask; - - internal NavSegmentPositionPointer currentMappedPosition; - internal PathRequest currentPathRequest; - - private Path currentPath = null; - private PathRequest repathPathRequest; - private float lastRepathTime; - private MovementState movementState; - private bool traversedLinkSinceLastRepath; - private bool traversedLinkSinceLastPath; - private bool stopRequested; - - // [项目新增] 上次寻路失败(NoPathFromStartToGoal)时算出的最近可达点,供执行层"寻路到最近可到达点"读取。 - private NavSegmentPositionPointer _lastClosestReachable = NavSegmentPositionPointer.Invalid; - - #region UNITY_METHODS - private void OnEnable() - { - status = State.Idle; - currentPathRequest = new PathRequest(this); - repathPathRequest = new PathRequest(this); - } - - private void Start() - { - UpdateMappedPosition(); - } - - private void OnValidate() - { - if (linkTraversalCostMultipliers == null) - linkTraversalCostMultipliers = new float[0]; - if (navTagTraversalCostMultipliers == null) - navTagTraversalCostMultipliers = new float[0]; - - if (linkTraversalCostMultipliers.Length != PathBerserker2dSettings.NavLinkTypeNames.Length) - { - Utility.ResizeWithDefault(ref linkTraversalCostMultipliers, PathBerserker2dSettings.NavLinkTypeNames.Length, 1); - } - if (navTagTraversalCostMultipliers.Length != PathBerserker2dSettings.NavTags.Length) - { - Utility.ResizeWithDefault(ref navTagTraversalCostMultipliers, PathBerserker2dSettings.NavTags.Length, 1); - } - - navTagMask = GetNavTagMask(); - } - - private void Update() - { - UpdateMappedPosition(); - HandlePathRequest(); - - switch (status) - { - case State.FollowPath: - Repath(); - - if (movementState == MovementState.OnLink) - { - //check if link still exists - if (CurrentPathSegment.link == null) - { - // link was destroyed. Wait for repath - break; - } - - TimeOnLink += Time.deltaTime; - OnLinkTraversal?.Invoke(this); - } - else if (movementState == MovementState.OnSegment) - { - if (stopRequested) - { - status = State.Idle; - stopRequested = false; - OnStop?.Invoke(this); - } - else - { - OnSegmentTraversal?.Invoke(this); - } - } - else - { - if (currentPath.Current.link.IsTraversable) - { - StartTraversingLink(); - } - } - break; - } - } - #endregion - - /// - /// Repositions the agent at the nearest segment the agent could be standing at. Segments the agent could not be at do to its tag or slope will be ignored. - /// - /// True, if warping was successful - public bool WarpToNearestSegment(float maximumWarpDistance = 10) - { - if (!currentMappedPosition.IsInvalid()) - { - // already close enough - this.Position = currentMappedPosition.Position; - return true; - } - - NavSegmentPositionPointer p; - if (PBWorld.TryMapPoint(Position, maximumWarpDistance, this, out p)) - { - this.Position = p.Position; - return true; - } - return false; - } - - /// - /// Starts the process of pathfinding to the closest of the given goals. - /// NOTE: Do not call this method every frame. Calculating a path takes longer than a frame, so the agent will never start moving. - /// - /// - /// Goals to pathfind to. - /// True, if the at least 1 goal and the agents own position could be mapped. This does not mean, that a path towards a goal exists. - public bool PathTo(params Vector2[] goals) - { - Stop(); - return UpdatePath(goals); - } - - /// - /// Starts the process of pathfinding to the given goal. - /// NOTE: Do not call this method every frame. Calculating a path takes longer than a frame, so the agent will never start moving. - /// - /// - /// Goals to pathfind to. - /// True, if the at least 1 goal and the agents own position could be mapped. This does not mean, that a path towards a goal exists. - public bool PathTo(Vector2 goal) - { - Stop(); - return UpdatePath(goal); - } - - /// - /// Starts the process of pathfinding to the closest given goal. - /// NOTE: Do not call this method every frame. Calculating a path takes longer than a frame, so the agent will never start moving. - /// - /// True, the agents own position could be mapped. This does not mean, that a path towards the goal exists. - private bool PathTo(IList goalPs) - { - Stop(); - return UpdatePath(goalPs); - } - - /// - /// Starts the process of pathfinding to the closest of the given goals. Will continue moving until the calculations for the new path are completed. - /// NOTE: Do not call this method every frame. Calculating a path takes longer than a frame, so the agent will never start moving. - /// - /// - /// Goals to pathfind to. - /// True, if the at least 1 goal and the agents own position could be mapped. This does not mean, that a path towards a goal exists. - public bool UpdatePath(params Vector2[] goals) - { - if (currentMappedPosition.IsInvalid()) - return false; - - List goalPs = new List(goals.Length); - NavSegmentPositionPointer p; - for (int i = 0; i < goals.Length; i++) - { - float maxDist = Vector2.Distance(Position, goals[i]) + 0.1f; - if (PBWorld.TryMapPoint(goals[i], maxDist, out p) && (allowCloseEnoughPath || CouldBeLocatedAt(p))) - { - goalPs.Add(p); - } - } - return UpdatePath(goalPs); - } - - /// - /// Starts the process of pathfinding to the given goal. Will continue moving until the calculations for the new path are completed. - /// NOTE: Do not call this method every frame. Calculating a path takes longer than a frame, so the agent will never start moving. - /// - /// - /// Goals to pathfind to. - /// True, if the at least 1 goal and the agents own position could be mapped. This does not mean, that a path towards a goal exists. - public bool UpdatePath(Vector2 goal) - { - if (currentMappedPosition.IsInvalid()) - return false; - - float maxDist = Vector2.Distance(Position, goal) + 0.1f; - NavSegmentPositionPointer p; - if (!PBWorld.TryMapPoint(goal, maxDist, out p) || (!allowCloseEnoughPath && !CouldBeLocatedAt(p))) - return false; - - return UpdatePath(new NavSegmentPositionPointer[] { p }); - } - - /// - /// Simple distance check between agent and CurrentSubGoal. - /// - /// True, if distance is less than maxDist - public bool HasReachedCurrentSubGoal(float maxDist = 0.05f) - { - Vector2 delta = PathSubGoal - Position; - float distance = delta.magnitude; - return distance < maxDist; - } - - /// - /// Starts the process of pathfinding to the closest given goal. Will continue moving until the calculations for the new path are completed. - /// - /// True, the agents own position could be mapped. This does not mean, that a path towards the goal exists. - private bool UpdatePath(IList goalPs) - { - if (currentPathRequest.Status == PathRequest.RequestState.Pending) - return false; - - if (goalPs.Count == 0) - return false; - - if (currentMappedPosition.IsInvalid()) - return false; - - currentPathRequest.start = currentMappedPosition; - currentPathRequest.goals = goalPs; - PBWorld.PathTo(currentPathRequest); - // 新请求发出 → 作废上一次的最近可达点(避免跨目标读到过期数据);本次若失败会由 RaiseFailedToFindPath 重新写入。 - _lastClosestReachable = NavSegmentPositionPointer.Invalid; - traversedLinkSinceLastPath = false; - return true; - } - - /// - /// Start pathfinding to a random position on the NavGraph. It cannot grantee that this position is reachable. Does the agent might not move after this is called. - /// - /// - public bool SetRandomDestination() - { - if (currentMappedPosition.IsInvalid()) - return false; - - Vector2 goal = PBWorld.GetRandomPointOnGraph(); - return PathTo(goal); - } - - // [项目新增] 段内随机游走:目标点限制在 agent 当前所站的这一条 NavSegment(cluster) 上, - // 不会跨越任何 NavLink(跳/落/拐角),避免地面单位游走时被崖边夹停或卡在无法穿越的 link 处。 - // 需要 agent 当前已映射到某条段上(currentMappedPosition 有效),否则返回 false。 - // 注意:一条 cluster 是一条直线段;被拐角/斜坡拆成多段的平台只会在当前这一段内游走。 - /// - /// Start pathfinding to a random position ON THE SAME segment the agent currently stands on. - /// Never crosses a NavLink, so a ground unit stays on its current platform segment. - /// insets the random range from BOTH segment ends (world units), - /// so the goal is never so close to the edge that a bodied agent can't stand there - /// (pass the agent's half-width + ledge-check margin). If the segment is shorter than - /// 2*endMargin the goal degenerates to the segment midpoint. - /// Returns false if the agent is not currently mapped to a segment. - /// - public bool SetRandomDestinationOnCurrentSegment(float endMargin = 0f) - { - if (currentMappedPosition.IsInvalid()) - return false; - - var cluster = currentMappedPosition.cluster; - float len = cluster.Length; - float m = Mathf.Clamp(endMargin, 0f, len * 0.5f); // 段太短 → 退化到中点 - float t = UnityEngine.Random.Range(m, len - m); - Vector2 goal = cluster.owner.LocalToWorld.MultiplyPoint3x4(cluster.GetPositionAlongSegment(t)); - return PathTo(goal); - } - - // [项目新增] 目标点吸附:把任意世界点映射到最近的可行走段(与 PB2d 自身"把鼠标点击等任意点映射到 - // 最近导航位置"同一机制),再按 endMargin 从段两端内缩,得到"身体真正站得住"的世界点(避免落在角色宽度 - // 站不住的崖沿被移动层夹停)。与 SetRandomDestinationOnCurrentSegment 同源:endMargin 传 agent 半宽+ - // 落崖检测余量。段短于 2*endMargin → 退化到中点。 - // - // maxSnapDistance = 允许"点离最近段"的最大真实距离(m),语义同 PathBerserker2dSettings.closestToSegmentMaxDistance - // ("想多大就多大")。注意 TryMapPoint 传入的是 AABB 边长、可靠搜索半径只有其一半(见 TryMapPointSurface 的 - // queryAABB=pointMapDistance/2),故这里传 2*maxSnapDistance 以保证"点在 maxSnapDistance 内一定被吸附"。 - // 只要目标离某条烘焙段不超过 maxSnapDistance,就一定映射得到——不会因固定小半径漏掉离地稍远的点。 - /// - /// Maps to the NEAREST walkable segment within - /// (same mechanism PB2d uses to map an arbitrary point such as a - /// mouse click to the graph — cf. closestToSegmentMaxDistance), then insets by - /// from BOTH segment ends so the returned point is one a bodied agent can - /// actually stand on (not clamped at a ledge). A segment shorter than 2*endMargin degenerates to its - /// midpoint. Returns false only if no baked segment lies within maxSnapDistance of the target. - /// - public bool TryGetStandablePointNear(Vector2 worldTarget, float maxSnapDistance, float endMargin, out Vector2 standable) - { - // TryMapPoint 的可靠搜索半径 ≈ 传入值/2(broadphase AABB 半边=pointMapDistance/2),故传 2 倍补偿。 - if (!PBWorld.TryMapPoint(worldTarget, maxSnapDistance * 2f, out var ptr)) - { - standable = worldTarget; - return false; - } - - var cluster = ptr.cluster; - float len = cluster.Length; - float m = Mathf.Clamp(endMargin, 0f, len * 0.5f); // 段太短 → 退化到中点 - float t = Mathf.Clamp(ptr.t, m, len - m); - standable = cluster.owner.LocalToWorld.MultiplyPoint3x4(cluster.GetPositionAlongSegment(t)); - return true; - } - - - /// - /// If you implement link traversal yourself, call this to complete a link traversal. - /// - public void CompleteLinkTraversal() - { - if (IsOnLink) - { - currentPath.MoveNext(); - StartTraversingSegment(); - } - } - - /// - /// If you implement segment traversal yourself, call this to complete a segment traversal. - /// - public void CompleteSegmentTraversal() - { - if (movementState == MovementState.OnSegment) - { - if (currentPath.HasNext) - { - if (CurrentPathSegment.link.IsTraversable) - { - StartTraversingLink(); - } - else - { - movementState = MovementState.WaitForLinkOnSegment; - } - } - else - { - status = State.Idle; - OnReachedGoal?.Invoke(this); - } - } - } - - /// - /// Determines, if in this agent is allowed to traverse the given link. - /// - public bool CanTraverseLink(INavLinkInstance link) - { - int linkType = link.LinkType; - return linkType == -1 || (GetLinkTraversalMultiplier(linkType) > 0 && height <= link.Clearance); - } - - /// - /// Get the traversal cost multiplier for a given link type. - /// - public float GetLinkTraversalMultiplier(int linkType) - { - return linkTraversalCostMultipliers[linkType]; - } - - /// - /// Get the traversal cost multiplier for a given nav tag. - /// - public float GetNavTagTraversalMultiplier(int navTag) - { - return navTagTraversalCostMultipliers[navTag] <= 0 ? float.PositiveInfinity : navTagTraversalCostMultipliers[navTag]; - } - - /// - /// Whether the agents current position contains the given NavTag. NOTE: Does not work, if the agent is not currently moving on a path. - /// - /// True, if current position has supplied NavTag. - public bool IsOnSegmentWithTag(int navTag) - { - if (IsOnSegment) - return (CurrentNavTagVector & (1 << navTag)) != 0; - else - return false; - } - - /// - /// Stops the current path following at the first opportunity. Link traversal will be completed before the agent stops. - /// - public void Stop() - { - stopRequested = true; - if (currentPathRequest.Status == PathRequest.RequestState.Pending) - currentPathRequest = new PathRequest(this); - } - - /// - /// Stops the current path following instantly. Agent might stop wihle traversing a link (e.g. while jumping in mid air) - /// - public void ForceStop() - { - status = State.Idle; - currentPathRequest = new PathRequest(this); - OnStop?.Invoke(this); - } - - /// - /// Tries to map the "other" and checks if the agent is mapped to the same segment. - /// If "other" can't be mapped this will return null. - /// Agents on a link will always return false. - /// If this agent currently can't be mapped this will return null. - /// - /// - public bool? IsOnSameSegmentAs(Vector2 other) - { - if (IsOnLink) - return false; - - NavSegmentPositionPointer p; - if (!PBWorld.TryMapPoint(other, out p) || currentMappedPosition.IsInvalid()) - return null; - return currentMappedPosition.surface == p.surface && currentMappedPosition.cluster == p.cluster; - } - - /// - /// Enumerates the points on the currently followed path. Corner links will result in the same point being enumerated twice in a row. First point will be the agents current position. - /// - public IEnumerable PathPoints() - { - if (!IsFollowingAPath) - yield break; - - yield return Position; - - var seg = currentPath.Current; - if (IsOnSegment) - yield return seg.LinkStart; - - if (seg.Next != null) - { - yield return seg.LinkEnd; - - seg = seg.Next; - while (seg.Next != null) - { - yield return seg.LinkStart; - yield return seg.LinkEnd; - seg = seg.Next; - } - - yield return seg.LinkStart; - } - } - - - - /// - /// Creates a pathrequest for this agent using the specified start and goal. The PathRequest is for your own use. The agent will take no further action. Use it to plan theoretical paths, without the agent moving. See also PBWorld.PathTo() - /// - /// A PathRequest or null, if start or goal couldn't be mapped. - public PathRequest CreatePathRequest(Vector2 start, Vector2 goal) - { - float maxDist = Vector2.Distance(Position, goal) + 0.1f; - NavSegmentPositionPointer startPointer; - if (!PBWorld.TryMapPoint(start, maxDist, this, out startPointer)) - return null; - - NavSegmentPositionPointer goalPointer; - if (!PBWorld.TryMapPoint(goal, maxDist, out goalPointer) || (!allowCloseEnoughPath && !CouldBeLocatedAt(goalPointer))) - return null; - - PathRequest request = new PathRequest(this); - request.start = startPointer; - request.goals = new[] { goalPointer }; - - return request; - } - - /// - /// Convenience function that will return if the agent could reach the given point from it's current location. It runs synchronously which is not optimal for performance. - /// - public bool CanReach(Vector2 goal) - { - var pr = CreatePathRequest(Position, goal); - PBWorld.PathTo(pr); - - while (pr.Status != PathRequest.RequestState.Finished && pr.Status != PathRequest.RequestState.Failed) - { - // fast spinning - } - return pr.Status == PathRequest.RequestState.Finished; - } - - /// - /// After the most recent failed path request (NoPathFromStartToGoal), returns the closest - /// reachable world position found towards the goal. Returns false if none is available. - /// - public bool TryGetClosestReachablePosition(out Vector2 worldPos) - { - if (!_lastClosestReachable.IsInvalid()) - { - worldPos = _lastClosestReachable.Position; - return true; - } - worldPos = Vector2.zero; - return false; - } - - // [项目新增] 记录失败请求的最近可达点后再广播寻路失败,供执行层读取。仅 NoPath 失败才有最近点。 - private void RaiseFailedToFindPath(PathRequest failedRequest) - { - _lastClosestReachable = (failedRequest != null - && failedRequest.FailReason == PathRequest.RequestFailReason.NoPathFromStartToGoal) - ? failedRequest.closestReachablePosition - : NavSegmentPositionPointer.Invalid; - OnFailedToFindPath?.Invoke(this); - } - - private int GetNavTagMask() - { - int navTagMask = 0; - for (int i = 0; i < navTagTraversalCostMultipliers.Length; i++) - { - if (navTagTraversalCostMultipliers[i] <= 0) - navTagMask |= 1 << i; - } - return ~navTagMask; - } - - internal bool CanTraverseSegment(Vector2 segNormal, float minClearance) - { - return Vector2.Angle(Vector2.up, segNormal) <= maxSlopeAngle && minClearance >= height; - } - - internal bool CouldBeLocatedAt(NavSegmentPositionPointer positionPointer) - { - return Vector2.Angle(Vector2.up, positionPointer.Normal) <= maxSlopeAngle && positionPointer.cluster.GetClearanceAlongSegment(positionPointer.t) >= height && (positionPointer.cluster.GetNavTagVector(positionPointer.t) & ~navTagMask) == 0; - } - - private void StartTraversingLink() - { - movementState = MovementState.OnLink; - traversedLinkSinceLastRepath = true; - traversedLinkSinceLastPath = true; - TimeOnLink = 0; - OnStartLinkTraversal?.Invoke(this); - } - - private void StartTraversingSegment() - { - movementState = MovementState.OnSegment; - OnStartSegmentTraversal?.Invoke(this); - } - - private void UpdateMappedPosition() - { - // probably not on ground when on link - if (IsOnLink) - { - // make sure to set the path to invalid - currentMappedPosition = NavSegmentPositionPointer.Invalid; - return; - } - //if (Time.time >= timeToRemapPosition) - //{ - // timeToRemapPosition = Time.time + 0.2f + UnityEngine.Random.value * 0.1f; - - PBWorld.TryMapAgent(Position, currentMappedPosition, this, out currentMappedPosition); - - // edge case fix - // happens if the navagent is on a corner and mapping disagrees with path - if (IsFollowingAPath && currentMappedPosition.cluster != currentPath.Current.cluster) - { - if (currentMappedPosition.t <= 0.05f) - { - currentMappedPosition = new NavSegmentPositionPointer(currentMappedPosition.surface, currentPath.Current.cluster, 0); - } - else if (currentMappedPosition.t >= currentMappedPosition.cluster.Length - 0.05f) - { - currentMappedPosition = new NavSegmentPositionPointer(currentMappedPosition.surface, currentPath.Current.cluster, currentPath.Current.cluster.Length); - } - } - } - - private void Repath() - { - switch (repathPathRequest.Status) - { - case PathRequest.RequestState.Draft: - if (IsOnSegment && !currentMappedPosition.IsInvalid() && Time.time - lastRepathTime >= Mathf.Max(0.1f, autoRepathIntervall)) - { - repathPathRequest.start = currentMappedPosition; - repathPathRequest.goals = currentPathRequest.goals; - - PBWorld.PathTo(repathPathRequest); - - lastRepathTime = Time.time; - traversedLinkSinceLastRepath = false; - } - break; - case PathRequest.RequestState.Failed: - if (repathPathRequest.FailReason == PathRequest.RequestFailReason.NoPathFromStartToGoal - || repathPathRequest.FailReason == PathRequest.RequestFailReason.WorldWasDestroyed) - { - Stop(); - RaiseFailedToFindPath(repathPathRequest); - } - - repathPathRequest.Reset(); - break; - case PathRequest.RequestState.Finished: - if (!traversedLinkSinceLastRepath && currentPathRequest.goals == repathPathRequest.goals) - { - StartFollowingPath(repathPathRequest); - } - - repathPathRequest.Reset(); - break; - } - } - - private void HandlePathRequest() - { - switch (currentPathRequest.Status) - { - case PathRequest.RequestState.Failed: - - if (!allowCloseEnoughPath) - { - Stop(); - - if (currentPathRequest.Status == PathRequest.RequestState.Failed && enableDebugMessages) - Debug.Log($"{name}: Pathrequest failed because: {currentPathRequest.FailReason}"); - - RaiseFailedToFindPath(currentPathRequest); - currentPathRequest.Reset(); - } - else if (currentPathRequest.FailReason == PathRequest.RequestFailReason.NoPathFromStartToGoal && !currentPathRequest.closestReachablePosition.IsInvalid()) - { - float maxDistance = 10; - float distance = Vector2.Distance(currentPathRequest.closestReachablePosition.Position, Position); - if (distance < maxDistance) - { - UpdatePath(new List() { currentPathRequest.closestReachablePosition }); - } - RaiseFailedToFindPath(currentPathRequest); - } - break; - case PathRequest.RequestState.Finished: - if (!traversedLinkSinceLastPath) - { - StartFollowingPath(currentPathRequest); - currentPathRequest.Reset(); - } - else - { - traversedLinkSinceLastPath = false; - // retry - if (IsOnSegment && !currentMappedPosition.IsInvalid()) - PathTo(currentPathRequest.goals); - } - break; - } - } - - private bool StartFollowingPath(PathRequest request) - { -#if PBDEBUG - Debug.Log("Pathrequest succeed. " + request.Path); - Debug.Assert(request.Status == PathRequest.RequestState.Finished); -#endif - // check that we are close to the path start - if (Vector2.Distance(request.start.Position, Position) > maximumDistanceToPathStart) - { -#if PBDEBUG - Debug.Log("Moved to far away from path start. Not using that path"); -#endif - request.Fail(PathRequest.RequestFailReason.ToFarFromStart); - return false; - } - - stopRequested = false; - lastRepathTime = Time.time; - this.status = State.FollowPath; - currentPath = request.Path; - - StartTraversingSegment(); - - OnStartFollowingNewPath?.Invoke(this); - return true; - } - } -} diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavAgent/NavAgent.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavAgent/NavAgent.cs.meta deleted file mode 100644 index 74d2c053..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavAgent/NavAgent.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 3864fd1487d130847b11b82f276d11b6 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: -50 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavAgent/NavAgentUsers.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavAgent/NavAgentUsers.meta deleted file mode 100644 index 85710692..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavAgent/NavAgentUsers.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 19f72ec82365a48439101af4e8b29c4e -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavAgent/NavAgentUsers/AdjustRotation.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavAgent/NavAgentUsers/AdjustRotation.cs deleted file mode 100644 index 744f0ca9..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavAgent/NavAgentUsers/AdjustRotation.cs +++ /dev/null @@ -1,32 +0,0 @@ -using UnityEngine; - -namespace PathBerserker2d -{ - /// - /// Adjust the NavAgents rotation to match the segments rotation. - /// - public class AdjustRotation : MonoBehaviour - { - [SerializeField] - public NavAgent agent; - - /// - /// Speed at which the agent is rotated. - /// - [SerializeField, Tooltip("Speed at which the agent is rotated.")] - public float rotationSpeed = 20; - - private void Update() - { - if (!agent.IsOnLink || agent.CurrentPathSegment?.link?.LinkTypeName != "corner") - { - this.transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(Vector3.forward, this.agent.CurrentSegmentNormal), Time.deltaTime * rotationSpeed); - } - } - - private void Reset() - { - agent = GetComponent(); - } - } -} diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavAgent/NavAgentUsers/AdjustRotation.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavAgent/NavAgentUsers/AdjustRotation.cs.meta deleted file mode 100644 index f1c36644..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavAgent/NavAgentUsers/AdjustRotation.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: f33302ff91c92994e9d60e1cf7668b8f -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavAgent/NavAgentUsers/Follower.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavAgent/NavAgentUsers/Follower.cs deleted file mode 100644 index e74b1ebc..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavAgent/NavAgentUsers/Follower.cs +++ /dev/null @@ -1,93 +0,0 @@ -using System.Collections; -using System.Collections.Generic; -using UnityEngine; - -namespace PathBerserker2d -{ - /// - /// Makes a NavAgent follow another. - /// - public class Follower : MonoBehaviour - { - [SerializeField] - public NavAgent navAgent = null; - [SerializeField] - public Transform target = null; - - /// - /// Radius when agent should start moving towards the target. Should be >= travelStopRadius - /// - [SerializeField, Tooltip("Radius when agent should start moving towards the target. Should be >= travelStopRadius")] - public float closeEnoughRadius = 3; - - /// - /// Radius when agent should stop moving towards the target. - /// - [SerializeField, Tooltip("Radius when agent should stop moving towards the target")] - public float travelStopRadius = 1; - - /// - /// Using the targets velocity, predicts the targets position in the future and uses this prediction as pathfinding goal. Useful for fast moving enemies. Only works when the target has a Rigidbody2d component or a component that implements IVelocityProvider. (NavAgent does not!) - /// - [SerializeField] - [Tooltip("Using the targets velocity, predicts the targets position in the future and uses this prediction as pathfinding goal. Useful for fast moving enemies. Only works when the target has a Rigidbody2d component or a component that implements IVelocityProvider. (NavAgent does not!)")] - public float targetPredictionTime = 0; - - void Update() - { - if (target == null) - return; - - Vector2 targetPos = GetTargetPosition(); - float distToTarget = Vector2.Distance(transform.position, targetPos); - - if (distToTarget > closeEnoughRadius && - !(navAgent.PathGoal.HasValue && Vector2.Distance(navAgent.PathGoal.Value, targetPos) < travelStopRadius)) - { - if (!navAgent.UpdatePath(targetPos) && targetPredictionTime > 0) - { - navAgent.UpdatePath(target.position); - } - } - else if (distToTarget < travelStopRadius) - { - navAgent.Stop(); - } - } - - private void OnDrawGizmosSelected() - { - Gizmos.color = Color.green; - Gizmos.DrawWireSphere(transform.position, closeEnoughRadius); - - Gizmos.color = Color.blue; - Gizmos.DrawWireSphere(transform.position, travelStopRadius); - } - - private void OnValidate() - { - closeEnoughRadius = Mathf.Max(travelStopRadius, closeEnoughRadius); - } - - private void Reset() - { - navAgent = GetComponent(); - } - - private Vector2 GetTargetPosition() - { - Vector2 tpos = target.position; - if (targetPredictionTime > 0) - { - IVelocityProvider velocityProvider = target.GetComponent(); - if (velocityProvider != null) - return tpos + velocityProvider.WorldVelocity * targetPredictionTime; - - Rigidbody2D rigidbody = target.GetComponent(); - if (rigidbody != null) - return tpos + rigidbody.velocity * targetPredictionTime; - } - return tpos; - } - } -} diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavAgent/NavAgentUsers/Follower.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavAgent/NavAgentUsers/Follower.cs.meta deleted file mode 100644 index adc01c54..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavAgent/NavAgentUsers/Follower.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: d3b58755f80ab91479f1f9314acdea17 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavAgent/NavAgentUsers/FootStepSounds.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavAgent/NavAgentUsers/FootStepSounds.cs deleted file mode 100644 index 9edbbdef..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavAgent/NavAgentUsers/FootStepSounds.cs +++ /dev/null @@ -1,90 +0,0 @@ -using System; -using UnityEngine; - -namespace PathBerserker2d -{ - /// - /// Play foot steps depending on the NavTags at the agents current position. - /// - public class FootStepSounds : MonoBehaviour - { - public AudioClip[] FootStepSoundClips - { - get => footstepSounds; - set - { - if (value == null) - throw new ArgumentNullException(); - if (value.Length != PathBerserker2dSettings.NavTags.Length) - throw new ArgumentException($"FootStepSoundClips needs to be an array of length equal to the amount of NavTags ({PathBerserker2dSettings.NavTags.Length})."); - - footstepSounds = value; - } - } - - [SerializeField] - public AudioSource audioSource = null; - - [SerializeField] - public NavAgent agent = null; - - /// - /// Delay between playing of footstep sounds. - /// - [SerializeField] - public float footStepDelay = 1f; - - /// - /// Used when no NavTag specific footStep was found, or if the current segment has no NavTag. - /// - [SerializeField] - public AudioClip defaultFootstep = null; - - /// - /// Footsteps to use for each NavTag. - /// - [SerializeField] - AudioClip[] footstepSounds = null; - - private float lastFootStepTime; - - void Update() - { - // time to play next step? Is agent moving on segment? - if (Time.time - lastFootStepTime >= footStepDelay && agent.IsMovingOnSegment) - { - lastFootStepTime = Time.time; - int navTagV = agent.CurrentNavTagVector; - - AudioClip chosenClip = defaultFootstep; - // chose the first step sound with matching NavTag - for (int i = 0; i < footstepSounds.Length; i++) - { - if ((navTagV & (1 << i)) != 0) - { - chosenClip = footstepSounds[i]; - break; - } - } - audioSource.PlayOneShot(chosenClip); - } - } - - private void OnValidate() - { - if (footstepSounds == null) - { - footstepSounds = new AudioClip[PathBerserker2dSettings.NavTags.Length]; - } - if (footstepSounds.Length != PathBerserker2dSettings.NavTags.Length) - { - System.Array.Resize(ref footstepSounds, PathBerserker2dSettings.NavTags.Length); - } - } - - private void Reset() - { - agent = GetComponent(); - } - } -} diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavAgent/NavAgentUsers/FootStepSounds.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavAgent/NavAgentUsers/FootStepSounds.cs.meta deleted file mode 100644 index fe65915e..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavAgent/NavAgentUsers/FootStepSounds.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: c5f023eaead09b849a79459b344a457f -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavAgent/NavAgentUsers/KeepGrounded.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavAgent/NavAgentUsers/KeepGrounded.cs deleted file mode 100644 index daf409f8..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavAgent/NavAgentUsers/KeepGrounded.cs +++ /dev/null @@ -1,35 +0,0 @@ -using UnityEngine; - -namespace PathBerserker2d -{ - /// - /// Keeps the agent on moving platforms, by parenting the agent to them. - /// - public class KeepGrounded : MonoBehaviour - { - [SerializeField] - public LayerMask movingPlatformLayermask = 0; - - Transform originalParent; - - private void Awake() - { - originalParent = transform.parent; - } - - void FixedUpdate() - { - var hit = Physics2D.Raycast(transform.position + transform.up * 0.1f, -transform.up, 0.4f, movingPlatformLayermask); - if (hit.collider != null) - { - // we hit a moving platform -> parent - transform.SetParent(hit.collider.transform, true); - } - else - { - // we didn't hit a moving platform -> unparent - transform.SetParent(originalParent, true); - } - } - } -} \ No newline at end of file diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavAgent/NavAgentUsers/KeepGrounded.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavAgent/NavAgentUsers/KeepGrounded.cs.meta deleted file mode 100644 index bde6e439..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavAgent/NavAgentUsers/KeepGrounded.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: db3357009171fec4db2b712ce84cd1b5 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavAgent/NavAgentUsers/MouseWalker.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavAgent/NavAgentUsers/MouseWalker.cs deleted file mode 100644 index 25526ce4..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavAgent/NavAgentUsers/MouseWalker.cs +++ /dev/null @@ -1,45 +0,0 @@ -using UnityEngine; -#if ENABLE_INPUT_SYSTEM && !ENABLE_LEGACY_INPUT_MANAGER -using UnityEngine.InputSystem; -#endif - -namespace PathBerserker2d -{ - /// - /// Let the NavAgent walk to a mouse click. - /// - class MouseWalker : MonoBehaviour - { - [SerializeField] - public NavAgent navAgent; - - void Update() - { - // mouse click occurred? -#if ENABLE_INPUT_SYSTEM && !ENABLE_LEGACY_INPUT_MANAGER - if (Mouse.current.leftButton.wasPressedThisFrame) -#else - if (Input.GetMouseButtonDown(0)) -#endif - { -#if ENABLE_INPUT_SYSTEM && !ENABLE_LEGACY_INPUT_MANAGER - Vector2 pos = Camera.main.ScreenToWorldPoint(Mouse.current.position.ReadValue()); -#else - Vector2 pos = Camera.main.ScreenToWorldPoint(Input.mousePosition); -#endif - if (!navAgent.PathTo(pos)) - { - if (navAgent.HasValidPosition) - Debug.Log($"{name}: Pathfinding failed."); - else - Debug.Log($"{name}: Agent is not on a NavSurface."); - } - } - } - - private void Reset() - { - navAgent = GetComponent(); - } - } -} diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavAgent/NavAgentUsers/MouseWalker.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavAgent/NavAgentUsers/MouseWalker.cs.meta deleted file mode 100644 index d3814b7d..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavAgent/NavAgentUsers/MouseWalker.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 2a20f61a67733b34ba53481d70603e95 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavAgent/NavAgentUsers/MultiGoalWalker.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavAgent/NavAgentUsers/MultiGoalWalker.cs deleted file mode 100644 index 24159403..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavAgent/NavAgentUsers/MultiGoalWalker.cs +++ /dev/null @@ -1,52 +0,0 @@ -using UnityEngine; - -namespace PathBerserker2d -{ - /// - /// Let the agent walk to the closest of the given goals. - /// - public class MultiGoalWalker : MonoBehaviour - { - [SerializeField] - public NavAgent navAgent; - [SerializeField] - Transform[] goals = null; - [SerializeField] - public bool activateOnStart = true; - - void Start() - { - if (activateOnStart) - { - MoveToClosestGoal(); - } - } - - private void Reset() - { - navAgent = GetComponent(); - } - - /// - /// Starts moving to closest of this.goals. - /// - public void MoveToClosestGoal() - { - Vector2[] vs = new Vector2[goals.Length]; - for (int i = 0; i < goals.Length; i++) - vs[i] = goals[i].position; - navAgent.PathTo(vs); - } - - /// - /// Starts moving to closest of supplied goals. - /// - public void MoveToClosestGoal(Transform[] goals) - { - Vector2[] vs = new Vector2[goals.Length]; - for (int i = 0; i < goals.Length; i++) - vs[i] = goals[i].position; - navAgent.PathTo(vs); - } - } -} diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavAgent/NavAgentUsers/MultiGoalWalker.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavAgent/NavAgentUsers/MultiGoalWalker.cs.meta deleted file mode 100644 index dbb1ee3c..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavAgent/NavAgentUsers/MultiGoalWalker.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 65ba0666f6ead714a9a712c134268969 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavAgent/NavAgentUsers/PatrolWalker.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavAgent/NavAgentUsers/PatrolWalker.cs deleted file mode 100644 index af173553..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavAgent/NavAgentUsers/PatrolWalker.cs +++ /dev/null @@ -1,79 +0,0 @@ -using System; -using UnityEngine; - -namespace PathBerserker2d -{ - /// - /// Let the NavAgent walk to a series of goals in a loop. - /// - public class PatrolWalker : MonoBehaviour - { - /// - /// Radius at which the agent starts calculating path to next goal on patrol route. Must be >= 0. - /// - public float CalcNextPathRad - { - get => calcNextPathRad; - set - { - if (calcNextPathRad < 0) - throw new ArgumentException("CalcNextPathRad must be greater or equal to 0"); - calcNextPathRad = value; - } - } - - public Transform[] PatrolRoute - { - get => goals; - set - { - this.goals = value; - this.currentGoal = 0; - } - } - - [SerializeField] - public NavAgent navAgent; - [SerializeField] - Transform[] goals = null; - [SerializeField] - float calcNextPathRad = 0.2f; - - private Transform goal => goals[currentGoal]; - - int currentGoal = 0; - - private void Start() - { - navAgent.PathTo(goal.position); - } - - void Update() - { - if (goals == null) - return; - - // close enough move to next - float dist = Vector2.Distance(navAgent.Position, goal.position); - if (dist < calcNextPathRad) - { - currentGoal++; - if (currentGoal >= goals.Length) - { - currentGoal = 0; - } - navAgent.UpdatePath(goal.position); - } - } - - private void OnValidate() - { - calcNextPathRad = Mathf.Max(calcNextPathRad, 0.1f); - } - - private void Reset() - { - navAgent = GetComponent(); - } - } -} \ No newline at end of file diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavAgent/NavAgentUsers/PatrolWalker.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavAgent/NavAgentUsers/PatrolWalker.cs.meta deleted file mode 100644 index 326d581c..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavAgent/NavAgentUsers/PatrolWalker.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: e2c32017511f38b48a9b544492b5d0f6 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavAgent/NavAgentUsers/RandomWalker.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavAgent/NavAgentUsers/RandomWalker.cs deleted file mode 100644 index 4cd494f9..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavAgent/NavAgentUsers/RandomWalker.cs +++ /dev/null @@ -1,53 +0,0 @@ -using System.Collections; -using UnityEngine; - -namespace PathBerserker2d -{ - /// - /// Lets the NavAgent walk to a random point - /// - public class RandomWalker : MonoBehaviour - { - [SerializeField] - public NavAgent navAgent; - - /// - /// The random destination my not always be reachable. RetryCount determines the maximum amount of rolls for a random reachable position. - /// - [SerializeField, Tooltip("The random destination may not always be reachable. RetryCount determines the maximum amount of rolls each update for a random reachable position.")] - public int retryCount = 10; - - /// - /// Will make the agent pick a new random position to walk to, after reaching the previous one. Makes the agent walk between random points, until its set to false. - /// - [SerializeField] - public bool keepWalkingRandomly = true; - - void Update() - { - if (keepWalkingRandomly && navAgent.IsIdle) - { - StartRandomWalk(); - } - } - - private void Reset() - { - navAgent = GetComponent(); - } - - /// - /// Picks a random position and makes the NavAgent walk to it. - /// - /// True, if a random reachable position was found within a maximum of retryCount tries. - public bool StartRandomWalk() - { - for (int i = 0; i < retryCount && !navAgent.SetRandomDestination(); i++) - { - - } - - return !navAgent.IsIdle; - } - } -} \ No newline at end of file diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavAgent/NavAgentUsers/RandomWalker.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavAgent/NavAgentUsers/RandomWalker.cs.meta deleted file mode 100644 index c2374e1d..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavAgent/NavAgentUsers/RandomWalker.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 9fc605c0d97145a45be2755ef52445e0 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavAgent/TransformBasedMovement.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavAgent/TransformBasedMovement.cs deleted file mode 100644 index c7c56155..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavAgent/TransformBasedMovement.cs +++ /dev/null @@ -1,369 +0,0 @@ -using UnityEngine; - -namespace PathBerserker2d -{ - /// - /// Moves a NavAgent by manipulating its transform. - /// - public class TransformBasedMovement : MonoBehaviour - { - [System.Flags] - public enum FeatureFlags - { - SegmentMovement = 1, - JumpLinks = 2, - CornerLinks = 4, - FallLinks = 8, - TeleportLinks = 16, - ClimbLinks = 32, - ElevatorLinks = 64, - OtherLinks = 128, - } - - [Tooltip("Speed on segments in unit/s.")] - [SerializeField] - public float movementSpeed = 5; - - [Tooltip("Speed on corner links in degrees/s.")] - [SerializeField] - public float cornerSpeed = 100; - - [Tooltip("Speed on jump links in unit/s.")] - [SerializeField] - public float jumpSpeed = 5; - - [Tooltip("Speed on fall links in unit/s.")] - [SerializeField] - public float fallSpeed = 5; - - [Tooltip("Speed on climb links in unit/s.")] - [SerializeField] - public float climbSpeed = 5; - - /// - /// If false, agent will not be rotated. - /// - [Tooltip("Controls whether the default movement handler is allowed to rotate the agent.")] - [SerializeField] - public bool enableAgentRotation = true; - - /// - /// Sets which links and segments this component will handle. Useful to override an Agents default behavior for a certain link type or segment. - /// - [Tooltip("Enable features by setting the flag.")] - [SerializeField] - public FeatureFlags enabledFeatures = (FeatureFlags)int.MaxValue; - - private float timeOnLink; - private float timeToCompleteLink; - private Vector2 direction; - private int state = 0; - private Transform elevatorTrans; - private float deltaDistance; - private bool handleLinkMovement; - private int minNumberOfLinkExecutions; - private Vector2 storedLinkStart; - - private void OnEnable() - { - var agent = GetComponent(); - agent.OnStartLinkTraversal += Agent_StartLinkTraversalEvent; - agent.OnStartSegmentTraversal += Agent_OnStartSegmentTraversal; - agent.OnSegmentTraversal += Agent_OnSegmentTraversal; - agent.OnLinkTraversal += Agent_OnLinkTraversal; - } - - private void OnDisable() - { - var agent = GetComponent(); - agent.OnStartLinkTraversal -= Agent_StartLinkTraversalEvent; - agent.OnStartSegmentTraversal -= Agent_OnStartSegmentTraversal; - agent.OnSegmentTraversal -= Agent_OnSegmentTraversal; - agent.OnLinkTraversal -= Agent_OnLinkTraversal; - } - - private void OnValidate() - { - if (jumpSpeed <= 0) - jumpSpeed = 0.01f; - if (fallSpeed <= 0) - fallSpeed = 0.01f; - if (climbSpeed <= 0) - climbSpeed = 0.01f; - } - - private void Agent_OnStartSegmentTraversal(NavAgent agent) - { - - } - - private void Agent_OnSegmentTraversal(NavAgent agent) - { - if (!enabledFeatures.HasFlag(FeatureFlags.SegmentMovement)) - return; - - Vector2 newPos; - bool reachedGoal = MoveAlongSegment(agent.Position, agent.PathSubGoal, agent.CurrentPathSegment.Point, agent.CurrentPathSegment.Tangent, Time.deltaTime * movementSpeed, out newPos); - agent.Position = newPos; - - if (reachedGoal) - { - agent.CompleteSegmentTraversal(); - } - } - - private void Agent_StartLinkTraversalEvent(NavAgent agent) - { - string linkType = agent.CurrentPathSegment.link.LinkTypeName; - - bool unknownLinkType = linkType != "corner" && linkType != "fall" && linkType != "jump" && linkType != "elevator" && linkType != "teleport" && linkType != "climb"; - - handleLinkMovement = - (unknownLinkType && enabledFeatures.HasFlag(FeatureFlags.OtherLinks)) || - (linkType == "corner" && enabledFeatures.HasFlag(FeatureFlags.CornerLinks)) || - (linkType == "fall" && enabledFeatures.HasFlag(FeatureFlags.FallLinks)) || - (linkType == "jump" && enabledFeatures.HasFlag(FeatureFlags.JumpLinks)) || - (linkType == "elevator" && enabledFeatures.HasFlag(FeatureFlags.ElevatorLinks)) || - (linkType == "teleport" && enabledFeatures.HasFlag(FeatureFlags.TeleportLinks)) || - (linkType == "climb" && enabledFeatures.HasFlag(FeatureFlags.ClimbLinks)); - - if (!handleLinkMovement) - return; - - timeOnLink = 0; - Vector2 delta = agent.PathSubGoal - agent.CurrentPathSegment.LinkStart; - deltaDistance = delta.magnitude; - direction = delta / deltaDistance; - minNumberOfLinkExecutions = 1; - storedLinkStart = agent.CurrentPathSegment.LinkStart; - - float speed = 1; - switch (agent.CurrentPathSegment.link.LinkTypeName) - { - case "corner": - if (!enableAgentRotation) - { - agent.CompleteLinkTraversal(); - break; - } - speed = cornerSpeed; - deltaDistance = agent.CurrentPathSegment.link.TravelCosts(Vector2.zero, Vector2.zero); - break; - case "fall": - speed = fallSpeed; - break; - case "climb": - speed = climbSpeed; - - Vector2 pos = agent.CurrentPathSegment.link.GameObject.transform.position; - Vector2 dir = agent.CurrentPathSegment.link.GameObject.transform.up; - - Vector2 start = Geometry.ProjectPointOnLine(agent.CurrentPathSegment.LinkStart, pos, dir); - Vector2 end = Geometry.ProjectPointOnLine(agent.PathSubGoal, pos, dir); - deltaDistance = Vector2.Distance(start, pos) + Vector2.Distance(start, end) + Vector2.Distance(end, agent.PathSubGoal); - - state = 0; - minNumberOfLinkExecutions = 3; - break; - case "jump": - speed = jumpSpeed; - break; - case "elevator": - speed = movementSpeed; - state = 0; - minNumberOfLinkExecutions = 4; - elevatorTrans = agent.CurrentPathSegment.link.GameObject.transform; - var childTrans = agent.CurrentPathSegment.link.GameObject.GetComponentsInChildren(); - foreach (var t in childTrans) - { - if (t.gameObject.layer == 8) - { - elevatorTrans = t; - break; - } - } - break; - } - - if (agent.CurrentPathSegment.link.LinkTypeName == "elevator") - timeToCompleteLink = float.PositiveInfinity; - else - timeToCompleteLink = (deltaDistance / speed); - } - - private void Agent_OnLinkTraversal(NavAgent agent) - { - if (!handleLinkMovement) - return; - - timeOnLink += Time.deltaTime; - timeOnLink = Mathf.Min(timeToCompleteLink, timeOnLink); - - switch (agent.CurrentPathSegment.link.LinkTypeName) - { - case "corner": - Corner(agent); - break; - case "jump": - Jump(agent); - break; - case "fall": - Fall(agent); - break; - case "teleport": - Teleport(agent); - timeOnLink = timeToCompleteLink + 1; - break; - case "climb": - Climb(agent); - break; - case "elevator": - Elevator(agent); - break; - default: - Jump(agent); - break; - } - - minNumberOfLinkExecutions--; - if (timeOnLink >= timeToCompleteLink && minNumberOfLinkExecutions <= 0) - { - agent.CompleteLinkTraversal(); - return; - } - } - - private void Corner(NavAgent agent) - { - var from = Quaternion.LookRotation(Vector3.forward, agent.CurrentPathSegment.Normal); - var to = Quaternion.LookRotation(Vector3.forward, agent.CurrentPathSegment.Next.Normal); - - - agent.transform.rotation = Quaternion.Slerp( - from, - to, - agent.TimeOnLink / (deltaDistance / cornerSpeed)); - } - - private void Jump(NavAgent agent) - { - Vector2 newPos = storedLinkStart + direction * timeOnLink * jumpSpeed; - newPos.y += deltaDistance * 0.3f * Mathf.Sin(Mathf.PI * timeOnLink / timeToCompleteLink); - agent.Position = newPos; - } - - private void Fall(NavAgent agent) - { - Vector2 newPos = storedLinkStart + direction * timeOnLink * fallSpeed; - agent.Position = newPos; - } - - private void Climb(NavAgent agent) - { - Vector2 linkPos = agent.CurrentPathSegment.link.GameObject.transform.position; - Vector2 linkDir = agent.CurrentPathSegment.link.GameObject.transform.up; - - Vector2 newPos = Vector2.zero; - switch (state) - { - case 0: - Vector2 start = Geometry.ProjectPointOnLine(agent.CurrentPathSegment.LinkStart, linkPos, linkDir); - if (MoveTo(agent.Position, start, climbSpeed * Time.deltaTime, out newPos)) - { - state = 1; - } - break; - case 1: - Vector2 end = Geometry.ProjectPointOnLine(agent.PathSubGoal, linkPos, linkDir); - if (MoveTo(agent.Position, end, climbSpeed * Time.deltaTime, out newPos)) - { - state = 2; - } - break; - case 2: - if (MoveTo(agent.Position, agent.PathSubGoal, climbSpeed * Time.deltaTime, out newPos)) - { - // force early exit - timeToCompleteLink = 0; - } - break; - } - agent.Position = newPos; - } - - private void Elevator(NavAgent agent) - { - // 3 phase - // 1. move on elevator - // 2. wait to reach destination - // 3. leave - - Vector2 newPos = agent.Position; - switch (state) - { - case 0: - Vector2 target = elevatorTrans.position; - if (agent.CurrentPathSegment.link.IsTraversable && Mathf.Abs(newPos.y - target.y) < 0.1f) - { - state = 1; - newPos.y = target.y; - direction = Vector2.right * Mathf.Sign(target.x - storedLinkStart.x); - } - break; - case 1: - newPos += movementSpeed * direction * Time.deltaTime; - - float targetX = agent.CurrentPathSegment.link.GameObject.transform.position.x; - if ((newPos.x - targetX) * direction.x >= 0) - { - state = 2; - newPos.x = targetX; - } - break; - case 2: - // wait till y matches elevation - // cast ray downwards to move with platform - float targetY = agent.PathSubGoal.y; - if (agent.CurrentPathSegment.link.IsTraversable && Mathf.Abs(newPos.y - targetY) < 0.1f) - { - state = 3; - newPos.y = targetY; - direction = Vector2.right * Mathf.Sign(agent.PathSubGoal.x - newPos.x); - timeOnLink = 0; - timeToCompleteLink = Mathf.Abs(agent.PathSubGoal.x - newPos.x) / movementSpeed; - } - break; - case 3: - newPos += movementSpeed * direction * Time.deltaTime; - break; - } - agent.Position = newPos; - } - - private void Teleport(NavAgent agent) - { - agent.Position = agent.PathSubGoal; - } - - private static bool MoveAlongSegment(Vector2 pos, Vector2 goal, Vector2 segPoint, Vector2 segTangent, float amount, out Vector2 newPos) - { - pos = Geometry.ProjectPointOnLine(pos, segPoint, segTangent); - goal = Geometry.ProjectPointOnLine(goal, segPoint, segTangent); - return MoveTo(pos, goal, amount, out newPos); - } - - private static bool MoveTo(Vector2 pos, Vector2 goal, float amount, out Vector2 newPos) - { - Vector2 dir = goal - pos; - float distance = dir.magnitude; - if (distance <= amount) - { - newPos = goal; - return true; - } - - newPos = pos + dir * amount / distance; - return false; - } - } -} diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavAgent/TransformBasedMovement.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavAgent/TransformBasedMovement.cs.meta deleted file mode 100644 index df66c74a..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavAgent/TransformBasedMovement.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 77030faff3812a7429edeaca91e9c873 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavGraph.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavGraph.meta deleted file mode 100644 index e5ac7800..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavGraph.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: cd0d5b7789d46e742afeb4aa400c1822 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavGraph/NavGraph.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavGraph/NavGraph.cs deleted file mode 100644 index 8f75ef75..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavGraph/NavGraph.cs +++ /dev/null @@ -1,831 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading; -using UnityEngine; -using UnityEngine.XR.WSA; - -namespace PathBerserker2d -{ - public enum NavGraphChange - { - NavSurfaceAdded, - NavSurfaceRemoved, - NavLinkAdded, - NavLinkRemoved, - SegmentModifierAdded, - SegmentModifierRemoved, - NavLinkMoved - } - - public interface INavGraphChangeSource - { - /// - /// Called after a group of changes has been applied to the NavGraph. When this is called, the changes are already applied and ready for use. For example NavSurfaceAdded means that that NavSurface is ready to be pathfinded on from now on, link mapping will work etc. - /// This may be called multiple times for the segment modifier related events as one SegmentModifier GameObject can produce multiple SegmentModifier changes. - /// Parameters: - /// - Change type - /// - the PBComponentId of the component (NavSurface, Link, SegmentModifier, ...) had. PBComponentId is a custom id that PathBerserker gives each component. Each component (NavSurface, Link, SegmentModifier, ...) has a PBComponentId property you can query to get its id. - /// - event Action OnGraphChange; - } - - internal class NavGraph : INavGraphChangeSource - { - public ReaderWriterLock graphLock = new ReaderWriterLock(); - public event Action OnGraphChange; - - internal readonly Dictionary segmentTrees = new Dictionary(); - - List changes = new List(20); - List stagedNewSurfaces = new List(4); - - private int pathfinderThreadCount; - - public NavGraph(int pathfinderThreadCount) - { - this.pathfinderThreadCount = pathfinderThreadCount; - } - - public void AddNavSurface(NavSurface surface) - { - var addSurface = new AddNavSurfaceChange(surface, pathfinderThreadCount); - if (!stagedNewSurfaces.Any(item => item.surface == surface)) - stagedNewSurfaces.Add(addSurface); - changes.Add(addSurface); - } - - public void RemoveNavSurface(NavSurface surface) - { - changes.Add(new RemoveNavSurfaceChange(surface)); - } - - public void AddNavLink(INavLinkInstance link, NavSegmentPositionPointer start, NavSegmentPositionPointer goal) - { - changes.Add(new AddNavLinkChange(link, start, goal)); - } - - public void RemoveNavLink(INavLinkInstance link, NavSegmentPositionPointer start, NavSegmentPositionPointer goal) - { - changes.Add(new RemoveNavLinkChange(link, start, goal)); - } - - public void MoveNavLinkStart(INavLinkInstance link, NavSegmentPositionPointer start, NavSegmentPositionPointer goal, NavSegmentPositionPointer oldStart) - { - changes.Add(new MoveNavLinkStartChange(link, start, goal, oldStart)); - } - - public void MoveNavLinkGoal(INavLinkInstance link, NavSegmentPositionPointer start, NavSegmentPositionPointer goal, NavSegmentPositionPointer oldGoal) - { - changes.Add(new MoveNavLinkGoalChange(link, start, goal, oldGoal)); - } - - public void AddSegmentModifier(NavAreaMarkerInstance modifier) - { - changes.Add(new AddSegmentModifierChange(modifier)); - } - - public void RemoveSegmentModifier(NavAreaMarkerInstance modifier) - { - changes.Add(new RemoveSegmentModifierChange(modifier)); - } - - public void Update() - { - // update navsurface position matricies - foreach (var entry in segmentTrees) - { - if (entry.Key != null) - entry.Value.LocalToWorld = entry.Key.LocalToWorldMatrix; - } - - if (changes.Count + stagedNewSurfaces.Count == 0) - return; - - graphLock.AcquireWriterLock(-1); - try - { - for (int i = 0; i < changes.Count; i++) - changes[i].Apply(this); - } - finally - { - graphLock.ReleaseWriterLock(); - } - - // fire events - if (OnGraphChange != null) - { - for (int i = 0; i < changes.Count; i++) - { - try - { - OnGraphChange(changes[i].ChangeType, changes[i].ChangeSource); - } - catch (Exception e) - { - // we don't want listener exceptions to take down the pathfinding system with it - Debug.LogError(e); - } - } - } - - stagedNewSurfaces.Clear(); - changes.Clear(); - } - - public void ForceApplyChanges() - { - for (int i = 0; i < changes.Count; i++) - changes[i].Apply(this); - - stagedNewSurfaces.Clear(); - changes.Clear(); - } - - public bool TryMapAgent(Vector2 position, NavSegmentPositionPointer pointer, NavAgent agent, out NavSegmentPositionPointer result) - { - if (!pointer.IsInvalid() && agent.CouldBeLocatedAt(pointer)) - { - NavGraphNodeCluster cluster; - if (TryGetClusterAt(pointer, out cluster)) - { - Vector2 localPos = pointer.surface.WorldToLocal(position); - float t = cluster.DistanceOfPointAlongSegment(localPos); - Vector2 proj = cluster.GetPositionAlongSegment(t); - float dist = (proj - localPos).sqrMagnitude; - - if (dist < 0.001f) - { - result = new NavSegmentPositionPointer(pointer.surface, pointer.cluster, cluster.DistanceOfPointAlongSegment(localPos)); - return true; - } - } - } - - return TryMapPoint(position, agent.CouldBeLocatedAt, out result); - } - - public bool TryMapPoint(Vector2 position, out NavSegmentPositionPointer pointer) - { - return TryMapPoint(position, (p) => true, out pointer); - } - - public bool TryMapPoint(Vector2 position, Func pointFilter, out NavSegmentPositionPointer pointer) - { - return TryMapPoint(position, pointFilter, PathBerserker2dSettings.PointMappingDistance, out pointer); - } - - public bool TryMapPoint(Vector2 position, Func pointFilter, float pointMapDistance, out NavSegmentPositionPointer result) - { - float halfPointMapDistance = pointMapDistance / 2f; - Rect queryAABB = new Rect(position - new Vector2(halfPointMapDistance, halfPointMapDistance), new Vector2(pointMapDistance, pointMapDistance)); - float minDistance = pointMapDistance; - result = NavSegmentPositionPointer.Invalid; - foreach (var pair in segmentTrees) - { - TryMapPointSurface(pair.Key, pair.Value.Clusters, queryAABB, position, pointFilter, ref minDistance, ref result); - } - - return result.IsValid(); - } - - public bool TryMapPointWithStaged(Vector2 position, out NavSegmentPositionPointer result) - { - if (TryMapPoint(position, out result)) - return true; - - float pointMapDistance = PathBerserker2dSettings.PointMappingDistance; - float halfPointMapDistance = pointMapDistance / 2f; - Rect queryAABB = new Rect(position - new Vector2(halfPointMapDistance, halfPointMapDistance), new Vector2(pointMapDistance, pointMapDistance)); - float minDistance = pointMapDistance; - result = NavSegmentPositionPointer.Invalid; - foreach (var change in stagedNewSurfaces) - { - TryMapPointSurface(change.surface, change.record.Clusters, queryAABB, position, (p) => true, ref minDistance, ref result); - } - - return result.IsValid(); - } - - public List BoxCast(Rect rect, float rotation, float filterAngleFrom, float filterAngleTo) - { - List results = new List(); - - // find bb of rect - Vector2[] rotCorn = ExtendedGeometry.RotateRectangle(rect, rotation); - - Vector2 min = Vector2.Min(Vector2.Min(Vector2.Min(rotCorn[0], rotCorn[1]), rotCorn[2]), rotCorn[3]); - Vector2 max = Vector2.Max(Vector2.Max(Vector2.Max(rotCorn[0], rotCorn[1]), rotCorn[2]), rotCorn[3]); - Rect boundingRect = new Rect(min, max - min); - - Matrix4x4 rotationMatrix = Matrix4x4.Rotate(Quaternion.Euler(0, 0, rotation)); - - foreach (var pair in segmentTrees) - { - BoxCastSurface(pair.Key, pair.Value.Clusters, rect, boundingRect, rotationMatrix, filterAngleFrom, filterAngleTo, ref results); - } - return results; - } - - public List BoxCastWithStaged(Rect rect, float rotation, float filterAngleFrom, float filterAngleTo) - { - List results = BoxCast(rect, rotation, filterAngleFrom, filterAngleTo); - - // find bb of rect - Vector2[] rotCorn = ExtendedGeometry.RotateRectangle(rect, rotation); - - Vector2 min = Vector2.Min(Vector2.Min(Vector2.Min(rotCorn[0], rotCorn[1]), rotCorn[2]), rotCorn[3]); - Vector2 max = Vector2.Max(Vector2.Max(Vector2.Max(rotCorn[0], rotCorn[1]), rotCorn[2]), rotCorn[3]); - Rect boundingRect = new Rect(min, max - min); - - Matrix4x4 rotationMatrix = Matrix4x4.Rotate(Quaternion.Euler(0, 0, rotation)); - - foreach (var change in stagedNewSurfaces) - { - BoxCastSurface(change.surface, change.record.Clusters, rect, boundingRect, rotationMatrix, filterAngleFrom, filterAngleTo, ref results); - } - return results; - } - - [Obsolete("Use TryMapPoint instead")] - public bool TryFindClosestPointTo(Vector2 position, float maxMappingDistance, out NavSegmentPositionPointer pointer) - { - return TryMapPoint(position, (p) => true, maxMappingDistance, out pointer); - } - - public Vector2 GetRandomPointOnGraph() - { - if (segmentTrees.Count == 0) - return Vector2.zero; - - var surf = Utility.WeightedRandomChoice(segmentTrees.Keys, - segmentTrees.Keys.Select(s => s.TotalLineLength)); - - var seg = Utility.WeightedRandomChoice(surf.NavSegments, - surf.NavSegments.Select(s => s.Length), surf.TotalLineLength); - - var t = UnityEngine.Random.Range(0, seg.Length); - - return surf.LocalToWorld(seg.GetPositionAlongSegment(t)); - } - - private void TryMapPointSurface(NavSurface surface, B2DynamicTree tree, Rect queryAABB, Vector2 position, Func filter, ref float minDistance, ref NavSegmentPositionPointer result) - { - if (!surface.WorldBounds.Overlaps(queryAABB)) - { - return; - } - - Vector2 localPoint = surface.WorldToLocal(position); - Rect localQuery = new Rect(surface.WorldToLocal(queryAABB.position), queryAABB.size); - - var iterator = tree.Query(localQuery); - while (iterator.MoveNext()) - { - var clusterCandidate = tree.GetUserData(iterator.Current); - float t = clusterCandidate.DistanceOfPointAlongSegment(localPoint); - Vector2 proj = clusterCandidate.GetPositionAlongSegment(t); - float dist = (proj - localPoint).magnitude; - - if (dist >= minDistance) - // closest point is already to far away - continue; - - if (filter(new NavSegmentPositionPointer(surface, clusterCandidate, t))) - { - minDistance = dist; - result = new NavSegmentPositionPointer(surface, clusterCandidate, t); - } - else - { - // sub sample segment - for (t = 0; t < clusterCandidate.Length; t += 0.5f) - { - if (filter(new NavSegmentPositionPointer(surface, clusterCandidate, t))) - { - proj = clusterCandidate.GetPositionAlongSegment(t); - dist = (proj - localPoint).magnitude; - - if (dist >= minDistance) - continue; - - result = new NavSegmentPositionPointer(surface, clusterCandidate, t); - minDistance = dist; - break; - } - } - } - } - } - - private void BoxCastSurface(NavSurface surface, B2DynamicTree tree, Rect rect, Rect boundingRect, Matrix4x4 rotationMatrix, float filterAngleFrom, float filterAngleTo, ref List results) - { - if (!surface.WorldBounds.Overlaps(boundingRect)) - return; - - Rect localQuery = new Rect(boundingRect); - localQuery.center = surface.WorldToLocal(localQuery.center); - - Rect localCast = new Rect(rect); - //localCast.center = surface.WorldToLocal(localCast.center); - - float u1, u2; - var iterator = tree.Query(localQuery); - while (iterator.MoveNext()) - { - var segCandidate = tree.GetUserData(iterator.Current); - - float angle = Vector2.SignedAngle(segCandidate.Tangent, Vector2.up); - if (!ExtendedGeometry.IsAngleBetweenAngles(filterAngleFrom, filterAngleTo, angle)) - continue; - - // test for rect intersection - Vector2 rotatedStart = rotationMatrix * surface.LocalToWorld(segCandidate.Start); - Vector2 rotatedEnd = rotationMatrix * surface.LocalToWorld(segCandidate.End); - if (ExtendedGeometry.RectLineIntersection(localCast, rotatedStart, rotatedEnd, out u1, out u2)) - { - u1 = u1 < 0 ? 0 : u1; - u2 = u2 > 1 ? 1 : u2; - u1 *= segCandidate.Length; - u2 *= segCandidate.Length; - - results.Add(new NavSubsegmentPointer(surface, iterator.Current, u1, u2 - u1)); - } - } - } - - private void InternalAddNavSurface(NavSurface surface, - NavSurfaceRecord record, int[] proxyIndecies) - { - if (segmentTrees.ContainsKey(surface)) - { -#if PBDEBUG - Debug.Log("AddNavSurface called but surface was already added!"); -#endif - return; - } - - // add corner links for connected segments - for (int iSeg = 0; iSeg < surface.NavSegments.Count; iSeg++) - { - var seg = surface.NavSegments[iSeg]; - var cluster = record.Clusters.GetUserData(proxyIndecies[iSeg]); - - if (seg.HasNext) - { - var goalCluster = record.Clusters.GetUserData(proxyIndecies[seg.NextSegmentIndex]); - - AddCornerLink(cluster, cluster.Length, surface, goalCluster, 0); - } - if (seg.HasPrev) - { - var goalCluster = record.Clusters.GetUserData(proxyIndecies[seg.PrevSegmentIndex]); - - AddCornerLink(cluster, 0, surface, goalCluster, goalCluster.Length); - } - } - - // add corner links for touching segments - for (int iSeg = 0; iSeg < surface.NavSegments.Count; iSeg++) - { - var seg = surface.NavSegments[iSeg]; - int proxyIndex = proxyIndecies[iSeg]; - var startCluster = record.Clusters.GetUserData(proxyIndex); - - CreateCornerLinksForClosePoints(seg.Start, startCluster, proxyIndex, record.Clusters, proxyIndecies, surface); - CreateCornerLinksForClosePoints(seg.End, startCluster, proxyIndex, record.Clusters, proxyIndecies, surface); - } - - segmentTrees.Add(surface, record); - } - - private void AddCornerLink(NavGraphNodeCluster startCluster, float startT, NavSurface startSurface, NavGraphNodeCluster goalCluster, float goalT) - { - float angle = Vector2.Angle(startCluster.Normal, goalCluster.Normal); - angle = angle < 0 ? 360 - angle : angle; - - var start = new NavSegmentPositionPointer(startSurface, startCluster, startT); - var goal = new NavSegmentPositionPointer(startSurface, goalCluster, goalT); - - startCluster.AddNode(pathfinderThreadCount, start.t, goal.cluster, goal.t, new CornerLink(start, goal, angle)); - } - - private void CreateCornerLinksForClosePoints(Vector2 point, NavGraphNodeCluster pointOwner, int pointOwnerProxyIndex, B2DynamicTree clusterTree, int[] proxyIndicies, NavSurface surface) - { - int prevSegProxyIndex = pointOwner.HasPrev ? proxyIndicies[pointOwner.PrevSegmentIndex] : -1; - - Vector2 queryRectSize = new Vector2(0.01f, 0.01f); - Rect query = new Rect(point - queryRectSize, point + queryRectSize); - var iterator = clusterTree.Query(query); - - while (iterator.MoveNext()) - { - if (prevSegProxyIndex == iterator.Current || iterator.Current == pointOwnerProxyIndex) - continue; - - var goalCluster = clusterTree.GetUserData(iterator.Current); - if (goalCluster.PointDistance(point) < 0.01f) - { - float startT = pointOwner.DistanceOfPointAlongSegment(point); - float goalT = goalCluster.DistanceOfPointAlongSegment(point); - - AddCornerLink(pointOwner, startT, surface, goalCluster, goalT); - AddCornerLink(goalCluster, goalT, surface, pointOwner, startT); - } - } - } - - private bool DoesLinkExist(INavLinkInstance link, NavSegmentPositionPointer start) - { - NavGraphNodeCluster cluster; - if (!TryGetClusterAt(start, out cluster)) - { - return false; - } - return cluster.DoesNodeExist(link); - } - - private void InternalRemoveNavSurface(NavSurface surface) - { - NavSurfaceRecord record = null; - try - { - record = segmentTrees[surface]; - - } - catch (KeyNotFoundException) - { -#if PBDEBUG - Debug.Log("RemoveNavSurface called but surface doesn't exist!"); -#endif - return; - } - record.Destroy(this); - segmentTrees.Remove(surface); - } - - private void InternalAddNavLink(INavLinkInstance link, NavSegmentPositionPointer start, NavSegmentPositionPointer goal) - { - start.cluster.AddNode( - pathfinderThreadCount, - start.t, - goal.cluster, - goal.t, - link); - - CreateSoftRefLink(link, start.surface); - if (start.surface != goal.surface) - { - CreateSoftRefLink(link, goal.surface); - } - } - - private void CreateSoftRefLink(INavLinkInstance link, NavSurface targetSurface) - { - try - { - segmentTrees[targetSurface].AddSoftRefLink(link); - } - catch (KeyNotFoundException) - { - // must be still staged - for (int i = 0; i < stagedNewSurfaces.Count; i++) - { - if (stagedNewSurfaces[i].surface == targetSurface) - { - stagedNewSurfaces[i].record.AddSoftRefLink(link); - return; - } - } - - throw new KeyNotFoundException(); - } - } - - private void RemoveSoftRefLink(INavLinkInstance link, NavSurface targetSurface) - { - if (targetSurface == null) - return; - try - { - segmentTrees[targetSurface].RemoveSoftRefLink(link); - } - catch (KeyNotFoundException) - { - // must be still staged - for (int i = 0; i < stagedNewSurfaces.Count; i++) - { - if (stagedNewSurfaces[i].surface == targetSurface) - { - stagedNewSurfaces[i].record.RemoveSoftRefLink(link); - return; - } - } - - throw new KeyNotFoundException(); - } - } - - internal void InternalRemoveNavLink(INavLinkInstance link, NavSegmentPositionPointer start, - NavSegmentPositionPointer goal) - { - if (start.surface == null || !DoesLinkExist(link, start)) - return; - - start.cluster.RemoveNode(link); - RemoveSoftRefLink(link, start.surface); - if (start.surface != goal.surface && segmentTrees.ContainsKey(goal.surface)) - RemoveSoftRefLink(link, goal.surface); - - link.OnRemove(); - } - - private void InternalMoveNavLinkStart(INavLinkInstance link, NavSegmentPositionPointer start, NavSegmentPositionPointer goal, NavSegmentPositionPointer oldStart) - { - if (oldStart.surface == start.surface && oldStart.cluster == start.cluster) - { - oldStart.cluster.MoveNode(link, start.t); - } - else - { - oldStart.cluster.RemoveNode(link); - RemoveSoftRefLink(link, oldStart.surface); - if (oldStart.surface != goal.surface) - RemoveSoftRefLink(link, goal.surface); - - InternalAddNavLink(link, start, goal); - } - } - - private void InternalMoveNavLinkGoal(INavLinkInstance link, NavSegmentPositionPointer start, NavSegmentPositionPointer goal, NavSegmentPositionPointer oldGoal) - { - var node = start.cluster.GetNode(link); - if (oldGoal.surface != goal.surface || oldGoal.cluster != goal.cluster) - node.LinkTarget = goal.cluster; - node.LinkTargetT = goal.t; - - if (goal.surface != oldGoal.surface) - { - if (start.surface != oldGoal.surface) - RemoveSoftRefLink(link, oldGoal.surface); - - if (start.surface != goal.surface) - CreateSoftRefLink(link, goal.surface); - } - } - - private void InternalAddSegmentModifier(NavAreaMarkerInstance mod) - { - if (TryGetClusterAt(mod.position, out var cluster)) - cluster.AddNodeClusterModifier(mod); - } - - private void InternalRemoveSegmentModifier(NavAreaMarkerInstance mod) - { - if (TryGetClusterAt(mod.position, out var cluster)) - cluster.RemoveNodeClusterModifier(mod); - } - - public bool TryGetClusterAt(NavSegmentPositionPointer tPoint, out NavGraphNodeCluster cluster) - { - if (tPoint.IsInvalid() || !segmentTrees.TryGetValue(tPoint.surface, out _)) - { - cluster = null; - return false; - } - - cluster = tPoint.cluster; - return true; - } - - public bool TryGetClusterAt(NavSubsegmentPointer tPoint, out NavGraphNodeCluster cluster) - { - NavSurfaceRecord navRec; - if (tPoint.IsInvalid() || !segmentTrees.TryGetValue(tPoint.surface, out navRec)) - { - cluster = null; - return false; - } - - cluster = navRec.Clusters.GetUserData(tPoint.proxyDataIndex); - return true; - } - - interface IGraphChange - { - NavGraphChange ChangeType { get; } - int ChangeSource { get; } - void Apply(NavGraph graph); - } - - class AddNavSurfaceChange : IGraphChange - { - public NavGraphChange ChangeType => NavGraphChange.NavSurfaceAdded; - public int ChangeSource { get; } - - public readonly NavSurfaceRecord record; - public readonly NavSurface surface; - int[] proxyIndecies; - - public AddNavSurfaceChange(NavSurface surface, int threadCount) - { - this.surface = surface; - this.ChangeSource = surface.PBComponentId; - - var tree = new B2DynamicTree(surface.NavSegments.Count + 10); - - proxyIndecies = new int[surface.NavSegments.Count]; - record = new NavSurfaceRecord(tree, surface.LocalToWorldMatrix, surface); - int fill = 0; - foreach (var seg in surface.NavSegments) - { - proxyIndecies[fill++] = tree.CreateProxy(seg.AABB, new NavGraphNodeCluster(seg, threadCount, record)); - } - } - - public void Apply(NavGraph graph) - { -#if PBDEBUG - Debug.Log("Added surface to graph"); -#endif - graph.InternalAddNavSurface(surface, record, proxyIndecies); - } - } - - class RemoveNavSurfaceChange : IGraphChange - { - public NavGraphChange ChangeType => NavGraphChange.NavSurfaceRemoved; - public int ChangeSource { get; } - - NavSurface surface; - GameObject changeSource; - - public RemoveNavSurfaceChange(NavSurface surface) - { - this.surface = surface; - this.ChangeSource = surface.PBComponentId; - } - - public void Apply(NavGraph graph) - { -#if PBDEBUG - Debug.Log("Removed surface from graph"); -#endif - graph.InternalRemoveNavSurface(surface); - } - } - - class AddNavLinkChange : IGraphChange - { - public NavGraphChange ChangeType => NavGraphChange.NavLinkAdded; - public int ChangeSource { get; } - - INavLinkInstance link; - NavSegmentPositionPointer start; - NavSegmentPositionPointer goal; - - public AddNavLinkChange(INavLinkInstance link, NavSegmentPositionPointer start, NavSegmentPositionPointer goal) - { - this.link = link; - this.start = start; - this.goal = goal; - ChangeSource = link.PBComponentId; - } - - public void Apply(NavGraph graph) - { -#if PBDEBUG - Debug.Log("Added link to graph"); -#endif - graph.InternalAddNavLink(link, start, goal); - } - } - - class RemoveNavLinkChange : IGraphChange - { - public NavGraphChange ChangeType => NavGraphChange.NavLinkRemoved; - public int ChangeSource { get; } - - INavLinkInstance link; - NavSegmentPositionPointer start; - NavSegmentPositionPointer goal; - - public RemoveNavLinkChange(INavLinkInstance link, NavSegmentPositionPointer start, NavSegmentPositionPointer goal) - { - this.link = link; - this.start = start; - this.goal = goal; - ChangeSource = link.PBComponentId; - } - - public void Apply(NavGraph graph) - { -#if PBDEBUG - Debug.Log("Removed link from graph"); -#endif - graph.InternalRemoveNavLink(link, start, goal); - } - } - - class MoveNavLinkStartChange : IGraphChange - { - public NavGraphChange ChangeType => NavGraphChange.NavLinkMoved; - public int ChangeSource { get; } - - INavLinkInstance link; - NavSegmentPositionPointer start; - NavSegmentPositionPointer goal; - NavSegmentPositionPointer oldStart; - - public MoveNavLinkStartChange(INavLinkInstance link, NavSegmentPositionPointer start, NavSegmentPositionPointer goal, NavSegmentPositionPointer oldStart) - { - this.link = link; - this.start = start; - this.goal = goal; - this.oldStart = oldStart; - ChangeSource = link.PBComponentId; - } - - public void Apply(NavGraph graph) - { -#if PBDEBUG - Debug.Log("Moved link start in graph"); -#endif - graph.InternalMoveNavLinkStart(link, start, goal, oldStart); - } - } - - class MoveNavLinkGoalChange : IGraphChange - { - public NavGraphChange ChangeType => NavGraphChange.NavLinkMoved; - public int ChangeSource { get; } - - INavLinkInstance link; - NavSegmentPositionPointer start; - NavSegmentPositionPointer goal; - NavSegmentPositionPointer oldGoal; - - public MoveNavLinkGoalChange(INavLinkInstance link, NavSegmentPositionPointer start, NavSegmentPositionPointer goal, NavSegmentPositionPointer oldGoal) - { - this.link = link; - this.start = start; - this.goal = goal; - this.oldGoal = oldGoal; - ChangeSource = link.PBComponentId; - } - - public void Apply(NavGraph graph) - { -#if PBDEBUG - Debug.Log("Moved link goal in graph"); -#endif - graph.InternalMoveNavLinkGoal(link, start, goal, oldGoal); - } - } - - class AddSegmentModifierChange : IGraphChange - { - public NavGraphChange ChangeType => NavGraphChange.SegmentModifierAdded; - public int ChangeSource { get; } - - NavAreaMarkerInstance mod; - - public AddSegmentModifierChange(NavAreaMarkerInstance mod) - { - this.mod = mod; - ChangeSource = mod.PBComponentId; - } - - public void Apply(NavGraph graph) - { -#if PBDEBUG - Debug.Log("Added modifier to graph"); -#endif - graph.InternalAddSegmentModifier(mod); - } - } - - class RemoveSegmentModifierChange : IGraphChange - { - public NavGraphChange ChangeType => NavGraphChange.SegmentModifierRemoved; - public int ChangeSource { get; } - - NavAreaMarkerInstance mod; - - public RemoveSegmentModifierChange(NavAreaMarkerInstance mod) - { - this.mod = mod; - ChangeSource = mod.PBComponentId; - } - - public void Apply(NavGraph graph) - { -#if PBDEBUG - Debug.Log("Removed modifier to graph"); -#endif - graph.InternalRemoveSegmentModifier(mod); - } - } - } -} diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavGraph/NavGraph.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavGraph/NavGraph.cs.meta deleted file mode 100644 index 27850889..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavGraph/NavGraph.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 026f93314fe2afa4db089d933acfcb9b -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavGraph/NavGraphNode.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavGraph/NavGraphNode.cs deleted file mode 100644 index 55509d47..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavGraph/NavGraphNode.cs +++ /dev/null @@ -1,96 +0,0 @@ -using System.Collections.Generic; -using UnityEngine; - -namespace PathBerserker2d -{ - internal class NavGraphNode - { - public float LinkTargetT { get; set; } - public NavGraphNodeCluster LinkTarget { get; set; } - - // location - public readonly NavGraphNodeCluster cluster; - public float t; - - public readonly INavLinkInstance link; - public PathValues[] pathValues; - - public bool IsGoal => link.LinkType == -1; - - public NavGraphNode(int threadCount, NavGraphNodeCluster owner, float t, NavGraphNodeCluster linkTarget, float linkTargetT, INavLinkInstance original) - { - this.cluster = owner; - this.t = t; - - this.LinkTargetT = linkTargetT; - this.LinkTarget = linkTarget; - - this.link = original; - - this.pathValues = new PathValues[threadCount]; - InitializePathValueArray(); - } - - public NavGraphNode(int threadCount, NavGraphNodeCluster owner, float t) - { - this.cluster = owner; - this.t = t; - this.link = new ArtificialLink(-1); - this.LinkTarget = cluster; - this.LinkTargetT = t; - - this.pathValues = new PathValues[threadCount]; - InitializePathValueArray(); - } - - public IEnumerable GetConnections(NavAgent agent, IList goals, int pathValueId) - { - return LinkTarget.EnumerateReachableNavVerts(LinkTargetT, agent, goals, pathValueId); - } - - // param must be local - public float HeuristicalCostsToGoal(Vector2 goal) - { - return Vector2.Distance(goal, GoalPosition()); - } - - public Vector2 GoalPosition() - { - return LinkTarget.GetPositionAlongSegment(LinkTargetT); - } - - public Vector2 WGoalPosition() - { - return LinkTarget.owner.LocalToWorld.MultiplyPoint3x4(LinkTarget.GetPositionAlongSegment(LinkTargetT)); - } - - public Vector2 Position() { - return cluster.GetPositionAlongSegment(t); - } - - public Vector2 WPosition() - { - return cluster.owner.LocalToWorld.MultiplyPoint3x4(cluster.GetPositionAlongSegment(t)); - } - - private void InitializePathValueArray() - { - for (int i = 0; i < pathValues.Length; i++) - { - pathValues[i] = new PathValues(this); - } - } - } - - internal struct NavConnection - { - public readonly NavGraphNode end; - public readonly float traversalCosts; - - public NavConnection(NavGraphNode end, float traversalCosts) - { - this.end = end; - this.traversalCosts = traversalCosts; - } - } -} \ No newline at end of file diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavGraph/NavGraphNode.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavGraph/NavGraphNode.cs.meta deleted file mode 100644 index b3f161f1..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavGraph/NavGraphNode.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: a5c4fab1500104040b48a3bb6aa7ba98 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavGraph/NavGraphNodeCluster.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavGraph/NavGraphNodeCluster.cs deleted file mode 100644 index 4e9eead5..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavGraph/NavGraphNodeCluster.cs +++ /dev/null @@ -1,155 +0,0 @@ -using System.Collections.Generic; -using UnityEngine; - -namespace PathBerserker2d -{ - internal class NavGraphNodeCluster : LineSegmentWithClearance - { - internal readonly List nodes = new List(); - // unsorted - internal readonly List modifiers = new List(1); - internal readonly bool[] containsGoal; - public readonly NavSurfaceRecord owner; - - public NavGraphNodeCluster(NavSegment segment, int threadCount, NavSurfaceRecord owner) : base(segment) - { - containsGoal = new bool[threadCount]; - this.owner = owner; - } - - public IEnumerable EnumerateReachableNavVerts(float t, NavAgent agent, IList goals, int pathValueId) - { - for (int iNode = 0; iNode < nodes.Count; iNode++) - { - var node = nodes[iNode]; - if (!IsAgentAbleToTraverse(agent, t, node)) - continue; - - yield return new NavConnection(node, node.link.TravelCosts(node.WPosition(), node.WGoalPosition()) * agent.GetLinkTraversalMultiplier(node.link.LinkType) * agent.GetNavTagTraversalMultiplier(node.link.NavTag) + TraversalCosts(t, node.t, agent)); - } - if (containsGoal[pathValueId]) - { - for (int iGoal = 0; iGoal < goals.Count; iGoal++) - { - if (goals[iGoal].cluster == this && IsAgentAbleToTraverse(agent, t, goals[iGoal])) - yield return new NavConnection(goals[iGoal], TraversalCosts(t, goals[iGoal].t, agent)); - } - } - } - - public void AddNode(int pathValueCount, float t, NavGraphNodeCluster linkTarget, float linkTargetT, - INavLinkInstance link) - { - nodes.Add( - new NavGraphNode( - pathValueCount, - this, - t, - linkTarget, linkTargetT, - link - )); - } - - public void RemoveNode(INavLinkInstance link) - { - int index = nodes.FindIndex(node => node.link == link); - if (index != -1) - nodes.RemoveAt(index); - } - - public void MoveNode(INavLinkInstance link, float newT) - { - int index = nodes.FindIndex(node => node.link == link); - nodes[index].t = newT; - } - - public NavGraphNode GetNode(INavLinkInstance link) - { - return nodes.Find(node => node.link == link); - } - - public bool DoesNodeExist(INavLinkInstance link) - { - return nodes.Exists(node => node.link == link); - } - - public void ApplyCellClearances(float[] differentClearances) - { - for (int i = 0; i < cellClearances.Length; i++) - { - cellClearances[i] = Mathf.Min(cellClearances[i], differentClearances[i]); - } - } - - public void AddNodeClusterModifier(NavAreaMarkerInstance mod) - { - modifiers.Add(mod); - } - - public void RemoveNodeClusterModifier(NavAreaMarkerInstance mod) - { - modifiers.Remove(mod); - } - - public int GetNavTagVector(float pos) - { - int vector = 0; - foreach (var mod in modifiers) - { - if (mod.T <= pos && mod.T + mod.Length >= pos) - vector |= (1 << mod.NavTag); - } - return vector; - } - - public int GetNavTagVector(Vector2 pos) - { - return GetNavTagVector(DistanceOfPointAlongSegment(pos)); - } - - public bool CanAgentReachPoint(NavAgent agent, float startT, float goalT) - { - return agent.CanTraverseSegment(owner.LocalToWorld.MultiplyVector(Normal), GetMinClearanceTo(startT, goalT)); - } - - public bool CanAgentBeAtPoint(NavAgent agent, float t) - { - return Vector2.Angle(Vector2.up, owner.LocalToWorld.MultiplyVector(Normal)) <= agent.MaxSlopeAngle && GetClearanceAlongSegment(t) >= agent.Height && (GetNavTagVector(t) & ~agent.NavTagMask) == 0; - } - - private bool IsAgentAbleToTraverse(NavAgent agent, float startT, NavGraphNode node) - { - return agent.CanTraverseLink(node.link) && CanAgentReachPoint(agent, startT, node.t); - } - - private float TraversalCosts(float t, float goal, NavAgent agent) - { - float a, b; - if (t < goal) - { - a = t; - b = goal; - } - else - { - a = goal; - b = t; - } - if (modifiers.Count == 0) - { - return b - a; - } - - float costs = b - a; - foreach (var mod in modifiers) - { - if (mod.T + mod.Length <= a || mod.T >= b) - continue; - - // some overlap exists - costs += (Mathf.Min(mod.T + mod.Length, b) - Mathf.Max(mod.T, a)) * agent.GetNavTagTraversalMultiplier(mod.NavTag); - } - return costs; - } - } -} diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavGraph/NavGraphNodeCluster.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavGraph/NavGraphNodeCluster.cs.meta deleted file mode 100644 index 824017ea..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavGraph/NavGraphNodeCluster.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 09696d0a858d6a249aac9a2ffc71fd9f -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavGraph/NavSurfaceRecord.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavGraph/NavSurfaceRecord.cs deleted file mode 100644 index 35a73cc5..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavGraph/NavSurfaceRecord.cs +++ /dev/null @@ -1,49 +0,0 @@ -using System.Collections.Generic; -using UnityEngine; - -namespace PathBerserker2d -{ - internal class NavSurfaceRecord - { - public B2DynamicTree Clusters { get; private set; } - public List SoftRefLinks { get; private set; } - - public Matrix4x4 LocalToWorld { get => localToWorld; set { - localToWorld = value; - worldToLocal = localToWorld.inverse; - } } - public Matrix4x4 WorldToLocal => worldToLocal; - public readonly NavSurface navSurface; - public readonly int bakeIteration; - - private Matrix4x4 localToWorld; - private Matrix4x4 worldToLocal; - - public NavSurfaceRecord(B2DynamicTree tree, Matrix4x4 localToWorld, NavSurface navSurface) - { - this.Clusters = tree; - SoftRefLinks = new List(); - this.localToWorld = localToWorld; - this.navSurface = navSurface; - this.bakeIteration = navSurface.BakeIteration; - } - - public void AddSoftRefLink(INavLinkInstance instance) - { - SoftRefLinks.Add(instance); - } - - public void RemoveSoftRefLink(INavLinkInstance instance) - { - SoftRefLinks.Remove(instance); - } - - public void Destroy(NavGraph graph) - { - foreach (var ls in SoftRefLinks) - { - ls.OnRemove(); - } - } - } -} diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavGraph/NavSurfaceRecord.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavGraph/NavSurfaceRecord.cs.meta deleted file mode 100644 index 1d27181d..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavGraph/NavSurfaceRecord.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 6641bbd92fce18c489cab9aaaee6d4f4 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavObjects.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavObjects.meta deleted file mode 100644 index 909fe0a5..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavObjects.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 9c37197ee5c1fb446ac98c67d0aa09bd -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavObjects/ArtificialLink.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavObjects/ArtificialLink.cs deleted file mode 100644 index 07300921..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavObjects/ArtificialLink.cs +++ /dev/null @@ -1,41 +0,0 @@ -using System; -using UnityEngine; - -namespace PathBerserker2d -{ - internal class ArtificialLink : INavLinkInstance - { - public NavSegmentPositionPointer Start => throw new NotImplementedException(); - - public NavSegmentPositionPointer Goal => throw new NotImplementedException(); - - public int LinkType => linkType; - - public string LinkTypeName => throw new NotImplementedException(); - - public GameObject GameObject => throw new NotImplementedException(); - - public float Clearance => float.MaxValue; - - public int NavTag => 0; - - public bool IsTraversable => true; - public int PBComponentId => 0; - - private int linkType; - - public ArtificialLink(int linkType) - { - this.linkType = linkType; - } - - public float TravelCosts(Vector2 start, Vector2 goal) - { - return 0; - } - - public void OnRemove() - { - } - } -} diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavObjects/ArtificialLink.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavObjects/ArtificialLink.cs.meta deleted file mode 100644 index e358b997..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavObjects/ArtificialLink.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 37b5756b029e50e409aec9ab1f691b6b -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavObjects/BaseNavLink.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavObjects/BaseNavLink.cs deleted file mode 100644 index f95b720c..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavObjects/BaseNavLink.cs +++ /dev/null @@ -1,109 +0,0 @@ -using System; -using UnityEngine; - -namespace PathBerserker2d -{ - /// - /// Common basis for NavLink and NavLinkCluster. - /// - public abstract class BaseNavLink : MonoBehaviour, INavLinkInstanceCreator - { - public int LinkType - { - get { return linkType; } - set { - if (value < 0 || value >= PathBerserker2dSettings.NavLinkTypeNames.Length) - throw new ArgumentOutOfRangeException($"{value} is not a valid link type."); - linkType = value; - } - } - public string LinkTypeName - { - get { return PathBerserker2dSettings.NavLinkTypeNames[linkType]; } - set { linkType = PathBerserker2dSettings.GetLinkTypeFromName(value); } - } - public float Clearance - { - get { return clearance; } - set { clearance = value; } - } - public float AvgWaitTime - { - get { return avgWaitTime; } - set { avgWaitTime = value; } - } - public float CostOverride - { - get { return costOverride; } - set { costOverride = value; } - } - public GameObject GameObject => gameObject; - public int NavTag - { - get { return navTag; } - set { navTag = PathBerserker2dSettings.EnsureNavTagExists(value); } - } - public float MaxTraversableDistance - { - get { return maxTraversableDistance; } - set { maxTraversableDistance = value; } - } - - public int PBComponentId { get; protected set; } - - [Tooltip("Cost of traversing this link. If this is <= 0 the distance between start and goal is used instead.")] - [SerializeField] - protected float costOverride = -1; - - [SerializeField] - protected int linkType = 1; - - [Tooltip("Maximum height an agent can be to traverse this link.")] - [SerializeField] - protected float clearance = 2; - - [SerializeField] - protected int navTag = 0; - - [Tooltip("Average time an agent has to wait before starting to traverse this link. This is purely to tune the pathfinding algorithm.")] - [SerializeField] - protected float avgWaitTime = 0; - - [Tooltip("Maximum distances between start and goal, that is considered traversable. If this distance is exceeded (e.g. on a moving platform) an agent will wait to traverse this link.")] - [SerializeField] - protected float maxTraversableDistance = 0; - - /// - /// Should this link be automatically mapped. If not, you have to call UpdateMapping() yourself. - /// - [SerializeField, Tooltip("Should this link be automatically mapped. If not, you have to call UpdateMapping() yourself.")] - public bool autoMap = true; - - protected virtual void Awake() - { - PBComponentId = PBWorld.GeneratePBComponentId(); - } - - protected virtual void OnValidate() - { - linkType = PathBerserker2dSettings.EnsureNavLinkTypeExists(linkType); - navTag = PathBerserker2dSettings.EnsureNavTagExists(navTag); - } - - /// - /// MUST BE THREAD SAFE! - /// Calculates the cost of traversing from start to goal. - /// - /// - /// - /// - public float TravelCosts(Vector2 start, Vector2 goal) - { - float costOverride = this.costOverride; - if (costOverride >= 0) - return costOverride + avgWaitTime; - else - return Mathf.Max(maxTraversableDistance, Vector2.Distance(start, goal)) + avgWaitTime; - } - } -} diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavObjects/BaseNavLink.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavObjects/BaseNavLink.cs.meta deleted file mode 100644 index dccc86df..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavObjects/BaseNavLink.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: ec2706faa1499754ab7972b2ce01acf5 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavObjects/DynamicObstacle.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavObjects/DynamicObstacle.cs deleted file mode 100644 index 99ad02ce..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavObjects/DynamicObstacle.cs +++ /dev/null @@ -1,13 +0,0 @@ -using UnityEngine; - -namespace PathBerserker2d -{ - /// - /// Attach to GameObject to mark it as dynamic. - /// Dynamic objects are ignored while baking a NavSurface. - /// - public class DynamicObstacle : MonoBehaviour - { - // ignored for baking - } -} diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavObjects/DynamicObstacle.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavObjects/DynamicObstacle.cs.meta deleted file mode 100644 index ba161cff..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavObjects/DynamicObstacle.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 098039b2e353c6242b6b156886f24db4 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavObjects/INavLink.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavObjects/INavLink.cs deleted file mode 100644 index 8e1311ab..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavObjects/INavLink.cs +++ /dev/null @@ -1,31 +0,0 @@ -using UnityEngine; - -namespace PathBerserker2d -{ - /// - /// Internal instance of a NavLink. - /// - /// - /// An instance is deliberately kept very basic. It links from a given start to a given goal. - /// - public interface INavLinkInstance - { - //NavSegmentPositionPointer Start { get; } - //NavSegmentPositionPointer Goal { get; } - int LinkType { get; } - int NavTag { get; } - - bool IsTraversable { get; } - - string LinkTypeName { get; } - - GameObject GameObject { get; } - - float Clearance { get; } - int PBComponentId { get; } - - float TravelCosts(Vector2 start, Vector2 goal); - - void OnRemove(); - } -} diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavObjects/INavLink.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavObjects/INavLink.cs.meta deleted file mode 100644 index a9e17fcd..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavObjects/INavLink.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: cb4c816f3b23aac42a66b17253265a5a -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavObjects/INavLinkInstanceCreator.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavObjects/INavLinkInstanceCreator.cs deleted file mode 100644 index f77dc2a9..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavObjects/INavLinkInstanceCreator.cs +++ /dev/null @@ -1,19 +0,0 @@ -using UnityEngine; - -namespace PathBerserker2d -{ - internal interface INavLinkInstanceCreator - { - int LinkType { get; } - int NavTag { get; } - int PBComponentId { get; } - - GameObject GameObject { get; } - float Clearance { get; } - float TravelCosts(Vector2 start, Vector2 goal); - float CostOverride { get; } - - float AvgWaitTime { get; } - float MaxTraversableDistance { get; } - } -} diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavObjects/INavLinkInstanceCreator.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavObjects/INavLinkInstanceCreator.cs.meta deleted file mode 100644 index f061bcfa..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavObjects/INavLinkInstanceCreator.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: c7dfb46afa8de8f4fb172b5323f315e9 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavObjects/NavAreaMarker.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavObjects/NavAreaMarker.cs deleted file mode 100644 index 7d565e24..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavObjects/NavAreaMarker.cs +++ /dev/null @@ -1,173 +0,0 @@ -using UnityEngine; -using System.Collections.Generic; - -namespace PathBerserker2d -{ - /// - /// Marks all segments within an area with a specific NavTag. - /// - [RequireComponent(typeof(RectTransform))] - [AddComponentMenu("PathBerserker2d/Nav Area Marker")] - [HelpURL("https://oribow.github.io/PathBerserker2dDemo/Documentation/classPathBerserker2d_1_1NavAreaMarker.html")] - public class NavAreaMarker : MonoBehaviour - { - public int NavTag - { - get => navTag; - set - { - navTag = PathBerserker2dSettings.EnsureNavTagExists(value); - } - } - public Color MarkerColor => PathBerserker2dSettings.GetNavTagColor(navTag); - - [SerializeField] - int navTag = 0; - - [Tooltip("Minimum angle between the segment tangent and up. Use this to only mark segments with certain angles.")] - [SerializeField, Range(0, 360)] - float minAngle = 0; - - [Tooltip("Maximum angle between the segment tangent and up. Use this to only mark segments with certain angles.")] - [SerializeField, Range(0, 360)] - float maxAngle = 360; - - /// - /// Updates the modified marked area after a continuous time period of no movement. - /// - [Tooltip("Updates the modified marked area after a continuous time period of no movement.")] - [SerializeField] - public float updateAfterTimeOfNoMovement = 0.2f; - - /// - /// Updates the modified marked area after this amount of time passed. - /// - [Tooltip("Updates the modified marked area after this amount of time passed.")] - [SerializeField] - public float updateAfterTime = 1; - - public int PBComponentId { get; } - - private RectTransform rectTransform; - private List instances; - private float lastMovementTime; - private float isDirtySince; - private bool isDirty = false; - - #region UNITY - private void OnEnable() - { - rectTransform = GetComponent(); - instances = new List(); - transform.hasChanged = false; - AddToGraph(); - } - - private void OnDisable() - { - RemoveFromGraph(); - } - - private void Update() - { - if (transform.hasChanged) - { - if (!isDirty) - isDirtySince = Time.time; - - isDirty = true; - transform.hasChanged = false; - lastMovementTime = Time.time; - } - - if (isDirty && - (Time.time - lastMovementTime > updateAfterTimeOfNoMovement - || Time.time - isDirtySince > updateAfterTime)) - { - AddToGraph(); - lastMovementTime = float.MaxValue; - } - } - - private void OnValidate() - { - navTag = PathBerserker2dSettings.EnsureNavTagExists(navTag); - updateAfterTimeOfNoMovement = Mathf.Max(0, updateAfterTimeOfNoMovement); - updateAfterTime = Mathf.Max(0, updateAfterTime); - } - - private void Reset() - { - // only modify sizeDelta, if its at default value - var rt = GetComponent(); - if (rt.sizeDelta == new Vector2(100, 100)) - rt.sizeDelta = Vector2.one; - } - #endregion - - /// - /// Updates area of effect mapping. Call after modifying NavAreaMarker transform. - /// Alternatively, instead of calling this function, set transform.hasChanged to true. - /// - public void UpdateMappings() - { - AddToGraph(); - lastMovementTime = float.MaxValue; - } - - private void AddToGraph() - { - isDirty = false; - if (instances.Count > 0) - RemoveFromGraph(); - - var r = rectTransform.rect; - Vector2 scaleFactor = rectTransform.lossyScale * r.size * 0.5f; - Vector2 center = r.center; - - r.min = center - scaleFactor + (Vector2)rectTransform.position; - r.max = center + scaleFactor + (Vector2)rectTransform.position; - - var results = PBWorld.BoxCastWithStaged(r, rectTransform.rotation.eulerAngles.z, minAngle, maxAngle); - - foreach (var pointer in results) - { - var instance = new NavAreaMarkerInstance(this, pointer); - PBWorld.NavGraph.AddSegmentModifier(instance); - instances.Add(instance); - } - } - - private void RemoveFromGraph() - { - foreach (var instance in instances) - { - PBWorld.NavGraph.RemoveSegmentModifier(instance); - } - instances.Clear(); - } - } - - internal class NavAreaMarkerInstance - { - public int NavTag => original.NavTag; - public float T => position.t; - public float Length => position.length; - - public NavSubsegmentPointer position; - public int PBComponentId => original.PBComponentId; - - NavAreaMarker original; - - public NavAreaMarkerInstance(NavAreaMarker original) - { - this.original = original; - } - - public NavAreaMarkerInstance(NavAreaMarker original, NavSubsegmentPointer position) - { - this.original = original; - this.position = position; - } - } -} diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavObjects/NavAreaMarker.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavObjects/NavAreaMarker.cs.meta deleted file mode 100644 index de129722..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavObjects/NavAreaMarker.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: cd188745fa9d851459105e6651b2b80a -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavObjects/NavLink.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavObjects/NavLink.cs deleted file mode 100644 index ae1163cd..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavObjects/NavLink.cs +++ /dev/null @@ -1,207 +0,0 @@ -using UnityEngine; - -namespace PathBerserker2d -{ - /// - /// A link from one segment to another. - /// - /// - /// NavLink gets added to the pathfinder at runtime. - /// It can be loaded and unloaded by enabling / disabling the component - /// After being loaded and added to the pathfinder, the position of the link will not be updated. - /// For example that means, if your link start position gets mapped to a position on a moving platform, the initial mapping of the link start to the segment won't change. - /// The mapped position is relative to the NavSurface containing the moving platform. - /// It will follow the movements of the platform, even though the start marker of the link will not. - /// ## Mapping - /// You can update the links mapping by calling - /// - /// Internally, when moving the start and end marker around in scene view while the game is playing, is called. - /// That means you can move the markers around and the link will update its mapping. - /// If you move them around by any other means however, you have to call afterwards. - /// ## Visualization - /// Everything visualization related is purely for you and is not meant to accessed at runtime. - /// Visualizations like bezier or projectile are meant to allow you to figure out a good clearance value. - /// ## Traversable - /// When a link is marked bidirectional, internally two links get added to the pathfinder. One for each direction. - /// Both links traversable can be set separately with and . - /// - /// **Not being traversable should always be temporary.** In the sense of, **"this link is not traversable right now, but will be in the future"**. - /// NavAgents will wait indefinitely for the link to become traversable again. - /// You can adjust AvgWaitTime to increase the cost of such not alway traversable links. - /// The pathfinder will add it to the cost of traversal. - /// The pathfinder does not care if a link is marked as traversable or not. It only cares about the cost of traversal. - /// If you want to disable a link for a longer time, consider disabling the link component. Then it will be unloaded and not considered for any pathfinding. - /// - [AddComponentMenu("PathBerserker2d/Nav Link")] - public sealed class NavLink : BaseNavLink - { - public enum VisualizationType - { - Linear = 0, - QuadradticBezier = 1, - Projectile = 2, - Teleport = 3, - None = 4, - TransformBasedMovement = 5 - } - - public Vector2 GoalWorldPosition - { - get - { - return transform.TransformPoint(goal); - } - set - { - goal = transform.InverseTransformPoint(value); - } - } - public Vector2 StartWorldPosition - { - get - { - return transform.TransformPoint(start); - } - set - { - start = transform.InverseTransformPoint(value); - } - } - public Vector2 StartLocalPosition - { - get - { - return start; - } - set - { - start = value; - } - } - public Vector2 GoalLocalPosition - { - get - { - return goal; - } - set - { - goal = value; - } - } - - public VisualizationType CurrentVisualizationType { get { return visualizationType; } } - - public bool IsBidirectional - { - get { return isBidirectional; } - set - { - if (isBidirectional != value && !value) - { - linkGoalToStart.RemoveFromWorld(); - } - isBidirectional = value; - } - } - - public bool IsAddedToWorld => linkStartToGoal?.IsAdded ?? false; - - internal float HorizontalSpeed => horizontalSpeed; - internal float TraversalAngle => traversalAngle; - internal Vector2 BezierControlPoint { get => bezierControlPoint; set => bezierControlPoint = value; } - - [Header("Location")] - [SerializeField] - Vector2 start = Vector2.left * 2; - [SerializeField] - Vector2 goal = Vector2.right * 2; - [SerializeField] - bool isBidirectional = true; - [SerializeField] - VisualizationType visualizationType = VisualizationType.TransformBasedMovement; - [SerializeField] - float traversalAngle = 0; - [SerializeField] - float horizontalSpeed = 1; - [SerializeField, HideInInspector] - Vector2 bezierControlPoint = Vector2.up * 3; - - private NavLinkInstance linkStartToGoal; - private NavLinkInstance linkGoalToStart; - - #region UNITY - private void OnEnable() - { - if (linkStartToGoal == null) - linkStartToGoal = new NavLinkInstance(this); - if (linkGoalToStart == null) - linkGoalToStart = new NavLinkInstance(this); - - AutoUpdateMapping(); - } - - private void OnDisable() - { - linkStartToGoal.RemoveFromWorld(); - linkGoalToStart.RemoveFromWorld(); - } - - protected override void OnValidate() - { - base.OnValidate(); - if (linkGoalToStart != null && (!linkGoalToStart.IsAdded || linkStartToGoal != null)) - { - AutoUpdateMapping(); - - if (!isBidirectional) - linkGoalToStart.RemoveFromWorld(); - } - } - #endregion - - /// - /// Update the mapping for both link instances. Call after link positions have been changed. - /// - public void UpdateMapping() - { - NavSegmentPositionPointer navStart, navGoal; - if (PBWorld.TryMapPointWithStaged(StartWorldPosition, out navStart) - && PBWorld.TryMapPointWithStaged(GoalWorldPosition, out navGoal)) - { - linkStartToGoal.UpdateMapping(navStart, navGoal, StartWorldPosition, GoalWorldPosition); - linkGoalToStart.UpdateMapping(navGoal, navStart, GoalWorldPosition, StartWorldPosition); - - linkStartToGoal.AddToWorld(); - if (isBidirectional) linkGoalToStart.AddToWorld(); - } - else - { - linkStartToGoal.RemoveFromWorld(); - linkGoalToStart.RemoveFromWorld(); - } - } - - /// - /// Set the link instance from start point to goal traversable. - /// - public void SetStartToGoalLinkTraversable(bool traversable) - { - this.linkStartToGoal.IsTraversable = traversable; - } - - /// - /// Set the link instance from goal point to start traversable. This link only exist, if the link is bidirectional. - /// - public void SetGoalToStartLinkTraversable(bool traversable) - { - this.linkGoalToStart.IsTraversable = traversable; - } - - private void AutoUpdateMapping() - { - if (autoMap) - UpdateMapping(); - } - } -} \ No newline at end of file diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavObjects/NavLink.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavObjects/NavLink.cs.meta deleted file mode 100644 index 1e63c149..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavObjects/NavLink.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 87d47b3e0cb42914b8b2ae885bebf30b -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {fileID: 2800000, guid: 579b19e3fcbb57e43adcf1e3f754f5ef, type: 3} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavObjects/NavLinkCluster.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavObjects/NavLinkCluster.cs deleted file mode 100644 index a6a110eb..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavObjects/NavLinkCluster.cs +++ /dev/null @@ -1,118 +0,0 @@ -using UnityEngine; -using System.Collections.Generic; - -namespace PathBerserker2d -{ - /// - /// Creates links to interconnect a collection. - /// - /// - /// Consists of a list of points. - /// At runtime a link is generated for each point to connect it with each other point. - /// This is a convenience component. It drastically reduces the amount of work required to setup an elevator or ladder for example. - /// - /// Otherwise it functions and behaves the same as a NavLink. - /// Reference the documentation for NavLink for further details. - /// - [AddComponentMenu("PathBerserker2d/Nav Link Cluster")] - public sealed class NavLinkCluster : BaseNavLink - { - internal enum PointTraversalType - { - Exit, - Entry, - Both - } - - internal LinkPoint[] LinkPoints => linkPoints; - - [SerializeField] - internal LinkPoint[] linkPoints = new LinkPoint[] { new LinkPoint(Vector2.left * 2), new LinkPoint(Vector2.right * 2) }; - - private List linkInstances; - - #region UNITY - private void OnEnable() - { - if (linkInstances == null) - linkInstances = new List(); - - if (autoMap) - UpdateMapping(); - } - - private void OnDisable() - { - foreach (var li in linkInstances) - li.RemoveFromWorld(); - } - #endregion - - /// - /// Update the mapping for all link instances. Call after link positions have been changed. - /// - public void UpdateMapping() - { - NavSegmentPositionPointer navStart, navGoal; - int instanceCounter = 0; - foreach (var startPoint in linkPoints) - { - if (startPoint.traversalType == PointTraversalType.Exit) - continue; - - Vector2 worldStart = transform.TransformPoint(startPoint.point); - foreach (var goalPoint in linkPoints) - { - if (goalPoint.traversalType == PointTraversalType.Entry || goalPoint.point == startPoint.point) - continue; - - Vector2 worldGoal = transform.TransformPoint(goalPoint.point); - if (instanceCounter >= linkInstances.Count) - { - linkInstances.Add(new NavLinkInstance(this)); - } - var linkInstance = linkInstances[instanceCounter++]; - - if (PBWorld.TryMapPointWithStaged(worldStart, out navStart) - && PBWorld.TryMapPointWithStaged(worldGoal, out navGoal)) - { - linkInstance.UpdateMapping(navStart, navGoal, worldStart, worldGoal); - linkInstance.AddToWorld(); - } - else - { - linkInstance.RemoveFromWorld(); - } - } - } - } - - /// - /// Set link instances to be traversable based on their start and end points. - /// - /// Determines whether to enable or disable the given link instance. Link instance is given as its start and goal position. - public void SetLinksTraversable(System.Func traversableFunc) - { - foreach (var link in linkInstances) - { - if (link.IsAdded) - link.IsTraversable = traversableFunc(link.Start.Position, link.Goal.Position); - } - } - - [System.Serializable] - internal struct LinkPoint - { - [SerializeField] - public Vector2 point; - [SerializeField] - public PointTraversalType traversalType; - - public LinkPoint(Vector2 point) - { - this.point = point; - this.traversalType = PointTraversalType.Both; - } - } - } -} \ No newline at end of file diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavObjects/NavLinkCluster.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavObjects/NavLinkCluster.cs.meta deleted file mode 100644 index ac275dd5..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavObjects/NavLinkCluster.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: be2a77a7bf2e29d438041e3d46dd5667 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavObjects/NavLinkInstance.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavObjects/NavLinkInstance.cs deleted file mode 100644 index 85e123e0..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavObjects/NavLinkInstance.cs +++ /dev/null @@ -1,106 +0,0 @@ -using UnityEngine; - -namespace PathBerserker2d -{ - internal sealed class NavLinkInstance : INavLinkInstance - { - public NavSegmentPositionPointer Start => start; - public NavSegmentPositionPointer Goal => goal; - public int LinkType => creator.LinkType; - public string LinkTypeName => PathBerserker2dSettings.GetLinkTypeName(creator.LinkType); - public GameObject GameObject => creator.GameObject; - public bool IsAdded => isAdded; - public float Clearance => creator.Clearance; - public float CostOverride => creator.CostOverride; - public int NavTag => creator.NavTag; - public bool IsTraversable - { - get - { - return isTraversable && (creator.MaxTraversableDistance <= 0 || Vector2.Distance(Start.Position, Goal.Position) <= creator.MaxTraversableDistance); - } - set - { - isTraversable = value; - } - } - public int PBComponentId => creator.PBComponentId; - internal INavLinkInstanceCreator Creator => creator; - - - private INavLinkInstanceCreator creator; - private NavSegmentPositionPointer start; - private Vector2 startPos; - private NavSegmentPositionPointer goal; - private Vector2 goalPos; - private bool isAdded = false; - private bool isTraversable = true; - - public NavLinkInstance(INavLinkInstanceCreator creator) - { - this.creator = creator; - } - - public float TravelCosts(Vector2 start, Vector2 goal) - { - return creator.TravelCosts(start, goal); - } - - - - public void AddToWorld() - { - if (!isAdded) - { - PBWorld.NavGraph.AddNavLink(this, start, goal); - isAdded = true; - } - } - - public void RemoveFromWorld() - { - if (isAdded) - { - PBWorld.NavGraph.RemoveNavLink(this, start, goal); - isAdded = false; - } - } - - public void UpdateMapping(NavSegmentPositionPointer start, NavSegmentPositionPointer goal, Vector2 startPos, Vector2 goalPos) - { - this.startPos = startPos; - this.goalPos = goalPos; - - if (isAdded) - { - if (start != this.start) - { - var oldPos = this.start; - this.start = start; - - PBWorld.NavGraph.MoveNavLinkStart(this, start, goal, oldPos); - } - if (goal != this.goal) - { - var oldPos = this.goal; - this.goal = goal; - - PBWorld.NavGraph.MoveNavLinkGoal(this, start, goal, oldPos); - } - } - else - { - this.start = start; - this.goal = goal; - } - } - - public void OnRemove() - { - if (start.surface != null) - RemoveFromWorld(); - else - isAdded = false; - } - } -} \ No newline at end of file diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavObjects/NavLinkInstance.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavObjects/NavLinkInstance.cs.meta deleted file mode 100644 index 7e3c51f8..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavObjects/NavLinkInstance.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: b8d40862c6107ef4a856664b359e51b9 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavObjects/NavSegmentSubstractor.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavObjects/NavSegmentSubstractor.cs deleted file mode 100644 index f87bca27..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavObjects/NavSegmentSubstractor.cs +++ /dev/null @@ -1,25 +0,0 @@ -using UnityEngine; - -namespace PathBerserker2d -{ - /// - /// Marks with its RectTransform an area to remove segments from. - /// - [RequireComponent(typeof(RectTransform))] - public class NavSegmentSubstractor : MonoBehaviour - { - /// - /// Minimum angle between the segment tangent and up. Use this to only remove segments with certain angles. - /// - [Tooltip("Minimum angle between the segment tangent and up. Use this to only remove segments with certain angles.")] - [SerializeField, Range(0, 360)] - public float fromAngle = 0; - - /// - /// Maximum angle between the segment tangent and up. Use this to only remove segments with certain angles. - /// - [Tooltip("Maximum angle between the segment tangent and up. Use this to only remove segments with certain angles.")] - [SerializeField, Range(0, 360)] - public float toAngle = 360; - } -} diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavObjects/NavSegmentSubstractor.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavObjects/NavSegmentSubstractor.cs.meta deleted file mode 100644 index 7d8df844..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavObjects/NavSegmentSubstractor.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: a276efee5bef16c408d4567ee5ed9369 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavObjects/SegmentConnectionLink.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavObjects/SegmentConnectionLink.cs deleted file mode 100644 index 4c59d413..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavObjects/SegmentConnectionLink.cs +++ /dev/null @@ -1,45 +0,0 @@ -using UnityEngine; - -namespace PathBerserker2d -{ - internal class CornerLink : INavLinkInstance - { - public NavSegmentPositionPointer Start => start; - - public NavSegmentPositionPointer Goal => goal; - - public int LinkType => 0; - - public string LinkTypeName => PathBerserker2dSettings.GetLinkTypeName(0); - - public GameObject GameObject => null; - - public float Clearance => float.MaxValue; - - public int NavTag => 0; - - public bool IsTraversable => true; - public int PBComponentId => 0; - - private NavSegmentPositionPointer start; - private NavSegmentPositionPointer goal; - private float angle; - - public CornerLink(NavSegmentPositionPointer start, NavSegmentPositionPointer goal, float angle) - { - this.start = start; - this.goal = goal; - this.angle = angle; - } - - public float TravelCosts(Vector2 start, Vector2 goal) - { - return angle; - } - - public void OnRemove() - { - - } - } -} diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavObjects/SegmentConnectionLink.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavObjects/SegmentConnectionLink.cs.meta deleted file mode 100644 index 15005903..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavObjects/SegmentConnectionLink.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: e3c7717cb27cab34d9ec825e3cbc10ea -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface.meta deleted file mode 100644 index 6058cfcd..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 874b67fb230896a43a6d44a87da38828 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/ColliderLayerFilter.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/ColliderLayerFilter.cs deleted file mode 100644 index 23570777..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/ColliderLayerFilter.cs +++ /dev/null @@ -1,26 +0,0 @@ -using UnityEngine; -using System.Collections.Generic; -using System.Linq; - -namespace PathBerserker2d -{ - internal class ColliderLayerFilter : IColliderFilter - { - private LayerMask layerMask; - private bool onlyStatic; - - public ColliderLayerFilter(LayerMask layerMask, bool onlyStatic) - { - this.layerMask = layerMask; - this.onlyStatic = onlyStatic; - } - - public IEnumerable Filter(IEnumerable colliders) - { - return colliders.Where( - (col) => layerMask.IsLayerWithinMask(col.gameObject.layer) && - !col.GetComponent() && - (!onlyStatic || col.gameObject.isStatic)); - } - } -} diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/ColliderLayerFilter.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/ColliderLayerFilter.cs.meta deleted file mode 100644 index 658ad22c..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/ColliderLayerFilter.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 548bcd56f78f38e418eb0a3ec41825a8 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/Creation.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/Creation.meta deleted file mode 100644 index 951c7470..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/Creation.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 8083133de4af48e48b87fdb05b356ca2 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/Creation/ColliderConverter.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/Creation/ColliderConverter.cs deleted file mode 100644 index 42f47a6b..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/Creation/ColliderConverter.cs +++ /dev/null @@ -1,236 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using UnityEngine; - -namespace PathBerserker2d -{ - internal class ColliderConverter - { - public Polygon[] Convert(Collider2D collider) - { - Polygon[] cachedPolys; - bool hasRigidbody = collider.GetComponentInParent(); - - if (collider is PolygonCollider2D && PathBerserker2dSettings.UsePolygonCollider2dPathsForBaking) - { - cachedPolys = PolygonColliderToPolygon((PolygonCollider2D)collider); - } - else - { - var mesh = collider.CreateMesh(hasRigidbody, hasRigidbody); - if (mesh == null) - { - if (collider.GetType() == typeof(EdgeCollider2D)) - { - //special handling for an open edge collider - cachedPolys = EdgeColliderToPolygon(collider as EdgeCollider2D); - } - else - { - Debug.LogWarning(string.Format("Unity's 'CreateMesh' returned null for Collider {0}({1}). Will ignore this collider.", collider.name, collider.GetType())); - - cachedPolys = new Polygon[0]; - } - } - else - { - cachedPolys = MeshToPolygons(mesh); - } - } - return cachedPolys; - } - - private static Polygon[] EdgeColliderToPolygon(EdgeCollider2D edgeCollider2D) - { - Matrix4x4 localToWorld = edgeCollider2D.transform.localToWorldMatrix * Matrix4x4.Translate(edgeCollider2D.offset); - return new Polygon[1] { - new Polygon( - new Contour( - Array.ConvertAll(edgeCollider2D.points, (v) => (Vector2)localToWorld.MultiplyPoint3x4(v)), - false)) - }; - } - - private static Polygon[] MeshToPolygons(Mesh mesh) - { - // 1. find connected regions of mesh - var verts = mesh.vertices; - var triangles = mesh.triangles; - - MonoBehaviour.DestroyImmediate(mesh); - - List[] graph = new List[verts.Length]; - for (int i = 0; i < graph.Length; i++) - graph[i] = new List(3); - - for (int iTris = 0; iTris < triangles.Length; iTris += 3) - { - int a = triangles[iTris]; - int b = triangles[iTris + 1]; - int c = triangles[iTris + 2]; - - AddEdgeToGraph(graph, a, b); - AddEdgeToGraph(graph, b, c); - AddEdgeToGraph(graph, c, a); - } - - int nextRegion = 1; - int[] regionMap = new int[verts.Length]; - for (int iVert = 0; iVert < verts.Length; iVert++) - { - if (regionMap[iVert] == 0) - { - Flood(nextRegion++, regionMap, graph, iVert); - } - } - - StableConnector[] connectors = new StableConnector[nextRegion - 1]; - for (int i = 0; i < connectors.Length; i++) - connectors[i] = new StableConnector(); - - for (int iVert = 0; iVert < verts.Length; iVert++) - { - var connections = graph[iVert]; - foreach (var conn in connections) - { - var other = graph[conn]; - if (!other.Contains(iVert)) - { - connectors[regionMap[iVert] - 1].Add(iVert, conn); - } - } - } - - List polygons = new List(connectors.Length); - for (int i = 0; i < connectors.Length; i++) - { - ConnectorToContours(connectors[i], verts, ref polygons); - } - // some polygons are contained by other polygons, make a check - for (int iPoly = 0; iPoly < polygons.Count; iPoly++) - { - var poly = polygons[iPoly]; - for (int iOtherPoly = iPoly + 1; iOtherPoly < polygons.Count; iOtherPoly++) - { - if (poly.Contains(polygons[iOtherPoly])) - { - poly.AddAsChild(polygons[iOtherPoly]); - polygons.RemoveAt(iOtherPoly); - iOtherPoly--; - } - } - } - return polygons.ToArray(); - } - - private static Polygon[] PolygonColliderToPolygon(PolygonCollider2D collider) - { - if (collider.pathCount == 0) - return new Polygon[0]; - - var path = collider.GetPath(0); - if (path.Length < 3) - return new Polygon[0]; - - var worldPath = path.Select(vert => (Vector2)collider.transform.TransformPoint(vert)).Reverse(); - return new Polygon[] { - new Polygon(new Contour(worldPath)) - }; - } - - private static void AddEdgeToGraph(List[] graph, int a, int b) - { - graph[a].Add(b); - } - - private static void Flood(int id, int[] regionMap, List[] graph, int start) - { - regionMap[start] = id; - - Stack indiciesToProcess = new Stack(10); - - indiciesToProcess.Push(start); - - while (indiciesToProcess.Count > 0) - { - int i = indiciesToProcess.Pop(); - - var connections = graph[i]; - foreach (var conn in connections) - { - if (regionMap[conn] != id) - { - regionMap[conn] = id; - indiciesToProcess.Push(conn); - } - } - } - } - - private static void ConnectorToContours(StableConnector connector, Vector3[] verts, ref List polygons) - { - List holes = new List(1); - List> hulls = new List>(1); - foreach (var chain in connector.closedPolygons) - { - List points = new List(chain.points.Count); - foreach (var p in chain.points) - { - points.Add(verts[p]); - } - - // simplification moved to later step in pipeline - //points = ExtendedGeometry.SimplifyContour(points, 0.1f); - /* - for (int i = 0; i < points.Count; i++) - { - points[i] = new Vector2((float)Math.Round(points[i].x, 3), - (float)Math.Round(points[i].y, 3)); ; - }*/ - - Contour c = new Contour(points); - double area = c.SignedArea(); - if (area > 0) - hulls.Add(new Tuple(area, new Polygon(c))); - else - holes.Add(c); - } - if (hulls.Count == 1) - { - hulls[0].Item2.Holes = holes; - polygons.Add(hulls[0].Item2); - } - else - { - hulls.Sort((a, b) => b.Item1.CompareTo(a.Item1)); - - for (int iHull = 0; iHull < hulls.Count; iHull++) - { - for (int iHull2 = iHull + 1; iHull2 < hulls.Count; iHull2++) - { - if (hulls[iHull].Item2.Contains(hulls[iHull2].Item2)) - { - hulls[iHull].Item2.AddAsChild(hulls[iHull2].Item2); - hulls.RemoveAt(iHull2); - iHull2--; - } - } - } - foreach (var hull in hulls) - { - for (int iHole = 0; iHole < holes.Count; iHole++) - { - if (hull.Item2.Contains(holes[iHole])) - { - hull.Item2.Holes.Add(holes[iHole]); - holes.RemoveAt(iHole); - iHole--; - } - } - } - polygons.AddRange(hulls.ConvertAll(t => t.Item2)); - } - } - } -} diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/Creation/ColliderConverter.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/Creation/ColliderConverter.cs.meta deleted file mode 100644 index c6c2133e..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/Creation/ColliderConverter.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 7608182b2081ee14db7b159b5c2f0267 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/Creation/IntersectionTester.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/Creation/IntersectionTester.cs deleted file mode 100644 index e677149e..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/Creation/IntersectionTester.cs +++ /dev/null @@ -1,639 +0,0 @@ -using System.Collections; -using System.Collections.Generic; -using UnityEngine; -using System; -using System.Linq; - -namespace PathBerserker2d -{ - internal class IntersectionTester - { - // 1,23456 -> 1234 - private const float FUDGE_FACTOR = 0.01f; - - public IClipper Clipper { get => clipper; } - - IClipper clipper; - ColliderConverter colliderConverter; - INavSegmentCreationParamProvider paramProvider; - Matrix4x4 surfaceWorldToLocal; - - public IntersectionTester(INavSegmentCreationParamProvider paramProvider, Matrix4x4 surfaceWorldToLocal) - { - this.clipper = new ClipperWrapper(); - this.colliderConverter = new ColliderConverter(); - this.paramProvider = paramProvider; - this.surfaceWorldToLocal = surfaceWorldToLocal; - } - - public Polygon[] ColliderToPolygon(Collider2D col) - { - return colliderConverter.Convert(col); - } - - public void MarkContour(Contour contour, NavSurface owner, PolygonSet polySet, List navSegments) - { - int prevSegIndex = -1; - int firstNavSegIndex = navSegments.Count; - bool lastSegTouchesLastPoint = false; - - for (int iPrevLine = contour.IsClosed ? contour.VertexCount - 1 : 0, iLine = contour.IsClosed ? 0 : 1; iLine < contour.VertexCount; iPrevLine = iLine, iLine++) - { - Vector2 a = contour[iPrevLine]; - Vector2 b = contour[iLine]; - - Vector2 dir = b - a; - float length = dir.magnitude; - dir /= length; - Vector2 normal = new Vector2(-dir.y, dir.x); - - int cellCount = Math.Max(1, Mathf.RoundToInt(length / paramProvider.CellSize)); - - Vector2 fudgedA = a + normal * FUDGE_FACTOR; - Vector2 fudgedB = b + normal * FUDGE_FACTOR; - Vector2 cellHeight = normal * paramProvider.MaxClearance; - - List cellSpace = new List(4); - cellSpace.Add(fudgedB); - cellSpace.Add(fudgedA); - cellSpace.Add(fudgedA + cellHeight); - cellSpace.Add(fudgedB + cellHeight); - - Polygon walkSpacePolygon = new Polygon(new Contour(cellSpace)); - - //var ts = new Polygon(new Contour(cellSpace.ToList())); - //GizmosQueue.Instance.Enqueue(5, () => - //{ - // Gizmos.color = Color.gray; - // ts.Draw(); - //}); - - List intersections = new List(5); - foreach (var testCandidate in polySet.Query(walkSpacePolygon.BoundingRect)) - { - if (testCandidate.Hull.IsClosed) - { - //GizmosQueue.Instance.Enqueue(5, () => - //{ - // Gizmos.color = Color.red; - // //testCandidate.Draw(); - //}); - - clipper.Compute(testCandidate, walkSpacePolygon, BoolOpType.INTERSECTION, out var clipResult); - intersections.AddRange(clipResult); - } - else - intersections.Add(testCandidate); - } - //could do a union now; to evaluate - // this is nonsense, but better leave as is. It ensures that all cells are the same size - if (intersections.Count == -1) - { - var newSeg = CreateFreeSegment(cellCount, owner, a, dir, length); - if (prevSegIndex != -1) - { - navSegments[prevSegIndex].NextSegmentIndex = navSegments.Count; - newSeg.PrevSegmentIndex = prevSegIndex; - } - prevSegIndex = navSegments.Count; - navSegments.Add(newSeg); - lastSegTouchesLastPoint = true; - } - else - { - float correctedCellSize = length / cellCount; - - Vector2 cellOffset = dir * correctedCellSize; - - cellSpace[0] = (fudgedA + cellOffset); - cellSpace[1] = (fudgedA); - cellSpace[2] = (fudgedA + cellHeight); - cellSpace[3] = (cellSpace[0] + cellHeight); - - List cellClearances = new List(cellCount); - bool searchForHead = true; - float segmentStart = 0; - for (int iCell = 0; iCell < cellCount; iCell++) - { - - var poly = new Polygon(new Contour(new List(cellSpace))); - walkSpacePolygon.UpdateBounds(); - - //GizmosQueue.Instance.Enqueue(5, () => { poly.Draw(); }); - - float clearance = CalculateCellClearance(walkSpacePolygon, normal, paramProvider.MinClearance, paramProvider.MaxClearance, intersections); - if (searchForHead) - { - if (clearance >= paramProvider.MinClearance) - { - segmentStart = iCell * correctedCellSize; - searchForHead = false; - cellClearances.Add(clearance); - } - else - { - prevSegIndex = -1; - } - } - else - { - if (clearance < paramProvider.MinClearance) - { - var newSeg = new NavSegment( - owner, - surfaceWorldToLocal.MultiplyPoint3x4(segmentStart * dir + a), - surfaceWorldToLocal.MultiplyVector(dir), - iCell * correctedCellSize - segmentStart, - cellClearances.ToArray() - ); - if (prevSegIndex != -1) - { - navSegments[prevSegIndex].NextSegmentIndex = navSegments.Count; - newSeg.PrevSegmentIndex = prevSegIndex; - } - prevSegIndex = -1; - navSegments.Add(newSeg); - - cellClearances.Clear(); - searchForHead = true; - - } - else - { - cellClearances.Add(clearance); - } - } - cellSpace[1] = fudgedA + cellOffset * iCell; - cellSpace[2] = fudgedA + cellHeight + cellOffset * iCell; - if (iCell < cellCount - 2) - { - cellSpace[0] = fudgedA + cellOffset * (iCell + 1); - cellSpace[3] = fudgedA + cellHeight + cellOffset * (iCell + 1); - } - else - { - cellSpace[0] = b + normal * FUDGE_FACTOR; - cellSpace[3] = cellSpace[0] + cellHeight; - } - } - if (!searchForHead) - { - var newSeg = new NavSegment( - owner, - surfaceWorldToLocal.MultiplyPoint3x4(segmentStart * dir + a), - surfaceWorldToLocal.MultiplyVector(dir), - length - segmentStart, - cellClearances.ToArray() - ); - - if (prevSegIndex != -1) - { - navSegments[prevSegIndex].NextSegmentIndex = navSegments.Count; - newSeg.PrevSegmentIndex = prevSegIndex; - } - prevSegIndex = navSegments.Count; - navSegments.Add(newSeg); - - } - lastSegTouchesLastPoint = !searchForHead; - } - } - //check for reach around - if (firstNavSegIndex < navSegments.Count && - lastSegTouchesLastPoint && - (navSegments[firstNavSegIndex].Start - - navSegments[navSegments.Count - 1].End).sqrMagnitude < 0.01f * 0.01f - ) - { - navSegments[firstNavSegIndex].PrevSegmentIndex = navSegments.Count - 1; - navSegments[navSegments.Count - 1].NextSegmentIndex = firstNavSegIndex; - } - } - - private NavSegment CreateFreeSegment(int cellCount, NavSurface owner, Vector2 a, Vector2 dir, float length) - { - float[] cellClearances = new float[cellCount]; - for (int i = 0; i < cellCount; i++) - cellClearances[i] = paramProvider.MaxClearance; - - return new NavSegment(owner, surfaceWorldToLocal.MultiplyPoint3x4(a), surfaceWorldToLocal.MultiplyVector(dir), length, cellClearances); - } - -#if false - public static void UpdateNavObstacle(IEnumerable surfaces, NavObstacle obstacle, Clipper clipper, NavSegmentCreationSettings settings) - { - foreach (var surface in surfaces) - { - UpdateNavObstacle(surface, obstacle, clipper, settings); - } - } - - public static void UpdateNavObstacle(NavSurface surface, NavObstacle obstacle, Clipper clipper, NavSegmentCreationSettings settings) - { - var obstacleBounds = obstacle.Bounds; - var surfBounds = surface.WorldBounds; - surfBounds.size += new Vector2(settings.AgentHeight, settings.AgentHeight) * 2; - if (surfBounds.Overlaps(obstacleBounds)) - { - for (int iSeg = 0; iSeg < surface.NavSegments.Count; iSeg++) - { - var seg = surface.NavSegments[iSeg]; - // is within effected bounds? - Vector2 min = seg.Start; - Vector2 max = seg.Start; - min = Vector2.Min(min, seg.End); - max = Vector2.Max(max, seg.End); - min = Vector2.Min(min, seg.End + seg.Normal * settings.AgentHeight); - max = Vector2.Max(max, seg.End + seg.Normal * settings.AgentHeight); - min = Vector2.Min(min, seg.Start + seg.Normal * settings.AgentHeight); - max = Vector2.Max(max, seg.Start + seg.Normal * settings.AgentHeight); - - Rect segBounds = new Rect(min.x, min.y, max.x - min.x, max.y - min.y); - /*GizmosQueue.Instance.Enqueue(10, () => - { - Gizmos.color = Color.red; - ABC.Utility.DrawRect(segBounds.position, segBounds.size); - });*/ - - if (obstacleBounds.Overlaps(segBounds)) - { - float[] clearances; - if (UpdateMarkOfNavSegment(seg, obstacle, settings, clipper, out clearances)) - { - obstacle.EffectedNavSegments.Add(new Tuple(new NavSegmentDataPointer(surface, iSeg), clearances)); - } - } - } - } - } - - public static void UpdateNavAreaMarker(IEnumerable surfaces, NavAreaMarker marker) - { - Matrix4x4 worldToMarker = marker.transform.worldToLocalMatrix; - - Rect rect = marker.Bounds; - marker.EffectedNavSegments.Clear(); - - foreach (var surf in surfaces) - { - for (int iSeg = 0; iSeg < surf.SegmentCount; iSeg++) - { - var seg = surf.NavSegments[iSeg]; - float u1, u2; - - /* - GizmosQueue.Instance.Enqueue(5, () => - { - - var old = Gizmos.matrix; - Gizmos.color = Color.magenta; - ABC.Utility.DrawRect(rect.position, rect.size); - Gizmos.matrix = marker.transform.localToWorldMatrix; - Gizmos.color = Color.red; - ABC.Utility.DrawRect(rect.position, rect.size); - Gizmos.color = Color.magenta; - Gizmos.matrix = worldToMarker; - Gizmos.DrawLine(seg.Start, seg.End); - Gizmos.matrix = old; - });*/ - - if (RectLineIntersection(rect, worldToMarker.MultiplyPoint(seg.Start), worldToMarker.MultiplyPoint(seg.End), out u1, out u2)) - { - // entirely inside - if (u1 < 0 && 1 < u2) - { - marker.EffectedNavSegments.Add(new Tuple( - new NavSegmentDataPointer(surf, iSeg), new Vector2(0, seg.Length))); - } - - // 2 intersections - else if (0 <= u1 && u1 < u2 && u2 <= 1) - { - marker.EffectedNavSegments.Add(new Tuple( - new NavSegmentDataPointer(surf, iSeg), - new Vector2(u1 * seg.Length, u2 * seg.Length))); - } - - // 1 intersection - else if (0 <= u1 && u1 <= 1) - { - marker.EffectedNavSegments.Add(new Tuple( - new NavSegmentDataPointer(surf, iSeg), - new Vector2(u1 * seg.Length, seg.Length))); - } - else if (0 <= u2 && u2 <= 1) - { - marker.EffectedNavSegments.Add(new Tuple( - new NavSegmentDataPointer(surf, iSeg), - new Vector2(0, u2 * seg.Length))); - } - } - } - } - } -#endif - - -#if false - public static void UpdateMarkAddNavSurface(IEnumerable navSegments, NavSurface navSurface, NavSegmentCreationSettings settings, Clipper clipper) - { - //1. find bounds of navSurface - var surfaceBounds = navSurface.Bounds; - var filter = new NavSurfaceColliderFilter(navSurface); - - foreach (var seg in navSegments) - { - // is within effected bounds? - - Vector2 min = seg.Start; - Vector2 max = seg.Start; - min = Vector2.Min(min, seg.End); - max = Vector2.Max(max, seg.End); - min = Vector2.Min(min, seg.End + seg.Normal * settings.AgentHeight); - max = Vector2.Max(max, seg.End + seg.Normal * settings.AgentHeight); - min = Vector2.Min(min, seg.Start + seg.Normal * settings.AgentHeight); - max = Vector2.Max(max, seg.Start + seg.Normal * settings.AgentHeight); - - if (surfaceBounds.Overlaps(new Rect(min.x, min.y, max.x - min.x, max.y - min.y))){ - UpdateMarkOfNavSegment(seg, filter, settings, clipper); - } - } - } -#endif -#if false - // filter needs to filter out non new colliders - public static bool UpdateMarkOfNavSegment(NavSegment navSegment, NavObstacle obstacle, NavSegmentCreationSettings settings, Clipper clipper, out float[] clearanceValues) - { - - List polygonToTestAgainst = ConvertHullToClipperFormat(HullFromCollider(obstacle.Collider, settings, obstacle.transform.localToWorldMatrix), settings.FloatToIntMultiplier); - - float correctedCellSize = navSegment.Length / navSegment.CellCount; - float f2iCellSize = CIntConversion.FloatToCInt(correctedCellSize); - float f2iMinClearance = settings.FloatToIntMultiplier * settings.MinClearance; - float f2iMaxClearance = settings.FloatToIntMultiplier * settings.AgentHeight; - IntPoint f2iA = CIntConversion.Vector2ToIntPoint(navSegment.LStart); - - IntPoint cellOffset = new IntPoint(navSegment.Tangent.x * f2iCellSize, navSegment.Tangent.y * f2iCellSize); - - List cellSpace = new List(4); - cellSpace.Add(f2iA + cellOffset); - cellSpace.Add(f2iA); - cellSpace.Add(f2iA); - cellSpace.Add(f2iA); - - clearanceValues = new float[navSegment.CellCount]; - bool segmentWasChanged = false; - for (int iCell = 0; iCell < navSegment.CellCount; iCell++) - { - float prevClearance = navSegment.GetCellClearance(iCell); - if (prevClearance <= settings.MinClearance) - continue; - - IntPoint cellHeight = CIntConversion.Vector2ToIntPoint(navSegment.Normal * prevClearance); - cellSpace[2] = cellSpace[1] + cellHeight; - cellSpace[3] = cellSpace[0] + cellHeight; - - /* - var clone = new List(cellSpace); - GizmosQueue.Instance.Enqueue(5, () => - { - Gizmos.DrawLine(CIntConversion.IntPointToVector2(clone[0], settings.FloatToIntMultiplier), CIntConversion.IntPointToVector2(clone[1], settings.FloatToIntMultiplier)); - Gizmos.DrawLine(CIntConversion.IntPointToVector2(clone[1], settings.FloatToIntMultiplier), CIntConversion.IntPointToVector2(clone[2], settings.FloatToIntMultiplier)); - Gizmos.DrawLine(CIntConversion.IntPointToVector2(clone[2], settings.FloatToIntMultiplier), CIntConversion.IntPointToVector2(clone[3], settings.FloatToIntMultiplier)); - Gizmos.DrawLine(CIntConversion.IntPointToVector2(clone[3], settings.FloatToIntMultiplier), CIntConversion.IntPointToVector2(clone[0], settings.FloatToIntMultiplier)); - }); - */ - - float clearance = CalculateCellClearance(cellSpace, navSegment.Normal, f2iMinClearance, prevClearance * settings.FloatToIntMultiplier, polygonToTestAgainst, clipper) / settings.FloatToIntMultiplier; - segmentWasChanged = clearance < prevClearance || segmentWasChanged; - clearanceValues[iCell] = clearance; - - cellSpace[1] += cellOffset; - if (iCell < navSegment.CellCount - 2) - { - cellSpace[0] += cellOffset; - } - else - { - cellSpace[0] = CIntConversion.Vector2ToIntPoint(navSegment.LEnd); - } - } - return segmentWasChanged; - } -#endif -#if false - public static bool UpdateMarkOfNavSegmentComplete(NavSegment navSegment, IColliderFilter filter, NavSegmentCreationSettings settings, Clipper clipper) - { - Vector2 oBoxPoint = navSegment.Start + navSegment.Tangent * navSegment.Length * 0.5f + navSegment.Normal * settings.AgentHeight * 0.5f; - Vector2 oBoxSize = new Vector2(navSegment.Length, settings.AgentHeight); - float oBoxAngle = Vector2.SignedAngle(Vector2.up, navSegment.Normal); - - Collider2D[] touchedColliders = Physics2D.OverlapBoxAll(oBoxPoint, oBoxSize, oBoxAngle, settings.IncludeLayers); - - List> polygonsToTestAgainst = new List>(touchedColliders.Length); - foreach (var col in filter.Filter(touchedColliders)) - { - polygonsToTestAgainst.Add(ConvertHullToClipperFormat(HullFromCollider(col, settings), settings.FloatToIntMultiplier)); - } - - float correctedCellSize = navSegment.Length / navSegment.CellCount; - float f2iCellSize = CIntConversion.FloatToCInt(correctedCellSize, settings.FloatToIntMultiplier); - float f2iMinClearance = settings.FloatToIntMultiplier * settings.MinClearance; - float f2iMaxClearance = settings.FloatToIntMultiplier * settings.AgentHeight; - IntPoint f2iA = CIntConversion.Vector2ToIntPoint(navSegment.Start, settings.FloatToIntMultiplier); - - Vector2 normal = navSegment.Normal; - IntPoint cellOffset = new IntPoint(navSegment.Tangent.x * f2iCellSize, navSegment.Tangent.y * f2iCellSize); - IntPoint cellHeight = new IntPoint(Mathf.RoundToInt(normal.x * settings.AgentHeight * settings.FloatToIntMultiplier), - Mathf.RoundToInt(normal.y * settings.AgentHeight * settings.FloatToIntMultiplier)); - - List cellSpace = new List(4); - cellSpace.Add(f2iA + cellOffset); - cellSpace.Add(f2iA); - cellSpace.Add(f2iA); - cellSpace.Add(f2iA); - - bool segmentWasChanged = false; - for (int iCell = 0; iCell < navSegment.CellCount; iCell++) - { - float prevClearance = navSegment.GetCellClearance(iCell); - - cellSpace[2] = cellSpace[1] + cellHeight; - cellSpace[3] = cellSpace[0] + cellHeight; - - /* - var clone = new List(cellSpace); - GizmosQueue.Instance.Enqueue(5, () => - { - Gizmos.DrawLine(CIntConversion.IntPointToVector2(clone[0], settings.FloatToIntMultiplier), CIntConversion.IntPointToVector2(clone[1], settings.FloatToIntMultiplier)); - Gizmos.DrawLine(CIntConversion.IntPointToVector2(clone[1], settings.FloatToIntMultiplier), CIntConversion.IntPointToVector2(clone[2], settings.FloatToIntMultiplier)); - Gizmos.DrawLine(CIntConversion.IntPointToVector2(clone[2], settings.FloatToIntMultiplier), CIntConversion.IntPointToVector2(clone[3], settings.FloatToIntMultiplier)); - Gizmos.DrawLine(CIntConversion.IntPointToVector2(clone[3], settings.FloatToIntMultiplier), CIntConversion.IntPointToVector2(clone[0], settings.FloatToIntMultiplier)); - }); - */ - - float clearance = CalculateCellClearance(cellSpace, navSegment.Normal, f2iMinClearance, f2iMaxClearance, polygonsToTestAgainst, clipper) / settings.FloatToIntMultiplier; - segmentWasChanged = clearance != prevClearance || segmentWasChanged; - navSegment.SetCellClearanceAt(iCell, clearance); - - cellSpace[1] += cellOffset; - if (iCell < navSegment.CellCount - 2) - { - cellSpace[0] += cellOffset; - } - else - { - cellSpace[0] = CIntConversion.Vector2ToIntPoint(navSegment.End, settings.FloatToIntMultiplier); - } - } - return segmentWasChanged; - } -#endif - private float CalculateCellClearance(Polygon cell, Vector2 lineNormalNorm, float minClearance, float maxClearance, List otherPolygons) - { - float clearance = maxClearance; - foreach (var testCandidate in otherPolygons) - { - if (testCandidate.Hull.IsClosed) - { - var resultType = clipper.Compute(cell, testCandidate, BoolOpType.INTERSECTION, out var resultPolygon); - - /*var a = cell; - var b = testCandidate; - GizmosQueue.Instance.Enqueue(5, () => - { - Gizmos.color = Color.red; - a.Draw(); - Gizmos.color = Color.blue; - b.Draw(); - });*/ - - if (resultType == ResultType.NoOverlap) - continue; - - double combinedArea = 0; - for (int i = 0; i < resultPolygon.Count; i++) - { - combinedArea += resultPolygon[i].Hull.Area(); - } - if (combinedArea < 0.001) - continue; - - foreach (var intersectionPolygon in resultPolygon) - { - foreach (var point in intersectionPolygon.Hull) - { - float dot = DistancePointLine(point, cell.Hull[1], lineNormalNorm); - if (dot < clearance) - { - clearance = dot; - if (clearance < minClearance) - { - return 0; - } - } - } - } - } - else - { - float c = OpenPolygonClearanceClipping( - testCandidate, cell, lineNormalNorm, minClearance, maxClearance); - if (c < clearance) - { - clearance = c; - if (clearance < minClearance) - { - return 0; - } - } - } - } - return clearance; - } - - private float OpenPolygonClearanceClipping(Polygon openPoly, Polygon target, Vector2 lineNormalNorm, float minClearance, float maxClearance) - { - float clearance = maxClearance; - bool inside = target.PointInPolyon(openPoly.Hull[0]); - bool prevNormalCheck = false; - for (int i = 0; i < openPoly.Hull.VertexCount - 1; i++) - { - Vector2 a = openPoly.Hull[i]; - Vector2 b = openPoly.Hull[i + 1]; - - clearance = EdgePolygonClearanceClipping(openPoly.Hull[i], - openPoly.Hull[i + 1], - lineNormalNorm, - target, - minClearance, - maxClearance, - clearance, - ref inside, - ref prevNormalCheck); - - if (clearance < minClearance) - { - return 0; - } - } - return clearance; - } - - private float EdgePolygonClearanceClipping(Vector2 a, Vector2 b, Vector2 lineNormal, Polygon target, - float minClearance, float maxClearance, float clearance, ref bool inside, ref bool prevNormalCheck) - { - Vector2 dir = b - a; - Vector2 normal = new Vector2(-dir.y, dir.x); - - bool normalCheck = Vector2.Dot(normal, lineNormal) < 0; - - - if (inside && (normalCheck || prevNormalCheck)) - { - float dist = DistancePointLine(a, target.Hull[1], lineNormal); - if (dist < clearance) - { - clearance = dist; - if (clearance < minClearance) - { - return 0; - } - } - } - prevNormalCheck = normalCheck; - - Vector2 inter; - if ((ExtendedGeometry.FindLineIntersection(a, b, target.Hull[0], target.Hull[1], out inter) - || ExtendedGeometry.FindLineIntersection(a, b, target.Hull[1], target.Hull[2], out inter) - || ExtendedGeometry.FindLineIntersection(a, b, target.Hull[2], target.Hull[3], out inter) - || ExtendedGeometry.FindLineIntersection(a, b, target.Hull[3], target.Hull[0], out inter)) - && inter != a && inter != b) - { - if (normalCheck) - { - float dist = DistancePointLine(inter, target.Hull[1], lineNormal); - if (dist < clearance) - { - clearance = dist; - if (clearance < minClearance) - { - return 0; - } - } - } - inside = !inside; - - clearance = EdgePolygonClearanceClipping( - inter, b, lineNormal, target, minClearance, maxClearance, clearance, - ref inside, ref prevNormalCheck); - } - return clearance; - } - - private float DistancePointLine(Vector2 point, Vector2 la, Vector2 lNormal) - { - return lNormal.x * (point.x - la.x) + lNormal.y * (point.y - la.y); - } - } -} \ No newline at end of file diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/Creation/IntersectionTester.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/Creation/IntersectionTester.cs.meta deleted file mode 100644 index 0bc7bce0..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/Creation/IntersectionTester.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: b5a6b159837bdea438010d88de208dfd -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/Creation/NavSurfaceBakeJob.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/Creation/NavSurfaceBakeJob.cs deleted file mode 100644 index 0f535fe2..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/Creation/NavSurfaceBakeJob.cs +++ /dev/null @@ -1,311 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Threading; -using System.Linq; -using UnityEngine; - -namespace PathBerserker2d -{ - internal class NavSurfaceBakeJob - { - public bool IsFinished { get { return bakeThread != null && !bakeThread.IsAlive; } } - public bool IsRunning { get { return bakeThread != null && bakeThread.IsAlive; } } - public float Progress { get { return progress; } } - public float TotalBakeTime { get; private set; } - - public List navSegments; - public Rect bounds; - - private Polygon[][] polygons; - private IntersectionTester it; - private NavSurface owner; - private Tuple[] subtractors; - Matrix4x4 surfaceWorldToLocal; - Matrix4x4 surfaceLocalToWorld; - - private Thread bakeThread; - private volatile float progress = 0; - private volatile bool aborted; - - public NavSurfaceBakeJob(NavSurface owner) - { - this.owner = owner; - } - - public void Start(Polygon[][] polygons, IntersectionTester it, Tuple[] subtractors, Matrix4x4 surfaceWorldToLocal) - { - this.polygons = polygons; - this.it = it; - this.subtractors = subtractors; - this.surfaceWorldToLocal = surfaceWorldToLocal; - this.surfaceLocalToWorld = surfaceWorldToLocal.inverse; - - aborted = false; - progress = 0; - - bakeThread = new Thread(Bake); - bakeThread.IsBackground = true; - bakeThread.Start(); - } - - public void AbortJoin() - { - if (bakeThread != null && bakeThread.IsAlive) - { - this.aborted = true; - bakeThread.Join(); - } - } - - private void Bake() - { - // filter out empty polygons - polygons = polygons.Where(p => p.Length > 0).ToArray(); - - if (polygons.Length == 0) - { - navSegments = new List(0); - bounds = new Rect(); - return; - } - - var sw = new System.Diagnostics.Stopwatch(); - sw.Start(); - - var polySet = new PolygonSet(); - foreach (var polys in polygons) - { - foreach (var poly in polys) - { - polySet.AddPolygon(it.Clipper, poly); - } - } - - //pre process, simplify countours - bounds = polySet.First().BoundingRect; - foreach (var poly in polySet) - { - poly.Simplify(owner.SmallestDistanceYouCareAbout); - bounds = bounds.CombineWith(poly.BoundingRect); - } - - float totalContourCount = 0; - foreach (var poly in polySet) - { - totalContourCount += poly.Holes.Count + 1; - } - - navSegments = new List((int)totalContourCount * 5); - float processedContourCount = 0; - foreach (var poly in polySet) - { - foreach (var contour in poly) - { - it.MarkContour(contour, owner, polySet, navSegments); - - processedContourCount++; - progress = processedContourCount / totalContourCount; - - if (aborted) - goto End; - } - } - - // post process - // 1. filter slopes - FilterSlopes(); - - // 2. substract substractors - FilterSubtractors(); - - // 3. filter by length - FilterSmallSegments(); - - End: - sw.Stop(); - TotalBakeTime = sw.ElapsedMilliseconds; - } - - private void RemoveSegmentAt(int index) - { - if (navSegments[index].HasNext) - { - navSegments[navSegments[index].NextSegmentIndex].PrevSegmentIndex = -1; - } - if (navSegments[index].HasPrev) - { - navSegments[navSegments[index].PrevSegmentIndex].NextSegmentIndex = -1; - } - - int lastIndex = navSegments.Count - 1; - if (lastIndex != index) - { - if (navSegments[lastIndex].HasNext) - { - navSegments[navSegments[lastIndex].NextSegmentIndex].PrevSegmentIndex = index; - } - if (navSegments[lastIndex].HasPrev) - { - navSegments[navSegments[lastIndex].PrevSegmentIndex].NextSegmentIndex = index; - } - navSegments[index] = navSegments[lastIndex]; - } - navSegments.RemoveAt(lastIndex); - } - - private void FilterSlopes() - { - for (int i = 0; i < navSegments.Count; i++) - { - var seg = navSegments[i]; - if (Vector2.Angle(Vector2.up, surfaceLocalToWorld.MultiplyVector(seg.Normal)) > owner.MaxSlopeAngle) - { - RemoveSegmentAt(i); - i--; - } - } - } - - private void FilterSubtractors() - { - float i1, i2; - for (int i = 0; i < navSegments.Count; i++) - { - float angle = Vector2.SignedAngle(navSegments[i].Tangent, Vector2.up); - - foreach (var s in subtractors) - { - if (!ExtendedGeometry.IsAngleBetweenAngles(s.Item2.x, s.Item2.y, angle)) - continue; - - if (ExtendedGeometry.RectLineIntersection(s.Item1, surfaceLocalToWorld.MultiplyPoint3x4(navSegments[i].GetPositionAlongSegment(0)), surfaceLocalToWorld.MultiplyPoint3x4(navSegments[i].GetPositionAlongSegment(navSegments[i].Length)), out i1, out i2)) - { - // entirely inside - if (i1 < 0 && i2 > 1) - { - RemoveSegmentAt(i); - i--; - break; - } - else if (i1 > 0 || i2 < 1) - { - // inside, 2 intersections, subdiv - float cellSize = (float)navSegments[i].Length / (float)navSegments[i].CellCount; - float[] clearances = navSegments[i].CloneCellClearances(); - - NavSegment segA = null; - NavSegment segB = null; - - if (i1 > 0 && i1 < 1) - { - int cellCountA = Mathf.CeilToInt(navSegments[i].CellCount * i1); - float cellSizeA = (float)(i1 * navSegments[i].Length) / (float)cellCountA; - float cellConvA = cellSizeA / cellSize; - bool cellSizeEqual = Mathf.Abs(cellSizeA - cellSize) < 0.001f; - - float[] clearancesA = new float[cellCountA]; - - for (int iCell = 0; iCell < clearancesA.Length; iCell++) - { - int a = Mathf.FloorToInt(iCell * cellConvA); - - if (cellSizeEqual) - clearancesA[iCell] = clearances[a]; - else - { - int b = Mathf.FloorToInt((iCell + 1) * cellConvA); - - // prevents rounding issue - if (b >= clearances.Length) - b--; - - clearancesA[iCell] = Mathf.Min(clearances[a], clearances[b]); - } - } - - Vector2 newStart = surfaceLocalToWorld.MultiplyPoint3x4(navSegments[i].Start); - segA = new NavSegment(owner, surfaceWorldToLocal.MultiplyPoint3x4(newStart), navSegments[i].Tangent, i1 * navSegments[i].Length, clearancesA); - } - - if (i2 > 0 && i2 < 1) - { - int cellCountB = Mathf.CeilToInt(navSegments[i].CellCount * (1f - i2)); - - float cellSizeB = (float)((1f - i2) * navSegments[i].Length) / (float)cellCountB; - float cellConvB = cellSizeB / cellSize; - float cellOffset = ((navSegments[i].Length / cellSizeB) - cellCountB) * cellConvB; - bool cellSizeEqual = Mathf.Abs(cellSizeB - cellSize) < 0.001f; - - float[] clearancesB = new float[cellCountB]; - - for (int iCell = 0; iCell < clearancesB.Length; iCell++) - { - int a = Mathf.FloorToInt(cellOffset + iCell * cellConvB); - - - //happens when cellsizes match exactly - if (cellSizeEqual) - clearancesB[iCell] = clearances[a]; - else - { - int b = Mathf.FloorToInt(cellOffset + (iCell + 1) * cellConvB); - - // prevents rounding issue - if (b >= clearances.Length) - b--; - - clearancesB[iCell] = Mathf.Min(clearances[a], clearances[b]); - } - } - - Vector2 newStart = navSegments[i].Start + navSegments[i].Tangent * i2 * navSegments[i].Length; - segB = new NavSegment(owner, newStart, navSegments[i].Tangent, (1f - i2) * navSegments[i].Length, clearancesB); - } - - if (segA != null && segB != null) - { - if (navSegments[i].HasNext) - navSegments[navSegments[i].NextSegmentIndex].PrevSegmentIndex = navSegments.Count; - - segA.PrevSegmentIndex = navSegments[i].PrevSegmentIndex; - segB.NextSegmentIndex = navSegments[i].NextSegmentIndex; - - navSegments[i] = segA; - navSegments.Add(segB); - } - else if (segA != null) - { - if (navSegments[i].HasNext) - navSegments[navSegments[i].NextSegmentIndex].PrevSegmentIndex = -1; - - segA.PrevSegmentIndex = navSegments[i].PrevSegmentIndex; - navSegments[i] = segA; - } - else if (segB != null) - { - if (navSegments[i].HasPrev) - navSegments[navSegments[i].PrevSegmentIndex].NextSegmentIndex = -1; - - segB.NextSegmentIndex = navSegments[i].NextSegmentIndex; - navSegments[i] = segB; - } - } - } - } - } - } - - private void FilterSmallSegments() - { - for (int i = 0; i < navSegments.Count; i++) - { - var seg = navSegments[i]; - if (seg.Length < owner.MinSegmentLength) - { - RemoveSegmentAt(i); - i--; - } - } - } - } -} diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/Creation/NavSurfaceBakeJob.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/Creation/NavSurfaceBakeJob.cs.meta deleted file mode 100644 index 85886e5c..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/Creation/NavSurfaceBakeJob.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: e80d421fda183c14f9f8fceb48c6d850 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/Creation/PolygonSet.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/Creation/PolygonSet.cs deleted file mode 100644 index 1acc553b..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/Creation/PolygonSet.cs +++ /dev/null @@ -1,91 +0,0 @@ -using System.Collections; -using System.Collections.Generic; -using UnityEngine; - -namespace PathBerserker2d -{ - internal class PolygonSet : IEnumerable - { - private B2DynamicTree polygonTree = new B2DynamicTree(); - - public void AddPolygon(IClipper clipper, Polygon newPoly) - { - if (newPoly.Hull.IsClosed) - { - // try to merge the new polygon with the existing once - List polygonsToInsert = new List(4); - var iterator = polygonTree.Query(newPoly.BoundingRect); - while (iterator.MoveNext()) - { - var poly = polygonTree.GetUserData(iterator.Current); - if (poly.Hull.IsClosed) - { - var resultType = clipper.Compute(poly, newPoly, BoolOpType.UNION, out var resultPolys); - if (resultType == ResultType.Clipped) - { - // delete poly - polygonTree.RemoveProxy(iterator.Current); - newPoly = resultPolys[0]; - } - } - else - { - var resultType = clipper.Compute(poly, newPoly, BoolOpType.DIFFERENCE, out var resultPolys, true); - if (resultType == ResultType.Clipped) - { - polygonsToInsert.AddRange(resultPolys); - polygonTree.RemoveProxy(iterator.Current); - } - } - } - foreach (var poly in polygonsToInsert) - polygonTree.CreateProxy(poly.BoundingRect, poly); - polygonTree.CreateProxy(newPoly.BoundingRect, newPoly); - } - else - { - List workList = new List(); - List polygonsToTest = new List(); - - polygonsToTest.Add(newPoly); - - var iterator = polygonTree.Query(newPoly.BoundingRect); - while (iterator.MoveNext()) - { - var poly = polygonTree.GetUserData(iterator.Current); - if (!poly.Hull.IsClosed) - continue; - foreach (var polyToTest in polygonsToTest) - { - var resultType = clipper.Compute(polyToTest, poly, BoolOpType.DIFFERENCE, out var result, true); - workList.AddRange(result); - } - var swap = polygonsToTest; - polygonsToTest = workList; - workList = swap; - workList.Clear(); - } - - foreach (var poly in polygonsToTest) - polygonTree.CreateProxy(poly.BoundingRect, poly); - } - } - - public IEnumerable Query(Rect aabb) - { - var iterator = polygonTree.Query(aabb); - while (iterator.MoveNext()) - yield return polygonTree.GetUserData(iterator.Current); - } - - public IEnumerator GetEnumerator() - { - return ((IEnumerable)polygonTree).GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return ((IEnumerable)polygonTree).GetEnumerator(); - } - } -} \ No newline at end of file diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/Creation/PolygonSet.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/Creation/PolygonSet.cs.meta deleted file mode 100644 index 8223d801..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/Creation/PolygonSet.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: b932c82fe004d5241a91ddc0c3110368 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/Creation/StableConnector.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/Creation/StableConnector.cs deleted file mode 100644 index 08d15b79..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/Creation/StableConnector.cs +++ /dev/null @@ -1,63 +0,0 @@ -using System.Collections.Generic; - -namespace PathBerserker2d -{ - internal class StableConnector where T : System.IEquatable - { - public void Add(T a, T b) - { - LinkedListNode> current = openPolygons.First; - - while (current != null) - { - LinkedListNode> next = current.Next; - - StablePointChain currentChain = current.Value; - - if (currentChain.LinkSegment(a, b)) - { - if (currentChain.IsClosed()) - { - closedPolygons.AddLast(currentChain); - openPolygons.Remove(current); - return; - } - else - { - LinkedListNode> innerCurrent = current.Next; - - while (innerCurrent != null) - { - LinkedListNode> innerNext = innerCurrent.Next; - - if (currentChain.LinkPointChain(innerCurrent.Value)) - { - openPolygons.Remove(innerCurrent); - break; - } - innerCurrent = innerNext; - } - } - return; - } - current = next; - } - openPolygons.AddLast(new StablePointChain(a, b)); - return; - } - - LinkedListNode> begin() { return closedPolygons.First; } - LinkedListNode> end() { return closedPolygons.Last; } - - public void Clear() - { - closedPolygons.Clear(); - openPolygons.Clear(); - } - - public int GetNumClosedPolygons() { return closedPolygons.Count; } - - LinkedList> openPolygons = new LinkedList>(); - public LinkedList> closedPolygons = new LinkedList>(); - } -} \ No newline at end of file diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/Creation/StableConnector.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/Creation/StableConnector.cs.meta deleted file mode 100644 index 72a7fd41..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/Creation/StableConnector.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 303b1b9f64c54d14fb937b565d682481 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/Creation/StablePointChain.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/Creation/StablePointChain.cs deleted file mode 100644 index d2ee3369..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/Creation/StablePointChain.cs +++ /dev/null @@ -1,90 +0,0 @@ -using System.Collections.Generic; -using System; - -namespace PathBerserker2d -{ - internal class StablePointChain where T : IEquatable - { - public LinkedList points = new LinkedList(); - - bool closed; // is the first point linked with the last one - - public StablePointChain(T a, T b) - { - closed = false; - - Add(a, b); - } - - public void Add(T a, T b) - { - points.AddLast(a); - points.AddLast(b); - } - - public bool LinkSegment(T a, T b) - { - if (b.Equals(points.First.Value)) - { - if (a.Equals(points.Last.Value)) - closed = true; - else - points.AddFirst(a); - return true; - } - if (a.Equals(points.Last.Value)) - { - if (b.Equals(points.First.Value)) - closed = true; - else - points.AddLast(b); - return true; - } - return false; - } - - public bool LinkPointChain(StablePointChain chain) - { - if (chain.points.First.Value.Equals(points.Last.Value)) - { - chain.points.RemoveFirst(); - AppendRange(chain.points); - - return true; - } - if (chain.points.Last.Value.Equals(points.First.Value)) - { - points.RemoveFirst(); - PrependRange(chain.points); - - return true; - } - return false; - } - - private void PrependRange(LinkedList list) - { - var node = list.Last; - do - { - this.points.AddFirst(node.Value); - } while ((node = node.Previous) != null); - } - - private void AppendRange(LinkedList list) - { - var node = list.First; - do - { - this.points.AddLast(node.Value); - } while ((node = node.Next) != null); - } - - public LinkedListNode First { get { return points.First; } } - public LinkedListNode Last { get { return points.Last; } } - - public bool IsClosed() { return closed; } - public void Clear() { points.Clear(); } - public int GetNumPoints() { return points.Count; } - } -} \ No newline at end of file diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/Creation/StablePointChain.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/Creation/StablePointChain.cs.meta deleted file mode 100644 index 67c7a12a..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/Creation/StablePointChain.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: c0d953896d15cb447b92d08cd1972cfd -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/IColliderFilter.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/IColliderFilter.cs deleted file mode 100644 index 45110a99..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/IColliderFilter.cs +++ /dev/null @@ -1,10 +0,0 @@ -using UnityEngine; -using System.Collections.Generic; - -namespace PathBerserker2d -{ - internal interface IColliderFilter - { - IEnumerable Filter(IEnumerable colliders); - } -} diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/IColliderFilter.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/IColliderFilter.cs.meta deleted file mode 100644 index 1724533d..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/IColliderFilter.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 2c3d0be58d090604f8d8340d3fcb51d5 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/INavSegmentCreationParamProvider.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/INavSegmentCreationParamProvider.cs deleted file mode 100644 index 61a48756..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/INavSegmentCreationParamProvider.cs +++ /dev/null @@ -1,12 +0,0 @@ -using UnityEngine; - -namespace PathBerserker2d -{ - internal interface INavSegmentCreationParamProvider - { - float MaxClearance { get; } - float MinClearance { get; } - float CellSize { get; } - LayerMask ColliderMask { get; } - } -} diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/INavSegmentCreationParamProvider.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/INavSegmentCreationParamProvider.cs.meta deleted file mode 100644 index fa37f565..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/INavSegmentCreationParamProvider.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: feb0a5de8c6910c4cbf247bff903f262 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/NavSegments.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/NavSegments.meta deleted file mode 100644 index 9fc5f6bd..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/NavSegments.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: c9ba631cc202a4d44a0f62ae74788b74 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/NavSegments/NavSegment.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/NavSegments/NavSegment.cs deleted file mode 100644 index 121eb40b..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/NavSegments/NavSegment.cs +++ /dev/null @@ -1,28 +0,0 @@ -using UnityEngine; - -namespace PathBerserker2d -{ - [System.Serializable] - internal class NavSegment : LineSegmentWithClearance, System.IEquatable - { - public NavSurface Owner { get { return owner; } } - - [SerializeField] - private NavSurface owner; - - public NavSegment(NavSurface owner, Vector2 start, Vector2 dirNorm, float length, float[] cellClearances) : base(start, dirNorm, length, cellClearances) - { - this.owner = owner; - } - - public bool Equals(NavSegment other) - { - return ReferenceEquals(other, this); - } - - public override string ToString() - { - return $"NavSegment({Start} -{Tangent}> {End})"; - } - } -} \ No newline at end of file diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/NavSegments/NavSegment.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/NavSegments/NavSegment.cs.meta deleted file mode 100644 index b569ff62..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/NavSegments/NavSegment.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: c1edc43a078c650468d85cf0e014d7d5 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/NavSegments/NavSegmentPointer.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/NavSegments/NavSegmentPointer.cs deleted file mode 100644 index cd968d55..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/NavSegments/NavSegmentPointer.cs +++ /dev/null @@ -1,51 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace PathBerserker2d -{ - /// - /// Points to a segment. - /// - public struct NavSegmentPointer : IEquatable - { - public static NavSegmentPointer Invalid { get { return new NavSegmentPointer(null, 0); } } - - public readonly int proxyDataIndex; - public readonly NavSurface surface; - - public NavSegmentPointer(NavSurface surface, int proxyDataIndex) - { - this.surface = surface; - this.proxyDataIndex = proxyDataIndex; - } - - public static bool operator ==(NavSegmentPointer a, NavSegmentPointer b) - { - return a.surface == b.surface && a.proxyDataIndex == b.proxyDataIndex; - } - - public static bool operator !=(NavSegmentPointer a, NavSegmentPointer b) - { - return a.surface != b.surface || a.proxyDataIndex != b.proxyDataIndex; - } - - public override bool Equals(object obj) - { - return obj is NavSegmentPointer && Equals((NavSegmentPointer)obj); - } - - public bool Equals(NavSegmentPointer other) - { - return proxyDataIndex == other.proxyDataIndex && - EqualityComparer.Default.Equals(surface, other.surface); - } - - public override int GetHashCode() - { - var hashCode = 1340906973; - hashCode = hashCode * -1521134295 + proxyDataIndex.GetHashCode(); - hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(surface); - return hashCode; - } - } -} diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/NavSegments/NavSegmentPointer.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/NavSegments/NavSegmentPointer.cs.meta deleted file mode 100644 index 248ebb48..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/NavSegments/NavSegmentPointer.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 9e41ae4e12fece74ea72adcba77c7b39 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/NavSegments/NavSegmentPositionPointer.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/NavSegments/NavSegmentPositionPointer.cs deleted file mode 100644 index 94acd2f0..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/NavSegments/NavSegmentPositionPointer.cs +++ /dev/null @@ -1,95 +0,0 @@ -using System; -using System.Collections.Generic; -using UnityEngine; - -namespace PathBerserker2d -{ - /// - /// Points to a position on a segment. - /// - public struct NavSegmentPositionPointer : IEquatable - { - public static NavSegmentPositionPointer Invalid { get { return new NavSegmentPositionPointer(null, null, 0); } } - - public Vector2 Position => cluster.owner.LocalToWorld.MultiplyPoint3x4(cluster.GetPositionAlongSegment(t)); - public Vector2 Normal => surface.LocalToWorldMatrix.MultiplyVector(cluster.Normal); - - internal readonly float t; - internal readonly NavGraphNodeCluster cluster; - internal readonly NavSurface surface; - // used to detect if the surface has changed - internal readonly int bakeIteration; - - internal NavSegmentPositionPointer(NavSurface surface, NavGraphNodeCluster cluster, float t) - { - this.surface = surface; - this.cluster = cluster; - this.t = t; - this.bakeIteration = surface != null ? surface.BakeIteration : -1; - } - - public static bool operator ==(NavSegmentPositionPointer a, NavSegmentPositionPointer b) - { - return a.surface == b.surface && a.cluster == b.cluster && a.t == b.t; - } - - public static bool operator !=(NavSegmentPositionPointer a, NavSegmentPositionPointer b) - { - return a.surface != b.surface || a.cluster != b.cluster || a.t != b.t; - } - - [Obsolete("Use the property Position instead.")] - public Vector2 GetPosition() - { - return cluster.owner.LocalToWorld.MultiplyPoint3x4(cluster.GetPositionAlongSegment(t)); - } - - public bool IsInvalid() - { - return surface == null || bakeIteration != surface.BakeIteration; - } - - public bool IsValid() - { - return surface != null && surface.BakeIteration == bakeIteration; - } - - public bool Equals(NavSegmentPositionPointer other) - { - return other != null && t == other.t && - cluster == other.cluster && - surface == other.surface; - } - - - public override bool Equals(object obj) - { - if ((obj == null) || !this.GetType().Equals(obj.GetType())) - { - return false; - } - else - { - var p = (NavSegmentPositionPointer)obj; - return Equals(p); - } - } - - public override string ToString() - { - if (IsInvalid()) - return $"NSP is invalid"; - return $"NSP points at " + Position; - } - - public override int GetHashCode() - { - int hashCode = 1774642579; - hashCode = hashCode * -1521134295 + t.GetHashCode(); - hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(cluster); - hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(surface); - hashCode = hashCode * -1521134295 + bakeIteration.GetHashCode(); - return hashCode; - } - } -} diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/NavSegments/NavSegmentPositionPointer.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/NavSegments/NavSegmentPositionPointer.cs.meta deleted file mode 100644 index e18da5c9..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/NavSegments/NavSegmentPositionPointer.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: e51973dfb11a2024f865147ad3348ab4 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/NavSegments/NavSubsegmentPointer.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/NavSegments/NavSubsegmentPointer.cs deleted file mode 100644 index 28a1af76..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/NavSegments/NavSubsegmentPointer.cs +++ /dev/null @@ -1,67 +0,0 @@ -using System; -using System.Collections.Generic; -using UnityEngine; - -namespace PathBerserker2d -{ - /// - /// Points to a subsection on a segment. It has a start point on the target segment and a length. - /// - public struct NavSubsegmentPointer : IEquatable - { - public static NavSubsegmentPointer Invalid { get { return new NavSubsegmentPointer(null, 0, 0, 0); } } - - public readonly float t; - public readonly float length; - public readonly int proxyDataIndex; - public readonly NavSurface surface; - public readonly int bakeIteration; - - public NavSubsegmentPointer(NavSurface surface, int proxyDataIndex, float t, float length) - { - this.surface = surface; - this.proxyDataIndex = proxyDataIndex; - this.t = t; - this.length = length; - this.bakeIteration = surface != null ? surface.BakeIteration : -1; - } - - public static bool operator ==(NavSubsegmentPointer a, NavSubsegmentPointer b) - { - return a.surface == b.surface && a.proxyDataIndex == b.proxyDataIndex && a.t == b.t && a.length == b.length; - } - - public static bool operator !=(NavSubsegmentPointer a, NavSubsegmentPointer b) - { - return a.surface != b.surface || a.proxyDataIndex != b.proxyDataIndex || a.t != b.t || a.length != b.length; - } - - public override bool Equals(object obj) - { - return obj is NavSubsegmentPointer && Equals((NavSubsegmentPointer)obj); - } - - public bool Equals(NavSubsegmentPointer other) - { - return t == other.t && - length == other.length && - proxyDataIndex == other.proxyDataIndex && - EqualityComparer.Default.Equals(surface, other.surface); - } - - public bool IsInvalid() - { - return surface == null || bakeIteration != surface.BakeIteration; - } - - public override int GetHashCode() - { - var hashCode = -1731056371; - hashCode = hashCode * -1521134295 + t.GetHashCode(); - hashCode = hashCode * -1521134295 + length.GetHashCode(); - hashCode = hashCode * -1521134295 + proxyDataIndex.GetHashCode(); - hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(surface); - return hashCode; - } - } -} diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/NavSegments/NavSubsegmentPointer.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/NavSegments/NavSubsegmentPointer.cs.meta deleted file mode 100644 index 0db7115a..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/NavSegments/NavSubsegmentPointer.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 5b6e634508177a64192239519f0e2e07 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/NavSurface.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/NavSurface.cs deleted file mode 100644 index 9a478a07..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/NavSurface.cs +++ /dev/null @@ -1,321 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using UnityEngine; - -namespace PathBerserker2d -{ - /// - /// A collection of line segments to traverse on. - /// - /// - /// NavSurfaces are independent collections of segments. At runtime their data gets added to the pathfinder. - /// You can load and unload NavSurfaces at runtime. This allows you to setup Prefabs with navigation data and stream them in at runtime. - /// Loading and unloading is as simple as enabling and disabling a NavSurface script. - /// ## Baking - /// The bake process **only consideres colliders that are children of the NavSurface**. - /// This also extends to the clearance calculation of segment cells. - /// Baking is currently limited to editor mode only. You can't bake at runtime. - /// ## Transformations - /// All baked postion data is relative to the current NavSurface transformation. - /// Segments in calculated paths remain relative to the NavSurface of origin. - /// If you pathfind on a NavSurface and then move it, the path will reflect that transformation, without any extra calculations. - /// - /// See also \ref cc_navagent "Core concepts: NavAgent". - /// - [ScriptExecutionOrder(-55)] - [AddComponentMenu("PathBerserker2d/Nav Surface")] - public class NavSurface : MonoBehaviour, INavSegmentCreationParamProvider - { - internal const int CurrentBakeVersion = 2; - - public Rect WorldBounds => Geometry.EnlargeRect(Geometry.TransformBoundingRect(localBoundingRect, LocalToWorldMatrix), PathBerserker2dSettings.PointMappingDistance); - - public float MaxClearance => maxClearance; - - public float MinClearance => minClearance; - - public float CellSize => cellSize; - - public LayerMask ColliderMask - { - get => includedColliders; - set => includedColliders = value; - } - - /// - /// Length of all segments combined - /// - public float TotalLineLength => totalLineLength; - - /// - /// Segments exceeding this angle are removed from the bake output. Should equal the highest slope angle of your NavAgents. - /// - public float MaxSlopeAngle => maxSlopeAngle; - - /// - /// Parameter for the line simplifier (Ramer-Douglas-Peucker). Higher values reduce overall segment count at the expense of fitting the original collider shape. - /// - public float SmallestDistanceYouCareAbout => smallestDistanceYouCareAbout; - - /// - /// Segments shorter than this will be removed from the bake output. - /// - public float MinSegmentLength => minSegmentLength; - - /// - /// Gets fired after a BakeJob initiated by a call to Bake() completes. - /// THIS DOES NOT mean that the changes are already available to the pathfinder. That will happen later. - /// Use OnReadyToPathfind for that instead. This only really tells you when you may start a new bake. - /// - public event Action OnBakingCompleted; - - /// Called after the NavSurface has been added to the pathfinder. Usually sometime after OnBakingCompleted has been called. Only know are the changes from baking actually visible in the pathfinder. - /// IF THERE ARE MULTIPLE NavSurface Components on this GameObject you are ass out. These events will fire for both of them always. Don't put 2 NavSurfaces on the same GameObject! - public event Action OnReadyToPathfind; - - /// Called after the NavSurface is removed from the pathfinder. Usually after the NavSurface is deleted OR REBAKED! Removing the old NavSurface data to replace it with new baked data will trigger this event. When this event is called, you can be sure that the old data NavData is no longer in use for anything. - /// IF THERE ARE MULTIPLE NavSurface Components on this GameObject you are ass out. These events will fire for both of them always. Don't put 2 NavSurfaces on the same GameObject! - public event Action OnRemovedFromPathfinding; - - internal List NavSegments => navSegments; - internal NavSurfaceBakeJob BakeJob { get; private set; } - internal bool hasDataChanged; - internal int BakeVersion => bakeVersion; - internal int BakeIteration => bakeIteration; - internal int PBComponentId { get; private set; } - - [Header("Bake Settings")] - [Tooltip("Maximum height that gets checked for potential obstructions. Should equal the height of your largest NavAgent.")] - [SerializeField] - float maxClearance = 1.8f; - - [Tooltip("Parts of segments with less unobstructed space will be erased. Should equal the height of your smallest NavAgent.")] - [SerializeField] - float minClearance = 0.1f; - - [Tooltip("Size of a single segment part. Smaller numbers increase the accuracy of obstruction calculations at the expense of both bake and runtime performance.")] - [SerializeField] - float cellSize = 0.1f; - - [Tooltip("Colliders to consider for the bake process.")] - [SerializeField] - LayerMask includedColliders = ~0; - - - [Tooltip("Use only colliders from gameobjects marked static.")] - [SerializeField] - bool onlyStaticColliders = false; - - [Tooltip("Segments exceeding this angle are removed from the bake output. Should equal the highest slope angle of your NavAgents.")] - [SerializeField] - [Range(0, 180)] - float maxSlopeAngle = 180f; - - [Tooltip("Parameter for the line simplifier (Ramer-Douglas-Peucker). Higher values reduce overall segment count at the expense of fitting the original collider shape.")] - [SerializeField] - float smallestDistanceYouCareAbout = 0.1f; - - [Tooltip("Segments shorter than this will be removed from the bake output.")] - [SerializeField] - float minSegmentLength = 0.1f; - - [SerializeField] - private List navSegments = new List(); - - [SerializeField, HideInInspector] - private Rect localBoundingRect; - [SerializeField, HideInInspector] - private float totalLineLength; - [SerializeField, HideInInspector] - // version of bake algorithm this surface was last baked with - private int bakeVersion = 0; - [SerializeField, HideInInspector] - // number of distinct bakes - private int bakeIteration = 0; - - Matrix4x4 localToWorldMat; - - #region Unity_Methods - private void Awake() - { - UpdateLocalMatrix(); - PBComponentId = PBWorld.GeneratePBComponentId(); - PBWorld.NavGraphChangeSource.OnGraphChange += NavGraphChangeSource_OnGraphChange; - } - - private void OnEnable() - { - if (navSegments != null && navSegments.Count > 0) - { - PBWorld.NavGraph.AddNavSurface(this); - } - } - - private void OnDisable() - { - PBWorld.NavGraph.RemoveNavSurface(this); - } - - private void OnValidate() - { - if (minClearance <= 0) - minClearance = 0.1f; - if (maxClearance <= minClearance) - maxClearance = minClearance + 0.1f; - if (cellSize <= 0) - cellSize = 0.1f; - - BakeJob = new NavSurfaceBakeJob(this); - hasDataChanged = true; - } - - private void Update() - { - UpdateLocalMatrix(); - } - - #endregion - - public Vector2 LocalToWorld(Vector2 pos) - { - return LocalToWorldMatrix.MultiplyPoint3x4(pos); - } - - public Matrix4x4 LocalToWorldMatrix - { - get - { - return localToWorldMat; - } - } - - internal Matrix4x4 LocalToWorldMatrixEditor - { - get - { - return Matrix4x4.TRS(transform.position, Quaternion.Euler(0, 0, transform.rotation.eulerAngles.z), Vector3.one); ; - } - } - - public Vector2 WorldToLocal(Vector2 pos) - { - return WorldToLocalMatrix.MultiplyPoint3x4(pos); - } - - public Matrix4x4 WorldToLocalMatrix => LocalToWorldMatrix.inverse; - - /// - /// Updates NavSurface baked data. Baking largely runs in a different thread. This function should be run as a Coroutine. NavSurface will be removed from World first and added back, when baking is completed. - /// Calling this function before the previous bake job completed, will abort the previous job. - /// - public IEnumerator Bake() - { - PBWorld.NavGraph.RemoveNavSurface(this); - StartBakeJob(); - - while (!BakeJob.IsFinished) - { - yield return null; - } - UpdateInternalData(BakeJob.navSegments, BakeJob.bounds); - PBWorld.NavGraph.AddNavSurface(this); - - OnBakingCompleted?.Invoke(); - } - - internal void StartBakeJob() - { - UpdateLocalMatrix(); - if (BakeJob == null) - BakeJob = new NavSurfaceBakeJob(this); - else - BakeJob.AbortJoin(); - - var subtractors = GetComponentsInChildren(); - Tuple[] substractorRects = new Tuple[subtractors.Length]; - for (int i = 0; i < subtractors.Length; i++) - { - var rT = subtractors[i].GetComponent(); - var rect = rT.rect; - Vector2 scaleFactor = rT.lossyScale * rect.size * 0.5f; - Vector2 center = rect.center; - - rect.min = center - scaleFactor + (Vector2)rT.position; - rect.max = center + scaleFactor + (Vector2)rT.position; - - substractorRects[i] = new Tuple(rect, new Vector2(subtractors[i].fromAngle, subtractors[i].toAngle)); - } - - var filter = new ColliderLayerFilter(includedColliders, onlyStaticColliders); - var allColliders = filter.Filter(this.GetComponentsInChildren()).ToArray(); - - var it = new IntersectionTester(this, WorldToLocalMatrix); - Polygon[][] polygons = new Polygon[allColliders.Length][]; - for (int i = 0; i < allColliders.Length; i++) - { - var col = allColliders[i]; - polygons[i] = it.ColliderToPolygon(col); - } - - BakeJob.Start(polygons, it, substractorRects, WorldToLocalMatrix); - } - - internal NavSegment GetSegment(int index) - { - return navSegments[index]; - } - - internal void UpdateInternalData(List segments, Rect bounds) - { - if (segments == null) - { - Debug.LogError("Updating NavSurface failed. Got null as segments"); - return; - } - - this.localBoundingRect = Geometry.TransformBoundingRect(bounds, WorldToLocalMatrix); - - this.totalLineLength = 0; - foreach (var seg in segments) - totalLineLength += seg.Length; - - this.navSegments = segments; - bakeVersion = CurrentBakeVersion; - hasDataChanged = true; - bakeIteration++; - } - - /// - /// Filters and rethrows change events that have this NavSurface as target. It's a convenience feature. - /// You may also just subscribe to PBWorld.NavGraphChangeSource.OnGraphChange and filter the changes yourself. - /// - /// - /// - /// - private void NavGraphChangeSource_OnGraphChange(NavGraphChange arg1, int srcCompId) - { - if (srcCompId == PBComponentId) - { - switch (arg1) - { - case NavGraphChange.NavSurfaceAdded: - OnReadyToPathfind?.Invoke(); - break; - case NavGraphChange.NavSurfaceRemoved: - OnRemovedFromPathfinding?.Invoke(); - break; - default: - // this could happen if there is another component on this gameobject which the change event was directed at. Just ignore it. - break; - } - } - } - - private void UpdateLocalMatrix() - { - localToWorldMat = Matrix4x4.TRS(transform.position, Quaternion.Euler(0, 0, transform.rotation.eulerAngles.z), Vector3.one); - } - } -} \ No newline at end of file diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/NavSurface.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/NavSurface.cs.meta deleted file mode 100644 index afd2205b..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/NavSurface.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 7616445e6074b27418ea1cd9bf9902f8 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: -55 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/PBWorld.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d/PBWorld.cs deleted file mode 100644 index 865e6952..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/PBWorld.cs +++ /dev/null @@ -1,235 +0,0 @@ -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Threading; -using UnityEngine; -using UnityEngine.SceneManagement; - -namespace PathBerserker2d -{ - /// - /// Singleton managing the global NavGraph instance. - /// - /// - /// Is instantiated automatically on scene load. - /// - /// Use it to access the NavGraph, which is the graph the pathfinder works on. - /// - [ScriptExecutionOrder(-100), AddComponentMenu("")] - public class PBWorld : MonoBehaviour - { - [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] - private static void Initialize() - { - PathBerserker2dSettings.instance = Resources.Load(PathBerserker2dSettings.GlobalSettingsFile); - var world = new GameObject("PBWorld").AddComponent(); - DontDestroyOnLoad(world); - instance = world; - } - - private static PBWorld instance; - - internal static NavGraph NavGraph { get; set; } - public static INavGraphChangeSource NavGraphChangeSource => NavGraph; - - // threading stuff - CancellationTokenSource pathfinderThreadCancelationSource; - ConcurrentQueue pathRequestQueue; - - private float lastGraphUpdate = -100; - - #region UNITY_METHODS - private void Awake() - { - SceneManager.sceneUnloaded += SceneManager_sceneUnloaded; - } - - private void SceneManager_sceneUnloaded(Scene arg0) - { - // cycle the navgraph one more time to remove all unloaded navgraphs in case the scene is just reloaded - NavGraph.ForceApplyChanges(); - } - - private void OnEnable() - { - NavGraph = new NavGraph(PathBerserker2dSettings.PathfinderThreadCount); - - // create pathfinder threads - pathRequestQueue = new ConcurrentQueue(); - pathfinderThreadCancelationSource = new CancellationTokenSource(); - StartPathfinderThreads(); - } - - private void Start() - { - NavGraph.Update(); - } - - private void OnDisable() - { - pathfinderThreadCancelationSource.Cancel(); - } - - private void Update() - { - if (Time.time - lastGraphUpdate > PathBerserker2dSettings.InitiateUpdateInterval) - { - NavGraph.Update(); - lastGraphUpdate = Time.time; - } - } - - private void Reset() - { - Debug.LogError("This component should not be added manually. It will be automatically instantiated at runtime."); - DestroyImmediate(this); - } - #endregion - - /// - /// Tries to map a point to a navigation position. The distance a point can be away from the nearest segment is specified by .PointMappingDistance - /// - /// Position to map - /// Pointer to mapped position or an invalid pointer, if mapping failed. - /// True, if mapping succeeded - public static bool TryMapPoint(Vector2 position, out NavSegmentPositionPointer pointer) - { - return NavGraph.TryMapPoint(position, out pointer); - } - - /// - /// Tries to map a point to a navigation position. The distance a point can be away is determined by searchRadius - /// - /// Position to map - /// Pointer to mapped position or an invalid pointer, if mapping failed. - /// Maxium search distance when trying to map. - /// True, if mapping succeeded - public static bool TryMapPoint(Vector2 position, float searchRadius, out NavSegmentPositionPointer pointer) - { - return NavGraph.TryMapPoint(position, p => true, searchRadius, out pointer); - } - - /// - /// Tries to map a point to a navigation position. The distance a point can be away is determined by searchRadius. Also makes sure that the point is traversable for the supplied NavAgent. - /// - /// Position to map - /// Pointer to mapped position or an invalid pointer, if mapping failed. - /// Maxium search distance when trying to map. - /// Maxium search distance when trying to map. - /// True, if mapping succeeded - public static bool TryMapPoint(Vector2 position, float searchRadius, NavAgent agent, out NavSegmentPositionPointer pointer) - { - return NavGraph.TryMapPoint(position, p => agent.CouldBeLocatedAt(p), searchRadius, out pointer); - } - - /// - /// Tries to map an Agent to a navigation position. Uses last mapping to speed up search. Will only map the agent to a surface it could traverse. - /// - /// Position to map - /// Pointer with the previously mapped position. Taken as start for search. - /// True, if mapping succeeded - internal static bool TryMapAgent(Vector2 position, NavSegmentPositionPointer lastMapping, NavAgent agent, out NavSegmentPositionPointer result) - { - return NavGraph.TryMapAgent(position, lastMapping, agent, out result); - } - - internal static bool TryMapPointWithStaged(Vector2 position, out NavSegmentPositionPointer pointer) - { - return NavGraph.TryMapPointWithStaged(position, out pointer); - } - - /// Random point on NavGraph. Might not be reachable. - public static Vector2 GetRandomPointOnGraph() - { - return NavGraph.GetRandomPointOnGraph(); - } - - /// - /// Enqueues a . The path will be solved async. Use the PathRequest object to check its status. - /// - /// PathRequest object representing the pathfinding job. - public static void PathTo(PathRequest pathRequest) - { - pathRequest.SetToPending(); -#if PBDEBUG - Debug.Log($"PathRequest from: {pathRequest.start.GetPosition()} to: {pathRequest.goals[0].GetPosition()}"); -#endif - instance.pathRequestQueue.Enqueue(pathRequest); - } - - /// - /// Get all segments intersecting a rotated box. Segments can additionally be filtered by angle. - /// - /// Intersection rect. - /// The rotation of the rect around its center. - /// Minium angle in degree of returned segments. - /// Maximum angle in degree of returned segments. - public static List BoxCast(Rect rect, float rotation, float filterFromAngle, float filterToAngle) - { - filterFromAngle = ClampAngle(filterFromAngle); - filterToAngle = ClampAngle(filterToAngle); - return NavGraph.BoxCast(rect, rotation, filterFromAngle, filterToAngle); - } - - internal static List BoxCastWithStaged(Rect rect, float rotation, float filterFromAngle, float filterToAngle) - { - return NavGraph.BoxCastWithStaged(rect, rotation, filterFromAngle, filterToAngle); - } - - /// - /// Similar to TryMapPoint, but meant for mapping goal positions. Has a configurable search radius. - /// - /// Position to map - /// Maximum distance away from position a mapping is allowed to be. - /// Mapped pointer - /// True, if successfully mapped. - [Obsolete("Use TryMapPoint instead")] - public static bool TryFindClosestPointTo(Vector2 position, float maxMappingDistance, out NavSegmentPositionPointer pointer) - { - return NavGraph.TryMapPoint(position, (p) => true, maxMappingDistance, out pointer); - } - - /// - /// Get the position the is pointing at. - /// - internal static NavGraphNodeCluster GetClusterFromPositionPointer(NavSegmentPositionPointer pointer) - { - NavGraphNodeCluster cluster = null; - NavGraph.TryGetClusterAt(pointer, out cluster); - return cluster; - } - - private static int nextFreeComponentId = 1; - internal static int GeneratePBComponentId() - { - return nextFreeComponentId++; - } - - private void StartPathfinderThreads() - { - if (Application.platform == RuntimePlatform.WebGLPlayer) - { - PathfinderThread p = new PathfinderThread(pathfinderThreadCancelationSource.Token, pathRequestQueue, NavGraph, 0); - StartCoroutine(p.CoroutineRun()); - } - else - { - for (int i = 0; i < PathBerserker2dSettings.PathfinderThreadCount; i++) - { - PathfinderThread p = new PathfinderThread(pathfinderThreadCancelationSource.Token, pathRequestQueue, NavGraph, i); - Thread t = new Thread(p.Run); - t.Start(); - } - } - } - - private static float ClampAngle(float angle) - { - while (angle > 360) - angle -= 360; - while (angle < 0) - angle += 360; - return angle; - } - } -} diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/PBWorld.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/PBWorld.cs.meta deleted file mode 100644 index ee2ff044..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/PBWorld.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 2048e50ad4fa22d40b52f955baa925d9 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: -100 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/PathBerserker2d.asmdef b/Assets/PathBerserker2d/Scripts/PathBerserker2d/PathBerserker2d.asmdef deleted file mode 100644 index 0f938ca9..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/PathBerserker2d.asmdef +++ /dev/null @@ -1,15 +0,0 @@ -{ - "name": "PathBerserker2d", - "references": [ - "GUID:75469ad4d38634e559750d17036d5f7c" - ], - "includePlatforms": [], - "excludePlatforms": [], - "allowUnsafeCode": false, - "overrideReferences": false, - "precompiledReferences": [], - "autoReferenced": true, - "defineConstraints": [], - "versionDefines": [], - "noEngineReferences": false -} \ No newline at end of file diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/PathBerserker2d.asmdef.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/PathBerserker2d.asmdef.meta deleted file mode 100644 index 4d6ad38e..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/PathBerserker2d.asmdef.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: f483b8ed1e509354483048b0c7a56768 -AssemblyDefinitionImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/PathBerserker2dSettings.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d/PathBerserker2dSettings.cs deleted file mode 100644 index 649572c4..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/PathBerserker2dSettings.cs +++ /dev/null @@ -1,298 +0,0 @@ -using System; -using UnityEngine; - -namespace PathBerserker2d -{ - /// - /// Contains all project wide settings for PathBerserker2d. - /// - /// - /// Find it at *Edit/Project Settings/PathBerserker2d* - /// - public class PathBerserker2dSettings : ScriptableObject - { - public const string GlobalSettingsFolder = "Assets/PathBerserker2d/Resources"; - public const string GlobalSettingsFile = "PathBerserker2dSettings"; - - internal readonly static string[] buildinNavLinkTypeNames = new string[] { - "corner", // -1 - "jump", - "fall", - "teleport", - "climb", - "elevator" - }; - - internal static PathBerserker2dSettings instance; - - /// - /// Should unselected links be drawn? Only relevant when not in play mode. - /// - public static bool DrawUnselectedLinks { get { return instance.drawUnselectedLinks; } } - - /// - /// Array of all link type names - /// - public static string[] NavLinkTypeNames { get { return instance.navLinkTypeNames; } } - - /// - /// Array of all NavTag colors - /// - public static Color[] NavLinkTypeColors { get { return instance.navLinkTypeColors; } } - - /// - /// Array of all NavTag names - /// - public static string[] NavTags { get { return instance.navTags; } } - - /// - /// Array of all NavTag colors - /// - public static Color[] NavTagColors { get { return instance.navTagColors; } } - - /// - /// Should unselected surfaces be drawn? Only relevant when not in play mode. - /// - public static bool DrawUnselectedSurfaces { get { return instance.drawUnselectedSurfaces; } } - - /// - /// Should unselected substractors be drawn? Only relevant when not in play mode. - /// - public static bool DrawUnselectedSubstractors { get { return instance.drawUnselectedSubstractors; } } - - /// - /// Should unselected area markers be drawn? Only relevant when not in play mode. - /// - public static bool DrawUnselectedAreaMarkers { get { return instance.drawUnselectedAreaMarkers; } } - - /// - /// Maximum distance a point will try to be mapped to the NavGraph. Used in performance critical functions (e.g. mapping a NavAgents position) and should be as small as possible. - /// - public static float PointMappingDistance { get { return instance.pointMappingDistance; } } - - /// - /// Time between NavGraph updates. NavGraph queues changes to apply them in batch at this interval. Lower values will lower performance. - /// - public static float InitiateUpdateInterval { get { return instance.initiateUpdateInterval; } } - - /// - /// Amount of threads used for pathfinding. NOTE: WebGL doesn't support threads. If you build for WebGL this number is meaningless. - /// - public static int PathfinderThreadCount - { - get - { - if (Application.platform == RuntimePlatform.WebGLPlayer) - return 1; - return instance.pathfinderThreadCount; - } - } - - /// - /// Draw the NavGraph while in play mode? - /// - public static bool DrawGraphWhilePlaying { get { return instance.drawGraphWhilePlaying; } } - - /// - /// Maximum distance to search for the nearest NavGraph position to a point. Used in functions to e.g. map a mouse cursor click to a nav position. Make it as large as you want. - /// - [System.Obsolete] - public static float ClosestToSegmentMaxDistance { get { return instance.closestToSegmentMaxDistance; } } - - /// - /// Line width of NavGraph/NavSurface visualization. - /// - public static float NavSurfaceLineWidth { get { return instance.navSurfaceLineWidth; } } - - /// - /// Line width of NavAreaMarker visualization (only visible in playmode) - /// - public static float NavAreaMarkerLineWidth { get { return instance.navAreaMarkerLineWidth; } } - - /// - /// Whether to convert a PolygonCollider2d to a polygon with CreateMesh() or by reading its first Path. - /// - public static bool UsePolygonCollider2dPathsForBaking { get { return instance.usePolygonCollider2dPathsForBaking; } } - - /// - /// Converts a link type name to its corresponding integer. Throws an ArgumentException if name is not a valid link type name. - /// - public static int GetLinkTypeFromName(string name) - { - var names = NavLinkTypeNames; - for (int i = 0; i < names.Length; i++) - { - if (name == names[i]) - return i; - } - throw new ArgumentException(name + "is not a valid link type name. (case sensitive!)"); - } - - [Tooltip("Maximum distance a point will try to be mapped to the NavGraph. Used in performance critical functions (e.g. mapping a NavAgents position) and should be as small as possible.")] - [Header("Pathfinding")] - [SerializeField, HideInInspector] - private float pointMappingDistance = 0.1f; - - [SerializeField, HideInInspector] - private int pathfinderThreadCount = 1; - - [Tooltip("Time between NavGraph updates. NavGraph queues changes to apply them in batch at this interval. Lower values will lower performance.")] - [SerializeField, HideInInspector] - private float initiateUpdateInterval = 0.1f; - - [Tooltip("Maximum distance to search for the nearest NavGraph position to a point. Used in functions to e.g. map a mouse cursor click to a nav position. Make it as large as you want.")] - [SerializeField, HideInInspector] - private float closestToSegmentMaxDistance = 20; - - [Header("NavLinks")] - [SerializeField, HideInInspector] - private string[] navLinkTypeNames = new string[] { }; - [SerializeField, HideInInspector] - private Color[] navLinkTypeColors = new Color[] { }; - - [Header("NavSegments")] - [SerializeField, HideInInspector] - private string[] navTags = new string[] { "default" }; - [SerializeField, HideInInspector] - private Color[] navTagColors = new Color[] { Color.clear }; - - [Tooltip("Should unselected links be drawn? Only relevant when not in play mode.")] - [Header("Visualization")] - [SerializeField, HideInInspector] - private bool drawUnselectedLinks = true; - - [Tooltip("Should unselected surfaces be drawn? Only relevant when not in play mode.")] - [SerializeField, HideInInspector] - private bool drawUnselectedSurfaces = true; - - [Tooltip("Should unselected substractors be drawn? Only relevant when not in play mode.")] - [SerializeField, HideInInspector] - private bool drawUnselectedSubstractors = true; - - [Tooltip("Should unselected area markers be drawn? Only relevant when not in play mode.")] - [SerializeField, HideInInspector] - private bool drawUnselectedAreaMarkers = true; - - [Tooltip("Draw the NavGraph while in play mode?")] - [SerializeField, HideInInspector] - private bool drawGraphWhilePlaying = true; - - [Tooltip("Line width of NavGraph/NavSurface visualization")] - [SerializeField, HideInInspector] - private float navSurfaceLineWidth = 0.04f; - - [Tooltip("Line width of NavAreaMarker visualization (only visible in playmode)")] - [SerializeField, HideInInspector] - private float navAreaMarkerLineWidth = 0.04f; - - [Tooltip("Whether to convert a PolygonCollider2d to a polygon with CreateMesh() or by reading its first Path.")] - [SerializeField, HideInInspector] - private bool usePolygonCollider2dPathsForBaking = false; - - internal void OnValidate() - { - ValidateLinkTypeNames(); - pointMappingDistance = Mathf.Max(0.001f, pointMappingDistance); - pathfinderThreadCount = Mathf.Max(1, pathfinderThreadCount); - initiateUpdateInterval = Mathf.Max(0.1f, initiateUpdateInterval); - - navTags[0] = "default"; - navTagColors[0] = Color.clear; - if (navTags.Length > 32) - { - System.Array.Resize(ref navTags, 32); - } - if (navTagColors.Length != navTags.Length) - { - int oldLength = navTagColors.Length; - System.Array.Resize(ref navTagColors, navTags.Length); - for (int i = oldLength; i < navTags.Length; i++) - navTagColors[i] = DifferentColors.GetColor(i); - } - } - - internal void ValidateLinkTypeNames() - { - if (navLinkTypeNames.Length < buildinNavLinkTypeNames.Length) - { - navLinkTypeNames = new string[buildinNavLinkTypeNames.Length]; - } - if (navLinkTypeNames.Length > 32) - { - System.Array.Resize(ref navLinkTypeNames, 32); - } - if (navLinkTypeColors.Length != navLinkTypeNames.Length) - { - int oldLength = navLinkTypeColors.Length; - System.Array.Resize(ref navLinkTypeColors, navLinkTypeNames.Length); - for (int i = oldLength; i < navLinkTypeNames.Length; i++) - navLinkTypeColors[i] = DifferentColors.GetColor(i); - } - - for (int i = 0; i < buildinNavLinkTypeNames.Length; i++) - { - navLinkTypeNames[i] = buildinNavLinkTypeNames[i]; - } - } - - /// - /// Get the human readable name of a specific link type. - /// - public static string GetLinkTypeName(int linkType) - { - return instance.navLinkTypeNames[linkType]; - } - - /// - /// Get color associated with specific link type. - /// - public static Color GetLinkTypeColor(int linkType) - { - return instance.navLinkTypeColors[linkType]; - } - - /// - /// Set the color of a specific NavLinkType. - /// - internal static void SetLinkTypeColor(int navTag, Color color) - { - instance.navLinkTypeColors[navTag] = color; - } - - /// - /// Get the assigned color of a specific NavTag. - /// - public static Color GetNavTagColor(int navTag) - { - return instance.navTagColors[navTag]; - } - - /// - /// If the NavTag does not exists, returns 0 - /// - public static int EnsureNavTagExists(int navTag) - { - if (navTag < 0 || navTag >= NavTags.Length) - return 0; - return navTag; - } - - /// - /// Set the color of a specific NavTag. - /// - internal static void SetNavTagColor(int navTag, Color color) - { - instance.navTagColors[navTag] = color; - } - - /// - /// If the linkType does not exists, returns 0 - /// - public static int EnsureNavLinkTypeExists(int linkType) - { - if (linkType < 0 || linkType >= NavLinkTypeNames.Length) - return 1; - return linkType; - } - } -} diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/PathBerserker2dSettings.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/PathBerserker2dSettings.cs.meta deleted file mode 100644 index b6117011..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/PathBerserker2dSettings.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 393b1ec75130eb047bc70f7635277936 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/Pathfinder.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/Pathfinder.meta deleted file mode 100644 index e975e822..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/Pathfinder.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: df7508c295beef243878bd13a3a37d46 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/Pathfinder/Path.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d/Pathfinder/Path.cs deleted file mode 100644 index 57fec3ac..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/Pathfinder/Path.cs +++ /dev/null @@ -1,111 +0,0 @@ -using System.Collections; -using System.Collections.Generic; -using UnityEngine; - -namespace PathBerserker2d -{ - /// - /// A path ready to be traversed - /// - public class Path : IEnumerator - { - public PathSegment Current { get; private set; } - object IEnumerator.Current => Current; - - public PathSegment NextSegment { get { return Current.Next; } } - public bool HasNext { get { return Current.Next != null; } } - - public Vector2 Goal => lastSeg.LinkStart; - public Vector2 Start => start; - public readonly float totalCosts; - - private readonly PathSegment firstSeg; - private readonly PathSegment lastSeg; - private readonly int segmentCount; - private readonly Vector2 start; - private int remainingSegmentCount; - - internal Path(PathSegment firstSeg, PathSegment lastSeg, Vector2 start, int segCount, float totalCosts) - { - this.firstSeg = firstSeg; - this.lastSeg = lastSeg; - this.Current = firstSeg; - this.segmentCount = segCount; - this.remainingSegmentCount = segCount; - this.totalCosts = totalCosts; - this.start = start; - } - - public override string ToString() - { - return string.Format("Path (VertCount: {0}, Costs: {1})", segmentCount, totalCosts); - } - - public void Dispose() - { - - } - - /// - /// Advanced the path by 1 segment. - /// - public bool MoveNext() - { - if (Current.Next != null) - { - Current = Current.Next; - remainingSegmentCount--; - return true; - } - return false; - } - - public void Reset() - { - remainingSegmentCount = segmentCount; - Current = firstSeg; - } - - /// - /// Creates a list of all path points. Current enumerator progress is ignored. - /// List starts with path start and ends with path goal. Corner links will result in the same point being enumerated twice in a row. - /// - public List AllPathPoints() - { - List pathPoints = new List(segmentCount * 2 + 2); - pathPoints.Add(Start); - - var seg = firstSeg; - while (seg.Next != null) - { - pathPoints.Add(seg.LinkStart); - pathPoints.Add(seg.LinkEnd); - seg = seg.Next; - } - pathPoints.Add(Goal); - return pathPoints; - } - - /// - /// Creates a list of all path points, starting from current segment. - /// List starts with current.linkstart and ends with path goal. If these points are equivalent, only goal will be returned. Corner links will result in the same point being enumerated twice in a row. - /// - public List RemainingPathPoints() - { - List pathPoints = new List(remainingSegmentCount * 2 + 2); - pathPoints.Add(Current.LinkStart); - - var seg = Current; - while (seg.Next != null) - { - pathPoints.Add(seg.LinkStart); - pathPoints.Add(seg.LinkEnd); - seg = seg.Next; - } - - if (Current.Next != null) - pathPoints.Add(Goal); - return pathPoints; - } - } -} diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/Pathfinder/Path.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/Pathfinder/Path.cs.meta deleted file mode 100644 index 3c85bf97..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/Pathfinder/Path.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 58dedc7e6d80873469cc62eee12e4a34 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/Pathfinder/PathRequest.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d/Pathfinder/PathRequest.cs deleted file mode 100644 index 6dd2655c..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/Pathfinder/PathRequest.cs +++ /dev/null @@ -1,90 +0,0 @@ -using System.Collections.Generic; -using UnityEngine; - -namespace PathBerserker2d -{ - /// - /// Represents an async path request. - /// - public class PathRequest - { - public enum RequestState { - Draft, - Pending, - Finished, - Failed - } - - public enum RequestFailReason { - CouldntMapStart, - CouldntMapGoal, - MappedStartChanged, - AllMappedGoalsChanged, - NoPathFromStartToGoal, - WorldWasDestroyed, - ToFarFromStart, - } - - /// - /// Status of the processing of the request. - /// - public RequestState Status{ get { return status; } } - /// - /// If the request failed, it will set this field to the cause of failure. - /// - public RequestFailReason FailReason { get; private set; } - /// - /// If the request succeeded, this is found path. - /// - public Path Path { get; private set; } - - /// - /// Start of the requested path - /// - public NavSegmentPositionPointer start; - /// - /// Goals of the requested path. - /// - public IList goals; - /// - /// NavAgent the calculated path should be usable by. - /// - public NavAgent client; - - /// - /// If the request failed, this will contain the closest reachable position found to the goal. This does NOT work when multiple goals where specified. - /// - public NavSegmentPositionPointer closestReachablePosition; - private volatile RequestState status = RequestState.Draft; - - public PathRequest(NavAgent client) - { - this.client = client; - this.start = client.currentMappedPosition; - } - - internal void SetToPending() - { - status = RequestState.Pending; - } - - internal void Reset() - { - Debug.Assert(status != RequestState.Pending); - status = RequestState.Draft; - } - - internal void Fulfill(Path path) { - this.Path = path; - this.status = RequestState.Finished; - } - - internal void Fail(RequestFailReason requestFailReason) { - this.FailReason = requestFailReason; - this.status = RequestState.Failed; -#if PBDEBUG - Debug.Log("Pathrequest failed because " + requestFailReason); -#endif - } - } -} diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/Pathfinder/PathRequest.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/Pathfinder/PathRequest.cs.meta deleted file mode 100644 index 4a76ed3b..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/Pathfinder/PathRequest.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 2750643c1f0175e4891d9493e72b9cc6 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/Pathfinder/PathSegment.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d/Pathfinder/PathSegment.cs deleted file mode 100644 index 47e8b649..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/Pathfinder/PathSegment.cs +++ /dev/null @@ -1,77 +0,0 @@ -using UnityEngine; - -namespace PathBerserker2d -{ - /// - /// Encapsulates the movement on a segment to a link and the traversal of that link. - /// - /// - /// Only the last PathSegment does not have a link. - /// - public class PathSegment - { - public PathSegment Next { get; internal set; } - /// - /// World position of the link start. May change from frame to frame, if corresponding NavSurface moves. - /// - public Vector2 LinkStart { get { return owner.LocalToWorld(linkStart); } } - /// - /// World position of the link end. May change from frame to frame, if corresponding NavSurface moves. - /// - public Vector2 LinkEnd { get { return Next.owner.LocalToWorld(linkEnd); } } - /// - /// Segments normal. May change from frame to frame, if corresponding NavSurface moves. - /// - public Vector2 Normal => owner.LocalToWorldMatrix.MultiplyVector(cluster.Normal); - /// - /// Segments tangent. May change from frame to frame, if corresponding NavSurface moves. - /// - public Vector2 Tangent => owner.LocalToWorldMatrix.MultiplyVector(cluster.Tangent); - /// - /// Point on segment that together with Tangent defines the segments line equation. May change from frame to frame, if corresponding NavSurface moves. - /// - public Vector2 Point => owner.LocalToWorldMatrix.MultiplyPoint3x4(cluster.Start); - - public readonly INavLinkInstance link; - public readonly NavSurface owner; - private Vector2 linkStart; - private Vector2 linkEnd; - internal NavGraphNodeCluster cluster; - - internal PathSegment(Vector2 linkStart, Vector2 linkEnd, NavSurface owner, INavLinkInstance link, NavGraphNodeCluster cluster) - { - this.linkStart = linkStart; - this.linkEnd = linkEnd; - this.owner = owner; - this.link = link; - this.cluster = cluster; - } - - /// - /// Get the NavTag vector at a distance along the segment. - /// - /// Distance along segment. - /// Integer with bits set to the existence of the corresponding nav tag at that position. - public int GetTagVector(float t) - { - return cluster.GetNavTagVector(t); - } - - /// - /// Like GetTagVector, but works by projecting the parameter on the segment. - /// - /// Integer with bits set to the existence of the corresponding nav tag at that position. - public int GetTagVector(Vector2 pos) - { - return cluster.GetNavTagVector(owner.WorldToLocal(pos)); - } - - /// - /// Projects a position on the segment and returns its distance from the segment start Result may change from frame to frame, if corresponding NavSurface moves. - /// - public float DistanceAlongSegment(Vector2 pos) - { - return Vector2.Dot(cluster.Tangent, owner.WorldToLocal(pos) - cluster.Start); - } - } -} \ No newline at end of file diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/Pathfinder/PathSegment.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/Pathfinder/PathSegment.cs.meta deleted file mode 100644 index 2c156e05..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/Pathfinder/PathSegment.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: ad1de11ac5ee257459efc73dd2bb1eaa -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/Pathfinder/PathValues.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d/Pathfinder/PathValues.cs deleted file mode 100644 index 468ccf9b..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/Pathfinder/PathValues.cs +++ /dev/null @@ -1,17 +0,0 @@ -using Priority_Queue; - -namespace PathBerserker2d -{ - internal class PathValues : FastPriorityQueueNode - { - public NavGraphNode node; - public NavGraphNode parent; - public float costSoFar; - public float estimatedFutherPath; - - public PathValues(NavGraphNode node) - { - this.node = node; - } - } -} diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/Pathfinder/PathValues.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/Pathfinder/PathValues.cs.meta deleted file mode 100644 index 0e788af5..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/Pathfinder/PathValues.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 4eeeecfc6e39a704f89e7c3539b74bf6 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/Pathfinder/Pathfinder.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d/Pathfinder/Pathfinder.cs deleted file mode 100644 index 67fad4bd..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/Pathfinder/Pathfinder.cs +++ /dev/null @@ -1,339 +0,0 @@ -using Priority_Queue; -using System.Collections.Generic; -using UnityEngine; - -namespace PathBerserker2d -{ - internal class Pathfinder - { - FastPriorityQueue openList = new FastPriorityQueue(1000); - HashSet closedList = new HashSet(); - NavGraph navGraph; - int pathValueId; - - float maxHeuristicAllowed; - NavSegmentPositionPointer closestReachablePosition; - NavAgent agent; - - public Pathfinder(NavGraph navGraph, int pathValueId) - { - this.navGraph = navGraph; - this.pathValueId = pathValueId; - } - - public void ProcessPathRequest(PathRequest request) - { - Path path = null; - this.agent = request.client; - - navGraph.graphLock.AcquireReaderLock(-1); - try - { - NavGraphNodeCluster startCluster; - if (!navGraph.TryGetClusterAt(request.start, out startCluster)) - { - request.Fail(PathRequest.RequestFailReason.MappedStartChanged); - return; - } - NavGraphNode nvStart = new NavGraphNode(pathValueId + 1, startCluster, request.start.t); - closestReachablePosition = request.start; - - IList nvGoals = new List(request.goals.Count); - NavGraphNodeCluster goalCluster; - for (int iGoal = 0; iGoal < request.goals.Count; iGoal++) - { - if (navGraph.TryGetClusterAt(request.goals[iGoal], out goalCluster)) - { - nvGoals.Add(new NavGraphNode(pathValueId + 1, goalCluster, request.goals[iGoal].t)); - goalCluster.containsGoal[pathValueId] = true; - } - } - if (nvGoals.Count == 0) - { - request.Fail(PathRequest.RequestFailReason.AllMappedGoalsChanged); - return; - } - - if (nvGoals.Count == 1) - { - path = this.FindPathSingleGoal(nvStart, nvGoals); - } - else - { - path = this.FindPathMultiGoal(nvStart, nvGoals); - } - maxHeuristicAllowed = float.MaxValue; - - for (int iGoal = 0; iGoal < nvGoals.Count; iGoal++) - { - nvGoals[iGoal].cluster.containsGoal[pathValueId] = false; - } - } - finally - { - navGraph.graphLock.ReleaseReaderLock(); - } - - if (path == null) - { - request.closestReachablePosition = closestReachablePosition; - request.Fail(PathRequest.RequestFailReason.NoPathFromStartToGoal); - } - else - { - request.Fulfill(path); - } - - } - - private Path FindPathSingleGoal(NavGraphNode start, IList goals) - { - Vector2 goalPos = goals[0].WPosition(); - Path path = null; - float closestH = float.MaxValue; - - Restart: - foreach (var conn in start.cluster.EnumerateReachableNavVerts(start.t, agent, goals, pathValueId)) - { - Expand(conn, start, goalPos); - } - UpdateClosestPositionToGoal(start, goalPos, ref closestH); - -#if PBDEBUG - int iterationCount = 0; -#endif - while (openList.Count > 0) - { -#if PBDEBUG - iterationCount++; -#endif - var vert = openList.Dequeue(); - var node = vert.node; - /*GizmosQueue.Instance.Enqueue(1, () => - { - Gizmos.color = Color.yellow; - Vector3 v = vert.WPosition(); - v.z = 5; - DebugDrawingExtensions.DrawCircle(v, 0.1f); - });*/ - if (node.IsGoal) - { - // reached goal !! - if (vert.costSoFar < 0) - { - Debug.LogError("Path found with negative values. This breaks pathfinding. Found path will be thrown away."); - return path; - } - - float v = CheckHeuristicValidity(start, node); - if (v != 0) - { - // heuristic was violated! start over. -#if PBDEBUG - Debug.Log("Heuristic was violated. Retrying with upper bound."); -#endif - maxHeuristicAllowed = v; - openList.Clear(); - closedList.Clear(); - - goto Restart; - } - - path = GatherPath(start, node); - break; - } - - closedList.Add(node); - - UpdateClosestPositionToGoal(node, goalPos, ref closestH); - - foreach (var conn in vert.node.GetConnections(agent, goals, pathValueId)) - { - Expand(conn, node, goalPos); - } - } - - openList.Clear(); - closedList.Clear(); -#if NOPE_DEBUG - if (path != null) - Debug.Log(string.Format( - "Found in {0} iteration the path: {1}", iterationCount, path)); - else - { - Debug.Log(string.Format( - "Found no path in {0} iteration.", iterationCount)); - } -#endif - - return path; - } - - private Path FindPathMultiGoal(NavGraphNode start, IList goals) - { - Path path = null; - - foreach (var conn in start.cluster.EnumerateReachableNavVerts(start.t, agent, goals, pathValueId)) - { - ExpandZeroH(conn, start); - } - -#if PBDEBUG - int iterationCount = 0; -#endif - while (openList.Count > 0) - { -#if PBDEBUG - iterationCount++; -#endif - var vert = openList.Dequeue(); - var node = vert.node; - if (node.IsGoal) - { - // reached goal !! - if (vert.costSoFar < 0) - { - Debug.LogError("Path found with negative values. This breaks pathfinding. Found path will be thrown away."); - return path; - } - - path = GatherPath(start, node); - break; - } - - closedList.Add(node); - foreach (var conn in node.GetConnections(agent, goals, pathValueId)) - { - ExpandZeroH(conn, node); - } - } - - openList.Clear(); - closedList.Clear(); -#if PBDEBUG - if (path != null) - Debug.Log(string.Format( - "Found in {0} iteration the path: {1}", iterationCount, path)); - else - { - Debug.Log(string.Format( - "Found no path in {0} iteration.", iterationCount)); - } -#endif - return path; - } - - private void Expand(NavConnection conn, NavGraphNode vert, Vector2 goalPos) - { - if (float.IsPositiveInfinity(conn.traversalCosts) || closedList.Contains(conn.end)) - return; - - - float costSoFar = vert.pathValues[pathValueId].costSoFar + conn.traversalCosts; - var pathValue = conn.end.pathValues[pathValueId]; - - bool isOpen = openList.Contains(pathValue); - if (isOpen && pathValue.costSoFar <= costSoFar) - { - // we know about this vert and have a faster way of accessing it - return; - } - - pathValue.parent = vert; - pathValue.costSoFar = costSoFar; - - float estimate = conn.end.HeuristicalCostsToGoal(vert.cluster.owner.WorldToLocal.MultiplyPoint3x4(goalPos)); - if (estimate > maxHeuristicAllowed) - estimate = maxHeuristicAllowed; - pathValue.estimatedFutherPath = estimate; - float totalCosts = costSoFar + estimate; - if (isOpen) - { - openList.UpdatePriority(pathValue, totalCosts); - } - else - { - openList.Enqueue(pathValue, totalCosts); - } - } - - private void ExpandZeroH(NavConnection conn, NavGraphNode vert) - { - if (float.IsPositiveInfinity(conn.traversalCosts) || closedList.Contains(conn.end)) - return; - - float costSoFar = vert.pathValues[pathValueId].costSoFar + conn.traversalCosts; - var pathValue = conn.end.pathValues[pathValueId]; - - bool isOpen = openList.Contains(pathValue); - if (isOpen && pathValue.costSoFar <= costSoFar) - { - // we know about this vert and have a faster way of accessing it - return; - } - - pathValue.parent = vert; - pathValue.costSoFar = costSoFar; - - if (isOpen) - { - openList.UpdatePriority(pathValue, costSoFar); - } - else - { - openList.Enqueue(pathValue, costSoFar); - } - } - - private Path GatherPath(NavGraphNode startVert, NavGraphNode goalVert) - { - int segCount = 1; - NavGraphNode vert = goalVert; - PathSegment lastSeg = new PathSegment(goalVert.Position(), Vector2.zero, goalVert.cluster.owner.navSurface, null, vert.cluster); - PathSegment prevSeg = lastSeg; - - while ((vert = vert.pathValues[pathValueId].parent) != startVert) - { - var seg = new PathSegment( - vert.Position(), - vert.LinkTarget.GetPositionAlongSegment(vert.LinkTargetT), - vert.cluster.owner.navSurface, - vert.link, - vert.cluster); - seg.Next = prevSeg; - prevSeg = seg; - - segCount++; - } - return new Path(prevSeg, lastSeg, startVert.Position(), segCount, goalVert.pathValues[pathValueId].costSoFar); - } - - private float CheckHeuristicValidity(NavGraphNode startVert, NavGraphNode goalVert) - { - float totalCosts = goalVert.pathValues[pathValueId].costSoFar; - NavGraphNode vert = goalVert; - while ((vert = vert.pathValues[pathValueId].parent) != startVert) - { - if (vert.pathValues[pathValueId].estimatedFutherPath > totalCosts) - { - return totalCosts; - } - } - return 0; - } - - private void UpdateClosestPositionToGoal(NavGraphNode node, Vector2 goalPos, ref float closestH) - { - float minDist = node.cluster.PointDistance(goalPos); - if (minDist < closestH) - { - closestH = minDist; - float t = node.cluster.DistanceOfPointAlongSegment(node.cluster.owner.WorldToLocal.MultiplyPoint3x4(goalPos)); - if (node.cluster.CanAgentReachPoint(agent, node.t, t)) - { - closestReachablePosition = new NavSegmentPositionPointer(node.cluster.owner.navSurface, node.cluster, t); - } - } - } - } -} diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/Pathfinder/Pathfinder.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/Pathfinder/Pathfinder.cs.meta deleted file mode 100644 index db2d4e8f..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/Pathfinder/Pathfinder.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 79dde31c2ed068841b732c032be29020 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/Pathfinder/PathfinderThread.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d/Pathfinder/PathfinderThread.cs deleted file mode 100644 index cf4900a5..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/Pathfinder/PathfinderThread.cs +++ /dev/null @@ -1,55 +0,0 @@ -using System.Collections; -using System.Collections.Concurrent; -using System.Threading; -using UnityEngine; - -namespace PathBerserker2d -{ - internal class PathfinderThread - { - CancellationToken cancelToken; - ConcurrentQueue pathRequestQueue; - Pathfinder pathfinder; - - public PathfinderThread(CancellationToken cancelToken, - ConcurrentQueue pathRequestQueue, NavGraph navGraph, int id) - { - this.cancelToken = cancelToken; - this.pathRequestQueue = pathRequestQueue; - this.pathfinder = new Pathfinder(navGraph, id); - } - - public void Run() - { - while (!cancelToken.IsCancellationRequested) - { - // will process a path or sleep for 0.1sec - PathRequest request; - if (pathRequestQueue.TryDequeue(out request)) - { - pathfinder.ProcessPathRequest(request); - } - else - { - Thread.Sleep(100); - } - } - } - - public IEnumerator CoroutineRun() - { - while (!cancelToken.IsCancellationRequested) - { - // will process a path or sleep for 0.1sec - PathRequest request; - if (pathRequestQueue.TryDequeue(out request)) - { - pathfinder.ProcessPathRequest(request); - yield return null; - } - else - yield return new WaitForSecondsRealtime(0.1f); - } - } - } -} diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/Pathfinder/PathfinderThread.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/Pathfinder/PathfinderThread.cs.meta deleted file mode 100644 index 3f14e00b..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/Pathfinder/PathfinderThread.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: d35f8bee578d72940a6e7061df49850e -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/Utilities.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/Utilities.meta deleted file mode 100644 index 5ee049fa..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/Utilities.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 0ca86d6ef0e3c0146984f0794920e007 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/Utilities/B2DynamicTree.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d/Utilities/B2DynamicTree.cs deleted file mode 100644 index a18c83df..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/Utilities/B2DynamicTree.cs +++ /dev/null @@ -1,959 +0,0 @@ - -// MIT License - -// Copyright (c) 2019 Erin Catto - -// 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. - -// ported by me, orignal source: https://github.com/erincatto/box2d/blob/master/src/collision/b2_dynamic_tree.cpp - -using System; -using System.Collections; -using System.Collections.Generic; -using UnityEngine; - -namespace PathBerserker2d -{ - /// A node in the dynamic tree. The client does not interact with this directly. - internal struct B2TreeNode - { - /// Enlarged AABB - public Rect aabb; - - public T userData; - - public int parent; - public int child1; - public int child2; - public int next; - - // leaf = 0, free node = -1 - public int height; - - public bool moved; - - public bool IsLeaf() - { - return child1 == -1; - } - } - - internal class B2DynamicTree : IEnumerable - { - public int NodeCount => nodeCount; - - private readonly float AABBExtension = 0.1f; - private readonly float AABBMultiplier = 4.0f; - - int root = -1; - B2TreeNode[] nodes; - int nodeCount = 0; - int nextFreeNode = 0; - - public B2DynamicTree(int capacity = 16) - { - nodes = new B2TreeNode[capacity]; - - // Build a linked list for the free list. - for (int i = 0; i < nodes.Length - 1; ++i) - { - nodes[i].next = i + 1; - nodes[i].height = -1; - } - nodes[nodes.Length - 1].next = -1; - nodes[nodes.Length - 1].height = -1; - } - - // Allocate a node from the pool. Grow the pool if necessary. - private int AllocateNode() - { - // Expand the node pool as needed. - if (nextFreeNode == -1) - { -#if PBDEBUG - Debug.Assert(nodes.Length == nodeCount); -#endif - - // The free list is empty. Rebuild a bigger pool. - Array.Resize(ref nodes, nodes.Length * 2); - - // Build a linked list for the free list. The parent - // pointer becomes the "next" pointer. - for (int i = nodeCount; i < nodes.Length - 1; ++i) - { - nodes[i].next = i + 1; - nodes[i].height = -1; - } - nodes[nodes.Length - 1].next = -1; - nodes[nodes.Length - 1].height = -1; - nextFreeNode = nodeCount; - } - - // Peel a node off the free list. - int nodeId = nextFreeNode; - nextFreeNode = nodes[nodeId].next; - nodes[nodeId].parent = -1; - nodes[nodeId].child1 = -1; - nodes[nodeId].child2 = -1; - nodes[nodeId].height = 0; - nodes[nodeId].userData = default(T); - nodes[nodeId].moved = false; - ++nodeCount; - return nodeId; - } - - // Return a node to the pool. - private void FreeNode(int nodeId) - { -#if PBDEBUG - Debug.Assert(0 <= nodeId && nodeId < nodes.Length); - Debug.Assert(0 < nodeCount); -#endif - nodes[nodeId].next = nextFreeNode; - nodes[nodeId].height = -1; - nextFreeNode = nodeId; - --nodeCount; - } - - // Create a proxy in the tree as a leaf node. We return the index - // of the node instead of a pointer so that we can grow - // the node pool. - public int CreateProxy(Rect aabb, T userData) - { - int proxyId = AllocateNode(); - - // Fatten the aabb. - Vector2 r = new Vector2(AABBExtension, AABBExtension); - nodes[proxyId].aabb.min = aabb.min - r; - nodes[proxyId].aabb.max = aabb.max + r; - nodes[proxyId].userData = userData; - nodes[proxyId].height = 0; - nodes[proxyId].moved = true; - - InsertLeaf(proxyId); - - return proxyId; - } - - public void RemoveProxy(int proxyId) - { -#if PBDEBUG - Debug.Assert(0 <= proxyId && proxyId < nodes.Length); - Debug.Assert(nodes[proxyId].IsLeaf()); -#endif - - if (!nodes[proxyId].IsLeaf()) - throw new Exception("Tried to remove non leaf node"); - - RemoveLeaf(proxyId); - FreeNode(proxyId); - } - - public bool MoveProxy(int proxyId, Rect aabb, Vector2 displacement) - { -#if PBDEBUG - Debug.Assert(0 <= proxyId && proxyId < nodes.Length); - Debug.Assert(nodes[proxyId].IsLeaf()); -#endif - - // Extend AABB - - Vector2 r = new Vector2(AABBExtension, AABBExtension); - Rect fatAABB = new Rect(aabb.min - r, aabb.size + 2 * r); - - // Predict AABB movement - Vector2 d = AABBMultiplier * displacement; - - if (d.x < 0.0f) - { - fatAABB.xMin += d.x; - } - else - { - fatAABB.xMax += d.x; - } - - if (d.y < 0.0f) - { - fatAABB.yMin += d.y; - } - else - { - fatAABB.yMin += d.y; - } - - Rect treeAABB = nodes[proxyId].aabb; - if (treeAABB.ContainsBounds(aabb)) - { - // The tree AABB still contains the object, but it might be too large. - // Perhaps the object was moving fast but has since gone to sleep. - // The huge AABB is larger than the new fat AABB. - Rect hugeAABB = new Rect(fatAABB.min - 4.0f * r, fatAABB.size + 8 * r); - - if (hugeAABB.ContainsBounds(treeAABB)) - { - // The tree AABB contains the object AABB and the tree AABB is - // not too large. No tree update needed. - return false; - } - - // Otherwise the tree AABB is huge and needs to be shrunk - } - - RemoveLeaf(proxyId); - - nodes[proxyId].aabb = fatAABB; - - InsertLeaf(proxyId); - - nodes[proxyId].moved = true; - - return true; - } - - - private void InsertLeaf(int leaf) - { - if (root == -1) - { - root = leaf; - nodes[root].parent = -1; - return; - } - - // Find the best sibling for this node - Rect leafAABB = nodes[leaf].aabb; - int index = root; - while (nodes[index].IsLeaf() == false) - { - int child1 = nodes[index].child1; - int child2 = nodes[index].child2; - - float area = nodes[index].aabb.Area(); - - Rect combinedAABB = leafAABB.CombineWith(nodes[index].aabb); - float combinedArea = combinedAABB.Area(); - - // Cost of creating a new parent for this node and the new leaf - float cost = 2.0f * combinedArea; - - // Minimum cost of pushing the leaf further down the tree - float inheritanceCost = 2.0f * (combinedArea - area); - - // Cost of descending into child1 - float cost1; - if (nodes[child1].IsLeaf()) - { - Rect aabb = leafAABB.CombineWith(nodes[child1].aabb); - cost1 = aabb.Area() + inheritanceCost; - } - else - { - Rect aabb = leafAABB.CombineWith(nodes[child1].aabb); - float oldArea = nodes[child1].aabb.Area(); - float newArea = aabb.Area(); - cost1 = (newArea - oldArea) + inheritanceCost; - } - - // Cost of descending into child2 - float cost2; - if (nodes[child2].IsLeaf()) - { - Rect aabb = leafAABB.CombineWith(nodes[child2].aabb); - cost2 = aabb.Area() + inheritanceCost; - } - else - { - Rect aabb = leafAABB.CombineWith(nodes[child2].aabb); - float oldArea = nodes[child2].aabb.Area(); - float newArea = aabb.Area(); - cost2 = newArea - oldArea + inheritanceCost; - } - - // Descend according to the minimum cost. - if (cost < cost1 && cost < cost2) - { - break; - } - - // Descend - if (cost1 < cost2) - { - index = child1; - } - else - { - index = child2; - } - } - - int sibling = index; - - // Create a new parent. - int oldParent = nodes[sibling].parent; - int newParent = AllocateNode(); - nodes[newParent].parent = oldParent; - nodes[newParent].userData = default(T); - nodes[newParent].aabb = leafAABB.CombineWith(nodes[sibling].aabb); - nodes[newParent].height = nodes[sibling].height + 1; - - if (oldParent != -1) - { - // The sibling was not the root. - if (nodes[oldParent].child1 == sibling) - { - nodes[oldParent].child1 = newParent; - } - else - { - nodes[oldParent].child2 = newParent; - } - - nodes[newParent].child1 = sibling; - nodes[newParent].child2 = leaf; - nodes[sibling].parent = newParent; - nodes[leaf].parent = newParent; - } - else - { - // The sibling was the root. - nodes[newParent].child1 = sibling; - nodes[newParent].child2 = leaf; - nodes[sibling].parent = newParent; - nodes[leaf].parent = newParent; - root = newParent; - } - - // Walk back up the tree fixing heights and AABBs - index = nodes[leaf].parent; - while (index != -1) - { - index = Balance(index); - - int child1 = nodes[index].child1; - int child2 = nodes[index].child2; - -#if PBDEBUG - Debug.Assert(child1 != -1); - Debug.Assert(child2 != -1); -#endif - - nodes[index].height = 1 + Mathf.Max(nodes[child1].height, nodes[child2].height); - nodes[index].aabb = nodes[child1].aabb.CombineWith(nodes[child2].aabb); - - index = nodes[index].parent; - } - - //Validate(); - } - - private void RemoveLeaf(int leaf) - { - if (leaf == root) - { - root = -1; - return; - } - - int parent = nodes[leaf].parent; - int grandParent = nodes[parent].parent; - int sibling; - if (nodes[parent].child1 == leaf) - { - sibling = nodes[parent].child2; - } - else - { - sibling = nodes[parent].child1; - } - - if (grandParent != -1) - { - // Destroy parent and connect sibling to grandParent. - if (nodes[grandParent].child1 == parent) - { - nodes[grandParent].child1 = sibling; - } - else - { - nodes[grandParent].child2 = sibling; - } - nodes[sibling].parent = grandParent; - FreeNode(parent); - - // Adjust ancestor bounds. - int index = grandParent; - while (index != -1) - { - index = Balance(index); - - int child1 = nodes[index].child1; - int child2 = nodes[index].child2; - - nodes[index].aabb = nodes[child1].aabb.CombineWith(nodes[child2].aabb); - nodes[index].height = 1 + Mathf.Max(nodes[child1].height, nodes[child2].height); - - index = nodes[index].parent; - } - } - else - { - root = sibling; - nodes[sibling].parent = -1; - FreeNode(parent); - } - - //Validate(); - } - - // Perform a left or right rotation if node A is imbalanced. - // Returns the new root index. - private int Balance(int iA) - { -#if PBDEBUG - Debug.Assert(iA != -1); -#endif - - if (nodes[iA].IsLeaf() || nodes[iA].height < 2) - { - return iA; - } - - int iB = nodes[iA].child1; - int iC = nodes[iA].child2; -#if PBDEBUG - Debug.Assert(0 <= iB && iB < nodes.Length); - Debug.Assert(0 <= iC && iC < nodes.Length); -#endif - - int balance = nodes[iC].height - nodes[iB].height; - - // Rotate C up - if (balance > 1) - { - int iF = nodes[iC].child1; - int iG = nodes[iC].child2; - -#if PBDEBUG - Debug.Assert(0 <= iF && iF < nodes.Length); - Debug.Assert(0 <= iG && iG < nodes.Length); -#endif - - // Swap A and C - nodes[iC].child1 = iA; - nodes[iC].parent = nodes[iA].parent; - nodes[iA].parent = iC; - - // A's old parent should point to C - if (nodes[iC].parent != -1) - { - if (nodes[nodes[iC].parent].child1 == iA) - { - nodes[nodes[iC].parent].child1 = iC; - } - else - { -#if PBDEBUG - Debug.Assert(nodes[nodes[iC].parent].child2 == iA); -#endif - nodes[nodes[iC].parent].child2 = iC; - } - } - else - { - root = iC; - } - - // Rotate - if (nodes[iF].height > nodes[iG].height) - { - nodes[iC].child2 = iF; - nodes[iA].child2 = iG; - nodes[iG].parent = iA; - nodes[iA].aabb = nodes[iB].aabb.CombineWith(nodes[iG].aabb); - nodes[iC].aabb = nodes[iA].aabb.CombineWith(nodes[iF].aabb); - - nodes[iA].height = 1 + Mathf.Max(nodes[iB].height, nodes[iG].height); - nodes[iC].height = 1 + Mathf.Max(nodes[iA].height, nodes[iF].height); - } - else - { - nodes[iC].child2 = iG; - nodes[iA].child2 = iF; - nodes[iF].parent = iA; - nodes[iA].aabb = nodes[iB].aabb.CombineWith(nodes[iF].aabb); - nodes[iC].aabb = nodes[iA].aabb.CombineWith(nodes[iG].aabb); - - nodes[iA].height = 1 + Mathf.Max(nodes[iB].height, nodes[iF].height); - nodes[iC].height = 1 + Mathf.Max(nodes[iA].height, nodes[iG].height); - } - - return iC; - } - - // Rotate B up - if (balance < -1) - { - int iD = nodes[iB].child1; - int iE = nodes[iB].child2; - -#if PBDEBUG - Debug.Assert(0 <= iD && iD < nodes.Length); - Debug.Assert(0 <= iE && iE < nodes.Length); -#endif - - // Swap A and B - nodes[iB].child1 = iA; - nodes[iB].parent = nodes[iA].parent; - nodes[iA].parent = iB; - - // A's old parent should point to B - if (nodes[iB].parent != -1) - { - if (nodes[nodes[iB].parent].child1 == iA) - { - nodes[nodes[iB].parent].child1 = iB; - } - else - { -#if PBDEBUG - Debug.Assert(nodes[nodes[iB].parent].child2 == iA); -#endif - nodes[nodes[iB].parent].child2 = iB; - } - } - else - { - root = iB; - } - - // Rotate - if (nodes[iD].height > nodes[iE].height) - { - nodes[iB].child2 = iD; - nodes[iA].child1 = iE; - nodes[iE].parent = iA; - nodes[iA].aabb = nodes[iC].aabb.CombineWith(nodes[iE].aabb); - nodes[iB].aabb = nodes[iA].aabb.CombineWith(nodes[iD].aabb); - - nodes[iA].height = 1 + Mathf.Max(nodes[iC].height, nodes[iE].height); - nodes[iB].height = 1 + Mathf.Max(nodes[iA].height, nodes[iD].height); - } - else - { - nodes[iB].child2 = iE; - nodes[iA].child1 = iD; - nodes[iD].parent = iA; - nodes[iA].aabb = nodes[iC].aabb.CombineWith(nodes[iD].aabb); - nodes[iB].aabb = nodes[iA].aabb.CombineWith(nodes[iE].aabb); - - nodes[iA].height = 1 + Mathf.Max(nodes[iC].height, nodes[iD].height); - nodes[iB].height = 1 + Mathf.Max(nodes[iA].height, nodes[iE].height); - } - - return iB; - } - - return iA; - } - - public int GetHeight() - { - if (root == -1) - { - return 0; - } - - return nodes[root].height; - } - - // - public float GetAreaRatio() - { - if (root == -1) - { - return 0.0f; - } - - float rootArea = nodes[root].aabb.Area(); - - float totalArea = 0.0f; - for (int i = 0; i < nodes.Length; ++i) - { - if (nodes[i].height < 0) - { - // Free node in pool - continue; - } - - totalArea += nodes[i].aabb.Area(); - } - - return totalArea / rootArea; - } - - // Compute the height of a sub-tree. - private int ComputeHeight(int nodeId) - { -#if PBDEBUG - Debug.Assert(0 <= nodeId && nodeId < nodes.Length); -#endif - - if (nodes[nodeId].IsLeaf()) - { - return 0; - } - - int height1 = ComputeHeight(nodes[nodeId].child1); - int height2 = ComputeHeight(nodes[nodeId].child2); - return 1 + Mathf.Max(height1, height2); - } - - private int ComputeHeight() - { - int height = ComputeHeight(root); - return height; - } - - private void ValidateStructure(int index) - { - if (index == -1) - { - return; - } - - if (index == root) - { - Debug.Assert(nodes[index].parent == -1); - } - - int child1 = nodes[index].child1; - int child2 = nodes[index].child2; - - if (nodes[index].IsLeaf()) - { - Debug.Assert(child1 == -1); - Debug.Assert(child2 == -1); - Debug.Assert(nodes[index].height == 0); - return; - } - - Debug.Assert(0 <= child1 && child1 < nodes.Length); - Debug.Assert(0 <= child2 && child2 < nodes.Length); - - Debug.Assert(nodes[child1].parent == index); - Debug.Assert(nodes[child2].parent == index); - - ValidateStructure(child1); - ValidateStructure(child2); - } - - private void ValidateMetrics(int index) - { - if (index == -1) - { - return; - } - - int child1 = nodes[index].child1; - int child2 = nodes[index].child2; - - if (nodes[index].IsLeaf()) - { - Debug.Assert(child1 == -1); - Debug.Assert(child2 == -1); - Debug.Assert(nodes[index].height == 0); - return; - } - - Debug.Assert(0 <= child1 && child1 < nodes.Length); - Debug.Assert(0 <= child2 && child2 < nodes.Length); - - int height1 = nodes[child1].height; - int height2 = nodes[child2].height; - int height; - height = 1 + Mathf.Max(height1, height2); - Debug.Assert(nodes[index].height == height); - - Rect aabb = nodes[child1].aabb.CombineWith(nodes[child2].aabb); - - Debug.Assert(aabb.min == nodes[index].aabb.min); - Debug.Assert(aabb.max == nodes[index].aabb.max); - - ValidateMetrics(child1); - ValidateMetrics(child2); - } - - public void Validate() - { -#if b2DEBUG - ValidateStructure(root); - ValidateMetrics(root); - - int freeCount = 0; - int freeIndex = nextFreeNode; - while (freeIndex != -1) - { - Debug.Assert(0 <= freeIndex && freeIndex < nodes.Length); - freeIndex = nodes[freeIndex].next; - ++freeCount; - } - - Debug.Assert(GetHeight() == ComputeHeight()); - - Debug.Assert(nodeCount + freeCount == nodes.Length); -#endif - } - - public int GetMaxBalance() - { - int maxBalance = 0; - for (int i = 0; i < nodes.Length; ++i) - { - if (nodes[i].height <= 1) - { - continue; - } - -#if PBDEBUG - Debug.Assert(nodes[i].IsLeaf() == false); -#endif - - int child1 = nodes[i].child1; - int child2 = nodes[i].child2; - int balance = Mathf.Abs(nodes[child2].height - nodes[child1].height); - maxBalance = Mathf.Max(maxBalance, balance); - } - - return maxBalance; - } - - public void RebuildBottomUp() - { - int[] nodeIndecies = new int[nodeCount]; - int count = 0; - - // Build array of leaves. Free the rest. - for (int i = 0; i < nodes.Length; ++i) - { - if (nodes[i].height < 0) - { - // free node in pool - continue; - } - - if (nodes[i].IsLeaf()) - { - nodes[i].parent = -1; - nodeIndecies[count] = i; - ++count; - } - else - { - FreeNode(i); - } - } - - while (count > 1) - { - float minCost = float.MaxValue; - int iMin = -1, jMin = -1; - for (int i = 0; i < count; ++i) - { - Rect aabbi = nodes[nodeIndecies[i]].aabb; - - for (int j = i + 1; j < count; ++j) - { - Rect aabbj = nodes[nodeIndecies[j]].aabb; - Rect b = aabbi.CombineWith(aabbj); - float cost = b.Area(); - if (cost < minCost) - { - iMin = i; - jMin = j; - minCost = cost; - } - } - } - - int index1 = nodeIndecies[iMin]; - int index2 = nodeIndecies[jMin]; - - int parentIndex = AllocateNode(); - nodes[parentIndex].child1 = index1; - nodes[parentIndex].child2 = index2; - nodes[parentIndex].height = 1 + Mathf.Max(nodes[index1].height, nodes[index2].height); - nodes[parentIndex].aabb = nodes[index1].aabb.CombineWith(nodes[index2].aabb); - nodes[parentIndex].parent = -1; - - nodes[index1].parent = parentIndex; - nodes[index2].parent = parentIndex; - - nodeIndecies[jMin] = nodeIndecies[count - 1]; - nodeIndecies[iMin] = parentIndex; - --count; - } - - root = nodeIndecies[0]; - - Validate(); - } - - public void ShiftOrigin(Vector2 newOrigin) - { - // Build array of leaves. Free the rest. - for (int i = 0; i < nodes.Length; ++i) - { - nodes[i].aabb.min -= newOrigin; - nodes[i].aabb.max -= newOrigin; - } - } - - public T GetUserData(int proxyId) - { -#if PBDEBUG - Debug.Assert(0 <= proxyId && proxyId < nodes.Length); -#endif - return nodes[proxyId].userData; - } - - public bool TryGetUserData(int proxyId, out T data) - { - if (proxyId < 0 || proxyId >= nodes.Length) - { - data = default(T); - return false; - } - data = nodes[proxyId].userData; - return true; - } - - public bool WasMoved(int proxyId) - { -#if PBDEBUG - Debug.Assert(0 <= proxyId && proxyId < nodes.Length); -#endif - return nodes[proxyId].moved; - } - - public void ClearMoved(int proxyId) - { -#if PBDEBUG - Debug.Assert(0 <= proxyId && proxyId < nodes.Length); -#endif - nodes[proxyId].moved = false; - } - - public Rect GetFatAABB(int proxyId) - { -#if PBDEBUG - Debug.Assert(0 <= proxyId && proxyId < nodes.Length); -#endif - return nodes[proxyId].aabb; - } - - Stack queryStack = new Stack(); - public QueryEnumerator Query(Rect aabb) - { - return new QueryEnumerator(this, aabb); - } - - public IEnumerator GetEnumerator() - { - // Build array of leaves. Free the rest. - for (int i = 0; i < nodes.Length; ++i) - { - if (nodes[i].height >= 0 && nodes[i].IsLeaf()) - { - yield return nodes[i].userData; - } - } - } - - IEnumerator IEnumerable.GetEnumerator() - { - return this.GetEnumerator(); - } - - public void Draw() - { - Draw(root); - } - - private void Draw(int index) - { - if (index == -1) - { - return; - } - - Gizmos.color = nodes[index].IsLeaf() ? Color.green : Color.red; - DebugDrawingExtensions.DrawRect(nodes[index].aabb); - - Draw(nodes[index].child1); - Draw(nodes[index].child2); - } - - public struct QueryEnumerator { - - B2DynamicTree tree; - Rect aabb; - - public QueryEnumerator(B2DynamicTree tree, Rect aabb) - { - this.tree = tree; - this.aabb = aabb; - Current = 0; - tree.queryStack.Push(tree.root); - } - - public int Current { - get; - private set; - } - - public bool MoveNext() - { - while (tree.queryStack.Count > 0) - { - int nodeId = tree.queryStack.Pop(); - if (nodeId == -1) - { - continue; - } - - if (tree.nodes[nodeId].aabb.Overlaps(aabb)) - { - if (tree.nodes[nodeId].IsLeaf()) - { - Current = nodeId; - return true; - } - else - { - tree.queryStack.Push(tree.nodes[nodeId].child1); - tree.queryStack.Push(tree.nodes[nodeId].child2); - } - } - } - return false; - } - } - } -} \ No newline at end of file diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/Utilities/B2DynamicTree.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/Utilities/B2DynamicTree.cs.meta deleted file mode 100644 index 45844578..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/Utilities/B2DynamicTree.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 50260b47c6ab16343834ce0701e7a454 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/Utilities/DebugDrawingExtensions.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d/Utilities/DebugDrawingExtensions.cs deleted file mode 100644 index b56d0d9d..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/Utilities/DebugDrawingExtensions.cs +++ /dev/null @@ -1,192 +0,0 @@ -using System; -using UnityEngine; - -namespace PathBerserker2d -{ - internal static class DebugDrawingExtensions - { - public static void DrawArrowHead(Vector2 basePos, Vector2 dir, float size) - { - dir.Normalize(); - Vector2 normal = new Vector2(-dir.y, dir.x) * size; - Gizmos.DrawLine(basePos - normal, basePos + normal); - Gizmos.DrawLine(basePos - normal, basePos + dir * size); - Gizmos.DrawLine(basePos + normal, basePos + dir * size); - } - - public static void DrawArrowHeadFromSpike(Vector2 pointyPos, Vector2 dir, float size) - { - dir.Normalize(); - pointyPos -= dir * size; - Vector2 normal = new Vector2(-dir.y, dir.x) * size; - Gizmos.DrawLine(pointyPos - normal, pointyPos + normal); - Gizmos.DrawLine(pointyPos - normal, pointyPos + dir * size); - Gizmos.DrawLine(pointyPos + normal, pointyPos + dir * size); - } - - public static void DrawArrow(Vector2 start, Vector2 end) - { - Vector2 dir = end - start; - float length = dir.magnitude; - dir /= length; - Vector2 baseA = start + dir * (length - 0.1f); - Gizmos.DrawLine(start, baseA); - - Vector2 normal = new Vector2(-dir.y, dir.x) * 0.1f; - Gizmos.DrawLine(baseA - normal, baseA + normal); - Gizmos.DrawLine(baseA - normal, end); - Gizmos.DrawLine(baseA + normal, end); - } - - public static void DrawCircle(Vector2 center, float radius = 0.05f) - { - int segmentCount = 10; - Vector2 prevPoint = center + Vector2.up * radius; - - for (float t = 1; t <= segmentCount; t++) - { - float x = (t / segmentCount) * Mathf.PI * 2.0f; - float cx = Mathf.Sin(x); - float cy = Mathf.Cos(x); - - Vector2 point = center + new Vector2(cx, cy) * radius; - Gizmos.DrawLine(prevPoint, point); - prevPoint = point; - } - Gizmos.DrawLine(prevPoint, center + Vector2.up * radius); - } - - public static void DrawBezierConnection(Vector2 start, Vector2 end, bool biDirectional) - { - Vector2 cp; - var tangent = (end - start); - var length = tangent.magnitude; - var normal = new Vector2(-tangent.y, tangent.x) / length; - cp = start + tangent * 0.5f + normal * (length / 5f); - - DrawBezierConnection(start, end, cp, biDirectional); - } - - public static void DrawBezierConnection(Vector2 start, Vector2 end, Vector2 cp, bool biDirectional) - { - float arcLength = (Vector2.Distance(end, start) * 2 + Vector2.Distance(end, cp) + Vector2.Distance(start, cp)) / 3f; - int numberOfSegments = Mathf.CeilToInt(arcLength); - Vector2 prev = start; - float t; - for (t = 1; t <= numberOfSegments; t++) - { - Vector2 v = QuadraticBezierCurve(t / numberOfSegments, start, cp, end); - Gizmos.DrawLine(prev, v); - prev = v; - } - - //draw arrows - t = (numberOfSegments - 1) / (float)numberOfSegments; - Vector2 dir = end - QuadraticBezierCurve(t, start, cp, end); - DrawArrowHeadFromSpike(end, dir, 0.3f); - if (biDirectional) - { - dir = start - QuadraticBezierCurve(1f / numberOfSegments, start, cp, end); - DrawArrowHeadFromSpike(start, dir, 0.3f); - } - } - - public static void DrawBezierConnectionWithOffset(Vector2 start, Vector2 end, Vector2 cp, Vector2 offset) - { - float arcLength = (Vector2.Distance(end, start) * 2 + Vector2.Distance(end, cp) + Vector2.Distance(start, cp)) / 3f; - int numberOfSegments = Mathf.CeilToInt(arcLength); - Vector2 prev = start + offset; - Gizmos.DrawLine(start, prev); - float t; - for (t = 1; t <= numberOfSegments; t++) - { - Vector2 v = QuadraticBezierCurve(t / numberOfSegments, start, cp, end) + offset; - Gizmos.DrawLine(v, v - offset); - Gizmos.DrawLine(prev, v); - prev = v; - } - } - - public static void DrawProjectileArc(Vector2 start, Vector2 end, float hSpeed, bool isBidiretional) - { - float hDelta = end.x - start.x; - float t = hDelta / hSpeed; - int numberOfSegments = Mathf.CeilToInt(t) + 4; - float p0 = start.y - end.y; - float v0 = 9.81f * t * 0.5f - p0 / t; - - Func func = x => 0.5f * -9.81f * x * x + v0 * x + p0; - - Vector2 prev = start; - float z; - float timePerSegment = t / numberOfSegments; - for (z = 1; z <= numberOfSegments; z++) - { - Vector2 v = new Vector2(start.x + z * timePerSegment * hSpeed, end.y + func(z * timePerSegment)); - Gizmos.DrawLine(prev, v); - prev = v; - } - - Vector2 dir = end - new Vector2(start.x + (numberOfSegments - 1) * timePerSegment * hSpeed, end.y + func((numberOfSegments - 1) * timePerSegment)); - DrawArrowHeadFromSpike(end, dir, 0.3f); - if (isBidiretional) - { - dir = start - new Vector2(start.x + timePerSegment * hSpeed, end.y + func(timePerSegment)); - DrawArrowHeadFromSpike(start, dir, 0.3f); - } - } - - public static void DrawProjectileArcWithOffset(Vector2 start, Vector2 end, float hSpeed, Vector2 offset) - { - float hDelta = end.x - start.x; - float t = hDelta / hSpeed; - int numberOfSegments = Mathf.CeilToInt(t) + 4; - float p0 = start.y - end.y; - float v0 = 9.81f * t * 0.5f - p0 / t; - - Func func = x => 0.5f * -9.81f * x * x + v0 * x + p0; - - Vector2 prev = start + offset; - Gizmos.DrawLine(start, prev); - float z; - float timePerSegment = t / numberOfSegments; - for (z = 1; z <= numberOfSegments; z++) - { - Vector2 v = new Vector2(start.x + z * timePerSegment * hSpeed, end.y + func(z * timePerSegment)) + offset; - Gizmos.DrawLine(prev, v); - Gizmos.DrawLine(v, v - offset); - prev = v; - } - } - - private static Vector2 QuadraticBezierCurve(float t, Vector2 a, Vector2 b, Vector2 c) - { - return (1 - t) * (1 - t) * a + 2 * (1 - t) * t * b + t * t * c; - } - - public static Color LinearBlendBetweenColors(float value, params Color[] colors) - { - value = Mathf.Clamp01(value); - int index = (int)(value * (colors.Length - 1)); - float t = (value * (colors.Length - 1)) - index; - Color b = index >= colors.Length - 1 ? colors[index] : colors[index + 1]; - return Color.Lerp(colors[index], b, t); - } - - public static void DrawRect(Vector2 position, Vector2 size) - { - Gizmos.DrawLine(position + size, new Vector3(position.x, position.y + size.y)); - Gizmos.DrawLine(position, new Vector3(position.x, position.y + size.y)); - Gizmos.DrawLine(position + size, new Vector3(position.x + size.x, position.y)); - Gizmos.DrawLine(position, new Vector3(position.x + size.x, position.y)); - } - - public static void DrawRect(Rect rect) - { - Gizmos.DrawLine(rect.position + rect.size, new Vector3(rect.position.x, rect.position.y + rect.size.y)); - Gizmos.DrawLine(rect.position, new Vector3(rect.position.x, rect.position.y + rect.size.y)); - Gizmos.DrawLine(rect.position + rect.size, new Vector3(rect.position.x + rect.size.x, rect.position.y)); - Gizmos.DrawLine(rect.position, new Vector3(rect.position.x + rect.size.x, rect.position.y)); - } - } -} diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/Utilities/DebugDrawingExtensions.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/Utilities/DebugDrawingExtensions.cs.meta deleted file mode 100644 index be929618..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/Utilities/DebugDrawingExtensions.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 1a74ed22fccf86e4ebb67f3dda822eb3 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/Utilities/DifferentColors.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d/Utilities/DifferentColors.cs deleted file mode 100644 index 6d222110..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/Utilities/DifferentColors.cs +++ /dev/null @@ -1,767 +0,0 @@ -using System.Globalization; -using UnityEngine; - -namespace PathBerserker2d -{ - internal class DifferentColors - { - public static Color32 GetRandomColor() - { - int id = Random.Range(0, colors.Length - 1); - return GetColor(id); - } - - public static Color32 GetColor(int id) - { - if (id < 0) - return Color.white; - while (id >= colors.Length) - { - id -= colors.Length; - } - int rgb = System.Int32.Parse(colors[id], NumberStyles.HexNumber); - return ToColor(rgb); - } - - static Color32 ToColor(int HexVal) - { - byte R = (byte)((HexVal >> 16) & 0xFF); - byte G = (byte)((HexVal >> 8) & 0xFF); - byte B = (byte)((HexVal) & 0xFF); - return new Color32(R, G, B, 255); - } - - readonly static string[] colors = new string[] - { - "9BC4E5", -"310106", -"04640D", -"FEFB0A", -"FB5514", -"E115C0", -"00587F", -"0BC582", -"FEB8C8", -"9E8317", -"01190F", -"847D81", -"58018B", -"B70639", -"703B01", -"F7F1DF", -"118B8A", -"4AFEFA", -"FCB164", -"796EE6", -"000D2C", -"53495F", -"F95475", -"61FC03", -"5D9608", -"DE98FD", -"98A088", -"4F584E", -"248AD0", -"5C5300", -"9F6551", -"BCFEC6", -"932C70", -"2B1B04", -"B5AFC4", -"D4C67A", -"AE7AA1", -"C2A393", -"0232FD", -"6A3A35", -"BA6801", -"168E5C", -"16C0D0", -"C62100", -"014347", -"233809", -"42083B", -"82785D", -"023087", -"B7DAD2", -"196956", -"8C41BB", -"ECEDFE", -"2B2D32", -"94C661", -"F8907D", -"895E6B", -"788E95", -"FB6AB8", -"576094", -"DB1474", -"8489AE", -"860E04", -"FBC206", -"6EAB9B", -"F2CDFE", -"645341", -"760035", -"647A41", -"496E76", -"E3F894", -"F9D7CD", -"876128", -"A1A711", -"01FB92", -"FD0F31", -"BE8485", -"C660FB", -"120104", -"D48958", -"05AEE8", -"C3C1BE", -"9F98F8", -"1167D9", -"D19012", -"B7D802", -"826392", -"5E7A6A", -"B29869", -"1D0051", -"8BE7FC", -"76E0C1", -"BACFA7", -"11BA09", -"462C36", -"65407D", -"491803", -"F5D2A8", -"03422C", -"72A46E", -"128EAC", -"47545E", -"B95C69", -"A14D12", -"C4C8FA", -"372A55", -"3F3610", -"D3A2C6", -"719FFA", -"0D841A", -"4C5B32", -"9DB3B7", -"B14F8F", -"747103", -"9F816D", -"D26A5B", -"8B934B", -"F98500", -"002935", -"D7F3FE", -"FCB899", -"1C0720", -"6B5F61", -"F98A9D", -"9B72C2", -"A6919D", -"2C3729", -"D7C70B", -"9F9992", -"EFFBD0", -"FDE2F1", -"923A52", -"5140A7", -"BC14FD", -"6D706C", -"0007C4", -"C6A62F", -"000C14", -"904431", -"600013", -"1C1B08", -"693955", -"5E7C99", -"6C6E82", -"D0AFB3", -"493B36", -"AC93CE", -"C4BA9C", -"09C4B8", -"69A5B8", -"374869", -"F868ED", -"E70850", -"C04841", -"C36333", -"700366", -"8A7A93", -"52351D", -"B503A2", -"D17190", -"A0F086", -"7B41FC", -"0EA64F", -"017499", -"08A882", -"7300CD", -"A9B074", -"4E6301", -"AB7E41", -"547FF4", -"134DAC", -"FDEC87", -"056164", -"FE12A0", -"C264BA", -"939DAD", -"0BCDFA", -"277442", -"1BDE4A", -"826958", -"977678", -"BAFCE8", -"7D8475", -"8CCF95", -"726638", -"FEA8EB", -"EAFEF0", -"6B9279", -"C2FE4B", -"304041", -"1EA6A7", -"022403", -"062A47", -"054B17", -"F4C673", -"02FEC7", -"9DBAA8", -"775551", -"835536", -"565BCC", -"80D7D2", -"7AD607", -"696F54", -"87089A", -"664B19", -"242235", -"7DB00D", -"BFC7D6", -"D5A97E", -"433F31", -"311A18", -"FDB2AB", -"D586C9", -"7A5FB1", -"32544A", -"EFE3AF", -"859D96", -"2B8570", -"8B282D", -"E16A07", -"4B0125", -"021083", -"114558", -"F707F9", -"C78571", -"7FB9BC", -"FC7F4B", -"8D4A92", -"6B3119", -"884F74", -"994E4F", -"9DA9D3", -"867B40", -"CED5C4", -"1CA2FE", -"D9C5B4", -"FEAA00", -"507B01", -"A7D0DB", -"53858D", -"588F4A", -"FBEEEC", -"FC93C1", -"D7CCD4", -"3E4A02", -"C8B1E2", -"7A8B62", -"9A5AE2", -"896C04", -"B1121C", -"402D7D", -"858701", -"D498A6", -"B484EF", -"5C474C", -"067881", -"C0F9FC", -"726075", -"8D3101", -"6C93B2", -"A26B3F", -"AA6582", -"4F4C4F", -"5A563D", -"E83005", -"32492D", -"FC7272", -"B9C457", -"552A5B", -"B50464", -"616E79", -"DCE2E4", -"CF8028", -"0AE2F0", -"4F1E24", -"FD5E46", -"4B694E", -"C5DEFC", -"5DC262", -"022D26", -"7776B8", -"FD9F66", -"B049B8", -"988F73", -"BE385A", -"2B2126", -"54805A", -"141B55", -"67C09B", -"456989", -"DDC1D9", -"166175", -"C1E29C", -"A397B5", -"2E2922", -"ABDBBE", -"B4A6A8", -"A06B07", -"A99949", -"0A0618", -"B14E2E", -"60557D", -"D4A556", -"82A752", -"4A005B", -"3C404F", -"6E6657", -"7E8BD5", -"1275B8", -"D79E92", -"230735", -"661849", -"7A8391", -"FE0F7B", -"B0B6A9", -"629591", -"D05591", -"97B68A", -"97939A", -"035E38", -"53E19E", -"DFD7F9", -"02436C", -"525A72", -"059A0E", -"3E736C", -"AC8E87", -"D10C92", -"B9906E", -"66BDFD", -"C0ABFD", -"0734BC", -"341224", -"8AAAC1", -"0E0B03", -"414522", -"6A2F3E", -"2D9A8A", -"4568FD", -"FDE6D2", -"FEE007", -"9A003C", -"AC8190", -"DCDD58", -"B7903D", -"1F2927", -"9B02E6", -"827A71", -"878B8A", -"8F724F", -"AC4B70", -"37233B", -"385559", -"F347C7", -"9DB4FE", -"D57179", -"DE505A", -"37F7DD", -"503500", -"1C2401", -"DD0323", -"00A4BA", -"955602", -"FA5B94", -"AA766C", -"B8E067", -"6A807E", -"4D2E27", -"73BED7", -"D7BC8A", -"614539", -"526861", -"716D96", -"829A17", -"210109", -"436C2D", -"784955", -"987BAB", -"8F0152", -"0452FA", -"B67757", -"A1659F", -"D4F8D8", -"48416F", -"DEBAAF", -"A5A9AA", -"8C6B83", -"403740", -"70872B", -"D9744D", -"151E2C", -"5C5E5E", -"B47C02", -"F4CBD0", -"E49D7D", -"DD9954", -"B0A18B", -"2B5308", -"EDFD64", -"9D72FC", -"2A3351", -"68496C", -"C94801", -"EED05E", -"826F6D", -"E0D6BB", -"5B6DB4", -"662F98", -"0C97CA", -"C1CA89", -"755A03", -"DFA619", -"CD70A8", -"BBC9C7", -"F6BCE3", -"A16462", -"01D0AA", -"87C6B3", -"E7B2FA", -"D85379", -"643AD5", -"D18AAE", -"13FD5E", -"B3E3FD", -"C977DB", -"C1A7BB", -"9286CB", -"A19B6A", -"8FFED7", -"6B1F17", -"DF503A", -"10DDD7", -"9A8457", -"60672F", -"7D327D", -"DD8782", -"59AC42", -"82FDB8", -"FC8AE7", -"909F6F", -"B691AE", -"B811CD", -"BCB24E", -"CB4BD9", -"2B2304", -"AA9501", -"5D5096", -"403221", -"F9FAB4", -"3990FC", -"70DE7F", -"95857F", -"84A385", -"50996F", -"797B53", -"7B6142", -"81D5FE", -"9CC428", -"0B0438", -"3E2005", -"4B7C91", -"523854", -"005EA9", -"F0C7AD", -"ACB799", -"FAC08E", -"502239", -"BFAB6A", -"2B3C48", -"0EB5D8", -"8A5647", -"49AF74", -"067AE9", -"F19509", -"554628", -"4426A4", -"7352C9", -"3F4287", -"8B655E", -"B480BF", -"9BA74C", -"5F514C", -"CC9BDC", -"BA7942", -"1C4138", -"3C3C3A", -"29B09C", -"02923F", -"701D2B", -"36577C", -"3F00EA", -"3D959E", -"440601", -"8AEFF3", -"6D442A", -"BEB1A8", -"A11C02", -"8383FE", -"A73839", -"DBDE8A", -"0283B3", -"888597", -"32592E", -"F5FDFA", -"01191B", -"AC707A", -"B6BD03", -"027B59", -"7B4F08", -"957737", -"83727D", -"035543", -"6F7E64", -"C39999", -"52847A", -"925AAC", -"77CEDA", -"516369", -"E0D7D0", -"FCDD97", -"555424", -"96E6B6", -"85BB74", -"5E2074", -"BD5E48", -"9BEE53", -"1A351E", -"3148CD", -"71575F", -"69A6D0", -"391A62", -"E79EA0", -"1C0F03", -"1B1636", -"D20C39", -"765396", -"7402FE", -"447F3E", -"CFD0A8", -"3A2600", -"685AFC", -"A4B3C6", -"534302", -"9AA097", -"FD5154", -"9B0085", -"403956", -"80A1A7", -"6E7A9A", -"605E6A", -"86F0E2", -"5A2B01", -"7E3D43", -"ED823B", -"32331B", -"424837", -"40755E", -"524F48", -"B75807", -"B40080", -"5B8CA1", -"FDCFE5", -"CCFEAC", -"755847", -"CAB296", -"C0D6E3", -"2D7100", -"D5E4DE", -"362823", -"69C63C", -"AC3801", -"163132", -"4750A6", -"61B8B2", -"FCC4B5", -"DEBA2E", -"FE0449", -"737930", -"8470AB", -"687D87", -"D7B760", -"6AAB86", -"8398B8", -"B7B6BF", -"92C4A1", -"B6084F", -"853B5E", -"D0BCBA", -"92826D", -"C6DDC6", -"BE5F5A", -"280021", -"435743", -"874514", -"63675A", -"E97963", -"8F9C9E", -"985262", -"909081", -"023508", -"DDADBF", -"D78493", -"363900", -"5B0120", -"603C47", -"C3955D", -"AC61CB", -"FD7BA7", -"716C74", -"8D895B", -"071001", -"82B4F2", -"B6BBD8", -"71887A", -"8B9FE3", -"997158", -"65A6AB", -"2E3067", -"321301", -"FEECCB", -"3B5E72", -"C8FE85", -"A1DCDF", -"CB49A6", -"B1C5E4", -"3E5EB0", -"88AEA7", -"04504C", -"975232", -"6786B9", -"068797", -"9A98C4", -"A1C3C2", -"1C3967", -"DBEA07", -"789658", -"E7E7C6", -"A6C886", -"957F89", -"752E62", -"171518", -"A75648", -"01D26F", -"0F535D", -"047E76", -"C54754", -"5D6E88", -"AB9483", -"803B99", -"FA9C48", -"4A8A22", -"654A5C", -"965F86", -"9D0CBB", -"A0E8A0", -"D3DBFA", -"FD908F", -"AEAB85", -"A13B89", -"F1B350", -"066898", -"948A42", -"C8BEDE", -"19252C", -"7046AA", -"E1EEFC", -"3E6557", -"CD3F26", -"2B1925", -"DDAD94", -"C0B109", -"37DFFE", -"039676", -"907468", -"9E86A5", -"3A1B49", -"BEE5B7", -"C29501", -"9E3645", -"DC580A", -"645631", -"444B4B", -"FD1A63", -"DDE5AE", -"887800", -"36006F", -"3A6260", -"784637", -"FEA0B7", -"A3E0D2", -"6D6316", -"5F7172", -"B99EC7", -"777A7E", -"E0FEFD", -"E16DC5", -"01344B", -"F8F8FC", -"9F9FB5", -"182617", -"FE3D21", -"7D0017", -"822F21", -"EFD9DC", -"6E68C4", -"35473E", -"007523", -"767667", -"A6825D", -"83DC5F", -"227285", -"A95E34", -"526172", -"979730", -"756F6D", -"716259", -"E8B2B5", -"B6C9BB", -"9078DA", -"4F326E", -"B2387B", -"888C6F", -"314B5F", -"E5B678", -"38A3C6", -"586148", -"5C515B", -"CDCCE1", -"C8977F" - }; - } -} diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/Utilities/DifferentColors.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/Utilities/DifferentColors.cs.meta deleted file mode 100644 index bd0c4ef7..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/Utilities/DifferentColors.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: ecd1377c04d5d854aafa2aecdbf09094 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/Utilities/ExtensionMethods.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d/Utilities/ExtensionMethods.cs deleted file mode 100644 index 48a78d1e..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/Utilities/ExtensionMethods.cs +++ /dev/null @@ -1,101 +0,0 @@ -using System.Collections.Generic; -using UnityEngine; - -namespace PathBerserker2d -{ - internal static class ExtensionMethods - { - - #region LinkedList - - public static void AppendRange(this LinkedList source, IEnumerable items) - { - foreach (T item in items) - { - source.AddLast(item); - } - } - - public static void PrependRange(this LinkedList source, IEnumerable items) - { - LinkedListNode first = source.First; - foreach (T item in items) - { - source.AddBefore(first, item); - } - } - - public static T[] ToArray(this LinkedList source) - { - T[] result = new T[source.Count]; - LinkedListNode cNode = source.First; - int index = 0; - do - { - result[index] = cNode.Value; - index++; - } while ((cNode = cNode.Next) != null); - return result; - } - - public static void Reverse(this LinkedList source) - { - var head = source.First; - while (head.Next != null) - { - var next = head.Next; - source.Remove(next); - source.AddFirst(next.Value); - } - } - #endregion - - public static bool IsLayerWithinMask(this LayerMask source, int other) - { - return source == (source | (1 << other)); - } - - public static Vector2 Rotate(this Vector2 v, float degrees) - { - float sin = Mathf.Sin(degrees * Mathf.Deg2Rad); - float cos = Mathf.Cos(degrees * Mathf.Deg2Rad); - - float tx = v.x; - float ty = v.y; - v.x = (cos * tx) - (sin * ty); - v.y = (sin * tx) + (cos * ty); - return v; - } - - public static Vector2 RotateRad(this Vector2 v, float rads) - { - float sin = Mathf.Sin(rads); - float cos = Mathf.Cos(rads); - - float tx = v.x; - float ty = v.y; - v.x = (cos * tx) - (sin * ty); - v.y = (sin * tx) + (cos * ty); - return v; - } - - public static bool ContainsBounds(this Rect source, Rect other) - { - return source.Contains(other.min) && source.Contains(other.max); - } - - public static Rect CombineWith(this Rect source, Rect other) - { - return Rect.MinMaxRect( - Mathf.Min(source.xMin, other.xMin), - Mathf.Min(source.yMin, other.yMin), - Mathf.Max(source.xMax, other.xMax), - Mathf.Max(source.yMax, other.yMax)); - } - - public static float Area(this Rect source) - { - return source.x * source.y; - } - } -} diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/Utilities/ExtensionMethods.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/Utilities/ExtensionMethods.cs.meta deleted file mode 100644 index 9596bed8..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/Utilities/ExtensionMethods.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 725e57c874bd99c44bb3ff3513a4e6e5 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/Utilities/Geometry.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d/Utilities/Geometry.cs deleted file mode 100644 index 3915aabc..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/Utilities/Geometry.cs +++ /dev/null @@ -1,71 +0,0 @@ -using System; -using System.Collections.Generic; -using UnityEngine; - -namespace PathBerserker2d -{ - public static class Geometry - { - public static float DistancePointLineSegment(Vector2 p, Vector2 a, Vector2 b) - { - return Vector2.Distance(p, ProjectPointOnLineSegment(p, a, b)); - } - - /// - /// Finds closest point to p on line a -> b - /// - public static Vector2 ProjectPointOnLineSegment(Vector2 p, Vector2 a, Vector2 b) - { - Vector2 dir = b - a; - float l2 = dir.sqrMagnitude; - if (l2 == 0.0) - return a; - - float t = Mathf.Clamp01(Vector2.Dot(p - a, dir) / l2); - Vector2 projection = a + t * dir; - return projection; - } - - /// - /// Project point on line. - /// - /// Point to proejct - /// Point on line - /// Line tangent. Must be normalized! - /// Closets point on line to p - public static Vector2 ProjectPointOnLine(Vector2 p, Vector2 a, Vector2 dir) - { - float t = Vector2.Dot(p - a, dir); - return a + t * dir; - } - - public static bool IsPointOnPositiveSideOfLine(Vector2 point, Vector2 linePointA, Vector2 normal) - { - return Vector2.Dot(point - linePointA, normal) >= 0; - } - - /// - /// Returns a rect that encapsulates the passed in rect after being transformed. - /// - public static Rect TransformBoundingRect(Rect bounds, Matrix4x4 transformation) - { - // bounds -> extract 2 diagonal corners - // transform corners - Vector2 a = transformation.MultiplyPoint3x4(bounds.min); - Vector2 b = transformation.MultiplyPoint3x4(bounds.max); - Vector2 c = transformation.MultiplyPoint3x4(new Vector2(bounds.xMin, bounds.yMax)); - Vector2 d = transformation.MultiplyPoint3x4(new Vector2(bounds.xMax, bounds.yMin)); - - // create new box containing corners - Vector2 min = Vector2.Min(d, Vector2.Min(c, Vector2.Min(a, b))); - Vector2 max = Vector2.Max(d, Vector2.Max(c, Vector2.Max(a, b))); - - return new Rect(min, max - min); - } - - public static Rect EnlargeRect(Rect rect, float amount) - { - return new Rect(rect.position - Vector2.one * amount, rect.size + Vector2.one * amount * 2); - } - } -} diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/Utilities/Geometry.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/Utilities/Geometry.cs.meta deleted file mode 100644 index baaed667..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/Utilities/Geometry.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 3f2df2ee5a1fccc4f86bb36c3db1860f -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/Utilities/LineSegment.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d/Utilities/LineSegment.cs deleted file mode 100644 index aa3953be..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/Utilities/LineSegment.cs +++ /dev/null @@ -1,67 +0,0 @@ -using System; -using UnityEngine; - -namespace PathBerserker2d -{ - [System.Serializable] - internal class LineSegment - { - public Vector2 Start { get { return start; } } - public Vector2 End { get { return GetPositionAlongSegment(Length); } } - public Vector2 Normal { get { return new Vector2(-Tangent.y, Tangent.x); } } - public Vector2 Tangent { get { return dirNorm; } } - public float Length { get { return length; } } - - public Rect AABB - { - get - { - Vector2 min = Vector2.Min(Start, End); - Vector2 max = Vector2.Max(Start, End); - return new Rect(min, max - min); - } - } - - [SerializeField] - private Vector2 start; - [SerializeField] - private float length; - [SerializeField] - private Vector2 dirNorm; - - public LineSegment(Vector2 start, Vector2 dirNorm, float length) - { - this.start = start; - this.length = length; - this.dirNorm = dirNorm; - } - - public LineSegment(LineSegment other) - { - this.start = other.start; - this.length = other.length; - this.dirNorm = other.dirNorm; - } - - public Vector2 GetPositionAlongSegment(float t) - { - return Start + Tangent * t; - } - - public Vector2 ProjectPointOnSegment(Vector2 lPoint) - { - return Start + DistanceOfPointAlongSegment(lPoint) * Tangent; - } - - public float DistanceOfPointAlongSegment(Vector2 lPoint) - { - Vector2 ap = lPoint - Start; - return Mathf.Clamp(Vector2.Dot(Tangent, ap), 0, Length); - } - - public float PointDistance(Vector2 position) - { - return Vector2.Distance(position, ProjectPointOnSegment(position)); - } - } -} diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/Utilities/LineSegment.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/Utilities/LineSegment.cs.meta deleted file mode 100644 index 5502b4b3..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/Utilities/LineSegment.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 21f708fb1003baa43a6477a00ed8fa0c -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/Utilities/LineSegmentWithClearance.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d/Utilities/LineSegmentWithClearance.cs deleted file mode 100644 index 9c4f320c..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/Utilities/LineSegmentWithClearance.cs +++ /dev/null @@ -1,93 +0,0 @@ -using System; -using UnityEngine; - -namespace PathBerserker2d -{ - [System.Serializable] - internal class LineSegmentWithClearance : LineSegment - { - public int CellCount { get { return cellClearances.Length; } } - public int NextSegmentIndex { get => nextSegIndex; internal set => nextSegIndex = value; } - public int PrevSegmentIndex { get => prevSegIndex; internal set => prevSegIndex = value; } - - public bool HasNext => nextSegIndex >= 0; - public bool HasPrev => prevSegIndex >= 0; - - [SerializeField] - protected float[] cellClearances; - [SerializeField] - private int prevSegIndex = -1; - [SerializeField] - private int nextSegIndex = -1; - - public LineSegmentWithClearance(Vector2 start, Vector2 dirNorm, float length, float[] cellClearances) : base(start, dirNorm, length) - { - this.cellClearances = cellClearances; - } - - public LineSegmentWithClearance(LineSegmentWithClearance other) : base(other) - { - this.prevSegIndex = other.prevSegIndex; - this.nextSegIndex = other.nextSegIndex; - this.cellClearances = (float[])other.cellClearances.Clone(); - } - - public float GetClearanceAlongSegment(float dist) - { - return cellClearances[CellIndexOf(dist)]; - } - - public bool DoesClearanceAllowTraversal(float startT, float endT, float agentHeight) - { - return GetMinClearanceTo(startT, endT) < agentHeight; - } - - private int CellIndexOf(float t) - { - if (t >= Length) - return cellClearances.Length - 1; - else if (t <= 0) - return 0; - else - return Mathf.FloorToInt(t * (cellClearances.Length / Length)); - } - - public float GetMinClearanceTo(float from, float to) - { - int cellFrom = CellIndexOf(from); - int cellTo = CellIndexOf(to); - - int dir = cellTo - cellFrom; - if (dir == 0) - { - // same cell - return cellClearances[cellFrom]; - } - else if (dir < 0) - { - float minClearance = cellClearances[cellFrom]; - for (int iCell = cellFrom - 1; iCell >= cellTo; iCell--) - { - if (minClearance > cellClearances[iCell]) - minClearance = cellClearances[iCell]; - } - return minClearance; - } - else - { - float minClearance = cellClearances[cellFrom]; - for (int iCell = cellFrom + 1; iCell <= cellTo; iCell++) - { - if (minClearance > cellClearances[iCell]) - minClearance = cellClearances[iCell]; - } - return minClearance; - } - } - - public float[] CloneCellClearances() - { - return (float[])cellClearances.Clone(); - } - } -} diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/Utilities/LineSegmentWithClearance.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/Utilities/LineSegmentWithClearance.cs.meta deleted file mode 100644 index 51cfdd04..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/Utilities/LineSegmentWithClearance.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: fdad88f454070c84d91ea61e5041129d -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/Utilities/Utility.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d/Utilities/Utility.cs deleted file mode 100644 index 1bad5451..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/Utilities/Utility.cs +++ /dev/null @@ -1,49 +0,0 @@ -using System.Collections.Generic; -using UnityEngine; - -namespace PathBerserker2d -{ - internal static class Utility - { - public static T WeightedRandomChoice(IEnumerable values, IEnumerable weights) - { - float total = 0; - foreach (var w in weights) - { - total += w; - } - return WeightedRandomChoice(values, weights, total); - } - - public static T WeightedRandomChoice(IEnumerable values, IEnumerable weights, float totalWeight) - { - float total = 0; - foreach (var w in weights) - { - total += w; - } - - float r = Random.value * total; - IEnumerator enumerator = values.GetEnumerator(); - foreach (var w in weights) - { - enumerator.MoveNext(); - if (w >= r) - return enumerator.Current; - - r -= w; - } - throw new System.Exception(); - } - - public static void ResizeWithDefault(ref T[] array, int newLength, T defaultElem) - { - int oldLength = array.Length; - System.Array.Resize(ref array, newLength); - for (int i = oldLength; i < newLength; i++) - { - array[i] = defaultElem; - } - } - } -} diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/Utilities/Utility.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/Utilities/Utility.cs.meta deleted file mode 100644 index 6666862c..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/Utilities/Utility.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 2d37807132db5f144aa8a58209a65a9a -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/clipper_library.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/clipper_library.meta deleted file mode 100644 index 48dc3c0a..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/clipper_library.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: b6c542d4b9468044a94955f41f82e1b3 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/clipper_library/Connector.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d/clipper_library/Connector.cs deleted file mode 100644 index 70ab7562..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/clipper_library/Connector.cs +++ /dev/null @@ -1,65 +0,0 @@ -using System.Collections.Generic; -using UnityEngine; - -namespace PathBerserker2d -{ - internal class Connector - { - public void Add(Vector2 a, Vector2 b) - { - LinkedListNode current = openPolygons.First; - - while (current != null) - { - LinkedListNode next = current.Next; - - PointChain currentChain = current.Value; - - if (currentChain.LinkSegment(a, b)) - { - if (currentChain.IsClosed()) - { - closedPolygons.AddLast(currentChain); - openPolygons.Remove(current); - return; - } - else - { - LinkedListNode innerCurrent = current.Next; - - while (innerCurrent != null) - { - LinkedListNode innerNext = innerCurrent.Next; - - if (currentChain.LinkPointChain(innerCurrent.Value)) - { - openPolygons.Remove(innerCurrent); - break; - } - innerCurrent = innerNext; - } - } - return; - } - current = next; - } - openPolygons.AddLast(new PointChain(a, b)); - return; - } - - LinkedListNode begin() { return closedPolygons.First; } - LinkedListNode end() { return closedPolygons.Last; } - - public void Clear() - { - closedPolygons.Clear(); - openPolygons.Clear(); - } - - public int GetNumClosedPolygons() { return closedPolygons.Count; } - public int GetNumOpenPolygons() { return openPolygons.Count; } - - public LinkedList openPolygons = new LinkedList(); - public LinkedList closedPolygons = new LinkedList(); - } -} \ No newline at end of file diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/clipper_library/Connector.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/clipper_library/Connector.cs.meta deleted file mode 100644 index 70f07d8a..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/clipper_library/Connector.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: eb67e4c79a6b6a24798f174e0ff3368b -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/clipper_library/ExtendedGeometry.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d/clipper_library/ExtendedGeometry.cs deleted file mode 100644 index 6c3da2b0..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/clipper_library/ExtendedGeometry.cs +++ /dev/null @@ -1,452 +0,0 @@ -using UnityEngine; -using System.Collections.Generic; - -namespace PathBerserker2d -{ - internal class ExtendedGeometry - { - public static float SignedArea(Vector2 a, Vector2 b, Vector2 c) - { - return (a.x - c.x) * (b.y - c.y) - (b.x - c.x) * (a.y - c.y); - } - - /** Signed area of the triangle ( (0,0), p1, p2) */ - public static float SignedArea(Vector2 b, Vector2 c) - { - return -c.x * (b.y - c.y) - -c.y * (b.x - c.x); - } - - /** Sign of triangle (p1, p2, o) */ - public static int Sign(Vector2 a, Vector2 b, Vector2 o) - { - float det = (a.x - o.x) * (b.y - o.y) - (b.x - o.x) * (a.y - o.y); - return (det < 0 ? -1 : (det > 0 ? +1 : 0)); - } - - public static float SignedAreaDoubledTris(Vector2 a, Vector2 b, Vector2 c) - { - return (a.x - c.x) * (b.y - c.y) - (b.x - c.x) * (a.y - c.y); - } - - /** Signed area of the triangle ( (0,0), p1, p2) */ - public static float SignedAreaDoubledTris(Vector2 b, Vector2 c) - { - return -c.x * (b.y - c.y) - -c.y * (b.x - c.x); - } - - /** Sign of triangle (p1, p2, o) */ - public static int SignTris(Vector2 a, Vector2 b, Vector2 o) - { - float det = (a.x - o.x) * (b.y - o.y) - (b.x - o.x) * (a.y - o.y); - return (det < 0 ? -1 : (det > 0 ? +1 : 0)); - } - - public static float SignedAreaDoubledRect(Vector2 a, Vector2 b, Vector2 c, Vector2 d) - { - return (a.y - c.y) * (d.x - b.x) + (b.y - d.y) * (a.x - c.x); - } - - public static bool DoesLineIntersectBounds(Vector2 pA, Vector2 pB, Bounds bounds) - { - if (pA.x > bounds.max.x && pB.x > bounds.max.x) return false; - if (pA.x < bounds.min.x && pB.x < bounds.min.x) return false; - if (pA.y > bounds.max.y && pB.y > bounds.max.y) return false; - if (pA.y < bounds.min.y && pB.y < bounds.min.y) return false; - - float z = pB.x * pA.y - pA.x * pB.y; - float x = pB.y - pA.y; - float y = pA.x - pB.x; - - float sign = Mathf.Sign(bounds.max.x * x + bounds.max.y * y + z); - return (sign == Mathf.Sign(bounds.min.x * x + bounds.max.y * y + z) && sign == Mathf.Sign(bounds.max.x * x + bounds.max.y * y + z) && sign == Mathf.Sign(bounds.max.x * x + bounds.max.y * y + z)); - } - - - public static bool IsOnLeftSideOfLine(Vector2 pA, Vector2 pB, Vector2 point) - { - return ((pB.x - pA.x) * (point.y - pA.y) - (pB.y - pA.y) * (point.x - pA.x)) > 0; - } - - const float LineCircle_FudgeFactor = 0.00001f; - // -1 = line is completly outside of the circle - // 0 = 0 intersections found, line is completly inside of circle - // 1 = 1 intersection found (i1) - // 2 = 2 intersections found (i1, i2) - public static int DoesLineIntersectWithCircle(Vector2 lA, Vector2 lB, Vector2 circleCenter, float radius, out Vector2 i1, out Vector2 i2) - { - i1 = Vector2.zero; - i2 = Vector2.zero; - - Vector2 dir = (lB - lA); - float distL = dir.magnitude; - dir /= distL; - - float t = dir.x * (circleCenter.x - lA.x) + dir.y * (circleCenter.y - lA.y); - - Vector2 tangent = t * dir + lA; - float distToCenter = (tangent - circleCenter).sqrMagnitude; - float radSquared = radius * radius; - - if (distToCenter < radSquared) - { - float dt = Mathf.Sqrt(radSquared - distToCenter); - float tMinDt = t - dt; - if (tMinDt > 0 + LineCircle_FudgeFactor || tMinDt < distL - LineCircle_FudgeFactor) - { - i1 = tMinDt * dir + lA - circleCenter; - - tMinDt = t + dt; - if (tMinDt > 0 + LineCircle_FudgeFactor || tMinDt < distL - LineCircle_FudgeFactor) - { - i2 = tMinDt * dir + lA - circleCenter; - return 2; - } - return 1; - } - tMinDt = t + dt; - if (tMinDt > 0 + LineCircle_FudgeFactor || tMinDt < distL - LineCircle_FudgeFactor) - { - i1 = tMinDt * dir + lA - circleCenter; - return 1; - } - return 0; - } - else if (distToCenter == radSquared) - { - i1 = tangent - circleCenter; - return 1; - } - else - { - return -1; - } - } - - public static bool FindLineIntersection(Vector2 l1a, Vector2 l1b, Vector2 l2a, Vector2 l2b, out Vector2 inter) - { - inter = Vector2.zero; - var d = (l2b.y - l2a.y) * (l1b.x - l1a.x) - (l2b.x - l2a.x) * (l1b.y - l1a.y); - - //n_a and n_b are calculated as seperate values for readability - var n_a = - (l2b.x - l2a.x) * (l1a.y - l2a.y) - - - (l2b.y - l2a.y) * (l1a.x - l2a.x); - - var n_b = - (l1b.x - l1a.x) * (l1a.y - l2a.y) - - - (l1b.y - l1a.y) * (l1a.x - l2a.x); - - // Make sure there is not a division by zero - this also indicates that - // the lines are parallel. - // If n_a and n_b were both equal to zero the lines would be on top of each - // other (coincidental). This check is not done because it is not - // necessary for this implementation (the parallel check accounts for this). - if (d == 0) - return false; - - // Calculate the intermediate fractional point that the lines potentially intersect. - var ua = n_a / d; - var ub = n_b / d; - - // The fractional point will be between 0 and 1 inclusive if the lines - // intersect. If the fractional calculation is larger than 1 or smaller - // than 0 the lines would need to be longer to intersect. - if (ua >= 0.0 && ua <= 1.0 && ub >= 0.0 && ub <= 1.0) - { - inter.x = l1a.x + (ua * (l1b.x - l1a.x)); - inter.y = l1a.y + (ua * (l1b.y - l1a.y)); - return true; - } - return false; - } - - //https://gist.github.com/ChickenProp/3194723 - public static bool RectLineIntersection(Rect rect, Vector2 la, Vector2 lb, out float u1, out float u2) - { - Vector2 lDelta = lb - la; - - float[] p = new float[4] { - -lDelta.x, - lDelta.x, - -lDelta.y, - lDelta.y - }; - - float[] q = new float[4] { - la.x - rect.xMin, - rect.xMax - la.x, - la.y - rect.yMin, - rect.yMax - la.y, - }; - - u1 = Mathf.NegativeInfinity; - u2 = Mathf.Infinity; - for (int i = 0; i < 4; i++) - { - if (p[i] == 0) - { - if (q[i] < 0) - return false; - } - else - { - var t = q[i] / p[i]; - if (p[i] < 0 && u1 < t) - { - u1 = t; - } - else if (p[i] > 0 && u2 > t) - { - u2 = t; - } - } - } - return u1 <= u2; - - /* - // entirely outside - if (u1 > u2) - { - return false; - } - - // entirely inside - if (u1 < 0 && 1 < u2) - { - return 0; - } - - // 2 intersections - if (0 < u1 && u1 < u2 && u2 < 1) - { - return 3; - } - - // 1 intersection - if (0 < u1 && u1 < 1) - { - return 1; - } - return 2;*/ - } - - public static void MergeCloseVerts(List points, float maxDistance) - { - float maxDistSq = maxDistance * maxDistance; - for (int i = 0, j = points.Count - 1; i < points.Count && points.Count > 3; j = i, i++) - { - float dist = (points[i] - points[j]).sqrMagnitude; - - if (dist <= maxDistSq) - { - Vector2 avg = (points[i] + points[j]) / 2f; - points[j] = avg; - points.RemoveAt(i); - - MergeCloseVerts(points, maxDistance); - return; - } - } - } - - public static List SimplifyContour(List points, float tolerance) - { - if (points == null || points.Count < 3) - return points; - - List pointIndeciesToKeep = new List(); - - int firstPoint = 0; - - //find furthest point to first point - int lastPoint = FurthestPointFrom(points, firstPoint); - - pointIndeciesToKeep.Add(firstPoint); - - DouglasPeuckerReduction(points, firstPoint, lastPoint, - tolerance, pointIndeciesToKeep); - - pointIndeciesToKeep.Add(lastPoint); - - DouglasPeuckerReductionReverse(points, lastPoint, firstPoint + points.Count, tolerance, pointIndeciesToKeep); - - - - if (pointIndeciesToKeep.Count < 3) - { -#if PBDEBUG - Debug.LogWarning("Simplification failed!"); -#endif - return points; - } - List returnPoints = new List(); - foreach (int index in pointIndeciesToKeep) - { - returnPoints.Add(points[index]); - } -#if PBDEBUG - Debug.Log(string.Format("Reduced vert count from {0}, to {1} with douglas peucker.", points.Count, returnPoints.Count)); -#endif - return returnPoints; - } - - private static void DouglasPeuckerReduction(List points, int firstPoint, int lastPoint, float tolerance, List pointsToKeep) - { - float dmax = tolerance; - int index = -1; - - for (int i = firstPoint + 1; i < lastPoint; i++) - { - float distance = PerpendicularDistance - (points[firstPoint], points[lastPoint], points[i]); - if (distance > dmax) - { - dmax = distance; - index = i; - } - } - - if (index != -1) - { - //Add the largest point that exceeds the tolerance - DouglasPeuckerReduction(points, firstPoint, index, tolerance, pointsToKeep); - pointsToKeep.Add(index); - DouglasPeuckerReduction(points, index, lastPoint, tolerance, pointsToKeep); - } - } - - private static void DouglasPeuckerReductionReverse(List points, int firstPoint, int lastPoint, float tolerance, List pointsToKeep) - { - float dmax = tolerance; - int index = -1; - int workingLastPoint = lastPoint >= points.Count ? lastPoint - points.Count : lastPoint; - - for (int i = firstPoint + 1; i < lastPoint; i++) - { - float distance = PerpendicularDistance - (points[firstPoint], points[workingLastPoint], points[i >= points.Count ? i - points.Count : i]); - if (distance > dmax) - { - dmax = distance; - index = i; - } - } - - if (index != -1) - { - //Add the largest point that exceeds the tolerance - DouglasPeuckerReductionReverse(points, firstPoint, index, tolerance, pointsToKeep); - pointsToKeep.Add(index >= points.Count ? index - points.Count : index); - DouglasPeuckerReductionReverse(points, index, lastPoint, tolerance, pointsToKeep); - } - } - - private static int FurthestPointFrom(List points, int index) - { - Vector2 v = points[index]; - float maxDistanceSq = 0; - int furthestIndex = -1; - - for (int i = 0; i < points.Count; i++) - { - if (i == index) - continue; - - float dist = (v - points[i]).sqrMagnitude; - if (dist > maxDistanceSq) - { - furthestIndex = i; - maxDistanceSq = dist; - } - } - return furthestIndex; - } - - private static float PerpendicularDistance(Vector2 a, Vector2 b, Vector2 p) - { - Vector2 ab = (b - a).normalized; - Vector2 ap = p - a; - - float dot = Vector2.Dot(ab, ap); - Vector2 proj = ap - dot * ab; - return proj.magnitude; - } - - public static void RemoveCollinearEdges(List points) - { - if (points.Count <= 3) - return; - - for (int i = 0, j = points.Count - 1, k = points.Count - 2; i < points.Count; k = j, j = i, i++) - { - while (SlopesEqual(points[k], points[j], points[j], points[i])) - { - points.RemoveAt(j); - } - } - } - - public static bool SlopesEqual(Vector2 a, Vector2 b, Vector2 x, Vector2 y) - { - return Vector2.Dot(b - a, y - x) == 0; - } - - public static bool ContainsPoint(IEnumerable path, Vector2 lastPointInPath, Vector2 point) - { - bool c = false; - foreach (var p in path) - { - if (((p.y > point.y) != (lastPointInPath.y > point.y)) && - (point.x < (lastPointInPath.x - p.x) * (point.y - p.y) / (lastPointInPath.y - p.y) + p.x)) - c = !c; - - lastPointInPath = p; - } - return c; - } - - /* - * angle in degrees - */ - public static Vector2[] RotateRectangle(Rect rect, float angle) - { - Vector2[] rotatedCorners = new Vector2[4]; - Vector2 center = rect.center; - Rect boundingRect = new Rect(center, Vector2.zero); - - float rotationInRad = Mathf.Deg2Rad * angle; - float angleCos = Mathf.Cos(rotationInRad); - float angleSin = Mathf.Sin(rotationInRad); - - rotatedCorners[0] = new Vector2( - ((rect.xMin - center.x) * angleCos) - ((rect.yMin - center.y) * angleSin), - ((rect.xMin - center.x) * angleSin) + ((rect.yMin - center.y) * angleCos)); - - rotatedCorners[1] = new Vector2( - ((rect.xMax - center.x) * angleCos) - ((rect.yMin - center.y) * angleSin), - ((rect.xMax - center.x) * angleSin) + ((rect.yMin - center.y) * angleCos)); - rotatedCorners[2] = -rotatedCorners[0]; - rotatedCorners[3] = -rotatedCorners[2]; - - for (int i = 0; i < 4; i++) - rotatedCorners[i] += center; - - return rotatedCorners; - } - - public static bool IsAngleBetweenAngles(float from, float to, float angle) - { - angle = angle < 0 ? angle + 360 : angle; - - to = to - from; - to = to < 0 ? to + 360 : to; - - angle = angle - from; - angle = angle < 0 ? angle + 360 : angle; - - return angle < to; - } - } -} diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/clipper_library/ExtendedGeometry.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/clipper_library/ExtendedGeometry.cs.meta deleted file mode 100644 index 177932ee..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/clipper_library/ExtendedGeometry.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: fb94fa6d3d7bd714cb89e9e11f4e7c1f -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/clipper_library/PointChain.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d/clipper_library/PointChain.cs deleted file mode 100644 index 1cee4011..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/clipper_library/PointChain.cs +++ /dev/null @@ -1,109 +0,0 @@ -using System.Collections.Generic; -using System; -using UnityEngine; - -namespace PathBerserker2d -{ - internal class PointChain - { - public LinkedList points = new LinkedList(); - - bool closed; // is the first point linked with the last one - - public PointChain(Vector2 a, Vector2 b) - { - closed = false; - - Add(a, b); - } - - public void Add(Vector2 a, Vector2 b) - { - points.AddLast(a); - points.AddLast(b); - } - - public bool LinkSegment(Vector2 a, Vector2 b) - { - if (b == points.First.Value) - { - if (a == points.Last.Value) - closed = true; - else - points.AddFirst(a); - return true; - } - if (a == points.Last.Value) - { - if (b.Equals(points.First.Value)) - closed = true; - else - points.AddLast(b); - return true; - } - return false; - } - - public bool LinkPointChain(PointChain chain) - { - if (chain.points.First.Value == (points.Last.Value)) - { - chain.points.RemoveFirst(); - AppendRange(chain.points); - - return true; - } - if (chain.points.Last.Value == (points.First.Value)) - { - points.RemoveFirst(); - PrependRange(chain.points); - - return true; - } - return false; - } - - private void PrependRange(LinkedList list) - { - var node = list.Last; - do - { - this.points.AddFirst(node.Value); - } while ((node = node.Previous) != null); - } - - private void PrependRangeReverse(LinkedList list) - { - var node = list.First; - do - { - this.points.AddFirst(node.Value); - } while ((node = node.Next) != null); - } - - private void AppendRange(LinkedList list) - { - var node = list.First; - do - { - this.points.AddLast(node.Value); - } while ((node = node.Next) != null); - } - - private void AppendRangeReverse(LinkedList list) - { - var node = list.Last; - do - { - this.points.AddLast(node.Value); - } while ((node = node.Previous) != null); - } - - public LinkedListNode First { get { return points.First; } } - public LinkedListNode Last { get { return points.Last; } } - - public bool IsClosed() { return closed; } - public void Clear() { points.Clear(); } - public int GetNumPoints() { return points.Count; } - } -} \ No newline at end of file diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/clipper_library/PointChain.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/clipper_library/PointChain.cs.meta deleted file mode 100644 index c3c70fd2..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/clipper_library/PointChain.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: d85c6281176d71c4c99634fd33cc0bcb -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/clipper_library/PolygonClipper.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d/clipper_library/PolygonClipper.cs deleted file mode 100644 index f7edaa19..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/clipper_library/PolygonClipper.cs +++ /dev/null @@ -1,684 +0,0 @@ -using UnityEngine; -using System.Collections.Generic; -using Priority_Queue; -using System; - -namespace PathBerserker2d -{ - internal class PolygonClipper : IClipper - { - public enum EdgeType { NORMAL, NON_CONTRIBUTING, SAME_TRANSITION, DIFFERENT_TRANSITION }; - public enum PolygonType { SUBJECT, CLIPPING }; - - private SweepEventPriorityQueue eventQueue = new SweepEventPriorityQueue(50); - private SweepEvent[] sweepEventPool = new SweepEvent[100]; - private int usedSweepEventCount = 0; - private SweepRay sweepRay = new SweepRay(20); - - public PolygonClipper() - { - for (int i = 0; i < sweepEventPool.Length; i++) - sweepEventPool[i] = new SweepEvent(); - } - - public ResultType Compute(Polygon sp, Polygon cp, BoolOpType op, out List result, bool includeOpenPolygons = false) - { - result = new List(); - if (sp.IsEmpty || cp.IsEmpty) - { - return ResultType.NoOverlap; - } - - //Trivial case: The polygons cannot intersect each other. - if (!sp.BoundsOverlap(cp)) - { - return ResultType.NoOverlap; - } - - //Init the event queue with the polygon edges - usedSweepEventCount = 0; - eventQueue.Clear(); - InsertPolygon(sp, PolygonType.SUBJECT); - InsertPolygon(cp, PolygonType.CLIPPING); - - sweepRay.Clear(); - SweepEvent cEvent; - float minRightBounds = Mathf.Min(sp.XMax, cp.XMax) + 0.01f; - Connector connector = new Connector(); - bool intersectionHappened = false; - - while (eventQueue.Count != 0) - { - cEvent = eventQueue.Dequeue(); - if ((op == BoolOpType.INTERSECTION && cEvent.point.x > minRightBounds) || - (op == BoolOpType.DIFFERENCE && cEvent.point.x > sp.XMax)) - { - //Exit the loop. No more intersections are to be found. - // Create a polygon out of the pointchain - return EvaluateResult(connector, op, intersectionHappened, includeOpenPolygons, ref result); - } - if (op == BoolOpType.UNION && cEvent.point.x > minRightBounds) - { - if (!cEvent.Left) - { - AddEventToConnector(connector, cEvent); - } - while (eventQueue.Count != 0) - { - cEvent = eventQueue.Dequeue(); - if (!cEvent.Left) - { - AddEventToConnector(connector, cEvent); - } - } - return EvaluateResult(connector, op, intersectionHappened, includeOpenPolygons, ref result); - } - - if (cEvent.Left) - {// the line segment must be inserted into S - int pos = sweepRay.Add(cEvent); - SweepEvent prev = sweepRay.Previous(pos); - if (prev == null) - cEvent.Inside = cEvent.InOut = false; - else if (prev.EdgeType != EdgeType.NORMAL) - { - if (pos - 1 == 0) - { - cEvent.Inside = true; - cEvent.InOut = false; - } - else - { - SweepEvent sliEvent = sweepRay.Previous(pos - 1); - if (prev.PolyType == cEvent.PolyType) - { - cEvent.InOut = !prev.InOut; - cEvent.Inside = !sliEvent.InOut; - } - else - { - cEvent.InOut = !sliEvent.InOut; - cEvent.Inside = !prev.InOut; - } - } - } - else if (cEvent.PolyType == prev.PolyType) - { // previous line segment in S belongs to the same polygon that "cEvent" belongs to - cEvent.Inside = prev.Inside; - cEvent.InOut = !prev.InOut; - } - else - { // previous line segment in S belongs to a different polygon that "cEvent" belongs to - cEvent.Inside = !prev.InOut; - cEvent.InOut = prev.Inside; - } - - SweepEvent nextEvent = sweepRay.Next(pos); - if (nextEvent != null) - intersectionHappened |= HandlePossibleIntersection(cEvent, nextEvent); - if (prev != null) - intersectionHappened |= HandlePossibleIntersection(cEvent, prev); - } - else - {// the line segment must be removed from S - int pos = sweepRay.Find(cEvent.other); - switch (cEvent.EdgeType) - { - case EdgeType.NORMAL: - switch (op) - { - case BoolOpType.INTERSECTION: - if (cEvent.other.Inside) - AddEventToConnector(connector, cEvent); - break; - case BoolOpType.UNION: - if (!cEvent.other.Inside) - AddEventToConnector(connector, cEvent); - break; - case BoolOpType.DIFFERENCE: - if (cEvent.PolyType == PolygonType.SUBJECT && !cEvent.other.Inside) - AddEventToConnector(connector, cEvent); - break; - } - break; - case EdgeType.SAME_TRANSITION: - if (op == BoolOpType.INTERSECTION || op == BoolOpType.UNION) - AddEventToConnector(connector, cEvent); - break; - case EdgeType.DIFFERENT_TRANSITION: - if (op == BoolOpType.DIFFERENCE) - AddEventToConnector(connector, cEvent); - break; - } - // delete line segment associated to e from S and check for intersection between the neighbors of "e" in S - SweepEvent next = sweepRay.Next(pos), prev = sweepRay.Previous(pos); - sweepRay.RemoveAt(pos); - if (next != null && prev != null) - intersectionHappened |= HandlePossibleIntersection(prev, next); - } - } - - return EvaluateResult(connector, op, intersectionHappened, includeOpenPolygons, ref result); - } - - private void AddEventToConnector(Connector connector, SweepEvent ev) - { - if (ev.WrapWiseLeft) connector.Add(ev.point, ev.other.point); else connector.Add(ev.other.point, ev.point); - } - - private ResultType EvaluateResult(Connector connector, BoolOpType opType, bool intersectionHappened, bool includeOpenPaths, ref List result) - { - if (!intersectionHappened && (opType == BoolOpType.INTERSECTION || (opType == BoolOpType.UNION && !includeOpenPaths))) - return ResultType.NoOverlap; - - Contour[] contours = new Contour[connector.GetNumClosedPolygons() + (includeOpenPaths ? connector.GetNumOpenPolygons() : 0)]; - - int fill = 0; - foreach (var closedPoly in connector.closedPolygons) - { - contours[fill++] = new Contour(closedPoly.points, true); - } - if (includeOpenPaths) - { - foreach (var openPoly in connector.openPolygons) - { - contours[fill++] = new Contour(openPoly.points, false); - } - } - - if (opType == BoolOpType.UNION) - { - if (connector.GetNumClosedPolygons() == 0) - return ResultType.NoOverlap; - - List holes = new List(contours.Length - 1); - Contour hull = null; - double largestArea = 0; - - foreach (var contour in contours) - { - double area = contour.Area(); - - if (area > largestArea) - { - if (hull != null) - { - holes.Add(hull); - } - hull = contour; - largestArea = area; - } - } - result.Add(new Polygon(hull, holes)); - } - else if (opType == BoolOpType.INTERSECTION || opType == BoolOpType.DIFFERENCE) - { - for (int i = 0; i < contours.Length; i++) - { - if (contours[i].IsClosed) - { - for (int j = i + 1; j < contours.Length; j++) - { - foreach (var cp in contours[j]) - { - if (ExtendedGeometry.ContainsPoint(contours[i], contours[i].Verts[contours[i].VertexCount - 1], cp) - ) - { - goto label1; - } - } - } - } - result.Add(new Polygon(contours[i])); - label1: - continue; - } - } - return ResultType.Clipped; - } - - private void InsertPolygon(Polygon polygon, PolygonType polygonType) - { - int sweepIndex = RequestSweepEvents(polygon.TotalVertCount() * 2); - foreach (var contour in polygon) - { - Vector2 cVal; - Vector2 cPrevVal = contour[contour.IsClosed ? contour.VertexCount - 1 : 0]; - for (int iVert = contour.IsClosed ? 0 : 1; iVert < contour.VertexCount; iVert++) - { - cVal = contour[iVert]; - if (cVal.x < cPrevVal.x || (cVal.x == cPrevVal.x && cVal.y < cPrevVal.y)) - { - sweepEventPool[sweepIndex++].SetData(cVal, true, false, polygonType); - sweepEventPool[sweepIndex++].SetData(cPrevVal, false, true, polygonType); - } - else - { - sweepEventPool[sweepIndex++].SetData(cVal, false, false, polygonType); - sweepEventPool[sweepIndex++].SetData(cPrevVal, true, true, polygonType); - } - sweepEventPool[sweepIndex - 1].other = sweepEventPool[sweepIndex - 2]; - sweepEventPool[sweepIndex - 2].other = sweepEventPool[sweepIndex - 1]; - cPrevVal = cVal; - - eventQueue.Enqueue(sweepEventPool[sweepIndex - 1]); - eventQueue.Enqueue(sweepEventPool[sweepIndex - 2]); - } - } - } - - private int RequestSweepEvents(int count) - { - if (sweepEventPool.Length - usedSweepEventCount < count) - { - int i = sweepEventPool.Length; - System.Array.Resize(ref sweepEventPool, usedSweepEventCount + count + 10); - - for (; i < sweepEventPool.Length; i++) - { - sweepEventPool[i] = new SweepEvent(); - } - } - usedSweepEventCount += count; - return usedSweepEventCount - count; - } - - private int FindIntersection(SweepEvent se1, SweepEvent se2, out Vector2 pA, out Vector2 pB) - { - //Assign the resulting points some dummy values - pA = Vector2.zero; - pB = Vector2.zero; - Vector2 se1_Begin = (se1.Left) ? se1.point : se1.other.point; - Vector2 se1_End = (se1.Left) ? se1.other.point : se1.point; - Vector2 se2_Begin = (se2.Left) ? se2.point : se2.other.point; - Vector2 se2_End = (se2.Left) ? se2.other.point : se2.point; - - Vector2 d0 = se1_End - se1_Begin; - Vector2 d1 = se2_End - se2_Begin; - Vector2 e = se2_Begin - se1_Begin; - - const double sqrEpsilon = 0.000001; - const double epsilon = 0.00001; - - double kross = d0.x * d1.y - d0.y * d1.x; - double sqrKross = kross * kross; - double sqrLen0 = d0.sqrMagnitude; - double sqrLen1 = d1.sqrMagnitude; - - if (sqrKross > sqrEpsilon * sqrLen0 * sqrLen1) - { - // lines of the segments are not parallel - double s = (e.x * d1.y - e.y * d1.x) / kross; - if ((s < 0) || (s > 1)) - { - return 0; - } - double t = (e.x * d0.y - e.y * d0.x) / kross; - if ((t < 0) || (t > 1)) - { - return 0; - } - // intersection of lines is a point an each segment - pA = new Vector2((float)(se1_Begin.x + s * d0.x), (float)(se1_Begin.y + s * d0.y)); - if ((pA - se1_Begin).magnitude < epsilon) pA = se1_Begin; - if ((pA - se1_End).magnitude < epsilon) pA = se1_End; - if ((pA - se2_Begin).magnitude < epsilon) pA = se2_Begin; - if ((pA - se2_End).magnitude < epsilon) pA = se2_End; - return 1; - } - - // lines of the segments are parallel - double sqrLenE = e.sqrMagnitude; - kross = e.x * d0.y - e.y * d0.x; - sqrKross = kross * kross; - if (sqrKross > sqrEpsilon * sqrLen0 * sqrLenE) - { - // lines of the segment are different - return 0; - } - - // Lines of the segments are the same. Need to test for overlap of segments. - double s0 = (d0.x * e.x + d0.y * e.y) / sqrLen0; // so = Dot (D0, E) * sqrLen0 - double s1 = s0 + (d0.x * d1.x + d0.y * d1.y) / sqrLen0; // s1 = s0 + Dot (D0, D1) * sqrLen0 - double smin = Math.Min(s0, s1); - double smax = Math.Max(s0, s1); - double[] w = new double[2]; - int imax = FindIntersection(0.0, 1.0, smin, smax, w); - - if (imax > 0) - { - pA = new Vector2((float)(se1_Begin.x + w[0] * d0.x), (float)(se1_Begin.y + w[0] * d0.y)); - if ((pA - se1_Begin).magnitude < epsilon) pA = se1_Begin; - if ((pA - se1_End).magnitude < epsilon) pA = se1_End; - if ((pA - se2_Begin).magnitude < epsilon) pA = se2_Begin; - if ((pA - se2_End).magnitude < epsilon) pA = se2_End; - if (imax > 1) - { - pB = new Vector2((float)(se1_Begin.x + w[1] * d0.x), (float)(se1_Begin.y + w[1] * d0.y)); - } - } - return imax; - } - - private int FindIntersection(double u0, double u1, double v0, double v1, double[] w) - { - if ((u1 < v0) || (u0 > v1)) - return 0; - if (u1 > v0) - { - if (u0 < v1) - { - w[0] = (u0 < v0) ? v0 : u0; - w[1] = (u1 > v1) ? v1 : u1; - return 2; - } - else - { - // u0 == v1 - w[0] = u0; - return 1; - } - } - else - { - // u1 == v0 - w[0] = u1; - return 1; - } - } - - private bool HandlePossibleIntersection(SweepEvent e1, SweepEvent e2) - { - /* - Vector2 ip1, ip2; // intersection points - int nintersections; - - if ((nintersections = FindIntersection(e1, e2, out ip1, out ip2)) == 0) - return false; - - if ((nintersections == 1) && ( - (e1.point == e2.point) || - (e1.other.point == e2.other.point) || - (e1.other.point == e2.point) || - (e2.point == e2.other.point))) - return false; // the line segments intersect at an endpoint of both line segments - - if (nintersections == 2 && e1.PolyType == e2.PolyType) - return false; // the line segments overlap, but they belong to the same polygon - */ - - if (e1.PolyType == e2.PolyType) - return false; // the line segments belong to the same polygon - - Vector2 ip1, ip2; // intersection points - int nintersections; - - if ((nintersections = FindIntersection(e1, e2, out ip1, out ip2)) == 0) - return false; - - if ((nintersections == 1) && ( - (e1.point == e2.point) || - (e1.other.point == e2.other.point) || - (e1.other.point == e2.point) || - (e2.point == e2.other.point))) - return true; // the line segments intersect at an endpoint of both line segments - - - - // The line segments associated to e1 and e2 intersect - if (nintersections == 1) - { - if (e1.point != ip1 && e1.other.point != ip1) // if ip1 is not an endpoint of the line segment associated to e1 then divide "e1" - DivideEdge(e1, ip1); - if (e2.point != ip1 && e2.other.point != ip1) // if ip1 is not an endpoint of the line segment associated to e2 then divide "e2" - DivideEdge(e2, ip1); - return true; - } - - // The line segments overlap - List sortedEvents = new List(2); - if (e1.point == e2.point) - { - sortedEvents.Add(null); - } - else if (e1.CompareTo(e2) > 0) - { - sortedEvents.Add(e2); - sortedEvents.Add(e1); - } - else - { - sortedEvents.Add(e1); - sortedEvents.Add(e2); - } - - if (e1.other.point == e2.other.point) - { - sortedEvents.Add(null); - } - else if (e1.other.CompareTo(e2.other) > 0) - { - sortedEvents.Add(e2.other); - sortedEvents.Add(e1.other); - } - else - { - sortedEvents.Add(e1.other); - sortedEvents.Add(e2.other); - } - - if (sortedEvents.Count == 2) - { // are both line segments equal? - e1.EdgeType = e1.other.EdgeType = EdgeType.NON_CONTRIBUTING; - e2.EdgeType = e2.other.EdgeType = (e1.InOut == e2.InOut) ? EdgeType.SAME_TRANSITION : EdgeType.DIFFERENT_TRANSITION; - return true; - } - if (sortedEvents.Count == 3) - { // the line segments share an endpoint - sortedEvents[1].EdgeType = sortedEvents[1].other.EdgeType = EdgeType.NON_CONTRIBUTING; - if (sortedEvents[0] != null) // is the right endpoint the shared point? - sortedEvents[0].other.EdgeType = (e1.InOut == e2.InOut) ? EdgeType.SAME_TRANSITION : EdgeType.DIFFERENT_TRANSITION; - else // the shared point is the left endpoint - sortedEvents[2].other.EdgeType = (e1.InOut == e2.InOut) ? EdgeType.SAME_TRANSITION : EdgeType.DIFFERENT_TRANSITION; - DivideEdge(sortedEvents[0] != null ? sortedEvents[0] : sortedEvents[2].other, sortedEvents[1].point); - return true; - } - if (sortedEvents[0] != sortedEvents[3].other) - { // no line segment includes totally the other one - sortedEvents[1].EdgeType = EdgeType.NON_CONTRIBUTING; - sortedEvents[2].EdgeType = (e1.InOut == e2.InOut) ? EdgeType.SAME_TRANSITION : EdgeType.DIFFERENT_TRANSITION; - DivideEdge(sortedEvents[0], sortedEvents[1].point); - DivideEdge(sortedEvents[1], sortedEvents[2].point); - return true; - } - // one line segment includes the other one - sortedEvents[1].EdgeType = sortedEvents[1].other.EdgeType = EdgeType.NON_CONTRIBUTING; - DivideEdge(sortedEvents[0], sortedEvents[1].point); - sortedEvents[3].other.EdgeType = (e1.InOut == e2.InOut) ? EdgeType.SAME_TRANSITION : EdgeType.DIFFERENT_TRANSITION; - DivideEdge(sortedEvents[3].other, sortedEvents[2].point); - - return true; - } - - private void DivideEdge(SweepEvent e, Vector2 p) - { - int sweepIndex = RequestSweepEvents(2); - - // "Right event" of the "left line segment" resulting from dividing e (the line segment associated to e) - SweepEvent r = sweepEventPool[sweepIndex++]; - r.SetData(p, false, e.other.WrapWiseLeft, e.PolyType); - r.EdgeType = e.EdgeType; - r.other = e; - - // "Left event" of the "right line segment" resulting from dividing e (the line segment associated to e) - SweepEvent l = sweepEventPool[sweepIndex]; - l.SetData(p, true, e.WrapWiseLeft, e.PolyType); - l.EdgeType = e.other.EdgeType; - l.other = e.other; - - if (l.CompareTo(e.other) > 0) - { // avoid a rounding error. The left event would be processed after the right event - e.other.Left = true; - l.Left = false; - } - e.other.other = l; - e.other = r; - eventQueue.Enqueue(r); - eventQueue.Enqueue(l); - } - - public class SweepEvent - { - public int queueIndex; - public Vector2 point; // point associated with the event - public SweepEvent other; // Event associated to the other endpoint of the segment - - public bool Left { get { return (data & 1) == 1; } set { data = (byte)(value ? (data | 1) : (data & ~1)); } } // is the point the left endpoint of the segment (p, other.p)? - public bool InOut { get { return (data & (1 << 1)) == 1 << 1; } set { data = (byte)(value ? (data | (1 << 1)) : (data & ~(1 << 1))); } } // Does the segment (p, other.p) represent an inside-outside transition in the polygon for a vertical ray from (p.x, -infinite) that crosses the segment? - public bool Inside { get { return (data & (1 << 2)) == 1 << 2; } set { data = (byte)(value ? (data | (1 << 2)) : (data & ~(1 << 2))); } } // Only used in "left" events. Is the segment (p, other.p) inside the other polygon? - public bool WrapWiseLeft { get { return (data & (1 << 3)) == 1 << 3; } set { data = (byte)(value ? (data | (1 << 3)) : (data & ~(1 << 3))); } } - - public PolygonType PolyType - { - get { return (data & (1 << 4)) != 0 ? PolygonType.CLIPPING : PolygonType.SUBJECT; } - set { data = (byte)(value == PolygonType.CLIPPING ? (data | (1 << 4)) : (data & ~(1 << 4))); } - } // Polygon to which the associated segment belongs to - - public EdgeType EdgeType - { - get - { - return (EdgeType)(data >> 5); - } - set - { - data = (byte)(data & ~(3 << 5) | (((int)value) << 5)); - } - } - - private byte data; - - public void SetData(Vector2 point, bool left, bool wrapwiseLeft, PolygonType polyType) - { - this.data = 0; - this.point = point; - this.Left = left; - this.WrapWiseLeft = wrapwiseLeft; - this.PolyType = polyType; - } - - /** Is the line segment (p, other.p) below point x */ - public bool IsBelow(Vector2 o) { return (Left) ? ExtendedGeometry.SignedAreaDoubledTris(point, other.point, o) > 0 : ExtendedGeometry.SignedAreaDoubledTris(other.point, point, o) > 0; } - /** Is the line segment (p, other.p) above point x */ - public bool IsAbove(Vector2 o) { return !IsBelow(o); } - - public override string ToString() - { - return "SE (p = " + point + ", l = " + Left + ", pl = " + PolyType + ", inOut = " + ((Left) ? InOut : other.InOut) + ", inside = " + ((Left) ? Inside : other.Inside) + ", other.p = " + other.point + ")"; - } - - // Return true(1) means that e1 is placed at the event queue after e2, i.e,, e1 is processed by the algorithm after e2 - public int CompareTo(SweepEvent other) - { - if (point.x > other.point.x) - return 1; - if (point.x < other.point.x) - return -1; - if (point.y > other.point.y) - return 1; - if (point.y < other.point.y) - return -1; - if (Left != other.Left) - { - if (Left) - return 1; - return -1; - } - if (IsAbove(other.other.point)) - return 1; - return -1; - } - } - - class SweepRay - { - List s; - - public SweepRay(int capacity) - { - s = new List(capacity); - } - - public int Add(SweepEvent e) - { - for (int i = 0; i < s.Count; i++) - { - SweepEvent se = s[i]; - if (IsEventOneMoreImportant(se, e)) - continue; - s.Insert(i, e); - return i; - } - s.Add(e); - return s.Count - 1; - } - - public int Find(SweepEvent e) - { - return s.IndexOf(e); - } - - public void RemoveAt(int index) - { - s.RemoveAt(index); - } - - public SweepEvent Next(int index) - { - index++; - if (index < s.Count) - return s[index]; - return null; - } - - public SweepEvent Previous(int index) - { - index--; - if (index >= 0) - return s[index]; - return null; - } - - public override string ToString() - { - string result = "[" + s.Count + "] "; - foreach (SweepEvent se in s) - result += ((se.Left) ? "l" : "r") + se.ToString() + ", "; - return result; - } - - private bool IsEventOneMoreImportant(SweepEvent se1, SweepEvent se2) - { - if (se1 == se2) - return false; - if (ExtendedGeometry.SignedAreaDoubledTris(se1.point, se1.other.point, se2.point) != 0 || ExtendedGeometry.SignedAreaDoubledTris(se1.point, se1.other.point, se2.other.point) != 0) - { - if (se1.point == se2.point) - return se1.IsBelow(se2.other.point); - - if (se1.CompareTo(se2) > 0) - return se2.IsAbove(se1.point); - return se1.IsBelow(se2.point); - } - if (se1.point == se2.point) - return false; //Not sure here. Seems like lines exactly overlap each other. Didnt found the < operator though. - return se1.CompareTo(se2) > 0; - } - - internal void Clear() - { - s.Clear(); - } - } - } -} \ No newline at end of file diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/clipper_library/PolygonClipper.cs.meta b/Assets/PathBerserker2d/Scripts/PathBerserker2d/clipper_library/PolygonClipper.cs.meta deleted file mode 100644 index 2896a1e9..00000000 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/clipper_library/PolygonClipper.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 237a9eb53886ee140b07c9b3e311e62e -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Shaders.meta b/Assets/PathBerserker2d/Shaders.meta deleted file mode 100644 index a7a181be..00000000 --- a/Assets/PathBerserker2d/Shaders.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 035cbf4ff2241d046806e6a8ee3bed35 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Shaders/UnlitSegmented.shader b/Assets/PathBerserker2d/Shaders/UnlitSegmented.shader deleted file mode 100644 index ebb7e8a9..00000000 --- a/Assets/PathBerserker2d/Shaders/UnlitSegmented.shader +++ /dev/null @@ -1,57 +0,0 @@ -Shader "Hidden/PB_UnlitSegmented" -{ - Properties - { - _SegmentSize ("Segment Size", Float) = 0.14 - _PauseSize ("Pause Size", Float) = 0.14 - _XOffset ("X Offset", Float) = 0 - _Color ("Color", Color) = (0, 0, 1, 1) - } - SubShader - { - Tags {"Queue" = "AlphaTest" "IgnoreProjector" = "True" "RenderType" = "TransparentCutout"} - LOD 100 - - Pass - { - CGPROGRAM - #pragma vertex vert - #pragma fragment frag - - #include "UnityCG.cginc" - - struct appdata - { - float4 vertex : POSITION; - }; - - struct v2f - { - float4 vertex : SV_POSITION; - float4 worldPos : TEXCOORD1; - }; - - float _SegmentSize; - float _PauseSize; - float _XOffset; - half4 _Color; - - v2f vert (appdata v) - { - v2f o; - o.vertex = UnityObjectToClipPos(v.vertex); - o.worldPos = mul(unity_ObjectToWorld, v.vertex); - return o; - } - - fixed4 frag (v2f i) : SV_Target - { - float seg = step(frac((i.worldPos.x - i.worldPos.y + _XOffset) / (_SegmentSize + _PauseSize)) * (_SegmentSize + _PauseSize), _SegmentSize); - half4 c = lerp(half4(0, 0, 0, 0), _Color, seg); - clip(c.a - 0.5); - return c; - } - ENDCG - } - } -} diff --git a/Assets/PathBerserker2d/Shaders/UnlitSegmented.shader.meta b/Assets/PathBerserker2d/Shaders/UnlitSegmented.shader.meta deleted file mode 100644 index 07f63a0f..00000000 --- a/Assets/PathBerserker2d/Shaders/UnlitSegmented.shader.meta +++ /dev/null @@ -1,9 +0,0 @@ -fileFormatVersion: 2 -guid: 02231c64b2135af49a06a478a9b08321 -ShaderImporter: - externalObjects: {} - defaultTextures: [] - nonModifiableTextures: [] - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Shaders/UnlitTransparentTinted.shader b/Assets/PathBerserker2d/Shaders/UnlitTransparentTinted.shader deleted file mode 100644 index 2b5fa311..00000000 --- a/Assets/PathBerserker2d/Shaders/UnlitTransparentTinted.shader +++ /dev/null @@ -1,47 +0,0 @@ -Shader "Hidden/PB_UnlitTransparentTinted" -{ - Properties - { - _Color("Color", Color) = (0, 0, 1, 0.5) - } - - SubShader - { - Tags { "Queue" = "AlphaTest" "RenderType" = "TransparentCutout" } - Blend SrcAlpha OneMinusSrcAlpha - - Pass - { - CGPROGRAM - #pragma vertex vert - #pragma fragment frag - - #include "UnityCG.cginc" - - struct appdata - { - float4 vertex : POSITION; - }; - - struct v2f - { - float4 vertex : SV_POSITION; - }; - - half4 _Color; - - v2f vert(appdata v) - { - v2f o; - o.vertex = UnityObjectToClipPos(v.vertex); - return o; - } - - fixed4 frag(v2f i) : SV_Target - { - return _Color; - } - ENDCG - } - } -} diff --git a/Assets/PathBerserker2d/Shaders/UnlitTransparentTinted.shader.meta b/Assets/PathBerserker2d/Shaders/UnlitTransparentTinted.shader.meta deleted file mode 100644 index 00a13eb2..00000000 --- a/Assets/PathBerserker2d/Shaders/UnlitTransparentTinted.shader.meta +++ /dev/null @@ -1,9 +0,0 @@ -fileFormatVersion: 2 -guid: d785db0244148c0498e9263bae01787c -ShaderImporter: - externalObjects: {} - defaultTextures: [] - nonModifiableTextures: [] - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Shaders/UnlitVertexColor.shader b/Assets/PathBerserker2d/Shaders/UnlitVertexColor.shader deleted file mode 100644 index 5fe751d4..00000000 --- a/Assets/PathBerserker2d/Shaders/UnlitVertexColor.shader +++ /dev/null @@ -1,42 +0,0 @@ -Shader "Hidden/PB_UnlitVertexColor" -{ - SubShader - { - Tags { "RenderType"="Opaque" } - - Pass - { - CGPROGRAM - #pragma vertex vert - #pragma fragment frag - - #include "UnityCG.cginc" - - struct appdata - { - float4 vertex : POSITION; - float4 color : COLOR; - }; - - struct v2f - { - float4 vertex : SV_POSITION; - float4 color : COLOR; - }; - - v2f vert (appdata v) - { - v2f o; - o.vertex = UnityObjectToClipPos(v.vertex); - o.color = v.color; - return o; - } - - fixed4 frag (v2f i) : SV_Target - { - return i.color; - } - ENDCG - } - } -} diff --git a/Assets/PathBerserker2d/Shaders/UnlitVertexColor.shader.meta b/Assets/PathBerserker2d/Shaders/UnlitVertexColor.shader.meta deleted file mode 100644 index 7f20ad6b..00000000 --- a/Assets/PathBerserker2d/Shaders/UnlitVertexColor.shader.meta +++ /dev/null @@ -1,9 +0,0 @@ -fileFormatVersion: 2 -guid: 61c630180c122d44d861fe528a32f3e5 -ShaderImporter: - externalObjects: {} - defaultTextures: [] - nonModifiableTextures: [] - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/PathBerserker2d/Shaders/UnlitVertexColorTransparent.shader b/Assets/PathBerserker2d/Shaders/UnlitVertexColorTransparent.shader deleted file mode 100644 index 5b28bbbe..00000000 --- a/Assets/PathBerserker2d/Shaders/UnlitVertexColorTransparent.shader +++ /dev/null @@ -1,43 +0,0 @@ -Shader "Hidden/PB_UnlitVertexColorTransparent" -{ - SubShader - { - Tags { "Queue" = "Transparent" "RenderType" = "Transparent" } - Blend SrcAlpha OneMinusSrcAlpha - - Pass - { - CGPROGRAM - #pragma vertex vert - #pragma fragment frag - - #include "UnityCG.cginc" - - struct appdata - { - float4 vertex : POSITION; - float4 color : COLOR; - }; - - struct v2f - { - float4 vertex : SV_POSITION; - float4 color : COLOR; - }; - - v2f vert(appdata v) - { - v2f o; - o.vertex = UnityObjectToClipPos(v.vertex); - o.color = v.color; - return o; - } - - fixed4 frag(v2f i) : SV_Target - { - return i.color; - } - ENDCG - } - } -} diff --git a/Assets/PathBerserker2d/Shaders/UnlitVertexColorTransparent.shader.meta b/Assets/PathBerserker2d/Shaders/UnlitVertexColorTransparent.shader.meta deleted file mode 100644 index 50f10c2f..00000000 --- a/Assets/PathBerserker2d/Shaders/UnlitVertexColorTransparent.shader.meta +++ /dev/null @@ -1,9 +0,0 @@ -fileFormatVersion: 2 -guid: 94d50acc24004424499c21186a02bb71 -ShaderImporter: - externalObjects: {} - defaultTextures: [] - nonModifiableTextures: [] - userData: - assetBundleName: - assetBundleVariant: