chore: initial commit

This commit is contained in:
2026-05-08 11:04:00 +08:00
commit f55d2a57c3
6278 changed files with 866081 additions and 0 deletions

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: e0383e08b93337e41bd2254c4304147f
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 21035a61c7bbb0c43adb502350355869
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,15 @@
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!

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 1605f3fdba2679842a2f72c81ec408ac
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 446c632a2de6b8c4c87487c4533abd7f
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

View File

@@ -0,0 +1,115 @@
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:

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

View File

@@ -0,0 +1,103 @@
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:

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

View File

@@ -0,0 +1,115 @@
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:

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

View File

@@ -0,0 +1,115 @@
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:

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

View File

@@ -0,0 +1,103 @@
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:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: f88aed787b8decc4086d9222249beace
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,54 @@
%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

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 25dcc2654112bc54090ee2accbac7499
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 0
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 80a179a567cbfc148b23c441354e6057
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: cd800ca490ca3504a91a04cbbe34fe93
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 91a2221b1f964c946af33b7bb66b948d
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,22 @@
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;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: bfac06ae39b4da041b0233fbe194c0a2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 1df174b62e1d3684f9fc16ede26d1866
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,51 @@
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;
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 99480f75d87fac34c9ad4d0125d7a2e5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0e5d17af10e083841ac8d81ba70fd984
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,73 @@
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";
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 88926f52dae6ae348a100721fd59f003
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,137 @@
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;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 38d3d3506e06653448c052e8936eb8dc
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,34 @@
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());
}
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d337207a086912840ae6fa25daa40c29
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 8a6fbf381f5910a46b7602b805ab3da5
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,239 @@
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<float, float> 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<float, float> 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);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 492511a86fc803947bc65e80cb38dcd1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,94 @@
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;
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 723a305b61a51e64ebec0506f93c1112
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,29 @@
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<RectTransform>();
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);
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ed60b9cfa1889ff4f8241ad268f4075f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,56 @@
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)));
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 15cdcbb829a70c74fb474d4fdee8f45f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,60 @@
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);
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f77a85715899ecd40946b0b29b2d294f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,129 @@
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<Texture2D>(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);
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 329c6c7610e18854cbfdf1038774b22f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,13 @@
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);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: dae66614c81006d4fa5cbb26894dd989
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,28 @@
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<RectTransform>();
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);
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 639e10eb7c848df40b745a7e356f1f87
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,135 @@
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<NavSurface, List<Mesh>> miterLinesMap;
public static void DrawNavSurface(NavSurface surface)
{
if (miterLinesMap == null)
miterLinesMap = new Dictionary<NavSurface, List<Mesh>>();
List<Mesh> 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<Mesh>();
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<Vector2> GatherContourPoints(NavSurface surface, NavSegment initialSeg, ref bool[] visited)
{
List<Vector2> contourPoints = new List<Vector2>();
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<Vector2> leftPoints = new List<Vector2>();
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;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 68c53e164cc0a494d81ff4bcf63313b9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,17 @@
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);
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 998c038260d5d72468b1e7310af820c4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: ef995227ea241d8438a3ed5b3425be5e
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,66 @@
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);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5d058cde802ff674eb7997fc35128da9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,61 @@
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();
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 86b5b5f74d10532448503446490e7a25
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,178 @@
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<NavSurface>();
}
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<Renderer>();
if (r == null) r = agent.GetComponentInChildren<Renderer>();
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<Collider2D>();
if (r == null) r = agent.GetComponentInChildren<Collider2D>();
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<MathUtilityDrawer>();
}
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);
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a4e1d5d0b0fa3dc4ea7d765130dd6e83
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,38 @@
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();
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4d33b2293443d0f43bdca36ef03dec3a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,130 @@
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<PositionHandle2D>(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);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3619cbf7ac94f9e4c88c3b613d191c69
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,246 @@
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);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1cac53c9931cf134ebd04b374ccfc151
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,33 @@
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<Transform>();
if (t.localRotation != Quaternion.identity)
{
EditorGUILayout.HelpBox("Rotation will not affect the rect.", MessageType.Warning);
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: dcd540a8a23f45d4ca6a11bbce598051
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,159 @@
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<Renderer>();
if (r == null)
return;
prop.floatValue = r.bounds.size.y;
GUI.changed = true;
}
}
if (GUILayout.Button("From object"))
{
EditorGUIUtility.ShowObjectPicker<Renderer>(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;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 294b9e1daad1eab4b8c2daab63b92b3a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,23 @@
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);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e15da2752391fa14fad448a06e11ed2b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,17 @@
{
"name": "PathBerserker2d.Editor",
"references": [
"GUID:f483b8ed1e509354483048b0c7a56768"
],
"includePlatforms": [
"Editor"
],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": true,
"precompiledReferences": [],
"autoReferenced": false,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 8ba7676b8a5ae4a49b272c008f388df1
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,258 @@
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>(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>();
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>(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);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 08eb9adc91334034ab02b597adb93a96
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: fa81fd185b0d300408709db17ffe2a92
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,65 @@
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));
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7000cfcfa4d6eb34c98c7738b59e9de2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,217 @@
using System;
using System.Collections.Generic;
using UnityEngine;
namespace PathBerserker2d
{
class MiterLineMeshCreator
{
private List<Vector3> verts = new List<Vector3>();
private List<Color32> colors = new List<Color32>();
private List<int> tris = new List<int>();
public void CreateLine(Mesh mesh, IList<Vector2> 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);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2b5a87ab77b93854fa9469929abc0685
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,31 @@
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;
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 19bb1e8824aba9041b7cd3f4ad60d8e0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,90 @@
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;
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 75f31dc41b4fc7c46a13317cf739b246
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 524863b9605ccf542ad776b1873da2fe
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,93 @@
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();
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a74345800bbb4a44ab3646a5bceeca7b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: fee4b89171754694689b0f4ac77ec981
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,62 @@
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();
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3bbdff88e6872d74d9dd37db0b6e9c12
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,198 @@
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<byte> 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<byte> Bytes(byte[] bytes, int offset, int length)
{
for (int i = offset; i < length; i++)
{
yield return bytes[i];
}
}
private IEnumerable<byte> 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<byte> Repeat(byte value, int count)
{
for (int i = 0; i < count; i++)
{
yield return value;
}
}
private IEnumerable<byte> 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;
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3d2b504d66469914ea89897e98917234
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,127 @@
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);
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3ad6757722d743440857770a88e128cb
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,17 @@
{
"name": "PathBerserker2d.Upgrade",
"references": [
"GUID:f483b8ed1e509354483048b0c7a56768"
],
"includePlatforms": [
"Editor"
],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": false,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: fd89c7216da4dd2478872203e056f46b
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Some files were not shown because too many files have changed in this diff Show More