mirror of
https://github.com/DerTyp7/grow-ai-unity.git
synced 2025-10-29 12:32:10 +01:00
init
This commit is contained in:
6
.vsconfig
Normal file
6
.vsconfig
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"version": "1.0",
|
||||
"components": [
|
||||
"Microsoft.VisualStudio.Workload.ManagedGame"
|
||||
]
|
||||
}
|
||||
8
Assets/NavMeshPlus.meta
Normal file
8
Assets/NavMeshPlus.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a39cca41ed2d8bf438f4250c2bfb61fe
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/NavMeshPlus/Gizmos.meta
Normal file
8
Assets/NavMeshPlus/Gizmos.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1f3d783ec2096a945b949dc7763121c8
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Assets/NavMeshPlus/Gizmos/NavMeshLink Icon.png
Normal file
BIN
Assets/NavMeshPlus/Gizmos/NavMeshLink Icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 20 KiB |
68
Assets/NavMeshPlus/Gizmos/NavMeshLink Icon.png.meta
Normal file
68
Assets/NavMeshPlus/Gizmos/NavMeshLink Icon.png.meta
Normal file
@@ -0,0 +1,68 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 92f4afa3e25264f5b964937ccea49ff2
|
||||
timeCreated: 1477656497
|
||||
licenseType: Pro
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
serializedVersion: 4
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 1
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
filterMode: -1
|
||||
aniso: -1
|
||||
mipBias: -1
|
||||
wrapMode: -1
|
||||
nPOTScale: 1
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 0
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 0
|
||||
textureShape: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
platformSettings:
|
||||
- buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Assets/NavMeshPlus/Gizmos/NavMeshModifierVolume Icon.png
Normal file
BIN
Assets/NavMeshPlus/Gizmos/NavMeshModifierVolume Icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 26 KiB |
@@ -0,0 +1,68 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cc7b9475dbddf4f9088d327d6e10ab77
|
||||
timeCreated: 1477656497
|
||||
licenseType: Pro
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
serializedVersion: 4
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 1
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
filterMode: -1
|
||||
aniso: -1
|
||||
mipBias: -1
|
||||
wrapMode: -1
|
||||
nPOTScale: 1
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 0
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 0
|
||||
textureShape: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
platformSettings:
|
||||
- buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Assets/NavMeshPlus/Gizmos/NavMeshSurface Icon.png
Normal file
BIN
Assets/NavMeshPlus/Gizmos/NavMeshSurface Icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 22 KiB |
68
Assets/NavMeshPlus/Gizmos/NavMeshSurface Icon.png.meta
Normal file
68
Assets/NavMeshPlus/Gizmos/NavMeshSurface Icon.png.meta
Normal file
@@ -0,0 +1,68 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e4f97225bcfb64760a1c81f460837f01
|
||||
timeCreated: 1477656497
|
||||
licenseType: Pro
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
serializedVersion: 4
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 1
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
filterMode: -1
|
||||
aniso: -1
|
||||
mipBias: -1
|
||||
wrapMode: -1
|
||||
nPOTScale: 1
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 0
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 0
|
||||
textureShape: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
platformSettings:
|
||||
- buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Assets/NavMeshPlus/Gizmos/NavMeshSurface2d Icon.png
Normal file
BIN
Assets/NavMeshPlus/Gizmos/NavMeshSurface2d Icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 22 KiB |
99
Assets/NavMeshPlus/Gizmos/NavMeshSurface2d Icon.png.meta
Normal file
99
Assets/NavMeshPlus/Gizmos/NavMeshSurface2d Icon.png.meta
Normal file
@@ -0,0 +1,99 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 871b885cd68224f4787ae765e0da9571
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
externalObjects: {}
|
||||
serializedVersion: 7
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 1
|
||||
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: 0
|
||||
wrapV: 0
|
||||
wrapW: 0
|
||||
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: 0
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 0
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 2
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
- serializedVersion: 2
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID: d96fbd3cbbcebff4f9e041b5a33e9786
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
spritePackingTag:
|
||||
pSDRemoveMatte: 0
|
||||
pSDShowRemoveMatteOption: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
21
Assets/NavMeshPlus/LICENSE
Normal file
21
Assets/NavMeshPlus/LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2019 h8man
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
7
Assets/NavMeshPlus/LICENSE.meta
Normal file
7
Assets/NavMeshPlus/LICENSE.meta
Normal file
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4aafea534cdccb843b27a8b6e839a76f
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/NavMeshPlus/NavMeshComponents.meta
Normal file
8
Assets/NavMeshPlus/NavMeshComponents.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7519ca32c072961498ed3151eae536a1
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
9
Assets/NavMeshPlus/NavMeshComponents/Editor.meta
Normal file
9
Assets/NavMeshPlus/NavMeshComponents/Editor.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 63b588f3892bb4b5eb73ad3d2791e05c
|
||||
folderAsset: yes
|
||||
timeCreated: 1477656493
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,325 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using UnityEditor.Experimental.SceneManagement;
|
||||
using UnityEditor.SceneManagement;
|
||||
using UnityEngine.AI;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityEditor.AI
|
||||
{
|
||||
public class NavMeshAssetManager : ScriptableSingleton<NavMeshAssetManager>
|
||||
{
|
||||
internal struct AsyncBakeOperation
|
||||
{
|
||||
public NavMeshSurface surface;
|
||||
public NavMeshData bakeData;
|
||||
public AsyncOperation bakeOperation;
|
||||
}
|
||||
|
||||
List<AsyncBakeOperation> m_BakeOperations = new List<AsyncBakeOperation>();
|
||||
internal List<AsyncBakeOperation> GetBakeOperations() { return m_BakeOperations; }
|
||||
|
||||
struct SavedPrefabNavMeshData
|
||||
{
|
||||
public NavMeshSurface surface;
|
||||
public NavMeshData navMeshData;
|
||||
}
|
||||
|
||||
List<SavedPrefabNavMeshData> m_PrefabNavMeshDataAssets = new List<SavedPrefabNavMeshData>();
|
||||
|
||||
static string GetAndEnsureTargetPath(NavMeshSurface surface)
|
||||
{
|
||||
// Create directory for the asset if it does not exist yet.
|
||||
var activeScenePath = surface.gameObject.scene.path;
|
||||
|
||||
var targetPath = "Assets";
|
||||
if (!string.IsNullOrEmpty(activeScenePath))
|
||||
{
|
||||
targetPath = Path.Combine(Path.GetDirectoryName(activeScenePath), Path.GetFileNameWithoutExtension(activeScenePath));
|
||||
}
|
||||
else
|
||||
{
|
||||
var prefabStage = PrefabStageUtility.GetPrefabStage(surface.gameObject);
|
||||
var isPartOfPrefab = prefabStage != null && prefabStage.IsPartOfPrefabContents(surface.gameObject);
|
||||
if (isPartOfPrefab && !string.IsNullOrEmpty(prefabStage.prefabAssetPath))
|
||||
{
|
||||
var prefabDirectoryName = Path.GetDirectoryName(prefabStage.prefabAssetPath);
|
||||
if (!string.IsNullOrEmpty(prefabDirectoryName))
|
||||
targetPath = prefabDirectoryName;
|
||||
}
|
||||
}
|
||||
if (!Directory.Exists(targetPath))
|
||||
Directory.CreateDirectory(targetPath);
|
||||
return targetPath;
|
||||
}
|
||||
|
||||
static void CreateNavMeshAsset(NavMeshSurface surface)
|
||||
{
|
||||
var targetPath = GetAndEnsureTargetPath(surface);
|
||||
|
||||
var combinedAssetPath = Path.Combine(targetPath, "NavMesh-" + surface.name + ".asset");
|
||||
combinedAssetPath = AssetDatabase.GenerateUniqueAssetPath(combinedAssetPath);
|
||||
AssetDatabase.CreateAsset(surface.navMeshData, combinedAssetPath);
|
||||
}
|
||||
|
||||
NavMeshData GetNavMeshAssetToDelete(NavMeshSurface navSurface)
|
||||
{
|
||||
if (PrefabUtility.IsPartOfPrefabInstance(navSurface) && !PrefabUtility.IsPartOfModelPrefab(navSurface))
|
||||
{
|
||||
// Don't allow deleting the asset belonging to the prefab parent
|
||||
var parentSurface = PrefabUtility.GetCorrespondingObjectFromSource(navSurface) as NavMeshSurface;
|
||||
if (parentSurface && navSurface.navMeshData == parentSurface.navMeshData)
|
||||
return null;
|
||||
}
|
||||
|
||||
// Do not delete the NavMeshData asset referenced from a prefab until the prefab is saved
|
||||
var prefabStage = PrefabStageUtility.GetPrefabStage(navSurface.gameObject);
|
||||
var isPartOfPrefab = prefabStage != null && prefabStage.IsPartOfPrefabContents(navSurface.gameObject);
|
||||
if (isPartOfPrefab && IsCurrentPrefabNavMeshDataStored(navSurface))
|
||||
return null;
|
||||
|
||||
return navSurface.navMeshData;
|
||||
}
|
||||
|
||||
void ClearSurface(NavMeshSurface navSurface)
|
||||
{
|
||||
var hasNavMeshData = navSurface.navMeshData != null;
|
||||
StoreNavMeshDataIfInPrefab(navSurface);
|
||||
|
||||
var assetToDelete = GetNavMeshAssetToDelete(navSurface);
|
||||
navSurface.RemoveData();
|
||||
|
||||
if (hasNavMeshData)
|
||||
{
|
||||
SetNavMeshData(navSurface, null);
|
||||
EditorSceneManager.MarkSceneDirty(navSurface.gameObject.scene);
|
||||
}
|
||||
|
||||
if (assetToDelete)
|
||||
AssetDatabase.DeleteAsset(AssetDatabase.GetAssetPath(assetToDelete));
|
||||
}
|
||||
|
||||
public void StartBakingSurfaces(UnityEngine.Object[] surfaces)
|
||||
{
|
||||
// Remove first to avoid double registration of the callback
|
||||
EditorApplication.update -= UpdateAsyncBuildOperations;
|
||||
EditorApplication.update += UpdateAsyncBuildOperations;
|
||||
|
||||
foreach (NavMeshSurface surf in surfaces)
|
||||
{
|
||||
StoreNavMeshDataIfInPrefab(surf);
|
||||
|
||||
var oper = new AsyncBakeOperation();
|
||||
|
||||
oper.bakeData = InitializeBakeData(surf);
|
||||
oper.bakeOperation = surf.UpdateNavMesh(oper.bakeData);
|
||||
oper.surface = surf;
|
||||
|
||||
m_BakeOperations.Add(oper);
|
||||
}
|
||||
}
|
||||
|
||||
static NavMeshData InitializeBakeData(NavMeshSurface surface)
|
||||
{
|
||||
var emptySources = new List<NavMeshBuildSource>();
|
||||
var emptyBounds = new Bounds();
|
||||
return UnityEngine.AI.NavMeshBuilder.BuildNavMeshData(surface.GetBuildSettings(), emptySources, emptyBounds
|
||||
, surface.transform.position, surface.transform.rotation);
|
||||
}
|
||||
|
||||
void UpdateAsyncBuildOperations()
|
||||
{
|
||||
foreach (var oper in m_BakeOperations)
|
||||
{
|
||||
if (oper.surface == null || oper.bakeOperation == null)
|
||||
continue;
|
||||
|
||||
if (oper.bakeOperation.isDone)
|
||||
{
|
||||
var surface = oper.surface;
|
||||
var delete = GetNavMeshAssetToDelete(surface);
|
||||
if (delete != null)
|
||||
AssetDatabase.DeleteAsset(AssetDatabase.GetAssetPath(delete));
|
||||
|
||||
surface.RemoveData();
|
||||
SetNavMeshData(surface, oper.bakeData);
|
||||
|
||||
if (surface.isActiveAndEnabled)
|
||||
surface.AddData();
|
||||
CreateNavMeshAsset(surface);
|
||||
EditorSceneManager.MarkSceneDirty(surface.gameObject.scene);
|
||||
}
|
||||
}
|
||||
m_BakeOperations.RemoveAll(o => o.bakeOperation == null || o.bakeOperation.isDone);
|
||||
if (m_BakeOperations.Count == 0)
|
||||
EditorApplication.update -= UpdateAsyncBuildOperations;
|
||||
}
|
||||
|
||||
public bool IsSurfaceBaking(NavMeshSurface surface)
|
||||
{
|
||||
if (surface == null)
|
||||
return false;
|
||||
|
||||
foreach (var oper in m_BakeOperations)
|
||||
{
|
||||
if (oper.surface == null || oper.bakeOperation == null)
|
||||
continue;
|
||||
|
||||
if (oper.surface == surface)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void ClearSurfaces(UnityEngine.Object[] surfaces)
|
||||
{
|
||||
foreach (NavMeshSurface s in surfaces)
|
||||
ClearSurface(s);
|
||||
}
|
||||
|
||||
static void SetNavMeshData(NavMeshSurface navSurface, NavMeshData navMeshData)
|
||||
{
|
||||
var so = new SerializedObject(navSurface);
|
||||
var navMeshDataProperty = so.FindProperty("m_NavMeshData");
|
||||
navMeshDataProperty.objectReferenceValue = navMeshData;
|
||||
so.ApplyModifiedPropertiesWithoutUndo();
|
||||
}
|
||||
|
||||
void StoreNavMeshDataIfInPrefab(NavMeshSurface surfaceToStore)
|
||||
{
|
||||
var prefabStage = PrefabStageUtility.GetPrefabStage(surfaceToStore.gameObject);
|
||||
var isPartOfPrefab = prefabStage != null && prefabStage.IsPartOfPrefabContents(surfaceToStore.gameObject);
|
||||
if (!isPartOfPrefab)
|
||||
return;
|
||||
|
||||
// check if data has already been stored for this surface
|
||||
foreach (var storedAssetInfo in m_PrefabNavMeshDataAssets)
|
||||
if (storedAssetInfo.surface == surfaceToStore)
|
||||
return;
|
||||
|
||||
if (m_PrefabNavMeshDataAssets.Count == 0)
|
||||
{
|
||||
PrefabStage.prefabSaving -= DeleteStoredNavMeshDataAssetsForOwnedSurfaces;
|
||||
PrefabStage.prefabSaving += DeleteStoredNavMeshDataAssetsForOwnedSurfaces;
|
||||
|
||||
PrefabStage.prefabStageClosing -= ForgetUnsavedNavMeshDataChanges;
|
||||
PrefabStage.prefabStageClosing += ForgetUnsavedNavMeshDataChanges;
|
||||
}
|
||||
|
||||
var isDataOwner = true;
|
||||
if (PrefabUtility.IsPartOfPrefabInstance(surfaceToStore) && !PrefabUtility.IsPartOfModelPrefab(surfaceToStore))
|
||||
{
|
||||
var basePrefabSurface = PrefabUtility.GetCorrespondingObjectFromSource(surfaceToStore) as NavMeshSurface;
|
||||
isDataOwner = basePrefabSurface == null || surfaceToStore.navMeshData != basePrefabSurface.navMeshData;
|
||||
}
|
||||
m_PrefabNavMeshDataAssets.Add(new SavedPrefabNavMeshData { surface = surfaceToStore, navMeshData = isDataOwner ? surfaceToStore.navMeshData : null });
|
||||
}
|
||||
|
||||
bool IsCurrentPrefabNavMeshDataStored(NavMeshSurface surface)
|
||||
{
|
||||
if (surface == null)
|
||||
return false;
|
||||
|
||||
foreach (var storedAssetInfo in m_PrefabNavMeshDataAssets)
|
||||
{
|
||||
if (storedAssetInfo.surface == surface)
|
||||
return storedAssetInfo.navMeshData == surface.navMeshData;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void DeleteStoredNavMeshDataAssetsForOwnedSurfaces(GameObject gameObjectInPrefab)
|
||||
{
|
||||
// Debug.LogFormat("DeleteStoredNavMeshDataAsset() when saving prefab {0}", gameObjectInPrefab.name);
|
||||
|
||||
var surfaces = gameObjectInPrefab.GetComponentsInChildren<NavMeshSurface>(true);
|
||||
foreach (var surface in surfaces)
|
||||
DeleteStoredPrefabNavMeshDataAsset(surface);
|
||||
}
|
||||
|
||||
void DeleteStoredPrefabNavMeshDataAsset(NavMeshSurface surface)
|
||||
{
|
||||
for (var i = m_PrefabNavMeshDataAssets.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var storedAssetInfo = m_PrefabNavMeshDataAssets[i];
|
||||
if (storedAssetInfo.surface == surface)
|
||||
{
|
||||
var storedNavMeshData = storedAssetInfo.navMeshData;
|
||||
if (storedNavMeshData != null && storedNavMeshData != surface.navMeshData)
|
||||
{
|
||||
var assetPath = AssetDatabase.GetAssetPath(storedNavMeshData);
|
||||
AssetDatabase.DeleteAsset(assetPath);
|
||||
}
|
||||
|
||||
m_PrefabNavMeshDataAssets.RemoveAt(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_PrefabNavMeshDataAssets.Count == 0)
|
||||
{
|
||||
PrefabStage.prefabSaving -= DeleteStoredNavMeshDataAssetsForOwnedSurfaces;
|
||||
PrefabStage.prefabStageClosing -= ForgetUnsavedNavMeshDataChanges;
|
||||
}
|
||||
}
|
||||
|
||||
void ForgetUnsavedNavMeshDataChanges(PrefabStage prefabStage)
|
||||
{
|
||||
// Debug.Log("On prefab closing - forget about this object's surfaces and stop caring about prefab saving");
|
||||
|
||||
if (prefabStage == null)
|
||||
return;
|
||||
|
||||
var allSurfacesInPrefab = prefabStage.prefabContentsRoot.GetComponentsInChildren<NavMeshSurface>(true);
|
||||
NavMeshSurface surfaceInPrefab = null;
|
||||
var index = 0;
|
||||
do
|
||||
{
|
||||
if (allSurfacesInPrefab.Length > 0)
|
||||
surfaceInPrefab = allSurfacesInPrefab[index];
|
||||
|
||||
for (var i = m_PrefabNavMeshDataAssets.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var storedPrefabInfo = m_PrefabNavMeshDataAssets[i];
|
||||
if (storedPrefabInfo.surface == null)
|
||||
{
|
||||
// Debug.LogFormat("A surface from the prefab got deleted after it has baked a new NavMesh but it hasn't saved it. Now the unsaved asset gets deleted. ({0})", storedPrefabInfo.navMeshData);
|
||||
|
||||
// surface got deleted, thus delete its initial NavMeshData asset
|
||||
if (storedPrefabInfo.navMeshData != null)
|
||||
{
|
||||
var assetPath = AssetDatabase.GetAssetPath(storedPrefabInfo.navMeshData);
|
||||
AssetDatabase.DeleteAsset(assetPath);
|
||||
}
|
||||
|
||||
m_PrefabNavMeshDataAssets.RemoveAt(i);
|
||||
}
|
||||
else if (surfaceInPrefab != null && storedPrefabInfo.surface == surfaceInPrefab)
|
||||
{
|
||||
//Debug.LogFormat("The surface {0} from the prefab was storing the original navmesh data and now will be forgotten", surfaceInPrefab);
|
||||
|
||||
var baseSurface = PrefabUtility.GetCorrespondingObjectFromSource(surfaceInPrefab) as NavMeshSurface;
|
||||
if (baseSurface == null || surfaceInPrefab.navMeshData != baseSurface.navMeshData)
|
||||
{
|
||||
var assetPath = AssetDatabase.GetAssetPath(surfaceInPrefab.navMeshData);
|
||||
AssetDatabase.DeleteAsset(assetPath);
|
||||
|
||||
//Debug.LogFormat("The surface {0} from the prefab has baked new NavMeshData but did not save this change so the asset has been now deleted. ({1})",
|
||||
// surfaceInPrefab, assetPath);
|
||||
}
|
||||
|
||||
m_PrefabNavMeshDataAssets.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
} while (++index < allSurfacesInPrefab.Length);
|
||||
|
||||
if (m_PrefabNavMeshDataAssets.Count == 0)
|
||||
{
|
||||
PrefabStage.prefabSaving -= DeleteStoredNavMeshDataAssetsForOwnedSurfaces;
|
||||
PrefabStage.prefabStageClosing -= ForgetUnsavedNavMeshDataChanges;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 178d8366aa1616849b91b66285c51454
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,325 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using UnityEditor.Experimental.SceneManagement;
|
||||
using UnityEditor.SceneManagement;
|
||||
using UnityEngine.AI;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityEditor.AI
|
||||
{
|
||||
public class NavMeshAssetManager2d : ScriptableSingleton<NavMeshAssetManager2d>
|
||||
{
|
||||
internal struct AsyncBakeOperation
|
||||
{
|
||||
public NavMeshSurface2d surface;
|
||||
public NavMeshData bakeData;
|
||||
public AsyncOperation bakeOperation;
|
||||
}
|
||||
|
||||
List<AsyncBakeOperation> m_BakeOperations = new List<AsyncBakeOperation>();
|
||||
internal List<AsyncBakeOperation> GetBakeOperations() { return m_BakeOperations; }
|
||||
|
||||
struct SavedPrefabNavMeshData
|
||||
{
|
||||
public NavMeshSurface2d surface;
|
||||
public NavMeshData navMeshData;
|
||||
}
|
||||
|
||||
List<SavedPrefabNavMeshData> m_PrefabNavMeshDataAssets = new List<SavedPrefabNavMeshData>();
|
||||
|
||||
static string GetAndEnsureTargetPath(NavMeshSurface2d surface)
|
||||
{
|
||||
// Create directory for the asset if it does not exist yet.
|
||||
var activeScenePath = surface.gameObject.scene.path;
|
||||
|
||||
var targetPath = "Assets";
|
||||
if (!string.IsNullOrEmpty(activeScenePath))
|
||||
{
|
||||
targetPath = Path.Combine(Path.GetDirectoryName(activeScenePath), Path.GetFileNameWithoutExtension(activeScenePath));
|
||||
}
|
||||
else
|
||||
{
|
||||
var prefabStage = PrefabStageUtility.GetPrefabStage(surface.gameObject);
|
||||
var isPartOfPrefab = prefabStage != null && prefabStage.IsPartOfPrefabContents(surface.gameObject);
|
||||
if (isPartOfPrefab && !string.IsNullOrEmpty(prefabStage.prefabAssetPath))
|
||||
{
|
||||
var prefabDirectoryName = Path.GetDirectoryName(prefabStage.prefabAssetPath);
|
||||
if (!string.IsNullOrEmpty(prefabDirectoryName))
|
||||
targetPath = prefabDirectoryName;
|
||||
}
|
||||
}
|
||||
if (!Directory.Exists(targetPath))
|
||||
Directory.CreateDirectory(targetPath);
|
||||
return targetPath;
|
||||
}
|
||||
|
||||
static void CreateNavMeshAsset(NavMeshSurface2d surface)
|
||||
{
|
||||
var targetPath = GetAndEnsureTargetPath(surface);
|
||||
|
||||
var combinedAssetPath = Path.Combine(targetPath, "NavMesh-" + surface.name + ".asset");
|
||||
combinedAssetPath = AssetDatabase.GenerateUniqueAssetPath(combinedAssetPath);
|
||||
AssetDatabase.CreateAsset(surface.navMeshData, combinedAssetPath);
|
||||
}
|
||||
|
||||
NavMeshData GetNavMeshAssetToDelete(NavMeshSurface2d navSurface)
|
||||
{
|
||||
if (PrefabUtility.IsPartOfPrefabInstance(navSurface) && !PrefabUtility.IsPartOfModelPrefab(navSurface))
|
||||
{
|
||||
// Don't allow deleting the asset belonging to the prefab parent
|
||||
var parentSurface = PrefabUtility.GetCorrespondingObjectFromSource(navSurface) as NavMeshSurface2d;
|
||||
if (parentSurface && navSurface.navMeshData == parentSurface.navMeshData)
|
||||
return null;
|
||||
}
|
||||
|
||||
// Do not delete the NavMeshData asset referenced from a prefab until the prefab is saved
|
||||
var prefabStage = PrefabStageUtility.GetPrefabStage(navSurface.gameObject);
|
||||
var isPartOfPrefab = prefabStage != null && prefabStage.IsPartOfPrefabContents(navSurface.gameObject);
|
||||
if (isPartOfPrefab && IsCurrentPrefabNavMeshDataStored(navSurface))
|
||||
return null;
|
||||
|
||||
return navSurface.navMeshData;
|
||||
}
|
||||
|
||||
void ClearSurface(NavMeshSurface2d navSurface)
|
||||
{
|
||||
var hasNavMeshData = navSurface.navMeshData != null;
|
||||
StoreNavMeshDataIfInPrefab(navSurface);
|
||||
|
||||
var assetToDelete = GetNavMeshAssetToDelete(navSurface);
|
||||
navSurface.RemoveData();
|
||||
|
||||
if (hasNavMeshData)
|
||||
{
|
||||
SetNavMeshData(navSurface, null);
|
||||
EditorSceneManager.MarkSceneDirty(navSurface.gameObject.scene);
|
||||
}
|
||||
|
||||
if (assetToDelete)
|
||||
AssetDatabase.DeleteAsset(AssetDatabase.GetAssetPath(assetToDelete));
|
||||
}
|
||||
|
||||
public void StartBakingSurfaces(UnityEngine.Object[] surfaces)
|
||||
{
|
||||
// Remove first to avoid double registration of the callback
|
||||
EditorApplication.update -= UpdateAsyncBuildOperations;
|
||||
EditorApplication.update += UpdateAsyncBuildOperations;
|
||||
|
||||
foreach (NavMeshSurface2d surf in surfaces)
|
||||
{
|
||||
StoreNavMeshDataIfInPrefab(surf);
|
||||
|
||||
var oper = new AsyncBakeOperation();
|
||||
|
||||
oper.bakeData = InitializeBakeData(surf);
|
||||
oper.bakeOperation = surf.UpdateNavMesh(oper.bakeData);
|
||||
oper.surface = surf;
|
||||
|
||||
m_BakeOperations.Add(oper);
|
||||
}
|
||||
}
|
||||
|
||||
static NavMeshData InitializeBakeData(NavMeshSurface2d surface)
|
||||
{
|
||||
var emptySources = new List<NavMeshBuildSource>();
|
||||
var emptyBounds = new Bounds();
|
||||
return UnityEngine.AI.NavMeshBuilder.BuildNavMeshData(surface.GetBuildSettings(), emptySources, emptyBounds
|
||||
, surface.transform.position, surface.transform.rotation);
|
||||
}
|
||||
|
||||
void UpdateAsyncBuildOperations()
|
||||
{
|
||||
foreach (var oper in m_BakeOperations)
|
||||
{
|
||||
if (oper.surface == null || oper.bakeOperation == null)
|
||||
continue;
|
||||
|
||||
if (oper.bakeOperation.isDone)
|
||||
{
|
||||
var surface = oper.surface;
|
||||
var delete = GetNavMeshAssetToDelete(surface);
|
||||
if (delete != null)
|
||||
AssetDatabase.DeleteAsset(AssetDatabase.GetAssetPath(delete));
|
||||
|
||||
surface.RemoveData();
|
||||
SetNavMeshData(surface, oper.bakeData);
|
||||
|
||||
if (surface.isActiveAndEnabled)
|
||||
surface.AddData();
|
||||
CreateNavMeshAsset(surface);
|
||||
EditorSceneManager.MarkSceneDirty(surface.gameObject.scene);
|
||||
}
|
||||
}
|
||||
m_BakeOperations.RemoveAll(o => o.bakeOperation == null || o.bakeOperation.isDone);
|
||||
if (m_BakeOperations.Count == 0)
|
||||
EditorApplication.update -= UpdateAsyncBuildOperations;
|
||||
}
|
||||
|
||||
public bool IsSurfaceBaking(NavMeshSurface2d surface)
|
||||
{
|
||||
if (surface == null)
|
||||
return false;
|
||||
|
||||
foreach (var oper in m_BakeOperations)
|
||||
{
|
||||
if (oper.surface == null || oper.bakeOperation == null)
|
||||
continue;
|
||||
|
||||
if (oper.surface == surface)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void ClearSurfaces(UnityEngine.Object[] surfaces)
|
||||
{
|
||||
foreach (NavMeshSurface2d s in surfaces)
|
||||
ClearSurface(s);
|
||||
}
|
||||
|
||||
static void SetNavMeshData(NavMeshSurface2d navSurface, NavMeshData navMeshData)
|
||||
{
|
||||
var so = new SerializedObject(navSurface);
|
||||
var navMeshDataProperty = so.FindProperty("m_NavMeshData");
|
||||
navMeshDataProperty.objectReferenceValue = navMeshData;
|
||||
so.ApplyModifiedPropertiesWithoutUndo();
|
||||
}
|
||||
|
||||
void StoreNavMeshDataIfInPrefab(NavMeshSurface2d surfaceToStore)
|
||||
{
|
||||
var prefabStage = PrefabStageUtility.GetPrefabStage(surfaceToStore.gameObject);
|
||||
var isPartOfPrefab = prefabStage != null && prefabStage.IsPartOfPrefabContents(surfaceToStore.gameObject);
|
||||
if (!isPartOfPrefab)
|
||||
return;
|
||||
|
||||
// check if data has already been stored for this surface
|
||||
foreach (var storedAssetInfo in m_PrefabNavMeshDataAssets)
|
||||
if (storedAssetInfo.surface == surfaceToStore)
|
||||
return;
|
||||
|
||||
if (m_PrefabNavMeshDataAssets.Count == 0)
|
||||
{
|
||||
PrefabStage.prefabSaving -= DeleteStoredNavMeshDataAssetsForOwnedSurfaces;
|
||||
PrefabStage.prefabSaving += DeleteStoredNavMeshDataAssetsForOwnedSurfaces;
|
||||
|
||||
PrefabStage.prefabStageClosing -= ForgetUnsavedNavMeshDataChanges;
|
||||
PrefabStage.prefabStageClosing += ForgetUnsavedNavMeshDataChanges;
|
||||
}
|
||||
|
||||
var isDataOwner = true;
|
||||
if (PrefabUtility.IsPartOfPrefabInstance(surfaceToStore) && !PrefabUtility.IsPartOfModelPrefab(surfaceToStore))
|
||||
{
|
||||
var basePrefabSurface = PrefabUtility.GetCorrespondingObjectFromSource(surfaceToStore) as NavMeshSurface2d;
|
||||
isDataOwner = basePrefabSurface == null || surfaceToStore.navMeshData != basePrefabSurface.navMeshData;
|
||||
}
|
||||
m_PrefabNavMeshDataAssets.Add(new SavedPrefabNavMeshData { surface = surfaceToStore, navMeshData = isDataOwner ? surfaceToStore.navMeshData : null });
|
||||
}
|
||||
|
||||
bool IsCurrentPrefabNavMeshDataStored(NavMeshSurface2d surface)
|
||||
{
|
||||
if (surface == null)
|
||||
return false;
|
||||
|
||||
foreach (var storedAssetInfo in m_PrefabNavMeshDataAssets)
|
||||
{
|
||||
if (storedAssetInfo.surface == surface)
|
||||
return storedAssetInfo.navMeshData == surface.navMeshData;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void DeleteStoredNavMeshDataAssetsForOwnedSurfaces(GameObject gameObjectInPrefab)
|
||||
{
|
||||
// Debug.LogFormat("DeleteStoredNavMeshDataAsset() when saving prefab {0}", gameObjectInPrefab.name);
|
||||
|
||||
var surfaces = gameObjectInPrefab.GetComponentsInChildren<NavMeshSurface2d>(true);
|
||||
foreach (var surface in surfaces)
|
||||
DeleteStoredPrefabNavMeshDataAsset(surface);
|
||||
}
|
||||
|
||||
void DeleteStoredPrefabNavMeshDataAsset(NavMeshSurface2d surface)
|
||||
{
|
||||
for (var i = m_PrefabNavMeshDataAssets.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var storedAssetInfo = m_PrefabNavMeshDataAssets[i];
|
||||
if (storedAssetInfo.surface == surface)
|
||||
{
|
||||
var storedNavMeshData = storedAssetInfo.navMeshData;
|
||||
if (storedNavMeshData != null && storedNavMeshData != surface.navMeshData)
|
||||
{
|
||||
var assetPath = AssetDatabase.GetAssetPath(storedNavMeshData);
|
||||
AssetDatabase.DeleteAsset(assetPath);
|
||||
}
|
||||
|
||||
m_PrefabNavMeshDataAssets.RemoveAt(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_PrefabNavMeshDataAssets.Count == 0)
|
||||
{
|
||||
PrefabStage.prefabSaving -= DeleteStoredNavMeshDataAssetsForOwnedSurfaces;
|
||||
PrefabStage.prefabStageClosing -= ForgetUnsavedNavMeshDataChanges;
|
||||
}
|
||||
}
|
||||
|
||||
void ForgetUnsavedNavMeshDataChanges(PrefabStage prefabStage)
|
||||
{
|
||||
// Debug.Log("On prefab closing - forget about this object's surfaces and stop caring about prefab saving");
|
||||
|
||||
if (prefabStage == null)
|
||||
return;
|
||||
|
||||
var allSurfacesInPrefab = prefabStage.prefabContentsRoot.GetComponentsInChildren<NavMeshSurface2d>(true);
|
||||
NavMeshSurface2d surfaceInPrefab = null;
|
||||
var index = 0;
|
||||
do
|
||||
{
|
||||
if (allSurfacesInPrefab.Length > 0)
|
||||
surfaceInPrefab = allSurfacesInPrefab[index];
|
||||
|
||||
for (var i = m_PrefabNavMeshDataAssets.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var storedPrefabInfo = m_PrefabNavMeshDataAssets[i];
|
||||
if (storedPrefabInfo.surface == null)
|
||||
{
|
||||
// Debug.LogFormat("A surface from the prefab got deleted after it has baked a new NavMesh but it hasn't saved it. Now the unsaved asset gets deleted. ({0})", storedPrefabInfo.navMeshData);
|
||||
|
||||
// surface got deleted, thus delete its initial NavMeshData asset
|
||||
if (storedPrefabInfo.navMeshData != null)
|
||||
{
|
||||
var assetPath = AssetDatabase.GetAssetPath(storedPrefabInfo.navMeshData);
|
||||
AssetDatabase.DeleteAsset(assetPath);
|
||||
}
|
||||
|
||||
m_PrefabNavMeshDataAssets.RemoveAt(i);
|
||||
}
|
||||
else if (surfaceInPrefab != null && storedPrefabInfo.surface == surfaceInPrefab)
|
||||
{
|
||||
//Debug.LogFormat("The surface {0} from the prefab was storing the original navmesh data and now will be forgotten", surfaceInPrefab);
|
||||
|
||||
var baseSurface = PrefabUtility.GetCorrespondingObjectFromSource(surfaceInPrefab) as NavMeshSurface2d;
|
||||
if (baseSurface == null || surfaceInPrefab.navMeshData != baseSurface.navMeshData)
|
||||
{
|
||||
var assetPath = AssetDatabase.GetAssetPath(surfaceInPrefab.navMeshData);
|
||||
AssetDatabase.DeleteAsset(assetPath);
|
||||
|
||||
//Debug.LogFormat("The surface {0} from the prefab has baked new NavMeshData but did not save this change so the asset has been now deleted. ({1})",
|
||||
// surfaceInPrefab, assetPath);
|
||||
}
|
||||
|
||||
m_PrefabNavMeshDataAssets.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
} while (++index < allSurfacesInPrefab.Length);
|
||||
|
||||
if (m_PrefabNavMeshDataAssets.Count == 0)
|
||||
{
|
||||
PrefabStage.prefabSaving -= DeleteStoredNavMeshDataAssetsForOwnedSurfaces;
|
||||
PrefabStage.prefabStageClosing -= ForgetUnsavedNavMeshDataChanges;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ce18366e52b6ecd4bb22b17b7c92a9b9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"name": "NavMeshComponentsEditor",
|
||||
"references": [
|
||||
"NavMeshComponents"
|
||||
],
|
||||
"optionalUnityReferences": [],
|
||||
"includePlatforms": [
|
||||
"Editor"
|
||||
],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 86c9d8e67265f41469be06142c397d17
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,258 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.AI;
|
||||
|
||||
namespace UnityEditor.AI
|
||||
{
|
||||
public static class NavMeshComponentsGUIUtility
|
||||
{
|
||||
public static void AreaPopup(string labelName, SerializedProperty areaProperty)
|
||||
{
|
||||
var areaIndex = -1;
|
||||
var areaNames = GameObjectUtility.GetNavMeshAreaNames();
|
||||
for (var i = 0; i < areaNames.Length; i++)
|
||||
{
|
||||
var areaValue = GameObjectUtility.GetNavMeshAreaFromName(areaNames[i]);
|
||||
if (areaValue == areaProperty.intValue)
|
||||
areaIndex = i;
|
||||
}
|
||||
ArrayUtility.Add(ref areaNames, "");
|
||||
ArrayUtility.Add(ref areaNames, "Open Area Settings...");
|
||||
|
||||
var rect = EditorGUILayout.GetControlRect(true, EditorGUIUtility.singleLineHeight);
|
||||
EditorGUI.BeginProperty(rect, GUIContent.none, areaProperty);
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
areaIndex = EditorGUI.Popup(rect, labelName, areaIndex, areaNames);
|
||||
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
if (areaIndex >= 0 && areaIndex < areaNames.Length - 2)
|
||||
areaProperty.intValue = GameObjectUtility.GetNavMeshAreaFromName(areaNames[areaIndex]);
|
||||
else if (areaIndex == areaNames.Length - 1)
|
||||
NavMeshEditorHelpers.OpenAreaSettings();
|
||||
}
|
||||
|
||||
EditorGUI.EndProperty();
|
||||
}
|
||||
|
||||
public static void AgentTypePopup(string labelName, SerializedProperty agentTypeID)
|
||||
{
|
||||
var index = -1;
|
||||
var count = NavMesh.GetSettingsCount();
|
||||
var agentTypeNames = new string[count + 2];
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
var id = NavMesh.GetSettingsByIndex(i).agentTypeID;
|
||||
var name = NavMesh.GetSettingsNameFromID(id);
|
||||
agentTypeNames[i] = name;
|
||||
if (id == agentTypeID.intValue)
|
||||
index = i;
|
||||
}
|
||||
agentTypeNames[count] = "";
|
||||
agentTypeNames[count + 1] = "Open Agent Settings...";
|
||||
|
||||
bool validAgentType = index != -1;
|
||||
if (!validAgentType)
|
||||
{
|
||||
EditorGUILayout.HelpBox("Agent Type invalid.", MessageType.Warning);
|
||||
}
|
||||
|
||||
var rect = EditorGUILayout.GetControlRect(true, EditorGUIUtility.singleLineHeight);
|
||||
EditorGUI.BeginProperty(rect, GUIContent.none, agentTypeID);
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
index = EditorGUI.Popup(rect, labelName, index, agentTypeNames);
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
if (index >= 0 && index < count)
|
||||
{
|
||||
var id = NavMesh.GetSettingsByIndex(index).agentTypeID;
|
||||
agentTypeID.intValue = id;
|
||||
}
|
||||
else if (index == count + 1)
|
||||
{
|
||||
NavMeshEditorHelpers.OpenAgentSettings(-1);
|
||||
}
|
||||
}
|
||||
|
||||
EditorGUI.EndProperty();
|
||||
}
|
||||
|
||||
// Agent mask is a set (internally array/list) of agentTypeIDs.
|
||||
// It is used to describe which agents modifiers apply to.
|
||||
// There is a special case of "None" which is an empty array.
|
||||
// There is a special case of "All" which is an array of length 1, and value of -1.
|
||||
public static void AgentMaskPopup(string labelName, SerializedProperty agentMask)
|
||||
{
|
||||
// Contents of the dropdown box.
|
||||
string popupContent = "";
|
||||
|
||||
if (agentMask.hasMultipleDifferentValues)
|
||||
popupContent = "\u2014";
|
||||
else
|
||||
popupContent = GetAgentMaskLabelName(agentMask);
|
||||
|
||||
var content = new GUIContent(popupContent);
|
||||
var popupRect = GUILayoutUtility.GetRect(content, EditorStyles.popup);
|
||||
|
||||
EditorGUI.BeginProperty(popupRect, GUIContent.none, agentMask);
|
||||
popupRect = EditorGUI.PrefixLabel(popupRect, 0, new GUIContent(labelName));
|
||||
bool pressed = GUI.Button(popupRect, content, EditorStyles.popup);
|
||||
|
||||
if (pressed)
|
||||
{
|
||||
var show = !agentMask.hasMultipleDifferentValues;
|
||||
var showNone = show && agentMask.arraySize == 0;
|
||||
var showAll = show && IsAll(agentMask);
|
||||
|
||||
var menu = new GenericMenu();
|
||||
menu.AddItem(new GUIContent("None"), showNone, SetAgentMaskNone, agentMask);
|
||||
menu.AddItem(new GUIContent("All"), showAll, SetAgentMaskAll, agentMask);
|
||||
menu.AddSeparator("");
|
||||
|
||||
var count = NavMesh.GetSettingsCount();
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
var id = NavMesh.GetSettingsByIndex(i).agentTypeID;
|
||||
var sname = NavMesh.GetSettingsNameFromID(id);
|
||||
|
||||
var showSelected = show && AgentMaskHasSelectedAgentTypeID(agentMask, id);
|
||||
var userData = new object[] { agentMask, id, !showSelected };
|
||||
menu.AddItem(new GUIContent(sname), showSelected, ToggleAgentMaskItem, userData);
|
||||
}
|
||||
|
||||
menu.DropDown(popupRect);
|
||||
}
|
||||
|
||||
EditorGUI.EndProperty();
|
||||
}
|
||||
|
||||
public static GameObject CreateAndSelectGameObject(string suggestedName, GameObject parent)
|
||||
{
|
||||
var parentTransform = parent != null ? parent.transform : null;
|
||||
var uniqueName = GameObjectUtility.GetUniqueNameForSibling(parentTransform, suggestedName);
|
||||
var child = new GameObject(uniqueName);
|
||||
|
||||
Undo.RegisterCreatedObjectUndo(child, "Create " + uniqueName);
|
||||
if (parentTransform != null)
|
||||
Undo.SetTransformParent(child.transform, parentTransform, "Parent " + uniqueName);
|
||||
|
||||
Selection.activeGameObject = child;
|
||||
|
||||
return child;
|
||||
}
|
||||
|
||||
static bool IsAll(SerializedProperty agentMask)
|
||||
{
|
||||
return agentMask.arraySize == 1 && agentMask.GetArrayElementAtIndex(0).intValue == -1;
|
||||
}
|
||||
|
||||
static void ToggleAgentMaskItem(object userData)
|
||||
{
|
||||
var args = (object[])userData;
|
||||
var agentMask = (SerializedProperty)args[0];
|
||||
var agentTypeID = (int)args[1];
|
||||
var value = (bool)args[2];
|
||||
|
||||
ToggleAgentMaskItem(agentMask, agentTypeID, value);
|
||||
}
|
||||
|
||||
static void ToggleAgentMaskItem(SerializedProperty agentMask, int agentTypeID, bool value)
|
||||
{
|
||||
if (agentMask.hasMultipleDifferentValues)
|
||||
{
|
||||
agentMask.ClearArray();
|
||||
agentMask.serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
|
||||
// Find which index this agent type is in the agentMask array.
|
||||
int idx = -1;
|
||||
for (var j = 0; j < agentMask.arraySize; j++)
|
||||
{
|
||||
var elem = agentMask.GetArrayElementAtIndex(j);
|
||||
if (elem.intValue == agentTypeID)
|
||||
idx = j;
|
||||
}
|
||||
|
||||
// Handle "All" special case.
|
||||
if (IsAll(agentMask))
|
||||
{
|
||||
agentMask.DeleteArrayElementAtIndex(0);
|
||||
}
|
||||
|
||||
// Toggle value.
|
||||
if (value)
|
||||
{
|
||||
if (idx == -1)
|
||||
{
|
||||
agentMask.InsertArrayElementAtIndex(agentMask.arraySize);
|
||||
agentMask.GetArrayElementAtIndex(agentMask.arraySize - 1).intValue = agentTypeID;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (idx != -1)
|
||||
{
|
||||
agentMask.DeleteArrayElementAtIndex(idx);
|
||||
}
|
||||
}
|
||||
|
||||
agentMask.serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
|
||||
static void SetAgentMaskNone(object data)
|
||||
{
|
||||
var agentMask = (SerializedProperty)data;
|
||||
agentMask.ClearArray();
|
||||
agentMask.serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
|
||||
static void SetAgentMaskAll(object data)
|
||||
{
|
||||
var agentMask = (SerializedProperty)data;
|
||||
agentMask.ClearArray();
|
||||
agentMask.InsertArrayElementAtIndex(0);
|
||||
agentMask.GetArrayElementAtIndex(0).intValue = -1;
|
||||
agentMask.serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
|
||||
static string GetAgentMaskLabelName(SerializedProperty agentMask)
|
||||
{
|
||||
if (agentMask.arraySize == 0)
|
||||
return "None";
|
||||
|
||||
if (IsAll(agentMask))
|
||||
return "All";
|
||||
|
||||
if (agentMask.arraySize <= 3)
|
||||
{
|
||||
var labelName = "";
|
||||
for (var j = 0; j < agentMask.arraySize; j++)
|
||||
{
|
||||
var elem = agentMask.GetArrayElementAtIndex(j);
|
||||
var settingsName = NavMesh.GetSettingsNameFromID(elem.intValue);
|
||||
if (string.IsNullOrEmpty(settingsName))
|
||||
continue;
|
||||
|
||||
if (labelName.Length > 0)
|
||||
labelName += ", ";
|
||||
labelName += settingsName;
|
||||
}
|
||||
return labelName;
|
||||
}
|
||||
|
||||
return "Mixed...";
|
||||
}
|
||||
|
||||
static bool AgentMaskHasSelectedAgentTypeID(SerializedProperty agentMask, int agentTypeID)
|
||||
{
|
||||
for (var j = 0; j < agentMask.arraySize; j++)
|
||||
{
|
||||
var elem = agentMask.GetArrayElementAtIndex(j);
|
||||
if (elem.intValue == agentTypeID)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 77fba670b979046f18d52d751e0d4659
|
||||
timeCreated: 1480524815
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
279
Assets/NavMeshPlus/NavMeshComponents/Editor/NavMeshLinkEditor.cs
Normal file
279
Assets/NavMeshPlus/NavMeshComponents/Editor/NavMeshLinkEditor.cs
Normal file
@@ -0,0 +1,279 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.AI;
|
||||
|
||||
namespace UnityEditor.AI
|
||||
{
|
||||
[CanEditMultipleObjects]
|
||||
[CustomEditor(typeof(NavMeshLink))]
|
||||
class NavMeshLinkEditor : Editor
|
||||
{
|
||||
SerializedProperty m_AgentTypeID;
|
||||
SerializedProperty m_Area;
|
||||
SerializedProperty m_CostModifier;
|
||||
SerializedProperty m_AutoUpdatePosition;
|
||||
SerializedProperty m_Bidirectional;
|
||||
SerializedProperty m_EndPoint;
|
||||
SerializedProperty m_StartPoint;
|
||||
SerializedProperty m_Width;
|
||||
|
||||
static int s_SelectedID;
|
||||
static int s_SelectedPoint = -1;
|
||||
|
||||
static Color s_HandleColor = new Color(255f, 167f, 39f, 210f) / 255;
|
||||
static Color s_HandleColorDisabled = new Color(255f * 0.75f, 167f * 0.75f, 39f * 0.75f, 100f) / 255;
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
m_AgentTypeID = serializedObject.FindProperty("m_AgentTypeID");
|
||||
m_Area = serializedObject.FindProperty("m_Area");
|
||||
m_CostModifier = serializedObject.FindProperty("m_CostModifier");
|
||||
m_AutoUpdatePosition = serializedObject.FindProperty("m_AutoUpdatePosition");
|
||||
m_Bidirectional = serializedObject.FindProperty("m_Bidirectional");
|
||||
m_EndPoint = serializedObject.FindProperty("m_EndPoint");
|
||||
m_StartPoint = serializedObject.FindProperty("m_StartPoint");
|
||||
m_Width = serializedObject.FindProperty("m_Width");
|
||||
|
||||
s_SelectedID = 0;
|
||||
s_SelectedPoint = -1;
|
||||
|
||||
NavMeshVisualizationSettings.showNavigation++;
|
||||
}
|
||||
|
||||
void OnDisable()
|
||||
{
|
||||
NavMeshVisualizationSettings.showNavigation--;
|
||||
}
|
||||
|
||||
static Matrix4x4 UnscaledLocalToWorldMatrix(Transform t)
|
||||
{
|
||||
return Matrix4x4.TRS(t.position, t.rotation, Vector3.one);
|
||||
}
|
||||
|
||||
void AlignTransformToEndPoints(NavMeshLink navLink)
|
||||
{
|
||||
var mat = UnscaledLocalToWorldMatrix(navLink.transform);
|
||||
|
||||
var worldStartPt = mat.MultiplyPoint(navLink.startPoint);
|
||||
var worldEndPt = mat.MultiplyPoint(navLink.endPoint);
|
||||
|
||||
var forward = worldEndPt - worldStartPt;
|
||||
var up = navLink.transform.up;
|
||||
|
||||
// Flatten
|
||||
forward -= Vector3.Dot(up, forward) * up;
|
||||
|
||||
var transform = navLink.transform;
|
||||
transform.rotation = Quaternion.LookRotation(forward, up);
|
||||
transform.position = (worldEndPt + worldStartPt) * 0.5f;
|
||||
transform.localScale = Vector3.one;
|
||||
|
||||
navLink.startPoint = transform.InverseTransformPoint(worldStartPt);
|
||||
navLink.endPoint = transform.InverseTransformPoint(worldEndPt);
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
serializedObject.Update();
|
||||
|
||||
NavMeshComponentsGUIUtility.AgentTypePopup("Agent Type", m_AgentTypeID);
|
||||
EditorGUILayout.Space();
|
||||
|
||||
EditorGUILayout.PropertyField(m_StartPoint);
|
||||
EditorGUILayout.PropertyField(m_EndPoint);
|
||||
|
||||
GUILayout.BeginHorizontal();
|
||||
GUILayout.Space(EditorGUIUtility.labelWidth);
|
||||
if (GUILayout.Button("Swap"))
|
||||
{
|
||||
foreach (NavMeshLink navLink in targets)
|
||||
{
|
||||
var tmp = navLink.startPoint;
|
||||
navLink.startPoint = navLink.endPoint;
|
||||
navLink.endPoint = tmp;
|
||||
}
|
||||
SceneView.RepaintAll();
|
||||
}
|
||||
if (GUILayout.Button("Align Transform"))
|
||||
{
|
||||
foreach (NavMeshLink navLink in targets)
|
||||
{
|
||||
Undo.RecordObject(navLink.transform, "Align Transform to End Points");
|
||||
Undo.RecordObject(navLink, "Align Transform to End Points");
|
||||
AlignTransformToEndPoints(navLink);
|
||||
}
|
||||
SceneView.RepaintAll();
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
EditorGUILayout.Space();
|
||||
|
||||
EditorGUILayout.PropertyField(m_Width);
|
||||
EditorGUILayout.PropertyField(m_CostModifier);
|
||||
EditorGUILayout.PropertyField(m_AutoUpdatePosition);
|
||||
EditorGUILayout.PropertyField(m_Bidirectional);
|
||||
|
||||
NavMeshComponentsGUIUtility.AreaPopup("Area Type", m_Area);
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
|
||||
EditorGUILayout.Space();
|
||||
}
|
||||
|
||||
static Vector3 CalcLinkRight(NavMeshLink navLink)
|
||||
{
|
||||
var dir = navLink.endPoint - navLink.startPoint;
|
||||
return (new Vector3(-dir.z, 0.0f, dir.x)).normalized;
|
||||
}
|
||||
|
||||
static void DrawLink(NavMeshLink navLink)
|
||||
{
|
||||
var right = CalcLinkRight(navLink);
|
||||
var rad = navLink.width * 0.5f;
|
||||
|
||||
Gizmos.DrawLine(navLink.startPoint - right * rad, navLink.startPoint + right * rad);
|
||||
Gizmos.DrawLine(navLink.endPoint - right * rad, navLink.endPoint + right * rad);
|
||||
Gizmos.DrawLine(navLink.startPoint - right * rad, navLink.endPoint - right * rad);
|
||||
Gizmos.DrawLine(navLink.startPoint + right * rad, navLink.endPoint + right * rad);
|
||||
}
|
||||
|
||||
[DrawGizmo(GizmoType.Selected | GizmoType.Active | GizmoType.Pickable)]
|
||||
static void RenderBoxGizmo(NavMeshLink navLink, GizmoType gizmoType)
|
||||
{
|
||||
if (!EditorApplication.isPlaying)
|
||||
navLink.UpdateLink();
|
||||
|
||||
var color = s_HandleColor;
|
||||
if (!navLink.enabled)
|
||||
color = s_HandleColorDisabled;
|
||||
|
||||
var oldColor = Gizmos.color;
|
||||
var oldMatrix = Gizmos.matrix;
|
||||
|
||||
Gizmos.matrix = UnscaledLocalToWorldMatrix(navLink.transform);
|
||||
|
||||
Gizmos.color = color;
|
||||
DrawLink(navLink);
|
||||
|
||||
Gizmos.matrix = oldMatrix;
|
||||
Gizmos.color = oldColor;
|
||||
|
||||
Gizmos.DrawIcon(navLink.transform.position, "NavMeshLink Icon", true);
|
||||
}
|
||||
|
||||
[DrawGizmo(GizmoType.NotInSelectionHierarchy | GizmoType.Pickable)]
|
||||
static void RenderBoxGizmoNotSelected(NavMeshLink navLink, GizmoType gizmoType)
|
||||
{
|
||||
if (NavMeshVisualizationSettings.showNavigation > 0)
|
||||
{
|
||||
var color = s_HandleColor;
|
||||
if (!navLink.enabled)
|
||||
color = s_HandleColorDisabled;
|
||||
|
||||
var oldColor = Gizmos.color;
|
||||
var oldMatrix = Gizmos.matrix;
|
||||
|
||||
Gizmos.matrix = UnscaledLocalToWorldMatrix(navLink.transform);
|
||||
|
||||
Gizmos.color = color;
|
||||
DrawLink(navLink);
|
||||
|
||||
Gizmos.matrix = oldMatrix;
|
||||
Gizmos.color = oldColor;
|
||||
}
|
||||
|
||||
Gizmos.DrawIcon(navLink.transform.position, "NavMeshLink Icon", true);
|
||||
}
|
||||
|
||||
public void OnSceneGUI()
|
||||
{
|
||||
var navLink = (NavMeshLink)target;
|
||||
if (!navLink.enabled)
|
||||
return;
|
||||
|
||||
var mat = UnscaledLocalToWorldMatrix(navLink.transform);
|
||||
|
||||
var startPt = mat.MultiplyPoint(navLink.startPoint);
|
||||
var endPt = mat.MultiplyPoint(navLink.endPoint);
|
||||
var midPt = Vector3.Lerp(startPt, endPt, 0.35f);
|
||||
var startSize = HandleUtility.GetHandleSize(startPt);
|
||||
var endSize = HandleUtility.GetHandleSize(endPt);
|
||||
var midSize = HandleUtility.GetHandleSize(midPt);
|
||||
|
||||
var zup = Quaternion.FromToRotation(Vector3.forward, Vector3.up);
|
||||
var right = mat.MultiplyVector(CalcLinkRight(navLink));
|
||||
|
||||
var oldColor = Handles.color;
|
||||
Handles.color = s_HandleColor;
|
||||
|
||||
Vector3 pos;
|
||||
|
||||
if (navLink.GetInstanceID() == s_SelectedID && s_SelectedPoint == 0)
|
||||
{
|
||||
EditorGUI.BeginChangeCheck();
|
||||
Handles.CubeHandleCap(0, startPt, zup, 0.1f * startSize, Event.current.type);
|
||||
pos = Handles.PositionHandle(startPt, navLink.transform.rotation);
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
Undo.RecordObject(navLink, "Move link point");
|
||||
navLink.startPoint = mat.inverse.MultiplyPoint(pos);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Handles.Button(startPt, zup, 0.1f * startSize, 0.1f * startSize, Handles.CubeHandleCap))
|
||||
{
|
||||
s_SelectedPoint = 0;
|
||||
s_SelectedID = navLink.GetInstanceID();
|
||||
}
|
||||
}
|
||||
|
||||
if (navLink.GetInstanceID() == s_SelectedID && s_SelectedPoint == 1)
|
||||
{
|
||||
EditorGUI.BeginChangeCheck();
|
||||
Handles.CubeHandleCap(0, endPt, zup, 0.1f * startSize, Event.current.type);
|
||||
pos = Handles.PositionHandle(endPt, navLink.transform.rotation);
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
Undo.RecordObject(navLink, "Move link point");
|
||||
navLink.endPoint = mat.inverse.MultiplyPoint(pos);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Handles.Button(endPt, zup, 0.1f * endSize, 0.1f * endSize, Handles.CubeHandleCap))
|
||||
{
|
||||
s_SelectedPoint = 1;
|
||||
s_SelectedID = navLink.GetInstanceID();
|
||||
}
|
||||
}
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
pos = Handles.Slider(midPt + right * navLink.width * 0.5f, right, midSize * 0.03f, Handles.DotHandleCap, 0);
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
Undo.RecordObject(navLink, "Adjust link width");
|
||||
navLink.width = Mathf.Max(0.0f, 2.0f * Vector3.Dot(right, (pos - midPt)));
|
||||
}
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
pos = Handles.Slider(midPt - right * navLink.width * 0.5f, -right, midSize * 0.03f, Handles.DotHandleCap, 0);
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
Undo.RecordObject(navLink, "Adjust link width");
|
||||
navLink.width = Mathf.Max(0.0f, 2.0f * Vector3.Dot(-right, (pos - midPt)));
|
||||
}
|
||||
|
||||
Handles.color = oldColor;
|
||||
}
|
||||
|
||||
[MenuItem("GameObject/AI/NavMesh Link", false, 2002)]
|
||||
static public void CreateNavMeshLink(MenuCommand menuCommand)
|
||||
{
|
||||
var parent = menuCommand.context as GameObject;
|
||||
GameObject go = NavMeshComponentsGUIUtility.CreateAndSelectGameObject("NavMesh Link", parent);
|
||||
go.AddComponent<NavMeshLink>();
|
||||
var view = SceneView.lastActiveSceneView;
|
||||
if (view != null)
|
||||
view.MoveToView(go.transform);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ece1e865d1ad84587872fe8580ab5a20
|
||||
timeCreated: 1477036743
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,49 @@
|
||||
using UnityEngine.AI;
|
||||
|
||||
namespace UnityEditor.AI
|
||||
{
|
||||
[CanEditMultipleObjects]
|
||||
[CustomEditor(typeof(NavMeshModifier))]
|
||||
class NavMeshModifierEditor : Editor
|
||||
{
|
||||
SerializedProperty m_AffectedAgents;
|
||||
SerializedProperty m_Area;
|
||||
SerializedProperty m_IgnoreFromBuild;
|
||||
SerializedProperty m_OverrideArea;
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
m_AffectedAgents = serializedObject.FindProperty("m_AffectedAgents");
|
||||
m_Area = serializedObject.FindProperty("m_Area");
|
||||
m_IgnoreFromBuild = serializedObject.FindProperty("m_IgnoreFromBuild");
|
||||
m_OverrideArea = serializedObject.FindProperty("m_OverrideArea");
|
||||
|
||||
NavMeshVisualizationSettings.showNavigation++;
|
||||
}
|
||||
|
||||
void OnDisable()
|
||||
{
|
||||
NavMeshVisualizationSettings.showNavigation--;
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
serializedObject.Update();
|
||||
|
||||
EditorGUILayout.PropertyField(m_IgnoreFromBuild);
|
||||
|
||||
EditorGUILayout.PropertyField(m_OverrideArea);
|
||||
if (m_OverrideArea.boolValue)
|
||||
{
|
||||
EditorGUI.indentLevel++;
|
||||
NavMeshComponentsGUIUtility.AreaPopup("Area Type", m_Area);
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
|
||||
NavMeshComponentsGUIUtility.AgentMaskPopup("Affected Agents", m_AffectedAgents);
|
||||
EditorGUILayout.Space();
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6fa04b4743e3947eba4d7b9e5832ea69
|
||||
timeCreated: 1477036742
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,146 @@
|
||||
using UnityEditor.IMGUI.Controls;
|
||||
using UnityEditorInternal;
|
||||
using UnityEngine.AI;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityEditor.AI
|
||||
{
|
||||
[CanEditMultipleObjects]
|
||||
[CustomEditor(typeof(NavMeshModifierVolume))]
|
||||
class NavMeshModifierVolumeEditor : Editor
|
||||
{
|
||||
SerializedProperty m_AffectedAgents;
|
||||
SerializedProperty m_Area;
|
||||
SerializedProperty m_Center;
|
||||
SerializedProperty m_Size;
|
||||
|
||||
static Color s_HandleColor = new Color(187f, 138f, 240f, 210f) / 255;
|
||||
static Color s_HandleColorDisabled = new Color(187f * 0.75f, 138f * 0.75f, 240f * 0.75f, 100f) / 255;
|
||||
|
||||
BoxBoundsHandle m_BoundsHandle = new BoxBoundsHandle();
|
||||
|
||||
bool editingCollider
|
||||
{
|
||||
get { return EditMode.editMode == EditMode.SceneViewEditMode.Collider && EditMode.IsOwner(this); }
|
||||
}
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
m_AffectedAgents = serializedObject.FindProperty("m_AffectedAgents");
|
||||
m_Area = serializedObject.FindProperty("m_Area");
|
||||
m_Center = serializedObject.FindProperty("m_Center");
|
||||
m_Size = serializedObject.FindProperty("m_Size");
|
||||
|
||||
NavMeshVisualizationSettings.showNavigation++;
|
||||
}
|
||||
|
||||
void OnDisable()
|
||||
{
|
||||
NavMeshVisualizationSettings.showNavigation--;
|
||||
}
|
||||
|
||||
Bounds GetBounds()
|
||||
{
|
||||
var navModifier = (NavMeshModifierVolume)target;
|
||||
return new Bounds(navModifier.transform.position, navModifier.size);
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
serializedObject.Update();
|
||||
|
||||
EditMode.DoEditModeInspectorModeButton(EditMode.SceneViewEditMode.Collider, "Edit Volume",
|
||||
EditorGUIUtility.IconContent("EditCollider"), GetBounds, this);
|
||||
|
||||
EditorGUILayout.PropertyField(m_Size);
|
||||
EditorGUILayout.PropertyField(m_Center);
|
||||
|
||||
NavMeshComponentsGUIUtility.AreaPopup("Area Type", m_Area);
|
||||
NavMeshComponentsGUIUtility.AgentMaskPopup("Affected Agents", m_AffectedAgents);
|
||||
EditorGUILayout.Space();
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
|
||||
[DrawGizmo(GizmoType.Selected | GizmoType.Active)]
|
||||
static void RenderBoxGizmo(NavMeshModifierVolume navModifier, GizmoType gizmoType)
|
||||
{
|
||||
var color = navModifier.enabled ? s_HandleColor : s_HandleColorDisabled;
|
||||
var colorTrans = new Color(color.r * 0.75f, color.g * 0.75f, color.b * 0.75f, color.a * 0.15f);
|
||||
|
||||
var oldColor = Gizmos.color;
|
||||
var oldMatrix = Gizmos.matrix;
|
||||
|
||||
Gizmos.matrix = navModifier.transform.localToWorldMatrix;
|
||||
|
||||
Gizmos.color = colorTrans;
|
||||
Gizmos.DrawCube(navModifier.center, navModifier.size);
|
||||
|
||||
Gizmos.color = color;
|
||||
Gizmos.DrawWireCube(navModifier.center, navModifier.size);
|
||||
|
||||
Gizmos.matrix = oldMatrix;
|
||||
Gizmos.color = oldColor;
|
||||
|
||||
Gizmos.DrawIcon(navModifier.transform.position, "NavMeshModifierVolume Icon", true);
|
||||
}
|
||||
|
||||
[DrawGizmo(GizmoType.NotInSelectionHierarchy | GizmoType.Pickable)]
|
||||
static void RenderBoxGizmoNotSelected(NavMeshModifierVolume navModifier, GizmoType gizmoType)
|
||||
{
|
||||
if (NavMeshVisualizationSettings.showNavigation > 0)
|
||||
{
|
||||
var color = navModifier.enabled ? s_HandleColor : s_HandleColorDisabled;
|
||||
var oldColor = Gizmos.color;
|
||||
var oldMatrix = Gizmos.matrix;
|
||||
|
||||
Gizmos.matrix = navModifier.transform.localToWorldMatrix;
|
||||
|
||||
Gizmos.color = color;
|
||||
Gizmos.DrawWireCube(navModifier.center, navModifier.size);
|
||||
|
||||
Gizmos.matrix = oldMatrix;
|
||||
Gizmos.color = oldColor;
|
||||
}
|
||||
|
||||
Gizmos.DrawIcon(navModifier.transform.position, "NavMeshModifierVolume Icon", true);
|
||||
}
|
||||
|
||||
void OnSceneGUI()
|
||||
{
|
||||
if (!editingCollider)
|
||||
return;
|
||||
|
||||
var vol = (NavMeshModifierVolume)target;
|
||||
var color = vol.enabled ? s_HandleColor : s_HandleColorDisabled;
|
||||
using (new Handles.DrawingScope(color, vol.transform.localToWorldMatrix))
|
||||
{
|
||||
m_BoundsHandle.center = vol.center;
|
||||
m_BoundsHandle.size = vol.size;
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
m_BoundsHandle.DrawHandle();
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
Undo.RecordObject(vol, "Modified NavMesh Modifier Volume");
|
||||
Vector3 center = m_BoundsHandle.center;
|
||||
Vector3 size = m_BoundsHandle.size;
|
||||
vol.center = center;
|
||||
vol.size = size;
|
||||
EditorUtility.SetDirty(target);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[MenuItem("GameObject/AI/NavMesh Modifier Volume", false, 2001)]
|
||||
static public void CreateNavMeshModifierVolume(MenuCommand menuCommand)
|
||||
{
|
||||
var parent = menuCommand.context as GameObject;
|
||||
var go = NavMeshComponentsGUIUtility.CreateAndSelectGameObject("NavMesh Modifier Volume", parent);
|
||||
go.AddComponent<NavMeshModifierVolume>();
|
||||
var view = SceneView.lastActiveSceneView;
|
||||
if (view != null)
|
||||
view.MoveToView(go.transform);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c0f3bef2a67ae4e139538afec3e59b03
|
||||
timeCreated: 1477036743
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,400 @@
|
||||
#define NAVMESHCOMPONENTS_SHOW_NAVMESHDATA_REF
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using UnityEditor.Experimental.SceneManagement;
|
||||
using UnityEditor.IMGUI.Controls;
|
||||
using UnityEditor.SceneManagement;
|
||||
using UnityEditorInternal;
|
||||
using UnityEngine.AI;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityEditor.AI
|
||||
{
|
||||
[CanEditMultipleObjects]
|
||||
[CustomEditor(typeof(NavMeshSurface))]
|
||||
class NavMeshSurfaceEditor : Editor
|
||||
{
|
||||
SerializedProperty m_AgentTypeID;
|
||||
SerializedProperty m_BuildHeightMesh;
|
||||
SerializedProperty m_Center;
|
||||
SerializedProperty m_CollectObjects;
|
||||
SerializedProperty m_DefaultArea;
|
||||
SerializedProperty m_LayerMask;
|
||||
SerializedProperty m_OverrideTileSize;
|
||||
SerializedProperty m_OverrideVoxelSize;
|
||||
SerializedProperty m_Size;
|
||||
SerializedProperty m_TileSize;
|
||||
SerializedProperty m_UseGeometry;
|
||||
SerializedProperty m_VoxelSize;
|
||||
|
||||
#if NAVMESHCOMPONENTS_SHOW_NAVMESHDATA_REF
|
||||
SerializedProperty m_NavMeshData;
|
||||
#endif
|
||||
class Styles
|
||||
{
|
||||
public readonly GUIContent m_LayerMask = new GUIContent("Include Layers");
|
||||
|
||||
public readonly GUIContent m_ShowInputGeom = new GUIContent("Show Input Geom");
|
||||
public readonly GUIContent m_ShowVoxels = new GUIContent("Show Voxels");
|
||||
public readonly GUIContent m_ShowRegions = new GUIContent("Show Regions");
|
||||
public readonly GUIContent m_ShowRawContours = new GUIContent("Show Raw Contours");
|
||||
public readonly GUIContent m_ShowContours = new GUIContent("Show Contours");
|
||||
public readonly GUIContent m_ShowPolyMesh = new GUIContent("Show Poly Mesh");
|
||||
public readonly GUIContent m_ShowPolyMeshDetail = new GUIContent("Show Poly Mesh Detail");
|
||||
}
|
||||
|
||||
static Styles s_Styles;
|
||||
|
||||
static bool s_ShowDebugOptions;
|
||||
|
||||
static Color s_HandleColor = new Color(127f, 214f, 244f, 100f) / 255;
|
||||
static Color s_HandleColorSelected = new Color(127f, 214f, 244f, 210f) / 255;
|
||||
static Color s_HandleColorDisabled = new Color(127f * 0.75f, 214f * 0.75f, 244f * 0.75f, 100f) / 255;
|
||||
|
||||
BoxBoundsHandle m_BoundsHandle = new BoxBoundsHandle();
|
||||
|
||||
bool editingCollider
|
||||
{
|
||||
get { return EditMode.editMode == EditMode.SceneViewEditMode.Collider && EditMode.IsOwner(this); }
|
||||
}
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
m_AgentTypeID = serializedObject.FindProperty("m_AgentTypeID");
|
||||
m_BuildHeightMesh = serializedObject.FindProperty("m_BuildHeightMesh");
|
||||
m_Center = serializedObject.FindProperty("m_Center");
|
||||
m_CollectObjects = serializedObject.FindProperty("m_CollectObjects");
|
||||
m_DefaultArea = serializedObject.FindProperty("m_DefaultArea");
|
||||
m_LayerMask = serializedObject.FindProperty("m_LayerMask");
|
||||
m_OverrideTileSize = serializedObject.FindProperty("m_OverrideTileSize");
|
||||
m_OverrideVoxelSize = serializedObject.FindProperty("m_OverrideVoxelSize");
|
||||
m_Size = serializedObject.FindProperty("m_Size");
|
||||
m_TileSize = serializedObject.FindProperty("m_TileSize");
|
||||
m_UseGeometry = serializedObject.FindProperty("m_UseGeometry");
|
||||
m_VoxelSize = serializedObject.FindProperty("m_VoxelSize");
|
||||
|
||||
#if NAVMESHCOMPONENTS_SHOW_NAVMESHDATA_REF
|
||||
m_NavMeshData = serializedObject.FindProperty("m_NavMeshData");
|
||||
#endif
|
||||
NavMeshVisualizationSettings.showNavigation++;
|
||||
}
|
||||
|
||||
void OnDisable()
|
||||
{
|
||||
NavMeshVisualizationSettings.showNavigation--;
|
||||
}
|
||||
|
||||
Bounds GetBounds()
|
||||
{
|
||||
var navSurface = (NavMeshSurface)target;
|
||||
return new Bounds(navSurface.transform.position, navSurface.size);
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
if (s_Styles == null)
|
||||
s_Styles = new Styles();
|
||||
|
||||
serializedObject.Update();
|
||||
|
||||
var bs = NavMesh.GetSettingsByID(m_AgentTypeID.intValue);
|
||||
|
||||
if (bs.agentTypeID != -1)
|
||||
{
|
||||
// Draw image
|
||||
const float diagramHeight = 80.0f;
|
||||
Rect agentDiagramRect = EditorGUILayout.GetControlRect(false, diagramHeight);
|
||||
NavMeshEditorHelpers.DrawAgentDiagram(agentDiagramRect, bs.agentRadius, bs.agentHeight, bs.agentClimb, bs.agentSlope);
|
||||
}
|
||||
NavMeshComponentsGUIUtility.AgentTypePopup("Agent Type", m_AgentTypeID);
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
EditorGUILayout.PropertyField(m_CollectObjects);
|
||||
if ((CollectObjects)m_CollectObjects.enumValueIndex == CollectObjects.Volume)
|
||||
{
|
||||
EditorGUI.indentLevel++;
|
||||
|
||||
EditMode.DoEditModeInspectorModeButton(EditMode.SceneViewEditMode.Collider, "Edit Volume",
|
||||
EditorGUIUtility.IconContent("EditCollider"), GetBounds, this);
|
||||
EditorGUILayout.PropertyField(m_Size);
|
||||
EditorGUILayout.PropertyField(m_Center);
|
||||
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (editingCollider)
|
||||
EditMode.QuitEditMode();
|
||||
}
|
||||
|
||||
EditorGUILayout.PropertyField(m_LayerMask, s_Styles.m_LayerMask);
|
||||
EditorGUILayout.PropertyField(m_UseGeometry);
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
m_OverrideVoxelSize.isExpanded = EditorGUILayout.Foldout(m_OverrideVoxelSize.isExpanded, "Advanced");
|
||||
if (m_OverrideVoxelSize.isExpanded)
|
||||
{
|
||||
EditorGUI.indentLevel++;
|
||||
|
||||
NavMeshComponentsGUIUtility.AreaPopup("Default Area", m_DefaultArea);
|
||||
|
||||
// Override voxel size.
|
||||
EditorGUILayout.PropertyField(m_OverrideVoxelSize);
|
||||
|
||||
using (new EditorGUI.DisabledScope(!m_OverrideVoxelSize.boolValue || m_OverrideVoxelSize.hasMultipleDifferentValues))
|
||||
{
|
||||
EditorGUI.indentLevel++;
|
||||
|
||||
EditorGUILayout.PropertyField(m_VoxelSize);
|
||||
|
||||
if (!m_OverrideVoxelSize.hasMultipleDifferentValues)
|
||||
{
|
||||
if (!m_AgentTypeID.hasMultipleDifferentValues)
|
||||
{
|
||||
float voxelsPerRadius = m_VoxelSize.floatValue > 0.0f ? (bs.agentRadius / m_VoxelSize.floatValue) : 0.0f;
|
||||
EditorGUILayout.LabelField(" ", voxelsPerRadius.ToString("0.00") + " voxels per agent radius", EditorStyles.miniLabel);
|
||||
}
|
||||
if (m_OverrideVoxelSize.boolValue)
|
||||
EditorGUILayout.HelpBox("Voxel size controls how accurately the navigation mesh is generated from the level geometry. A good voxel size is 2-4 voxels per agent radius. Making voxel size smaller will increase build time.", MessageType.None);
|
||||
}
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
|
||||
// Override tile size
|
||||
EditorGUILayout.PropertyField(m_OverrideTileSize);
|
||||
|
||||
using (new EditorGUI.DisabledScope(!m_OverrideTileSize.boolValue || m_OverrideTileSize.hasMultipleDifferentValues))
|
||||
{
|
||||
EditorGUI.indentLevel++;
|
||||
|
||||
EditorGUILayout.PropertyField(m_TileSize);
|
||||
|
||||
if (!m_TileSize.hasMultipleDifferentValues && !m_VoxelSize.hasMultipleDifferentValues)
|
||||
{
|
||||
float tileWorldSize = m_TileSize.intValue * m_VoxelSize.floatValue;
|
||||
EditorGUILayout.LabelField(" ", tileWorldSize.ToString("0.00") + " world units", EditorStyles.miniLabel);
|
||||
}
|
||||
|
||||
if (!m_OverrideTileSize.hasMultipleDifferentValues)
|
||||
{
|
||||
if (m_OverrideTileSize.boolValue)
|
||||
EditorGUILayout.HelpBox("Tile size controls the how local the changes to the world are (rebuild or carve). Small tile size allows more local changes, while potentially generating more data overall.", MessageType.None);
|
||||
}
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
|
||||
|
||||
// Height mesh
|
||||
using (new EditorGUI.DisabledScope(true))
|
||||
{
|
||||
EditorGUILayout.PropertyField(m_BuildHeightMesh);
|
||||
}
|
||||
|
||||
EditorGUILayout.Space();
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
|
||||
var hadError = false;
|
||||
var multipleTargets = targets.Length > 1;
|
||||
foreach (NavMeshSurface navSurface in targets)
|
||||
{
|
||||
var settings = navSurface.GetBuildSettings();
|
||||
// Calculating bounds is potentially expensive when unbounded - so here we just use the center/size.
|
||||
// It means the validation is not checking vertical voxel limit correctly when the surface is set to something else than "in volume".
|
||||
var bounds = new Bounds(Vector3.zero, Vector3.zero);
|
||||
if (navSurface.collectObjects == CollectObjects.Volume)
|
||||
{
|
||||
bounds = new Bounds(navSurface.center, navSurface.size);
|
||||
}
|
||||
|
||||
var errors = settings.ValidationReport(bounds);
|
||||
if (errors.Length > 0)
|
||||
{
|
||||
if (multipleTargets)
|
||||
EditorGUILayout.LabelField(navSurface.name);
|
||||
foreach (var err in errors)
|
||||
{
|
||||
EditorGUILayout.HelpBox(err, MessageType.Warning);
|
||||
}
|
||||
GUILayout.BeginHorizontal();
|
||||
GUILayout.Space(EditorGUIUtility.labelWidth);
|
||||
if (GUILayout.Button("Open Agent Settings...", EditorStyles.miniButton))
|
||||
NavMeshEditorHelpers.OpenAgentSettings(navSurface.agentTypeID);
|
||||
GUILayout.EndHorizontal();
|
||||
hadError = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (hadError)
|
||||
EditorGUILayout.Space();
|
||||
|
||||
#if NAVMESHCOMPONENTS_SHOW_NAVMESHDATA_REF
|
||||
var nmdRect = EditorGUILayout.GetControlRect(true, EditorGUIUtility.singleLineHeight);
|
||||
|
||||
EditorGUI.BeginProperty(nmdRect, GUIContent.none, m_NavMeshData);
|
||||
var rectLabel = EditorGUI.PrefixLabel(nmdRect, GUIUtility.GetControlID(FocusType.Passive), new GUIContent(m_NavMeshData.displayName));
|
||||
EditorGUI.EndProperty();
|
||||
|
||||
using (new EditorGUI.DisabledScope(true))
|
||||
{
|
||||
EditorGUI.BeginProperty(nmdRect, GUIContent.none, m_NavMeshData);
|
||||
EditorGUI.ObjectField(rectLabel, m_NavMeshData, GUIContent.none);
|
||||
EditorGUI.EndProperty();
|
||||
}
|
||||
#endif
|
||||
using (new EditorGUI.DisabledScope(Application.isPlaying || m_AgentTypeID.intValue == -1))
|
||||
{
|
||||
GUILayout.BeginHorizontal();
|
||||
GUILayout.Space(EditorGUIUtility.labelWidth);
|
||||
if (GUILayout.Button("Clear"))
|
||||
{
|
||||
NavMeshAssetManager.instance.ClearSurfaces(targets);
|
||||
SceneView.RepaintAll();
|
||||
}
|
||||
|
||||
if (GUILayout.Button("Bake"))
|
||||
{
|
||||
NavMeshAssetManager.instance.StartBakingSurfaces(targets);
|
||||
}
|
||||
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
// Show progress for the selected targets
|
||||
var bakeOperations = NavMeshAssetManager.instance.GetBakeOperations();
|
||||
for (int i = bakeOperations.Count - 1; i >= 0; --i)
|
||||
{
|
||||
if (!targets.Contains(bakeOperations[i].surface))
|
||||
continue;
|
||||
|
||||
var oper = bakeOperations[i].bakeOperation;
|
||||
if (oper == null)
|
||||
continue;
|
||||
|
||||
var p = oper.progress;
|
||||
if (oper.isDone)
|
||||
{
|
||||
SceneView.RepaintAll();
|
||||
continue;
|
||||
}
|
||||
|
||||
GUILayout.BeginHorizontal();
|
||||
|
||||
if (GUILayout.Button("Cancel", EditorStyles.miniButton))
|
||||
{
|
||||
var bakeData = bakeOperations[i].bakeData;
|
||||
UnityEngine.AI.NavMeshBuilder.Cancel(bakeData);
|
||||
bakeOperations.RemoveAt(i);
|
||||
}
|
||||
|
||||
EditorGUI.ProgressBar(EditorGUILayout.GetControlRect(), p, "Baking: " + (int)(100 * p) + "%");
|
||||
if (p <= 1)
|
||||
Repaint();
|
||||
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
}
|
||||
|
||||
[DrawGizmo(GizmoType.Selected | GizmoType.Active | GizmoType.Pickable)]
|
||||
static void RenderBoxGizmoSelected(NavMeshSurface navSurface, GizmoType gizmoType)
|
||||
{
|
||||
RenderBoxGizmo(navSurface, gizmoType, true);
|
||||
}
|
||||
|
||||
[DrawGizmo(GizmoType.NotInSelectionHierarchy | GizmoType.Pickable)]
|
||||
static void RenderBoxGizmoNotSelected(NavMeshSurface navSurface, GizmoType gizmoType)
|
||||
{
|
||||
if (NavMeshVisualizationSettings.showNavigation > 0)
|
||||
RenderBoxGizmo(navSurface, gizmoType, false);
|
||||
else
|
||||
Gizmos.DrawIcon(navSurface.transform.position, "NavMeshSurface Icon", true);
|
||||
}
|
||||
|
||||
static void RenderBoxGizmo(NavMeshSurface navSurface, GizmoType gizmoType, bool selected)
|
||||
{
|
||||
var color = selected ? s_HandleColorSelected : s_HandleColor;
|
||||
if (!navSurface.enabled)
|
||||
color = s_HandleColorDisabled;
|
||||
|
||||
var oldColor = Gizmos.color;
|
||||
var oldMatrix = Gizmos.matrix;
|
||||
|
||||
// Use the unscaled matrix for the NavMeshSurface
|
||||
var localToWorld = Matrix4x4.TRS(navSurface.transform.position, navSurface.transform.rotation, Vector3.one);
|
||||
Gizmos.matrix = localToWorld;
|
||||
|
||||
if (navSurface.collectObjects == CollectObjects.Volume)
|
||||
{
|
||||
Gizmos.color = color;
|
||||
Gizmos.DrawWireCube(navSurface.center, navSurface.size);
|
||||
|
||||
if (selected && navSurface.enabled)
|
||||
{
|
||||
var colorTrans = new Color(color.r * 0.75f, color.g * 0.75f, color.b * 0.75f, color.a * 0.15f);
|
||||
Gizmos.color = colorTrans;
|
||||
Gizmos.DrawCube(navSurface.center, navSurface.size);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (navSurface.navMeshData != null)
|
||||
{
|
||||
var bounds = navSurface.navMeshData.sourceBounds;
|
||||
Gizmos.color = Color.grey;
|
||||
Gizmos.DrawWireCube(bounds.center, bounds.size);
|
||||
}
|
||||
}
|
||||
|
||||
Gizmos.matrix = oldMatrix;
|
||||
Gizmos.color = oldColor;
|
||||
|
||||
Gizmos.DrawIcon(navSurface.transform.position, "NavMeshSurface Icon", true);
|
||||
}
|
||||
|
||||
void OnSceneGUI()
|
||||
{
|
||||
if (!editingCollider)
|
||||
return;
|
||||
|
||||
var navSurface = (NavMeshSurface)target;
|
||||
var color = navSurface.enabled ? s_HandleColor : s_HandleColorDisabled;
|
||||
var localToWorld = Matrix4x4.TRS(navSurface.transform.position, navSurface.transform.rotation, Vector3.one);
|
||||
using (new Handles.DrawingScope(color, localToWorld))
|
||||
{
|
||||
m_BoundsHandle.center = navSurface.center;
|
||||
m_BoundsHandle.size = navSurface.size;
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
m_BoundsHandle.DrawHandle();
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
Undo.RecordObject(navSurface, "Modified NavMesh Surface");
|
||||
Vector3 center = m_BoundsHandle.center;
|
||||
Vector3 size = m_BoundsHandle.size;
|
||||
navSurface.center = center;
|
||||
navSurface.size = size;
|
||||
EditorUtility.SetDirty(target);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[MenuItem("GameObject/AI/NavMesh Surface", false, 2000)]
|
||||
public static void CreateNavMeshSurface(MenuCommand menuCommand)
|
||||
{
|
||||
var parent = menuCommand.context as GameObject;
|
||||
var go = NavMeshComponentsGUIUtility.CreateAndSelectGameObject("NavMesh Surface", parent);
|
||||
go.AddComponent<NavMeshSurface>();
|
||||
var view = SceneView.lastActiveSceneView;
|
||||
if (view != null)
|
||||
view.MoveToView(go.transform);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1c32167dbf3314852b6006a288eb449b
|
||||
timeCreated: 1476968447
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,448 @@
|
||||
#define NAVMESHCOMPONENTS_SHOW_NAVMESHDATA_REF
|
||||
|
||||
using System.Linq;
|
||||
using UnityEditor.IMGUI.Controls;
|
||||
using UnityEditorInternal;
|
||||
using UnityEngine.AI;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityEditor.AI
|
||||
{
|
||||
[CanEditMultipleObjects]
|
||||
[CustomEditor(typeof(NavMeshSurface2d))]
|
||||
class NavMeshSurfaceEditor2d : Editor
|
||||
{
|
||||
SerializedProperty m_AgentTypeID;
|
||||
SerializedProperty m_BuildHeightMesh;
|
||||
SerializedProperty m_Center;
|
||||
SerializedProperty m_CollectObjects;
|
||||
SerializedProperty m_DefaultArea;
|
||||
SerializedProperty m_LayerMask;
|
||||
|
||||
SerializedProperty m_OverrideByGrid;
|
||||
SerializedProperty m_UseMeshPrefab;
|
||||
SerializedProperty m_CompressBounds;
|
||||
SerializedProperty m_OverrideVector;
|
||||
|
||||
SerializedProperty m_OverrideTileSize;
|
||||
SerializedProperty m_OverrideVoxelSize;
|
||||
SerializedProperty m_Size;
|
||||
SerializedProperty m_TileSize;
|
||||
SerializedProperty m_UseGeometry;
|
||||
SerializedProperty m_VoxelSize;
|
||||
|
||||
SerializedProperty m_HideEditorLogs;
|
||||
|
||||
#if NAVMESHCOMPONENTS_SHOW_NAVMESHDATA_REF
|
||||
SerializedProperty m_NavMeshData;
|
||||
#endif
|
||||
class Styles
|
||||
{
|
||||
public readonly GUIContent m_LayerMask = new GUIContent("Include Layers");
|
||||
|
||||
public readonly GUIContent m_ShowInputGeom = new GUIContent("Show Input Geom");
|
||||
public readonly GUIContent m_ShowVoxels = new GUIContent("Show Voxels");
|
||||
public readonly GUIContent m_ShowRegions = new GUIContent("Show Regions");
|
||||
public readonly GUIContent m_ShowRawContours = new GUIContent("Show Raw Contours");
|
||||
public readonly GUIContent m_ShowContours = new GUIContent("Show Contours");
|
||||
public readonly GUIContent m_ShowPolyMesh = new GUIContent("Show Poly Mesh");
|
||||
public readonly GUIContent m_ShowPolyMeshDetail = new GUIContent("Show Poly Mesh Detail");
|
||||
}
|
||||
|
||||
static Styles s_Styles;
|
||||
|
||||
static bool s_ShowDebugOptions;
|
||||
|
||||
static Color s_HandleColor = new Color(127f, 214f, 244f, 100f) / 255;
|
||||
static Color s_HandleColorSelected = new Color(127f, 214f, 244f, 210f) / 255;
|
||||
static Color s_HandleColorDisabled = new Color(127f * 0.75f, 214f * 0.75f, 244f * 0.75f, 100f) / 255;
|
||||
|
||||
BoxBoundsHandle m_BoundsHandle = new BoxBoundsHandle();
|
||||
|
||||
bool editingCollider
|
||||
{
|
||||
get { return EditMode.editMode == EditMode.SceneViewEditMode.Collider && EditMode.IsOwner(this); }
|
||||
}
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
m_AgentTypeID = serializedObject.FindProperty("m_AgentTypeID");
|
||||
m_BuildHeightMesh = serializedObject.FindProperty("m_BuildHeightMesh");
|
||||
m_Center = serializedObject.FindProperty("m_Center");
|
||||
m_CollectObjects = serializedObject.FindProperty("m_CollectObjects");
|
||||
m_DefaultArea = serializedObject.FindProperty("m_DefaultArea");
|
||||
m_LayerMask = serializedObject.FindProperty("m_LayerMask");
|
||||
|
||||
m_OverrideByGrid = serializedObject.FindProperty("m_OverrideByGrid");
|
||||
m_UseMeshPrefab = serializedObject.FindProperty("m_UseMeshPrefab");
|
||||
m_CompressBounds = serializedObject.FindProperty("m_CompressBounds");
|
||||
m_OverrideVector = serializedObject.FindProperty("m_OverrideVector");
|
||||
|
||||
m_OverrideTileSize = serializedObject.FindProperty("m_OverrideTileSize");
|
||||
m_OverrideVoxelSize = serializedObject.FindProperty("m_OverrideVoxelSize");
|
||||
m_Size = serializedObject.FindProperty("m_Size");
|
||||
m_TileSize = serializedObject.FindProperty("m_TileSize");
|
||||
m_UseGeometry = serializedObject.FindProperty("m_UseGeometry");
|
||||
m_VoxelSize = serializedObject.FindProperty("m_VoxelSize");
|
||||
|
||||
m_HideEditorLogs = serializedObject.FindProperty("m_HideEditorLogs");
|
||||
|
||||
#if NAVMESHCOMPONENTS_SHOW_NAVMESHDATA_REF
|
||||
m_NavMeshData = serializedObject.FindProperty("m_NavMeshData");
|
||||
#endif
|
||||
NavMeshVisualizationSettings.showNavigation++;
|
||||
}
|
||||
|
||||
void OnDisable()
|
||||
{
|
||||
NavMeshVisualizationSettings.showNavigation--;
|
||||
}
|
||||
|
||||
Bounds GetBounds()
|
||||
{
|
||||
var navSurface = (NavMeshSurface2d)target;
|
||||
return new Bounds(navSurface.transform.position, navSurface.size);
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
if (s_Styles == null)
|
||||
s_Styles = new Styles();
|
||||
|
||||
serializedObject.Update();
|
||||
|
||||
var bs = NavMesh.GetSettingsByID(m_AgentTypeID.intValue);
|
||||
|
||||
if (bs.agentTypeID != -1)
|
||||
{
|
||||
// Draw image
|
||||
const float diagramHeight = 80.0f;
|
||||
Rect agentDiagramRect = EditorGUILayout.GetControlRect(false, diagramHeight);
|
||||
NavMeshEditorHelpers.DrawAgentDiagram(agentDiagramRect, bs.agentRadius, bs.agentHeight, bs.agentClimb, bs.agentSlope);
|
||||
}
|
||||
NavMeshComponentsGUIUtility.AgentTypePopup("Agent Type", m_AgentTypeID);
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
if ((CollectObjects)m_CollectObjects.enumValueIndex != CollectObjects.Children
|
||||
&& GameObject.FindObjectOfType<Grid>() == null)
|
||||
{
|
||||
EditorGUILayout.HelpBox($"{CollectObjects.All} or {CollectObjects.Volume} is not intended to be used without root Grid object in scene. Use {CollectObjects.Children} instead.", MessageType.Warning);
|
||||
}
|
||||
|
||||
EditorGUILayout.PropertyField(m_CollectObjects);
|
||||
if ((CollectObjects)m_CollectObjects.enumValueIndex == CollectObjects.Volume)
|
||||
{
|
||||
EditorGUI.indentLevel++;
|
||||
|
||||
EditMode.DoEditModeInspectorModeButton(EditMode.SceneViewEditMode.Collider, "Edit Volume",
|
||||
EditorGUIUtility.IconContent("EditCollider"), GetBounds, this);
|
||||
EditorGUILayout.PropertyField(m_Size);
|
||||
EditorGUILayout.PropertyField(m_Center);
|
||||
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (editingCollider)
|
||||
EditMode.QuitEditMode();
|
||||
}
|
||||
|
||||
EditorGUILayout.PropertyField(m_LayerMask, s_Styles.m_LayerMask);
|
||||
EditorGUILayout.PropertyField(m_UseGeometry);
|
||||
|
||||
EditorGUILayout.Space();
|
||||
EditorGUILayout.PropertyField(m_OverrideByGrid);
|
||||
EditorGUILayout.PropertyField(m_UseMeshPrefab);
|
||||
EditorGUILayout.PropertyField(m_CompressBounds);
|
||||
EditorGUILayout.PropertyField(m_OverrideVector);
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
m_OverrideVoxelSize.isExpanded = EditorGUILayout.Foldout(m_OverrideVoxelSize.isExpanded, "Advanced");
|
||||
if (m_OverrideVoxelSize.isExpanded)
|
||||
{
|
||||
EditorGUI.indentLevel++;
|
||||
|
||||
NavMeshComponentsGUIUtility.AreaPopup("Default Area", m_DefaultArea);
|
||||
|
||||
// Override voxel size.
|
||||
EditorGUILayout.PropertyField(m_OverrideVoxelSize);
|
||||
|
||||
using (new EditorGUI.DisabledScope(!m_OverrideVoxelSize.boolValue || m_OverrideVoxelSize.hasMultipleDifferentValues))
|
||||
{
|
||||
EditorGUI.indentLevel++;
|
||||
|
||||
EditorGUILayout.PropertyField(m_VoxelSize);
|
||||
|
||||
if (!m_OverrideVoxelSize.hasMultipleDifferentValues)
|
||||
{
|
||||
if (!m_AgentTypeID.hasMultipleDifferentValues)
|
||||
{
|
||||
float voxelsPerRadius = m_VoxelSize.floatValue > 0.0f ? (bs.agentRadius / m_VoxelSize.floatValue) : 0.0f;
|
||||
EditorGUILayout.LabelField(" ", voxelsPerRadius.ToString("0.00") + " voxels per agent radius", EditorStyles.miniLabel);
|
||||
}
|
||||
if (m_OverrideVoxelSize.boolValue)
|
||||
EditorGUILayout.HelpBox("Voxel size controls how accurately the navigation mesh is generated from the level geometry. A good voxel size is 2-4 voxels per agent radius. Making voxel size smaller will increase build time.", MessageType.None);
|
||||
}
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
|
||||
// Override tile size
|
||||
EditorGUILayout.PropertyField(m_OverrideTileSize);
|
||||
|
||||
using (new EditorGUI.DisabledScope(!m_OverrideTileSize.boolValue || m_OverrideTileSize.hasMultipleDifferentValues))
|
||||
{
|
||||
EditorGUI.indentLevel++;
|
||||
|
||||
EditorGUILayout.PropertyField(m_TileSize);
|
||||
|
||||
if (!m_TileSize.hasMultipleDifferentValues && !m_VoxelSize.hasMultipleDifferentValues)
|
||||
{
|
||||
float tileWorldSize = m_TileSize.intValue * m_VoxelSize.floatValue;
|
||||
EditorGUILayout.LabelField(" ", tileWorldSize.ToString("0.00") + " world units", EditorStyles.miniLabel);
|
||||
}
|
||||
|
||||
if (!m_OverrideTileSize.hasMultipleDifferentValues)
|
||||
{
|
||||
if (m_OverrideTileSize.boolValue)
|
||||
EditorGUILayout.HelpBox("Tile size controls the how local the changes to the world are (rebuild or carve). Small tile size allows more local changes, while potentially generating more data in overal.", MessageType.None);
|
||||
}
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
|
||||
|
||||
// Height mesh
|
||||
using (new EditorGUI.DisabledScope(true))
|
||||
{
|
||||
EditorGUILayout.PropertyField(m_BuildHeightMesh);
|
||||
}
|
||||
|
||||
EditorGUILayout.Space();
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
// Hide editor logs
|
||||
EditorGUILayout.PropertyField(m_HideEditorLogs);
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
|
||||
var hadError = false;
|
||||
var multipleTargets = targets.Length > 1;
|
||||
foreach (NavMeshSurface2d navSurface in targets)
|
||||
{
|
||||
var settings = navSurface.GetBuildSettings();
|
||||
// Calculating bounds is potentially expensive when unbounded - so here we just use the center/size.
|
||||
// It means the validation is not checking vertical voxel limit correctly when the surface is set to something else than "in volume".
|
||||
var bounds = new Bounds(Vector3.zero, Vector3.zero);
|
||||
if (navSurface.collectObjects == CollectObjects2d.Volume)
|
||||
{
|
||||
bounds = new Bounds(navSurface.center, navSurface.size);
|
||||
}
|
||||
|
||||
var errors = settings.ValidationReport(bounds);
|
||||
if (errors.Length > 0)
|
||||
{
|
||||
if (multipleTargets)
|
||||
EditorGUILayout.LabelField(navSurface.name);
|
||||
foreach (var err in errors)
|
||||
{
|
||||
EditorGUILayout.HelpBox(err, MessageType.Warning);
|
||||
}
|
||||
GUILayout.BeginHorizontal();
|
||||
GUILayout.Space(EditorGUIUtility.labelWidth);
|
||||
if (GUILayout.Button("Open Agent Settings...", EditorStyles.miniButton))
|
||||
NavMeshEditorHelpers.OpenAgentSettings(navSurface.agentTypeID);
|
||||
GUILayout.EndHorizontal();
|
||||
hadError = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (hadError)
|
||||
EditorGUILayout.Space();
|
||||
|
||||
#if NAVMESHCOMPONENTS_SHOW_NAVMESHDATA_REF
|
||||
var nmdRect = EditorGUILayout.GetControlRect(true, EditorGUIUtility.singleLineHeight);
|
||||
|
||||
EditorGUI.BeginProperty(nmdRect, GUIContent.none, m_NavMeshData);
|
||||
var rectLabel = EditorGUI.PrefixLabel(nmdRect, GUIUtility.GetControlID(FocusType.Passive), new GUIContent(m_NavMeshData.displayName));
|
||||
EditorGUI.EndProperty();
|
||||
|
||||
using (new EditorGUI.DisabledScope(true))
|
||||
{
|
||||
EditorGUI.BeginProperty(nmdRect, GUIContent.none, m_NavMeshData);
|
||||
EditorGUI.ObjectField(rectLabel, m_NavMeshData, GUIContent.none);
|
||||
EditorGUI.EndProperty();
|
||||
}
|
||||
#endif
|
||||
using (new EditorGUI.DisabledScope(Application.isPlaying || m_AgentTypeID.intValue == -1))
|
||||
{
|
||||
GUILayout.BeginHorizontal();
|
||||
GUILayout.Space(EditorGUIUtility.labelWidth);
|
||||
if (GUILayout.Button("Clear"))
|
||||
{
|
||||
NavMeshAssetManager2d.instance.ClearSurfaces(targets);
|
||||
SceneView.RepaintAll();
|
||||
}
|
||||
|
||||
if (GUILayout.Button("Bake"))
|
||||
{
|
||||
NavMeshAssetManager2d.instance.StartBakingSurfaces(targets);
|
||||
}
|
||||
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
GUILayout.BeginHorizontal();
|
||||
GUILayout.Space(EditorGUIUtility.labelWidth);
|
||||
if (GUILayout.Button("Rotate Surface to XY"))
|
||||
{
|
||||
foreach (var item in targets)
|
||||
{
|
||||
var o = item as NavMeshSurface2d;
|
||||
o.transform.rotation = Quaternion.Euler(-90f, 0f, 0f);
|
||||
}
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
foreach (NavMeshSurface2d navSurface in targets)
|
||||
{
|
||||
if (!Mathf.Approximately(navSurface.transform.eulerAngles.x, 270f))
|
||||
{
|
||||
EditorGUILayout.HelpBox("NavMeshSurface2d is not rotated respectively to (x-90;y0;z0). Apply rotation unless intended.", MessageType.Warning);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Show progress for the selected targets
|
||||
var bakeOperations = NavMeshAssetManager2d.instance.GetBakeOperations();
|
||||
for (int i = bakeOperations.Count - 1; i >= 0; --i)
|
||||
{
|
||||
if (!targets.Contains(bakeOperations[i].surface))
|
||||
continue;
|
||||
|
||||
var oper = bakeOperations[i].bakeOperation;
|
||||
if (oper == null)
|
||||
continue;
|
||||
|
||||
var p = oper.progress;
|
||||
if (oper.isDone)
|
||||
{
|
||||
SceneView.RepaintAll();
|
||||
continue;
|
||||
}
|
||||
|
||||
GUILayout.BeginHorizontal();
|
||||
|
||||
if (GUILayout.Button("Cancel", EditorStyles.miniButton))
|
||||
{
|
||||
var bakeData = bakeOperations[i].bakeData;
|
||||
UnityEngine.AI.NavMeshBuilder.Cancel(bakeData);
|
||||
bakeOperations.RemoveAt(i);
|
||||
}
|
||||
|
||||
EditorGUI.ProgressBar(EditorGUILayout.GetControlRect(), p, "Baking: " + (int)(100 * p) + "%");
|
||||
if (p <= 1)
|
||||
Repaint();
|
||||
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
}
|
||||
|
||||
[DrawGizmo(GizmoType.Selected | GizmoType.Active | GizmoType.Pickable)]
|
||||
static void RenderBoxGizmoSelected(NavMeshSurface2d navSurface, GizmoType gizmoType)
|
||||
{
|
||||
RenderBoxGizmo(navSurface, gizmoType, true);
|
||||
}
|
||||
|
||||
[DrawGizmo(GizmoType.NotInSelectionHierarchy | GizmoType.Pickable)]
|
||||
static void RenderBoxGizmoNotSelected(NavMeshSurface2d navSurface, GizmoType gizmoType)
|
||||
{
|
||||
if (NavMeshVisualizationSettings.showNavigation > 0)
|
||||
RenderBoxGizmo(navSurface, gizmoType, false);
|
||||
else
|
||||
Gizmos.DrawIcon(navSurface.transform.position, "NavMeshSurface Icon", true);
|
||||
}
|
||||
|
||||
static void RenderBoxGizmo(NavMeshSurface2d navSurface, GizmoType gizmoType, bool selected)
|
||||
{
|
||||
var color = selected ? s_HandleColorSelected : s_HandleColor;
|
||||
if (!navSurface.enabled)
|
||||
color = s_HandleColorDisabled;
|
||||
|
||||
var oldColor = Gizmos.color;
|
||||
var oldMatrix = Gizmos.matrix;
|
||||
|
||||
// Use the unscaled matrix for the NavMeshSurface
|
||||
var localToWorld = Matrix4x4.TRS(navSurface.transform.position, navSurface.transform.rotation, Vector3.one);
|
||||
Gizmos.matrix = localToWorld;
|
||||
|
||||
if (navSurface.collectObjects == CollectObjects2d.Volume)
|
||||
{
|
||||
Gizmos.color = color;
|
||||
Gizmos.DrawWireCube(navSurface.center, navSurface.size);
|
||||
|
||||
if (selected && navSurface.enabled)
|
||||
{
|
||||
var colorTrans = new Color(color.r * 0.75f, color.g * 0.75f, color.b * 0.75f, color.a * 0.15f);
|
||||
Gizmos.color = colorTrans;
|
||||
Gizmos.DrawCube(navSurface.center, navSurface.size);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (navSurface.navMeshData != null)
|
||||
{
|
||||
var bounds = navSurface.navMeshData.sourceBounds;
|
||||
Gizmos.color = Color.grey;
|
||||
Gizmos.DrawWireCube(bounds.center, bounds.size);
|
||||
}
|
||||
}
|
||||
|
||||
Gizmos.matrix = oldMatrix;
|
||||
Gizmos.color = oldColor;
|
||||
|
||||
Gizmos.DrawIcon(navSurface.transform.position, "NavMeshSurface Icon", true);
|
||||
}
|
||||
|
||||
void OnSceneGUI()
|
||||
{
|
||||
if (!editingCollider)
|
||||
return;
|
||||
|
||||
var navSurface = (NavMeshSurface2d)target;
|
||||
var color = navSurface.enabled ? s_HandleColor : s_HandleColorDisabled;
|
||||
var localToWorld = Matrix4x4.TRS(navSurface.transform.position, navSurface.transform.rotation, Vector3.one);
|
||||
using (new Handles.DrawingScope(color, localToWorld))
|
||||
{
|
||||
m_BoundsHandle.center = navSurface.center;
|
||||
m_BoundsHandle.size = navSurface.size;
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
m_BoundsHandle.DrawHandle();
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
Undo.RecordObject(navSurface, "Modified NavMesh Surface");
|
||||
Vector3 center = m_BoundsHandle.center;
|
||||
Vector3 size = m_BoundsHandle.size;
|
||||
navSurface.center = center;
|
||||
navSurface.size = size;
|
||||
EditorUtility.SetDirty(target);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[MenuItem("GameObject/AI/NavMesh Surface 2D", false, 2000)]
|
||||
public static void CreateNavMeshSurface(MenuCommand menuCommand)
|
||||
{
|
||||
var parent = menuCommand.context as GameObject;
|
||||
var go = NavMeshComponentsGUIUtility.CreateAndSelectGameObject("NavMesh Surface", parent);
|
||||
go.AddComponent<NavMeshSurface2d>();
|
||||
var view = SceneView.lastActiveSceneView;
|
||||
if (view != null)
|
||||
view.MoveToView(go.transform);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 69fa4f647e3f44d4fac10fd739f1fde5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
9
Assets/NavMeshPlus/NavMeshComponents/Scripts.meta
Normal file
9
Assets/NavMeshPlus/NavMeshComponents/Scripts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ce67aa87f613246dda63a54a59c6399e
|
||||
folderAsset: yes
|
||||
timeCreated: 1477656493
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
296
Assets/NavMeshPlus/NavMeshComponents/Scripts/NavMeshBuilder2d.cs
Normal file
296
Assets/NavMeshPlus/NavMeshComponents/Scripts/NavMeshBuilder2d.cs
Normal file
@@ -0,0 +1,296 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine.Tilemaps;
|
||||
|
||||
namespace UnityEngine.AI
|
||||
{
|
||||
class NavMeshBuilder2dWrapper
|
||||
{
|
||||
public Dictionary<Sprite, Mesh> map;
|
||||
public Dictionary<uint, Mesh> coliderMap;
|
||||
public int defaultArea;
|
||||
public int layerMask;
|
||||
public int agentID;
|
||||
public bool overrideByGrid;
|
||||
public GameObject useMeshPrefab;
|
||||
public bool compressBounds;
|
||||
public Vector3 overrideVector;
|
||||
public NavMeshCollectGeometry CollectGeometry;
|
||||
public CollectObjects2d CollectObjects;
|
||||
public GameObject parent;
|
||||
public bool hideEditorLogs;
|
||||
|
||||
public NavMeshBuilder2dWrapper()
|
||||
{
|
||||
map = new Dictionary<Sprite, Mesh>();
|
||||
coliderMap = new Dictionary<uint, Mesh>();
|
||||
}
|
||||
|
||||
public Mesh GetMesh(Sprite sprite)
|
||||
{
|
||||
Mesh mesh;
|
||||
if (map.ContainsKey(sprite))
|
||||
{
|
||||
mesh = map[sprite];
|
||||
}
|
||||
else
|
||||
{
|
||||
mesh = new Mesh();
|
||||
NavMeshBuilder2d.sprite2mesh(sprite, mesh);
|
||||
map.Add(sprite, mesh);
|
||||
}
|
||||
return mesh;
|
||||
}
|
||||
|
||||
internal Mesh GetMesh(Collider2D collider)
|
||||
{
|
||||
#if UNITY_2019_3_OR_NEWER
|
||||
Mesh mesh;
|
||||
uint hash = collider.GetShapeHash();
|
||||
if (coliderMap.ContainsKey(hash))
|
||||
{
|
||||
mesh = coliderMap[hash];
|
||||
}
|
||||
else
|
||||
{
|
||||
mesh = collider.CreateMesh(false, false);
|
||||
coliderMap.Add(hash, mesh);
|
||||
}
|
||||
return mesh;
|
||||
#else
|
||||
throw new InvalidOperationException("PhysicsColliders supported in Unity 2019.3 and higher.");
|
||||
#endif
|
||||
}
|
||||
|
||||
internal IEnumerable<GameObject> GetRoot()
|
||||
{
|
||||
switch (CollectObjects)
|
||||
{
|
||||
case CollectObjects2d.Children: return new[] { parent };
|
||||
case CollectObjects2d.Volume:
|
||||
case CollectObjects2d.All:
|
||||
default:
|
||||
return new[] { GameObject.FindObjectOfType<Grid>().gameObject };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class NavMeshBuilder2d
|
||||
{
|
||||
internal static void CollectSources(List<NavMeshBuildSource> sources, NavMeshBuilder2dWrapper builder)
|
||||
{
|
||||
var root = builder.GetRoot();
|
||||
foreach (var it in root)
|
||||
{
|
||||
CollectSources(it, sources, builder);
|
||||
}
|
||||
}
|
||||
|
||||
private static void CollectSources(GameObject root, List<NavMeshBuildSource> sources, NavMeshBuilder2dWrapper builder)
|
||||
{
|
||||
foreach (var modifier in root.GetComponentsInChildren<NavMeshModifier>())
|
||||
{
|
||||
if (((0x1 << modifier.gameObject.layer) & builder.layerMask) == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (!modifier.AffectsAgentType(builder.agentID))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
int area = builder.defaultArea;
|
||||
//if it is walkable
|
||||
if (builder.defaultArea != 1 && !modifier.ignoreFromBuild)
|
||||
{
|
||||
var tilemap = modifier.GetComponent<Tilemap>();
|
||||
if (tilemap != null)
|
||||
{
|
||||
if (builder.compressBounds)
|
||||
{
|
||||
tilemap.CompressBounds();
|
||||
}
|
||||
|
||||
if (!builder.hideEditorLogs) Debug.Log($"Walkable Bounds [{tilemap.name}]: {tilemap.localBounds}");
|
||||
var box = BoxBoundSource(NavMeshSurface2d.GetWorldBounds(tilemap.transform.localToWorldMatrix, tilemap.localBounds));
|
||||
box.area = builder.defaultArea;
|
||||
sources.Add(box);
|
||||
}
|
||||
}
|
||||
|
||||
if (modifier.overrideArea)
|
||||
{
|
||||
area = modifier.area;
|
||||
}
|
||||
if (!modifier.ignoreFromBuild)
|
||||
{
|
||||
if (builder.CollectGeometry == NavMeshCollectGeometry.PhysicsColliders)
|
||||
{
|
||||
CollectSources(sources, modifier, area, builder);
|
||||
}
|
||||
else
|
||||
{
|
||||
var tilemap = modifier.GetComponent<Tilemap>();
|
||||
if (tilemap != null)
|
||||
{
|
||||
CollectTileSources(sources, tilemap, area, builder);
|
||||
}
|
||||
var sprite = modifier.GetComponent<SpriteRenderer>();
|
||||
if (sprite != null)
|
||||
{
|
||||
CollectSources(sources, sprite, area, builder);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!builder.hideEditorLogs) Debug.Log("Sources " + sources.Count);
|
||||
}
|
||||
|
||||
private static void CollectSources(List<NavMeshBuildSource> sources, SpriteRenderer sprite, int area, NavMeshBuilder2dWrapper builder)
|
||||
{
|
||||
if (sprite == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
var src = new NavMeshBuildSource();
|
||||
src.shape = NavMeshBuildSourceShape.Mesh;
|
||||
src.area = area;
|
||||
|
||||
Mesh mesh;
|
||||
mesh = builder.GetMesh(sprite.sprite);
|
||||
if (mesh == null)
|
||||
{
|
||||
if (!builder.hideEditorLogs) Debug.Log($"{sprite.name} mesh is null");
|
||||
return;
|
||||
}
|
||||
src.transform = Matrix4x4.TRS(Vector3.Scale(sprite.transform.position, builder.overrideVector), sprite.transform.rotation, sprite.transform.lossyScale);
|
||||
src.sourceObject = mesh;
|
||||
sources.Add(src);
|
||||
}
|
||||
|
||||
private static void CollectSources(List<NavMeshBuildSource> sources, NavMeshModifier modifier, int area, NavMeshBuilder2dWrapper builder)
|
||||
{
|
||||
var collider = modifier.GetComponent<Collider2D>();
|
||||
if (collider == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (collider.usedByComposite)
|
||||
{
|
||||
collider = collider.GetComponent<CompositeCollider2D>();
|
||||
}
|
||||
|
||||
var src = new NavMeshBuildSource();
|
||||
src.shape = NavMeshBuildSourceShape.Mesh;
|
||||
src.area = area;
|
||||
|
||||
Mesh mesh;
|
||||
mesh = builder.GetMesh(collider);
|
||||
if (mesh == null)
|
||||
{
|
||||
if (!builder.hideEditorLogs) Debug.Log($"{collider.name} mesh is null");
|
||||
return;
|
||||
}
|
||||
if (collider.attachedRigidbody)
|
||||
{
|
||||
src.transform = Matrix4x4.TRS(Vector3.Scale(collider.attachedRigidbody.transform.position, builder.overrideVector), collider.attachedRigidbody.transform.rotation, Vector3.one);
|
||||
}
|
||||
else
|
||||
{
|
||||
src.transform = Matrix4x4.identity;
|
||||
}
|
||||
src.sourceObject = mesh;
|
||||
sources.Add(src);
|
||||
}
|
||||
|
||||
static private void CollectTileSources(List<NavMeshBuildSource> sources, Tilemap tilemap, int area, NavMeshBuilder2dWrapper builder)
|
||||
{
|
||||
var bound = tilemap.cellBounds;
|
||||
|
||||
var vec3int = new Vector3Int(0, 0, 0);
|
||||
|
||||
var size = new Vector3(tilemap.layoutGrid.cellSize.x, tilemap.layoutGrid.cellSize.y, 0);
|
||||
Mesh sharedMesh = null;
|
||||
Quaternion rot = default;
|
||||
|
||||
var src = new NavMeshBuildSource();
|
||||
src.shape = NavMeshBuildSourceShape.Mesh;
|
||||
src.area = area;
|
||||
|
||||
Mesh mesh;
|
||||
|
||||
if (builder.useMeshPrefab != null)
|
||||
{
|
||||
sharedMesh = builder.useMeshPrefab.GetComponent<MeshFilter>().sharedMesh;
|
||||
size = builder.useMeshPrefab.transform.localScale;
|
||||
rot = builder.useMeshPrefab.transform.rotation;
|
||||
}
|
||||
for (int i = bound.xMin; i < bound.xMax; i++)
|
||||
{
|
||||
for (int j = bound.yMin; j < bound.yMax; j++)
|
||||
{
|
||||
vec3int.x = i;
|
||||
vec3int.y = j;
|
||||
if (!tilemap.HasTile(vec3int))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!builder.overrideByGrid && tilemap.GetColliderType(vec3int) == Tile.ColliderType.Sprite)
|
||||
{
|
||||
var sprite = tilemap.GetSprite(vec3int);
|
||||
if (sprite != null)
|
||||
{
|
||||
mesh = builder.GetMesh(sprite);
|
||||
src.transform = Matrix4x4.TRS(Vector3.Scale(tilemap.GetCellCenterWorld(vec3int), builder.overrideVector) - tilemap.layoutGrid.cellGap, tilemap.transform.rotation, tilemap.transform.lossyScale) * tilemap.orientationMatrix * tilemap.GetTransformMatrix(vec3int);
|
||||
src.sourceObject = mesh;
|
||||
sources.Add(src);
|
||||
}
|
||||
}
|
||||
else if (builder.useMeshPrefab != null || (builder.overrideByGrid && builder.useMeshPrefab != null))
|
||||
{
|
||||
src.transform = Matrix4x4.TRS(Vector3.Scale(tilemap.GetCellCenterWorld(vec3int), builder.overrideVector), rot, size);
|
||||
src.sourceObject = sharedMesh;
|
||||
sources.Add(src);
|
||||
}
|
||||
else //default to box
|
||||
{
|
||||
var boxsrc = new NavMeshBuildSource();
|
||||
boxsrc.transform = Matrix4x4.TRS(Vector3.Scale(tilemap.GetCellCenterWorld(vec3int), builder.overrideVector) - tilemap.layoutGrid.cellGap, tilemap.transform.rotation, tilemap.transform.lossyScale) * tilemap.orientationMatrix * tilemap.GetTransformMatrix(vec3int);
|
||||
boxsrc.shape = NavMeshBuildSourceShape.Box;
|
||||
boxsrc.size = size;
|
||||
boxsrc.area = area;
|
||||
sources.Add(boxsrc);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static void sprite2mesh(Sprite sprite, Mesh mesh)
|
||||
{
|
||||
Vector3[] vert = new Vector3[sprite.vertices.Length];
|
||||
for (int i = 0; i < sprite.vertices.Length; i++)
|
||||
{
|
||||
vert[i] = new Vector3(sprite.vertices[i].x, sprite.vertices[i].y, 0);
|
||||
}
|
||||
mesh.vertices = vert;
|
||||
mesh.uv = sprite.uv;
|
||||
int[] tri = new int[sprite.triangles.Length];
|
||||
for (int i = 0; i < sprite.triangles.Length; i++)
|
||||
{
|
||||
tri[i] = sprite.triangles[i];
|
||||
}
|
||||
mesh.triangles = tri;
|
||||
}
|
||||
|
||||
static private NavMeshBuildSource BoxBoundSource(Bounds localBounds)
|
||||
{
|
||||
var src = new NavMeshBuildSource();
|
||||
src.transform = Matrix4x4.Translate(localBounds.center);
|
||||
src.shape = NavMeshBuildSourceShape.Box;
|
||||
src.size = localBounds.size;
|
||||
src.area = 0;
|
||||
return src;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 72f0dd11bca0bfd459699d21003f89ba
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"name": "NavMeshComponents",
|
||||
"references": [],
|
||||
"optionalUnityReferences": [],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": []
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8c4dd21966739024fbd72155091d199e
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
172
Assets/NavMeshPlus/NavMeshComponents/Scripts/NavMeshLink.cs
Normal file
172
Assets/NavMeshPlus/NavMeshComponents/Scripts/NavMeshLink.cs
Normal file
@@ -0,0 +1,172 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace UnityEngine.AI
|
||||
{
|
||||
[ExecuteInEditMode]
|
||||
[DefaultExecutionOrder(-101)]
|
||||
[AddComponentMenu("Navigation/NavMeshLink", 33)]
|
||||
[HelpURL("https://github.com/Unity-Technologies/NavMeshComponents#documentation-draft")]
|
||||
public class NavMeshLink : MonoBehaviour
|
||||
{
|
||||
[SerializeField]
|
||||
int m_AgentTypeID;
|
||||
public int agentTypeID { get { return m_AgentTypeID; } set { m_AgentTypeID = value; UpdateLink(); } }
|
||||
|
||||
[SerializeField]
|
||||
Vector3 m_StartPoint = new Vector3(0.0f, 0.0f, -2.5f);
|
||||
public Vector3 startPoint { get { return m_StartPoint; } set { m_StartPoint = value; UpdateLink(); } }
|
||||
|
||||
[SerializeField]
|
||||
Vector3 m_EndPoint = new Vector3(0.0f, 0.0f, 2.5f);
|
||||
public Vector3 endPoint { get { return m_EndPoint; } set { m_EndPoint = value; UpdateLink(); } }
|
||||
|
||||
[SerializeField]
|
||||
float m_Width;
|
||||
public float width { get { return m_Width; } set { m_Width = value; UpdateLink(); } }
|
||||
|
||||
[SerializeField]
|
||||
int m_CostModifier = -1;
|
||||
public int costModifier { get { return m_CostModifier; } set { m_CostModifier = value; UpdateLink(); } }
|
||||
|
||||
[SerializeField]
|
||||
bool m_Bidirectional = true;
|
||||
public bool bidirectional { get { return m_Bidirectional; } set { m_Bidirectional = value; UpdateLink(); } }
|
||||
|
||||
[SerializeField]
|
||||
bool m_AutoUpdatePosition;
|
||||
public bool autoUpdate { get { return m_AutoUpdatePosition; } set { SetAutoUpdate(value); } }
|
||||
|
||||
[SerializeField]
|
||||
int m_Area;
|
||||
public int area { get { return m_Area; } set { m_Area = value; UpdateLink(); } }
|
||||
|
||||
NavMeshLinkInstance m_LinkInstance = new NavMeshLinkInstance();
|
||||
|
||||
Vector3 m_LastPosition = Vector3.zero;
|
||||
Quaternion m_LastRotation = Quaternion.identity;
|
||||
|
||||
static readonly List<NavMeshLink> s_Tracked = new List<NavMeshLink>();
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
AddLink();
|
||||
if (m_AutoUpdatePosition && m_LinkInstance.valid)
|
||||
AddTracking(this);
|
||||
}
|
||||
|
||||
void OnDisable()
|
||||
{
|
||||
RemoveTracking(this);
|
||||
m_LinkInstance.Remove();
|
||||
}
|
||||
|
||||
public void UpdateLink()
|
||||
{
|
||||
m_LinkInstance.Remove();
|
||||
AddLink();
|
||||
}
|
||||
|
||||
static void AddTracking(NavMeshLink link)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
if (s_Tracked.Contains(link))
|
||||
{
|
||||
Debug.LogError("Link is already tracked: " + link);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (s_Tracked.Count == 0)
|
||||
NavMesh.onPreUpdate += UpdateTrackedInstances;
|
||||
|
||||
s_Tracked.Add(link);
|
||||
}
|
||||
|
||||
static void RemoveTracking(NavMeshLink link)
|
||||
{
|
||||
s_Tracked.Remove(link);
|
||||
|
||||
if (s_Tracked.Count == 0)
|
||||
NavMesh.onPreUpdate -= UpdateTrackedInstances;
|
||||
}
|
||||
|
||||
void SetAutoUpdate(bool value)
|
||||
{
|
||||
if (m_AutoUpdatePosition == value)
|
||||
return;
|
||||
m_AutoUpdatePosition = value;
|
||||
if (value)
|
||||
AddTracking(this);
|
||||
else
|
||||
RemoveTracking(this);
|
||||
}
|
||||
|
||||
void AddLink()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
if (m_LinkInstance.valid)
|
||||
{
|
||||
Debug.LogError("Link is already added: " + this);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
var link = new NavMeshLinkData();
|
||||
link.startPosition = m_StartPoint;
|
||||
link.endPosition = m_EndPoint;
|
||||
link.width = m_Width;
|
||||
link.costModifier = m_CostModifier;
|
||||
link.bidirectional = m_Bidirectional;
|
||||
link.area = m_Area;
|
||||
link.agentTypeID = m_AgentTypeID;
|
||||
m_LinkInstance = NavMesh.AddLink(link, transform.position, transform.rotation);
|
||||
if (m_LinkInstance.valid)
|
||||
m_LinkInstance.owner = this;
|
||||
|
||||
m_LastPosition = transform.position;
|
||||
m_LastRotation = transform.rotation;
|
||||
}
|
||||
|
||||
bool HasTransformChanged()
|
||||
{
|
||||
if (m_LastPosition != transform.position) return true;
|
||||
if (m_LastRotation != transform.rotation) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void OnDidApplyAnimationProperties()
|
||||
{
|
||||
UpdateLink();
|
||||
}
|
||||
|
||||
static void UpdateTrackedInstances()
|
||||
{
|
||||
foreach (var instance in s_Tracked)
|
||||
{
|
||||
if (instance.HasTransformChanged())
|
||||
instance.UpdateLink();
|
||||
}
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
void OnValidate()
|
||||
{
|
||||
m_Width = Mathf.Max(0.0f, m_Width);
|
||||
|
||||
if (!m_LinkInstance.valid)
|
||||
return;
|
||||
|
||||
UpdateLink();
|
||||
|
||||
if (!m_AutoUpdatePosition)
|
||||
{
|
||||
RemoveTracking(this);
|
||||
}
|
||||
else if (!s_Tracked.Contains(this))
|
||||
{
|
||||
AddTracking(this);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6eeb5dc026fdf4b488bc7ae0138ab719
|
||||
timeCreated: 1477924439
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {fileID: 2800000, guid: 92f4afa3e25264f5b964937ccea49ff2, type: 3}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,54 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace UnityEngine.AI
|
||||
{
|
||||
[ExecuteInEditMode]
|
||||
[AddComponentMenu("Navigation/NavMeshModifier", 32)]
|
||||
[HelpURL("https://github.com/Unity-Technologies/NavMeshComponents#documentation-draft")]
|
||||
public class NavMeshModifier : MonoBehaviour
|
||||
{
|
||||
[SerializeField]
|
||||
bool m_OverrideArea;
|
||||
public bool overrideArea { get { return m_OverrideArea; } set { m_OverrideArea = value; } }
|
||||
|
||||
[SerializeField]
|
||||
int m_Area;
|
||||
public int area { get { return m_Area; } set { m_Area = value; } }
|
||||
|
||||
[SerializeField]
|
||||
bool m_IgnoreFromBuild;
|
||||
public bool ignoreFromBuild { get { return m_IgnoreFromBuild; } set { m_IgnoreFromBuild = value; } }
|
||||
|
||||
// List of agent types the modifier is applied for.
|
||||
// Special values: empty == None, m_AffectedAgents[0] =-1 == All.
|
||||
[SerializeField]
|
||||
List<int> m_AffectedAgents = new List<int>(new int[] { -1 }); // Default value is All
|
||||
|
||||
static readonly List<NavMeshModifier> s_NavMeshModifiers = new List<NavMeshModifier>();
|
||||
|
||||
public static List<NavMeshModifier> activeModifiers
|
||||
{
|
||||
get { return s_NavMeshModifiers; }
|
||||
}
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
if (!s_NavMeshModifiers.Contains(this))
|
||||
s_NavMeshModifiers.Add(this);
|
||||
}
|
||||
|
||||
void OnDisable()
|
||||
{
|
||||
s_NavMeshModifiers.Remove(this);
|
||||
}
|
||||
|
||||
public bool AffectsAgentType(int agentTypeID)
|
||||
{
|
||||
if (m_AffectedAgents.Count == 0)
|
||||
return false;
|
||||
if (m_AffectedAgents[0] == -1)
|
||||
return true;
|
||||
return m_AffectedAgents.IndexOf(agentTypeID) != -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1e3fdca004f2d45fe8abbed571a8abd5
|
||||
timeCreated: 1477924411
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {fileID: 2800000, guid: cc7b9475dbddf4f9088d327d6e10ab77, type: 3}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,54 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace UnityEngine.AI
|
||||
{
|
||||
[ExecuteInEditMode]
|
||||
[AddComponentMenu("Navigation/NavMeshModifierVolume", 31)]
|
||||
[HelpURL("https://github.com/Unity-Technologies/NavMeshComponents#documentation-draft")]
|
||||
public class NavMeshModifierVolume : MonoBehaviour
|
||||
{
|
||||
[SerializeField]
|
||||
Vector3 m_Size = new Vector3(4.0f, 3.0f, 4.0f);
|
||||
public Vector3 size { get { return m_Size; } set { m_Size = value; } }
|
||||
|
||||
[SerializeField]
|
||||
Vector3 m_Center = new Vector3(0, 1.0f, 0);
|
||||
public Vector3 center { get { return m_Center; } set { m_Center = value; } }
|
||||
|
||||
[SerializeField]
|
||||
int m_Area;
|
||||
public int area { get { return m_Area; } set { m_Area = value; } }
|
||||
|
||||
// List of agent types the modifier is applied for.
|
||||
// Special values: empty == None, m_AffectedAgents[0] =-1 == All.
|
||||
[SerializeField]
|
||||
List<int> m_AffectedAgents = new List<int>(new int[] { -1 }); // Default value is All
|
||||
|
||||
static readonly List<NavMeshModifierVolume> s_NavMeshModifiers = new List<NavMeshModifierVolume>();
|
||||
|
||||
public static List<NavMeshModifierVolume> activeModifiers
|
||||
{
|
||||
get { return s_NavMeshModifiers; }
|
||||
}
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
if (!s_NavMeshModifiers.Contains(this))
|
||||
s_NavMeshModifiers.Add(this);
|
||||
}
|
||||
|
||||
void OnDisable()
|
||||
{
|
||||
s_NavMeshModifiers.Remove(this);
|
||||
}
|
||||
|
||||
public bool AffectsAgentType(int agentTypeID)
|
||||
{
|
||||
if (m_AffectedAgents.Count == 0)
|
||||
return false;
|
||||
if (m_AffectedAgents[0] == -1)
|
||||
return true;
|
||||
return m_AffectedAgents.IndexOf(agentTypeID) != -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 35e95dc5ff2b64380880dd7ac5922847
|
||||
timeCreated: 1477924430
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {fileID: 2800000, guid: cc7b9475dbddf4f9088d327d6e10ab77, type: 3}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
486
Assets/NavMeshPlus/NavMeshComponents/Scripts/NavMeshSurface.cs
Normal file
486
Assets/NavMeshPlus/NavMeshComponents/Scripts/NavMeshSurface.cs
Normal file
@@ -0,0 +1,486 @@
|
||||
using System.Collections.Generic;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
using UnityEditor.SceneManagement;
|
||||
#endif
|
||||
|
||||
namespace UnityEngine.AI
|
||||
{
|
||||
public enum CollectObjects
|
||||
{
|
||||
All = 0,
|
||||
Volume = 1,
|
||||
Children = 2,
|
||||
}
|
||||
|
||||
[ExecuteAlways]
|
||||
[DefaultExecutionOrder(-102)]
|
||||
[AddComponentMenu("Navigation/NavMeshSurface", 30)]
|
||||
[HelpURL("https://github.com/Unity-Technologies/NavMeshComponents#documentation-draft")]
|
||||
public class NavMeshSurface : MonoBehaviour
|
||||
{
|
||||
[SerializeField]
|
||||
int m_AgentTypeID;
|
||||
public int agentTypeID { get { return m_AgentTypeID; } set { m_AgentTypeID = value; } }
|
||||
|
||||
[SerializeField]
|
||||
CollectObjects m_CollectObjects = CollectObjects.All;
|
||||
public CollectObjects collectObjects { get { return m_CollectObjects; } set { m_CollectObjects = value; } }
|
||||
|
||||
[SerializeField]
|
||||
Vector3 m_Size = new Vector3(10.0f, 10.0f, 10.0f);
|
||||
public Vector3 size { get { return m_Size; } set { m_Size = value; } }
|
||||
|
||||
[SerializeField]
|
||||
Vector3 m_Center = new Vector3(0, 2.0f, 0);
|
||||
public Vector3 center { get { return m_Center; } set { m_Center = value; } }
|
||||
|
||||
[SerializeField]
|
||||
LayerMask m_LayerMask = ~0;
|
||||
public LayerMask layerMask { get { return m_LayerMask; } set { m_LayerMask = value; } }
|
||||
|
||||
[SerializeField]
|
||||
NavMeshCollectGeometry m_UseGeometry = NavMeshCollectGeometry.RenderMeshes;
|
||||
public NavMeshCollectGeometry useGeometry { get { return m_UseGeometry; } set { m_UseGeometry = value; } }
|
||||
|
||||
[SerializeField]
|
||||
int m_DefaultArea;
|
||||
public int defaultArea { get { return m_DefaultArea; } set { m_DefaultArea = value; } }
|
||||
|
||||
[SerializeField]
|
||||
bool m_IgnoreNavMeshAgent = true;
|
||||
public bool ignoreNavMeshAgent { get { return m_IgnoreNavMeshAgent; } set { m_IgnoreNavMeshAgent = value; } }
|
||||
|
||||
[SerializeField]
|
||||
bool m_IgnoreNavMeshObstacle = true;
|
||||
public bool ignoreNavMeshObstacle { get { return m_IgnoreNavMeshObstacle; } set { m_IgnoreNavMeshObstacle = value; } }
|
||||
|
||||
[SerializeField]
|
||||
bool m_OverrideTileSize;
|
||||
public bool overrideTileSize { get { return m_OverrideTileSize; } set { m_OverrideTileSize = value; } }
|
||||
[SerializeField]
|
||||
int m_TileSize = 256;
|
||||
public int tileSize { get { return m_TileSize; } set { m_TileSize = value; } }
|
||||
[SerializeField]
|
||||
bool m_OverrideVoxelSize;
|
||||
public bool overrideVoxelSize { get { return m_OverrideVoxelSize; } set { m_OverrideVoxelSize = value; } }
|
||||
[SerializeField]
|
||||
float m_VoxelSize;
|
||||
public float voxelSize { get { return m_VoxelSize; } set { m_VoxelSize = value; } }
|
||||
|
||||
// Currently not supported advanced options
|
||||
[SerializeField]
|
||||
bool m_BuildHeightMesh;
|
||||
public bool buildHeightMesh { get { return m_BuildHeightMesh; } set { m_BuildHeightMesh = value; } }
|
||||
|
||||
// Reference to whole scene navmesh data asset.
|
||||
[UnityEngine.Serialization.FormerlySerializedAs("m_BakedNavMeshData")]
|
||||
[SerializeField]
|
||||
NavMeshData m_NavMeshData;
|
||||
public NavMeshData navMeshData { get { return m_NavMeshData; } set { m_NavMeshData = value; } }
|
||||
|
||||
// Do not serialize - runtime only state.
|
||||
NavMeshDataInstance m_NavMeshDataInstance;
|
||||
Vector3 m_LastPosition = Vector3.zero;
|
||||
Quaternion m_LastRotation = Quaternion.identity;
|
||||
|
||||
static readonly List<NavMeshSurface> s_NavMeshSurfaces = new List<NavMeshSurface>();
|
||||
|
||||
public static List<NavMeshSurface> activeSurfaces
|
||||
{
|
||||
get { return s_NavMeshSurfaces; }
|
||||
}
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
Register(this);
|
||||
AddData();
|
||||
}
|
||||
|
||||
void OnDisable()
|
||||
{
|
||||
RemoveData();
|
||||
Unregister(this);
|
||||
}
|
||||
|
||||
public void AddData()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
var isInPreviewScene = EditorSceneManager.IsPreviewSceneObject(this);
|
||||
var isPrefab = isInPreviewScene || EditorUtility.IsPersistent(this);
|
||||
if (isPrefab)
|
||||
{
|
||||
//Debug.LogFormat("NavMeshData from {0}.{1} will not be added to the NavMesh world because the gameObject is a prefab.",
|
||||
// gameObject.name, name);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
if (m_NavMeshDataInstance.valid)
|
||||
return;
|
||||
|
||||
if (m_NavMeshData != null)
|
||||
{
|
||||
m_NavMeshDataInstance = NavMesh.AddNavMeshData(m_NavMeshData, transform.position, transform.rotation);
|
||||
m_NavMeshDataInstance.owner = this;
|
||||
}
|
||||
|
||||
m_LastPosition = transform.position;
|
||||
m_LastRotation = transform.rotation;
|
||||
}
|
||||
|
||||
public void RemoveData()
|
||||
{
|
||||
m_NavMeshDataInstance.Remove();
|
||||
m_NavMeshDataInstance = new NavMeshDataInstance();
|
||||
}
|
||||
|
||||
public NavMeshBuildSettings GetBuildSettings()
|
||||
{
|
||||
var buildSettings = NavMesh.GetSettingsByID(m_AgentTypeID);
|
||||
if (buildSettings.agentTypeID == -1)
|
||||
{
|
||||
Debug.LogWarning("No build settings for agent type ID " + agentTypeID, this);
|
||||
buildSettings.agentTypeID = m_AgentTypeID;
|
||||
}
|
||||
|
||||
if (overrideTileSize)
|
||||
{
|
||||
buildSettings.overrideTileSize = true;
|
||||
buildSettings.tileSize = tileSize;
|
||||
}
|
||||
if (overrideVoxelSize)
|
||||
{
|
||||
buildSettings.overrideVoxelSize = true;
|
||||
buildSettings.voxelSize = voxelSize;
|
||||
}
|
||||
return buildSettings;
|
||||
}
|
||||
|
||||
public void BuildNavMesh()
|
||||
{
|
||||
var sources = CollectSources();
|
||||
|
||||
// Use unscaled bounds - this differs in behaviour from e.g. collider components.
|
||||
// But is similar to reflection probe - and since navmesh data has no scaling support - it is the right choice here.
|
||||
var sourcesBounds = new Bounds(m_Center, Abs(m_Size));
|
||||
if (m_CollectObjects == CollectObjects.All || m_CollectObjects == CollectObjects.Children)
|
||||
{
|
||||
sourcesBounds = CalculateWorldBounds(sources);
|
||||
}
|
||||
|
||||
var data = NavMeshBuilder.BuildNavMeshData(GetBuildSettings(),
|
||||
sources, sourcesBounds, transform.position, transform.rotation);
|
||||
|
||||
if (data != null)
|
||||
{
|
||||
data.name = gameObject.name;
|
||||
RemoveData();
|
||||
m_NavMeshData = data;
|
||||
if (isActiveAndEnabled)
|
||||
AddData();
|
||||
}
|
||||
}
|
||||
|
||||
public AsyncOperation UpdateNavMesh(NavMeshData data)
|
||||
{
|
||||
var sources = CollectSources();
|
||||
|
||||
// Use unscaled bounds - this differs in behaviour from e.g. collider components.
|
||||
// But is similar to reflection probe - and since navmesh data has no scaling support - it is the right choice here.
|
||||
var sourcesBounds = new Bounds(m_Center, Abs(m_Size));
|
||||
if (m_CollectObjects == CollectObjects.All || m_CollectObjects == CollectObjects.Children)
|
||||
sourcesBounds = CalculateWorldBounds(sources);
|
||||
|
||||
return NavMeshBuilder.UpdateNavMeshDataAsync(data, GetBuildSettings(), sources, sourcesBounds);
|
||||
}
|
||||
|
||||
static void Register(NavMeshSurface surface)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
var isInPreviewScene = EditorSceneManager.IsPreviewSceneObject(surface);
|
||||
var isPrefab = isInPreviewScene || EditorUtility.IsPersistent(surface);
|
||||
if (isPrefab)
|
||||
{
|
||||
//Debug.LogFormat("NavMeshData from {0}.{1} will not be added to the NavMesh world because the gameObject is a prefab.",
|
||||
// surface.gameObject.name, surface.name);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
if (s_NavMeshSurfaces.Count == 0)
|
||||
NavMesh.onPreUpdate += UpdateActive;
|
||||
|
||||
if (!s_NavMeshSurfaces.Contains(surface))
|
||||
s_NavMeshSurfaces.Add(surface);
|
||||
}
|
||||
|
||||
static void Unregister(NavMeshSurface surface)
|
||||
{
|
||||
s_NavMeshSurfaces.Remove(surface);
|
||||
|
||||
if (s_NavMeshSurfaces.Count == 0)
|
||||
NavMesh.onPreUpdate -= UpdateActive;
|
||||
}
|
||||
|
||||
static void UpdateActive()
|
||||
{
|
||||
for (var i = 0; i < s_NavMeshSurfaces.Count; ++i)
|
||||
s_NavMeshSurfaces[i].UpdateDataIfTransformChanged();
|
||||
}
|
||||
|
||||
void AppendModifierVolumes(ref List<NavMeshBuildSource> sources)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
var myStage = StageUtility.GetStageHandle(gameObject);
|
||||
if (!myStage.IsValid())
|
||||
return;
|
||||
#endif
|
||||
// Modifiers
|
||||
List<NavMeshModifierVolume> modifiers;
|
||||
if (m_CollectObjects == CollectObjects.Children)
|
||||
{
|
||||
modifiers = new List<NavMeshModifierVolume>(GetComponentsInChildren<NavMeshModifierVolume>());
|
||||
modifiers.RemoveAll(x => !x.isActiveAndEnabled);
|
||||
}
|
||||
else
|
||||
{
|
||||
modifiers = NavMeshModifierVolume.activeModifiers;
|
||||
}
|
||||
|
||||
foreach (var m in modifiers)
|
||||
{
|
||||
if ((m_LayerMask & (1 << m.gameObject.layer)) == 0)
|
||||
continue;
|
||||
if (!m.AffectsAgentType(m_AgentTypeID))
|
||||
continue;
|
||||
#if UNITY_EDITOR
|
||||
if (!myStage.Contains(m.gameObject))
|
||||
continue;
|
||||
#endif
|
||||
var mcenter = m.transform.TransformPoint(m.center);
|
||||
var scale = m.transform.lossyScale;
|
||||
var msize = new Vector3(m.size.x * Mathf.Abs(scale.x), m.size.y * Mathf.Abs(scale.y), m.size.z * Mathf.Abs(scale.z));
|
||||
|
||||
var src = new NavMeshBuildSource();
|
||||
src.shape = NavMeshBuildSourceShape.ModifierBox;
|
||||
src.transform = Matrix4x4.TRS(mcenter, m.transform.rotation, Vector3.one);
|
||||
src.size = msize;
|
||||
src.area = m.area;
|
||||
sources.Add(src);
|
||||
}
|
||||
}
|
||||
|
||||
List<NavMeshBuildSource> CollectSources()
|
||||
{
|
||||
var sources = new List<NavMeshBuildSource>();
|
||||
var markups = new List<NavMeshBuildMarkup>();
|
||||
|
||||
List<NavMeshModifier> modifiers;
|
||||
if (m_CollectObjects == CollectObjects.Children)
|
||||
{
|
||||
modifiers = new List<NavMeshModifier>(GetComponentsInChildren<NavMeshModifier>());
|
||||
modifiers.RemoveAll(x => !x.isActiveAndEnabled);
|
||||
}
|
||||
else
|
||||
{
|
||||
modifiers = NavMeshModifier.activeModifiers;
|
||||
}
|
||||
|
||||
foreach (var m in modifiers)
|
||||
{
|
||||
if ((m_LayerMask & (1 << m.gameObject.layer)) == 0)
|
||||
continue;
|
||||
if (!m.AffectsAgentType(m_AgentTypeID))
|
||||
continue;
|
||||
var markup = new NavMeshBuildMarkup();
|
||||
markup.root = m.transform;
|
||||
markup.overrideArea = m.overrideArea;
|
||||
markup.area = m.area;
|
||||
markup.ignoreFromBuild = m.ignoreFromBuild;
|
||||
markups.Add(markup);
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
if (!EditorApplication.isPlaying)
|
||||
{
|
||||
if (m_CollectObjects == CollectObjects.All)
|
||||
{
|
||||
UnityEditor.AI.NavMeshBuilder.CollectSourcesInStage(
|
||||
null, m_LayerMask, m_UseGeometry, m_DefaultArea, markups, gameObject.scene, sources);
|
||||
}
|
||||
else if (m_CollectObjects == CollectObjects.Children)
|
||||
{
|
||||
UnityEditor.AI.NavMeshBuilder.CollectSourcesInStage(
|
||||
transform, m_LayerMask, m_UseGeometry, m_DefaultArea, markups, gameObject.scene, sources);
|
||||
}
|
||||
else if (m_CollectObjects == CollectObjects.Volume)
|
||||
{
|
||||
Matrix4x4 localToWorld = Matrix4x4.TRS(transform.position, transform.rotation, Vector3.one);
|
||||
var worldBounds = GetWorldBounds(localToWorld, new Bounds(m_Center, m_Size));
|
||||
|
||||
UnityEditor.AI.NavMeshBuilder.CollectSourcesInStage(
|
||||
worldBounds, m_LayerMask, m_UseGeometry, m_DefaultArea, markups, gameObject.scene, sources);
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
if (m_CollectObjects == CollectObjects.All)
|
||||
{
|
||||
NavMeshBuilder.CollectSources(null, m_LayerMask, m_UseGeometry, m_DefaultArea, markups, sources);
|
||||
}
|
||||
else if (m_CollectObjects == CollectObjects.Children)
|
||||
{
|
||||
NavMeshBuilder.CollectSources(transform, m_LayerMask, m_UseGeometry, m_DefaultArea, markups, sources);
|
||||
}
|
||||
else if (m_CollectObjects == CollectObjects.Volume)
|
||||
{
|
||||
Matrix4x4 localToWorld = Matrix4x4.TRS(transform.position, transform.rotation, Vector3.one);
|
||||
var worldBounds = GetWorldBounds(localToWorld, new Bounds(m_Center, m_Size));
|
||||
NavMeshBuilder.CollectSources(worldBounds, m_LayerMask, m_UseGeometry, m_DefaultArea, markups, sources);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_IgnoreNavMeshAgent)
|
||||
sources.RemoveAll((x) => (x.component != null && x.component.gameObject.GetComponent<NavMeshAgent>() != null));
|
||||
|
||||
if (m_IgnoreNavMeshObstacle)
|
||||
sources.RemoveAll((x) => (x.component != null && x.component.gameObject.GetComponent<NavMeshObstacle>() != null));
|
||||
|
||||
AppendModifierVolumes(ref sources);
|
||||
|
||||
return sources;
|
||||
}
|
||||
|
||||
static Vector3 Abs(Vector3 v)
|
||||
{
|
||||
return new Vector3(Mathf.Abs(v.x), Mathf.Abs(v.y), Mathf.Abs(v.z));
|
||||
}
|
||||
|
||||
static Bounds GetWorldBounds(Matrix4x4 mat, Bounds bounds)
|
||||
{
|
||||
var absAxisX = Abs(mat.MultiplyVector(Vector3.right));
|
||||
var absAxisY = Abs(mat.MultiplyVector(Vector3.up));
|
||||
var absAxisZ = Abs(mat.MultiplyVector(Vector3.forward));
|
||||
var worldPosition = mat.MultiplyPoint(bounds.center);
|
||||
var worldSize = absAxisX * bounds.size.x + absAxisY * bounds.size.y + absAxisZ * bounds.size.z;
|
||||
return new Bounds(worldPosition, worldSize);
|
||||
}
|
||||
|
||||
Bounds CalculateWorldBounds(List<NavMeshBuildSource> sources)
|
||||
{
|
||||
// Use the unscaled matrix for the NavMeshSurface
|
||||
Matrix4x4 worldToLocal = Matrix4x4.TRS(transform.position, transform.rotation, Vector3.one);
|
||||
worldToLocal = worldToLocal.inverse;
|
||||
|
||||
var result = new Bounds();
|
||||
foreach (var src in sources)
|
||||
{
|
||||
switch (src.shape)
|
||||
{
|
||||
case NavMeshBuildSourceShape.Mesh:
|
||||
{
|
||||
var m = src.sourceObject as Mesh;
|
||||
result.Encapsulate(GetWorldBounds(worldToLocal * src.transform, m.bounds));
|
||||
break;
|
||||
}
|
||||
case NavMeshBuildSourceShape.Terrain:
|
||||
{
|
||||
// Terrain pivot is lower/left corner - shift bounds accordingly
|
||||
var t = src.sourceObject as TerrainData;
|
||||
result.Encapsulate(GetWorldBounds(worldToLocal * src.transform, new Bounds(0.5f * t.size, t.size)));
|
||||
break;
|
||||
}
|
||||
case NavMeshBuildSourceShape.Box:
|
||||
case NavMeshBuildSourceShape.Sphere:
|
||||
case NavMeshBuildSourceShape.Capsule:
|
||||
case NavMeshBuildSourceShape.ModifierBox:
|
||||
result.Encapsulate(GetWorldBounds(worldToLocal * src.transform, new Bounds(Vector3.zero, src.size)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Inflate the bounds a bit to avoid clipping co-planar sources
|
||||
result.Expand(0.1f);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool HasTransformChanged()
|
||||
{
|
||||
if (m_LastPosition != transform.position) return true;
|
||||
if (m_LastRotation != transform.rotation) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void UpdateDataIfTransformChanged()
|
||||
{
|
||||
if (HasTransformChanged())
|
||||
{
|
||||
RemoveData();
|
||||
AddData();
|
||||
}
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
bool UnshareNavMeshAsset()
|
||||
{
|
||||
// Nothing to unshare
|
||||
if (m_NavMeshData == null)
|
||||
return false;
|
||||
|
||||
// Prefab parent owns the asset reference
|
||||
var isInPreviewScene = EditorSceneManager.IsPreviewSceneObject(this);
|
||||
var isPersistentObject = EditorUtility.IsPersistent(this);
|
||||
if (isInPreviewScene || isPersistentObject)
|
||||
return false;
|
||||
|
||||
// An instance can share asset reference only with its prefab parent
|
||||
var prefab = UnityEditor.PrefabUtility.GetCorrespondingObjectFromSource(this) as NavMeshSurface;
|
||||
if (prefab != null && prefab.navMeshData == navMeshData)
|
||||
return false;
|
||||
|
||||
// Don't allow referencing an asset that's assigned to another surface
|
||||
for (var i = 0; i < s_NavMeshSurfaces.Count; ++i)
|
||||
{
|
||||
var surface = s_NavMeshSurfaces[i];
|
||||
if (surface != this && surface.m_NavMeshData == m_NavMeshData)
|
||||
return true;
|
||||
}
|
||||
|
||||
// Asset is not referenced by known surfaces
|
||||
return false;
|
||||
}
|
||||
|
||||
void OnValidate()
|
||||
{
|
||||
if (UnshareNavMeshAsset())
|
||||
{
|
||||
Debug.LogWarning("Duplicating NavMeshSurface does not duplicate the referenced navmesh data", this);
|
||||
m_NavMeshData = null;
|
||||
}
|
||||
|
||||
var settings = NavMesh.GetSettingsByID(m_AgentTypeID);
|
||||
if (settings.agentTypeID != -1)
|
||||
{
|
||||
// When unchecking the override control, revert to automatic value.
|
||||
const float kMinVoxelSize = 0.01f;
|
||||
if (!m_OverrideVoxelSize)
|
||||
m_VoxelSize = settings.agentRadius / 3.0f;
|
||||
if (m_VoxelSize < kMinVoxelSize)
|
||||
m_VoxelSize = kMinVoxelSize;
|
||||
|
||||
// When unchecking the override control, revert to default value.
|
||||
const int kMinTileSize = 16;
|
||||
const int kMaxTileSize = 1024;
|
||||
const int kDefaultTileSize = 256;
|
||||
|
||||
if (!m_OverrideTileSize)
|
||||
m_TileSize = kDefaultTileSize;
|
||||
// Make sure tilesize is in sane range.
|
||||
if (m_TileSize < kMinTileSize)
|
||||
m_TileSize = kMinTileSize;
|
||||
if (m_TileSize > kMaxTileSize)
|
||||
m_TileSize = kMaxTileSize;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7a5ac11cc976e418e8d13136b07e1f52
|
||||
timeCreated: 1477658803
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {fileID: 2800000, guid: e4f97225bcfb64760a1c81f460837f01, type: 3}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
582
Assets/NavMeshPlus/NavMeshComponents/Scripts/NavMeshSurface2d.cs
Normal file
582
Assets/NavMeshPlus/NavMeshComponents/Scripts/NavMeshSurface2d.cs
Normal file
@@ -0,0 +1,582 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine.Tilemaps;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
using UnityEditor.SceneManagement;
|
||||
#endif
|
||||
|
||||
namespace UnityEngine.AI
|
||||
{
|
||||
public enum CollectObjects2d
|
||||
{
|
||||
All = 0,
|
||||
Volume = 1,
|
||||
Children = 2,
|
||||
}
|
||||
|
||||
[ExecuteAlways]
|
||||
[DefaultExecutionOrder(-102)]
|
||||
[AddComponentMenu("Navigation/NavMeshSurface2d", 30)]
|
||||
[HelpURL("https://github.com/Unity-Technologies/NavMeshComponents#documentation-draft")]
|
||||
public class NavMeshSurface2d : MonoBehaviour
|
||||
{
|
||||
[SerializeField]
|
||||
int m_AgentTypeID;
|
||||
public int agentTypeID { get { return m_AgentTypeID; } set { m_AgentTypeID = value; } }
|
||||
|
||||
[SerializeField]
|
||||
CollectObjects2d m_CollectObjects = CollectObjects2d.All;
|
||||
public CollectObjects2d collectObjects { get { return m_CollectObjects; } set { m_CollectObjects = value; } }
|
||||
|
||||
[SerializeField]
|
||||
Vector3 m_Size = new Vector3(10.0f, 10.0f, 10.0f);
|
||||
public Vector3 size { get { return m_Size; } set { m_Size = value; } }
|
||||
|
||||
[SerializeField]
|
||||
Vector3 m_Center = new Vector3(0, 2.0f, 0);
|
||||
public Vector3 center { get { return m_Center; } set { m_Center = value; } }
|
||||
|
||||
[SerializeField]
|
||||
LayerMask m_LayerMask = ~0;
|
||||
public LayerMask layerMask { get { return m_LayerMask; } set { m_LayerMask = value; } }
|
||||
|
||||
[SerializeField]
|
||||
NavMeshCollectGeometry m_UseGeometry = NavMeshCollectGeometry.RenderMeshes;
|
||||
public NavMeshCollectGeometry useGeometry { get { return m_UseGeometry; } set { m_UseGeometry = value; } }
|
||||
|
||||
[SerializeField]
|
||||
bool m_OverrideByGrid;
|
||||
public bool overrideByGrid { get { return m_OverrideByGrid; } set { m_OverrideByGrid = value; } }
|
||||
|
||||
[SerializeField]
|
||||
GameObject m_UseMeshPrefab;
|
||||
public GameObject useMeshPrefab { get { return m_UseMeshPrefab; } set { m_UseMeshPrefab = value; } }
|
||||
|
||||
[SerializeField]
|
||||
bool m_CompressBounds;
|
||||
public bool compressBounds { get { return m_CompressBounds; } set { m_CompressBounds = value; } }
|
||||
|
||||
[SerializeField]
|
||||
Vector3 m_OverrideVector = Vector3.one;
|
||||
public Vector3 overrideVector { get { return m_OverrideVector; } set { m_OverrideVector = value; } }
|
||||
|
||||
[SerializeField]
|
||||
int m_DefaultArea;
|
||||
public int defaultArea { get { return m_DefaultArea; } set { m_DefaultArea = value; } }
|
||||
|
||||
[SerializeField]
|
||||
bool m_IgnoreNavMeshAgent = true;
|
||||
public bool ignoreNavMeshAgent { get { return m_IgnoreNavMeshAgent; } set { m_IgnoreNavMeshAgent = value; } }
|
||||
|
||||
[SerializeField]
|
||||
bool m_IgnoreNavMeshObstacle = true;
|
||||
public bool ignoreNavMeshObstacle { get { return m_IgnoreNavMeshObstacle; } set { m_IgnoreNavMeshObstacle = value; } }
|
||||
|
||||
[SerializeField]
|
||||
bool m_OverrideTileSize;
|
||||
public bool overrideTileSize { get { return m_OverrideTileSize; } set { m_OverrideTileSize = value; } }
|
||||
[SerializeField]
|
||||
int m_TileSize = 256;
|
||||
public int tileSize { get { return m_TileSize; } set { m_TileSize = value; } }
|
||||
[SerializeField]
|
||||
bool m_OverrideVoxelSize;
|
||||
public bool overrideVoxelSize { get { return m_OverrideVoxelSize; } set { m_OverrideVoxelSize = value; } }
|
||||
[SerializeField]
|
||||
float m_VoxelSize;
|
||||
public float voxelSize { get { return m_VoxelSize; } set { m_VoxelSize = value; } }
|
||||
|
||||
// Currently not supported advanced options
|
||||
[SerializeField]
|
||||
bool m_BuildHeightMesh;
|
||||
public bool buildHeightMesh { get { return m_BuildHeightMesh; } set { m_BuildHeightMesh = value; } }
|
||||
|
||||
[SerializeField]
|
||||
bool m_HideEditorLogs;
|
||||
public bool hideEditorLogs { get { return m_HideEditorLogs; } set { m_HideEditorLogs = value; } }
|
||||
|
||||
// Reference to whole scene navmesh data asset.
|
||||
[UnityEngine.Serialization.FormerlySerializedAs("m_BakedNavMeshData")]
|
||||
[SerializeField]
|
||||
NavMeshData m_NavMeshData;
|
||||
public NavMeshData navMeshData { get { return m_NavMeshData; } set { m_NavMeshData = value; } }
|
||||
|
||||
// Do not serialize - runtime only state.
|
||||
NavMeshDataInstance m_NavMeshDataInstance;
|
||||
Vector3 m_LastPosition = Vector3.zero;
|
||||
Quaternion m_LastRotation = Quaternion.identity;
|
||||
|
||||
static readonly List<NavMeshSurface2d> s_NavMeshSurfaces = new List<NavMeshSurface2d>();
|
||||
|
||||
public static List<NavMeshSurface2d> activeSurfaces
|
||||
{
|
||||
get { return s_NavMeshSurfaces; }
|
||||
}
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
Register(this);
|
||||
AddData();
|
||||
}
|
||||
|
||||
void OnDisable()
|
||||
{
|
||||
RemoveData();
|
||||
Unregister(this);
|
||||
}
|
||||
|
||||
public void AddData()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
var isInPreviewScene = EditorSceneManager.IsPreviewSceneObject(this);
|
||||
var isPrefab = isInPreviewScene || EditorUtility.IsPersistent(this);
|
||||
if (isPrefab)
|
||||
{
|
||||
//Debug.LogFormat("NavMeshData from {0}.{1} will not be added to the NavMesh world because the gameObject is a prefab.",
|
||||
// gameObject.name, name);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
if (m_NavMeshDataInstance.valid)
|
||||
return;
|
||||
|
||||
if (m_NavMeshData != null)
|
||||
{
|
||||
m_NavMeshDataInstance = NavMesh.AddNavMeshData(m_NavMeshData, transform.position, transform.rotation);
|
||||
m_NavMeshDataInstance.owner = this;
|
||||
}
|
||||
|
||||
m_LastPosition = transform.position;
|
||||
m_LastRotation = transform.rotation;
|
||||
}
|
||||
|
||||
public void RemoveData()
|
||||
{
|
||||
m_NavMeshDataInstance.Remove();
|
||||
m_NavMeshDataInstance = new NavMeshDataInstance();
|
||||
}
|
||||
|
||||
public NavMeshBuildSettings GetBuildSettings()
|
||||
{
|
||||
var buildSettings = NavMesh.GetSettingsByID(m_AgentTypeID);
|
||||
if (buildSettings.agentTypeID == -1)
|
||||
{
|
||||
if (!m_HideEditorLogs) Debug.LogWarning("No build settings for agent type ID " + agentTypeID, this);
|
||||
buildSettings.agentTypeID = m_AgentTypeID;
|
||||
}
|
||||
|
||||
if (overrideTileSize)
|
||||
{
|
||||
buildSettings.overrideTileSize = true;
|
||||
buildSettings.tileSize = tileSize;
|
||||
}
|
||||
if (overrideVoxelSize)
|
||||
{
|
||||
buildSettings.overrideVoxelSize = true;
|
||||
buildSettings.voxelSize = voxelSize;
|
||||
}
|
||||
return buildSettings;
|
||||
}
|
||||
|
||||
public void BuildNavMesh()
|
||||
{
|
||||
var sources = CollectSources();
|
||||
|
||||
// Use unscaled bounds - this differs in behaviour from e.g. collider components.
|
||||
// But is similar to reflection probe - and since navmesh data has no scaling support - it is the right choice here.
|
||||
var sourcesBounds = new Bounds(m_Center, Abs(m_Size));
|
||||
if (m_CollectObjects != CollectObjects2d.Volume)
|
||||
{
|
||||
sourcesBounds = CalculateWorldBounds(sources);
|
||||
}
|
||||
|
||||
var data = NavMeshBuilder.BuildNavMeshData(GetBuildSettings(),
|
||||
sources, sourcesBounds, transform.position, transform.rotation);
|
||||
|
||||
if (data != null)
|
||||
{
|
||||
data.name = gameObject.name;
|
||||
RemoveData();
|
||||
m_NavMeshData = data;
|
||||
if (isActiveAndEnabled)
|
||||
AddData();
|
||||
}
|
||||
}
|
||||
|
||||
// Source: https://github.com/Unity-Technologies/NavMeshComponents/issues/97#issuecomment-528692289
|
||||
public AsyncOperation BuildNavMeshAsync()
|
||||
{
|
||||
RemoveData();
|
||||
m_NavMeshData = new NavMeshData(m_AgentTypeID)
|
||||
{
|
||||
name = gameObject.name,
|
||||
position = transform.position,
|
||||
rotation = transform.rotation
|
||||
};
|
||||
|
||||
if (isActiveAndEnabled)
|
||||
{
|
||||
AddData();
|
||||
}
|
||||
|
||||
return UpdateNavMesh(m_NavMeshData);
|
||||
}
|
||||
|
||||
public AsyncOperation UpdateNavMesh(NavMeshData data)
|
||||
{
|
||||
var sources = CollectSources();
|
||||
|
||||
// Use unscaled bounds - this differs in behaviour from e.g. collider components.
|
||||
// But is similar to reflection probe - and since navmesh data has no scaling support - it is the right choice here.
|
||||
var sourcesBounds = new Bounds(m_Center, Abs(m_Size));
|
||||
if (m_CollectObjects != CollectObjects2d.Volume)
|
||||
sourcesBounds = CalculateWorldBounds(sources);
|
||||
|
||||
return NavMeshBuilder.UpdateNavMeshDataAsync(data, GetBuildSettings(), sources, sourcesBounds);
|
||||
}
|
||||
|
||||
static void Register(NavMeshSurface2d surface)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
var isInPreviewScene = EditorSceneManager.IsPreviewSceneObject(surface);
|
||||
var isPrefab = isInPreviewScene || EditorUtility.IsPersistent(surface);
|
||||
if (isPrefab)
|
||||
{
|
||||
//Debug.LogFormat("NavMeshData from {0}.{1} will not be added to the NavMesh world because the gameObject is a prefab.",
|
||||
// surface.gameObject.name, surface.name);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
if (s_NavMeshSurfaces.Count == 0)
|
||||
NavMesh.onPreUpdate += UpdateActive;
|
||||
|
||||
if (!s_NavMeshSurfaces.Contains(surface))
|
||||
s_NavMeshSurfaces.Add(surface);
|
||||
}
|
||||
|
||||
static void Unregister(NavMeshSurface2d surface)
|
||||
{
|
||||
s_NavMeshSurfaces.Remove(surface);
|
||||
|
||||
if (s_NavMeshSurfaces.Count == 0)
|
||||
NavMesh.onPreUpdate -= UpdateActive;
|
||||
}
|
||||
|
||||
static void UpdateActive()
|
||||
{
|
||||
for (var i = 0; i < s_NavMeshSurfaces.Count; ++i)
|
||||
s_NavMeshSurfaces[i].UpdateDataIfTransformChanged();
|
||||
}
|
||||
|
||||
void AppendModifierVolumes(ref List<NavMeshBuildSource> sources)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
var myStage = StageUtility.GetStageHandle(gameObject);
|
||||
if (!myStage.IsValid())
|
||||
return;
|
||||
#endif
|
||||
// Modifiers
|
||||
List<NavMeshModifierVolume> modifiers;
|
||||
if (m_CollectObjects == CollectObjects2d.Children)
|
||||
{
|
||||
modifiers = new List<NavMeshModifierVolume>(GetComponentsInChildren<NavMeshModifierVolume>());
|
||||
modifiers.RemoveAll(x => !x.isActiveAndEnabled);
|
||||
}
|
||||
else
|
||||
{
|
||||
modifiers = NavMeshModifierVolume.activeModifiers;
|
||||
}
|
||||
|
||||
foreach (var m in modifiers)
|
||||
{
|
||||
if ((m_LayerMask & (1 << m.gameObject.layer)) == 0)
|
||||
continue;
|
||||
if (!m.AffectsAgentType(m_AgentTypeID))
|
||||
continue;
|
||||
#if UNITY_EDITOR
|
||||
if (!myStage.Contains(m.gameObject))
|
||||
continue;
|
||||
#endif
|
||||
var mcenter = m.transform.TransformPoint(m.center);
|
||||
var scale = m.transform.lossyScale;
|
||||
var msize = new Vector3(m.size.x * Mathf.Abs(scale.x), m.size.y * Mathf.Abs(scale.y), m.size.z * Mathf.Abs(scale.z));
|
||||
|
||||
var src = new NavMeshBuildSource();
|
||||
src.shape = NavMeshBuildSourceShape.ModifierBox;
|
||||
src.transform = Matrix4x4.TRS(mcenter, m.transform.rotation, Vector3.one);
|
||||
src.size = msize;
|
||||
src.area = m.area;
|
||||
sources.Add(src);
|
||||
}
|
||||
}
|
||||
|
||||
List<NavMeshBuildSource> CollectSources()
|
||||
{
|
||||
var sources = new List<NavMeshBuildSource>();
|
||||
var markups = new List<NavMeshBuildMarkup>();
|
||||
|
||||
List<NavMeshModifier> modifiers;
|
||||
if (m_CollectObjects == CollectObjects2d.Children)
|
||||
{
|
||||
modifiers = new List<NavMeshModifier>(GetComponentsInChildren<NavMeshModifier>());
|
||||
modifiers.RemoveAll(x => !x.isActiveAndEnabled);
|
||||
}
|
||||
else
|
||||
{
|
||||
modifiers = NavMeshModifier.activeModifiers;
|
||||
}
|
||||
|
||||
foreach (var m in modifiers)
|
||||
{
|
||||
if ((m_LayerMask & (1 << m.gameObject.layer)) == 0)
|
||||
continue;
|
||||
if (!m.AffectsAgentType(m_AgentTypeID))
|
||||
continue;
|
||||
var markup = new NavMeshBuildMarkup();
|
||||
markup.root = m.transform;
|
||||
markup.overrideArea = m.overrideArea;
|
||||
markup.area = m.area;
|
||||
markup.ignoreFromBuild = m.ignoreFromBuild;
|
||||
markups.Add(markup);
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
if (!EditorApplication.isPlaying)
|
||||
{
|
||||
if (m_CollectObjects == CollectObjects2d.All)
|
||||
{
|
||||
UnityEditor.AI.NavMeshBuilder.CollectSourcesInStage(
|
||||
null, m_LayerMask, m_UseGeometry, m_DefaultArea, markups, gameObject.scene, sources);
|
||||
}
|
||||
else if (m_CollectObjects == CollectObjects2d.Children)
|
||||
{
|
||||
UnityEditor.AI.NavMeshBuilder.CollectSourcesInStage(
|
||||
transform, m_LayerMask, m_UseGeometry, m_DefaultArea, markups, gameObject.scene, sources);
|
||||
}
|
||||
else if (m_CollectObjects == CollectObjects2d.Volume)
|
||||
{
|
||||
Matrix4x4 localToWorld = Matrix4x4.TRS(transform.position, transform.rotation, Vector3.one);
|
||||
var worldBounds = GetWorldBounds(localToWorld, new Bounds(m_Center, m_Size));
|
||||
|
||||
UnityEditor.AI.NavMeshBuilder.CollectSourcesInStage(
|
||||
worldBounds, m_LayerMask, m_UseGeometry, m_DefaultArea, markups, gameObject.scene, sources);
|
||||
}
|
||||
if (!hideEditorLogs && !Mathf.Approximately(transform.eulerAngles.x, 270f))
|
||||
Debug.LogWarning("NavMeshSurface2d is not rotated respectively to (x-90;y0;z0). Apply rotation unless intended.");
|
||||
var builder = new NavMeshBuilder2dWrapper();
|
||||
builder.defaultArea = defaultArea;
|
||||
builder.layerMask = layerMask;
|
||||
builder.agentID = agentTypeID;
|
||||
builder.useMeshPrefab = useMeshPrefab;
|
||||
builder.overrideByGrid = overrideByGrid;
|
||||
builder.compressBounds = compressBounds;
|
||||
builder.overrideVector = overrideVector;
|
||||
builder.CollectGeometry = useGeometry;
|
||||
builder.CollectObjects = collectObjects;
|
||||
builder.parent = gameObject;
|
||||
builder.hideEditorLogs = hideEditorLogs;
|
||||
NavMeshBuilder2d.CollectSources(sources, builder);
|
||||
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
if (m_CollectObjects == CollectObjects2d.All)
|
||||
{
|
||||
NavMeshBuilder.CollectSources(null, m_LayerMask, m_UseGeometry, m_DefaultArea, markups, sources);
|
||||
}
|
||||
else if (m_CollectObjects == CollectObjects2d.Children)
|
||||
{
|
||||
NavMeshBuilder.CollectSources(transform, m_LayerMask, m_UseGeometry, m_DefaultArea, markups, sources);
|
||||
}
|
||||
else if (m_CollectObjects == CollectObjects2d.Volume)
|
||||
{
|
||||
Matrix4x4 localToWorld = Matrix4x4.TRS(transform.position, transform.rotation, Vector3.one);
|
||||
var worldBounds = GetWorldBounds(localToWorld, new Bounds(m_Center, m_Size));
|
||||
NavMeshBuilder.CollectSources(worldBounds, m_LayerMask, m_UseGeometry, m_DefaultArea, markups, sources);
|
||||
}
|
||||
if (!hideEditorLogs && !Mathf.Approximately(transform.eulerAngles.x, 270f))
|
||||
Debug.LogWarning("NavMeshSurface2d is not rotated respectively to (x-90;y0;z0). Apply rotation unless intended.");
|
||||
var builder = new NavMeshBuilder2dWrapper();
|
||||
builder.defaultArea = defaultArea;
|
||||
builder.layerMask = layerMask;
|
||||
builder.agentID = agentTypeID;
|
||||
builder.useMeshPrefab = useMeshPrefab;
|
||||
builder.overrideByGrid = overrideByGrid;
|
||||
builder.compressBounds = compressBounds;
|
||||
builder.overrideVector = overrideVector;
|
||||
builder.CollectGeometry = useGeometry;
|
||||
builder.CollectObjects = collectObjects;
|
||||
builder.parent = gameObject;
|
||||
builder.hideEditorLogs = hideEditorLogs;
|
||||
NavMeshBuilder2d.CollectSources(sources, builder);
|
||||
}
|
||||
if (m_IgnoreNavMeshAgent)
|
||||
sources.RemoveAll((x) => (x.component != null && x.component.gameObject.GetComponent<NavMeshAgent>() != null));
|
||||
|
||||
if (m_IgnoreNavMeshObstacle)
|
||||
sources.RemoveAll((x) => (x.component != null && x.component.gameObject.GetComponent<NavMeshObstacle>() != null));
|
||||
|
||||
AppendModifierVolumes(ref sources);
|
||||
|
||||
return sources;
|
||||
}
|
||||
|
||||
static Vector3 Abs(Vector3 v)
|
||||
{
|
||||
return new Vector3(Mathf.Abs(v.x), Mathf.Abs(v.y), Mathf.Abs(v.z));
|
||||
}
|
||||
|
||||
public static Bounds GetWorldBounds(Matrix4x4 mat, Bounds bounds)
|
||||
{
|
||||
var absAxisX = Abs(mat.MultiplyVector(Vector3.right));
|
||||
var absAxisY = Abs(mat.MultiplyVector(Vector3.up));
|
||||
var absAxisZ = Abs(mat.MultiplyVector(Vector3.forward));
|
||||
var worldPosition = mat.MultiplyPoint(bounds.center);
|
||||
var worldSize = absAxisX * bounds.size.x + absAxisY * bounds.size.y + absAxisZ * bounds.size.z;
|
||||
return new Bounds(worldPosition, worldSize);
|
||||
}
|
||||
|
||||
Bounds CalculateWorldBounds(List<NavMeshBuildSource> sources)
|
||||
{
|
||||
// Use the unscaled matrix for the NavMeshSurface
|
||||
Matrix4x4 worldToLocal = Matrix4x4.TRS(transform.position, transform.rotation, Vector3.one);
|
||||
worldToLocal = worldToLocal.inverse;
|
||||
var result = new Bounds();
|
||||
if (collectObjects != CollectObjects2d.Children)
|
||||
{
|
||||
result.Encapsulate(CalculateGridWorldBounds(worldToLocal));
|
||||
}
|
||||
|
||||
foreach (var src in sources)
|
||||
{
|
||||
switch (src.shape)
|
||||
{
|
||||
case NavMeshBuildSourceShape.Mesh:
|
||||
{
|
||||
var m = src.sourceObject as Mesh;
|
||||
result.Encapsulate(GetWorldBounds(worldToLocal * src.transform, m.bounds));
|
||||
break;
|
||||
}
|
||||
case NavMeshBuildSourceShape.Terrain:
|
||||
{
|
||||
// Terrain pivot is lower/left corner - shift bounds accordingly
|
||||
var t = src.sourceObject as TerrainData;
|
||||
result.Encapsulate(GetWorldBounds(worldToLocal * src.transform, new Bounds(0.5f * t.size, t.size)));
|
||||
break;
|
||||
}
|
||||
case NavMeshBuildSourceShape.Box:
|
||||
case NavMeshBuildSourceShape.Sphere:
|
||||
case NavMeshBuildSourceShape.Capsule:
|
||||
case NavMeshBuildSourceShape.ModifierBox:
|
||||
result.Encapsulate(GetWorldBounds(worldToLocal * src.transform, new Bounds(Vector3.zero, src.size)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Inflate the bounds a bit to avoid clipping co-planar sources
|
||||
result.Expand(0.1f);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static Bounds CalculateGridWorldBounds(Matrix4x4 worldToLocal)
|
||||
{
|
||||
var bounds = new Bounds();
|
||||
var grid = FindObjectOfType<Grid>();
|
||||
var tilemaps = grid.GetComponentsInChildren<Tilemap>();
|
||||
if (tilemaps == null || tilemaps.Length < 1)
|
||||
{
|
||||
|
||||
throw new NullReferenceException("Add at least one tilemap");
|
||||
}
|
||||
foreach (var tilemap in tilemaps)
|
||||
{
|
||||
//Debug.Log($"From Local Bounds [{tilemap.name}]: {tilemap.localBounds}");
|
||||
var lbounds = GetWorldBounds(worldToLocal * tilemap.transform.localToWorldMatrix, tilemap.localBounds);
|
||||
bounds.Encapsulate(lbounds);
|
||||
//Debug.Log($"To World Bounds: {bounds}");
|
||||
}
|
||||
bounds.Expand(0.1f);
|
||||
return bounds;
|
||||
}
|
||||
|
||||
bool HasTransformChanged()
|
||||
{
|
||||
if (m_LastPosition != transform.position) return true;
|
||||
if (m_LastRotation != transform.rotation) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void UpdateDataIfTransformChanged()
|
||||
{
|
||||
if (HasTransformChanged())
|
||||
{
|
||||
RemoveData();
|
||||
AddData();
|
||||
}
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
bool UnshareNavMeshAsset()
|
||||
{
|
||||
// Nothing to unshare
|
||||
if (m_NavMeshData == null)
|
||||
return false;
|
||||
|
||||
// Prefab parent owns the asset reference
|
||||
var isInPreviewScene = EditorSceneManager.IsPreviewSceneObject(this);
|
||||
var isPersistentObject = EditorUtility.IsPersistent(this);
|
||||
if (isInPreviewScene || isPersistentObject)
|
||||
return false;
|
||||
|
||||
// An instance can share asset reference only with its prefab parent
|
||||
var prefab = UnityEditor.PrefabUtility.GetCorrespondingObjectFromSource(this) as NavMeshSurface2d;
|
||||
if (prefab != null && prefab.navMeshData == navMeshData)
|
||||
return false;
|
||||
|
||||
// Don't allow referencing an asset that's assigned to another surface
|
||||
for (var i = 0; i < s_NavMeshSurfaces.Count; ++i)
|
||||
{
|
||||
var surface = s_NavMeshSurfaces[i];
|
||||
if (surface != this && surface.m_NavMeshData == m_NavMeshData)
|
||||
return true;
|
||||
}
|
||||
|
||||
// Asset is not referenced by known surfaces
|
||||
return false;
|
||||
}
|
||||
|
||||
void OnValidate()
|
||||
{
|
||||
if (UnshareNavMeshAsset())
|
||||
{
|
||||
if (!m_HideEditorLogs) Debug.LogWarning("Duplicating NavMeshSurface does not duplicate the referenced navmesh data", this);
|
||||
m_NavMeshData = null;
|
||||
}
|
||||
|
||||
var settings = NavMesh.GetSettingsByID(m_AgentTypeID);
|
||||
if (settings.agentTypeID != -1)
|
||||
{
|
||||
// When unchecking the override control, revert to automatic value.
|
||||
const float kMinVoxelSize = 0.01f;
|
||||
if (!m_OverrideVoxelSize)
|
||||
m_VoxelSize = settings.agentRadius / 3.0f;
|
||||
if (m_VoxelSize < kMinVoxelSize)
|
||||
m_VoxelSize = kMinVoxelSize;
|
||||
|
||||
// When unchecking the override control, revert to default value.
|
||||
const int kMinTileSize = 16;
|
||||
const int kMaxTileSize = 1024;
|
||||
const int kDefaultTileSize = 256;
|
||||
|
||||
if (!m_OverrideTileSize)
|
||||
m_TileSize = kDefaultTileSize;
|
||||
// Make sure tilesize is in sane range.
|
||||
if (m_TileSize < kMinTileSize)
|
||||
m_TileSize = kMinTileSize;
|
||||
if (m_TileSize > kMaxTileSize)
|
||||
m_TileSize = kMaxTileSize;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 148387606d0ccd84fa326ca211f274ba
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {fileID: 2800000, guid: 871b885cd68224f4787ae765e0da9571, type: 3}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
58
Assets/NavMeshPlus/README.md
Normal file
58
Assets/NavMeshPlus/README.md
Normal file
@@ -0,0 +1,58 @@
|
||||
# NavMeshPlus
|
||||
|
||||
NavMesh building components provide you with ability to create navigation meshes that are generated automatically from your Scene
|
||||
geometry, which allows characters to move intelligently around the game world.
|
||||
|
||||

|
||||
|
||||
# Unity 2D Pathfinding
|
||||
|
||||
This repo is a proof of concept of Unity NavMesh and Pathfinding in 2D. It is explores NavMeshComponents capabilities. [[link]](https://docs.unity3d.com/Manual/class-NavMeshSurface.html)
|
||||
|
||||
## Wiki [[here]](https://github.com/h8man/NavMeshPlus/wiki)
|
||||
|
||||
See [how-to](https://github.com/h8man/NavMeshPlus/wiki/HOW-TO) for full tutorial
|
||||
|
||||
## Setup
|
||||
|
||||
You can use this in two different ways: downloading this repository or adding it to your project's Package Manager manifest.
|
||||
Alternatively, you can pick scripts and place in your project's `Assets` folder.
|
||||
|
||||
### Variant 1. Download
|
||||
Download or clone this repository into your project in the folder `Packages/com.h8man.2d.navmeshplus`.
|
||||
|
||||
### Variant 2. Package Manager Manifest
|
||||
[Git](https://git-scm.com/) must be installed and added to your path.
|
||||
|
||||
The following line needs to be added to your `Packages/manifest.json` file in your Unity Project under the `dependencies` section:
|
||||
|
||||
```
|
||||
"com.h8man.2d.navmeshplus": "https://github.com/h8man/NavMeshPlus.git#master"
|
||||
```
|
||||
## Misc
|
||||
|
||||
### How To [[pdf]](https://github.com/h8man/NavMeshPlus/blob/master/navmeshplus.pdf ).
|
||||
|
||||
### Demo [[github]](https://github.com/h8man/RedHotSweetPepper ).
|
||||
|
||||
### Discuss [[unityforum]](https://forum.unity.com/threads/2d-navmesh-pathfinding.503596/ ).
|
||||
|
||||
## 2D NavMesh
|
||||
|
||||
In repo you will find implementation of NavMeshSurface2d for tilemap top down games.
|
||||
|
||||
To use it in your project:
|
||||
|
||||
1. Copy repo into your Asset folder
|
||||
2. Create Empty Object in scene root and rotated respectively to Tilemap (x-90;y0;z0)
|
||||
3. Add NavMeshSurface2d component to Empty Object
|
||||
4. Add Tilemap with NavMeshModifier component, override the area.
|
||||
5. In NavMeshSurface2d hit Bake.
|
||||
|
||||
How does it works:
|
||||
|
||||
1. It uses https://docs.unity3d.com/Manual/class-NavMeshSurface.html as base implementation.
|
||||
2. Implements world bound calculation.
|
||||
3. Implements source collector of tiles, sprites and 2d colliders
|
||||
4. Creates walkable mesh box from world bounds.
|
||||
5. Convert tiles, sprites and 2d colliders to sources as NavMeshBuilder would do.
|
||||
7
Assets/NavMeshPlus/README.md.meta
Normal file
7
Assets/NavMeshPlus/README.md.meta
Normal file
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2f77fe52aa3396942bf2eecff964b4d0
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/NavMeshPlus/Unity.meta
Normal file
8
Assets/NavMeshPlus/Unity.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2d085361c3a06be448c4127d3d5e22f4
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
21
Assets/NavMeshPlus/Unity/LICENSE
Normal file
21
Assets/NavMeshPlus/Unity/LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016, Unity Technologies
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
7
Assets/NavMeshPlus/Unity/LICENSE.meta
Normal file
7
Assets/NavMeshPlus/Unity/LICENSE.meta
Normal file
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4919e823dd64ccf498a5a5e4da60a79e
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
60
Assets/NavMeshPlus/Unity/README.md
Normal file
60
Assets/NavMeshPlus/Unity/README.md
Normal file
@@ -0,0 +1,60 @@
|
||||
> Please use the branch matching the version of your Unity editor: [master](../../tree/master) for the latest released version, [2018.3](../../tree/2018.3), [2018.2](../../tree/2018.2), [2018.1](../../tree/2018.1), [2017.2](../../tree/2017.2) for up to 2017.4-LTS, [2017.1](../../tree/2017.1), [5.6](../../tree/5.6).
|
||||
|
||||
# Components for Runtime NavMesh Building
|
||||
|
||||
Here we introduce four components for the navigation system:
|
||||
|
||||
* __NavMeshSurface__ – for building and enabling a NavMesh surface for one agent type.
|
||||
* __NavMeshModifier__ – affects the NavMesh generation of NavMesh area types, based on the transform hierarchy.
|
||||
* __NavMeshModifierVolume__ – affects the NavMesh generation of NavMesh area types, based on volume.
|
||||
* __NavMeshLink__ – connects same or different NavMesh surfaces for one agent type.
|
||||
|
||||
These components comprise the high level controls for building and using NavMeshes at runtime as well as edit time.
|
||||
|
||||
Detailed information can be found in the [Documentation](Documentation) section or in the [NavMesh building components](https://docs.unity3d.com/Manual/NavMesh-BuildingComponents.html) section of the Unity Manual.
|
||||
|
||||
# How To Get Started
|
||||
|
||||
Download and install Unity 5.6 or newer.
|
||||
|
||||
Clone or download this repository and open the project in Unity.
|
||||
Alternatively, you can copy the contents of `Assets/NavMeshComponents` to an existing project. Make sure to select a branch of the repository that matches the Unity version.
|
||||
|
||||
Additional examples are available in the `Assets/Examples` folder.
|
||||
The examples are provided "as is". They are neither generic nor robust, but serve as inspiration.
|
||||
|
||||
_Note: During the beta cycle features and API are subject to change.\
|
||||
**Make sure to backup an existing project before opening it with a beta build.**_
|
||||
|
||||
# FAQ
|
||||
|
||||
Q: Can I bake a NavMesh at runtime?
|
||||
A: Yes.
|
||||
|
||||
Q: Can I use NavMesh'es for more than one agent size?
|
||||
A: Yes.
|
||||
|
||||
Q: Can I put a NavMesh in a prefab?
|
||||
A: Yes - with some limitations.
|
||||
|
||||
Q: How do I connect two NavMesh surfaces?
|
||||
A: Use the NavMeshLink to connect the two sides.
|
||||
|
||||
Q: How do I query the NavMesh for one specific size of agent?
|
||||
A: Use the NavMeshQuery filter when querying the NavMesh.
|
||||
|
||||
Q: What's the deal with the 'DefaultExecutionOrder' attribute?
|
||||
A: It gives a way of controlling the order of execution of scripts - specifically it allows us to build a NavMesh before the
|
||||
(native) NavMeshAgent component is enabled.
|
||||
|
||||
Q: What's the use of the new delegate 'NavMesh.onPreUpdate'?
|
||||
A: It allows you to hook in to controlling the NavMesh data and links set up before the navigation update loop is called on the native side.
|
||||
|
||||
Q: Can I do moving NavMesh platforms?
|
||||
A: No - new API is required for consistently moving platforms carrying agents.
|
||||
|
||||
Q: Is OffMeshLink now obsolete?
|
||||
A: No - you can still use OffMeshLink - however you'll find that NavMeshLink is more flexible and have less overhead.
|
||||
|
||||
Q: What happened to HeightMesh and Auto Generated OffMeshLinks?
|
||||
A: They're not supported in the new NavMesh building feature. HeightMesh will be added at some point. Auto OffMeshLink generation will possibly be replaced with a solution that allows better control of placement.
|
||||
7
Assets/NavMeshPlus/Unity/README.md.meta
Normal file
7
Assets/NavMeshPlus/Unity/README.md.meta
Normal file
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 32745b071c7e5004f946a98ebaf2fc15
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Assets/NavMeshPlus/navmeshplus.pdf
Normal file
BIN
Assets/NavMeshPlus/navmeshplus.pdf
Normal file
Binary file not shown.
7
Assets/NavMeshPlus/navmeshplus.pdf.meta
Normal file
7
Assets/NavMeshPlus/navmeshplus.pdf.meta
Normal file
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0d419d21003cd354bb186fc0ad3a84fd
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
13
Assets/NavMeshPlus/package.json
Normal file
13
Assets/NavMeshPlus/package.json
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
|
||||
"name": "com.h8man.2d.navmeshplus",
|
||||
"displayName": "NavMeshPlus",
|
||||
"version": "0.1.0",
|
||||
"unity": "2019.2",
|
||||
"description": "NavMesh building components provide you with ability to create navigation meshes that are generated automatically from your Scene geometry, which allows characters to move intelligently around the game world.",
|
||||
"keywords": ["2d"],
|
||||
"category": "2D",
|
||||
"dependencies": {
|
||||
}
|
||||
|
||||
}
|
||||
7
Assets/NavMeshPlus/package.json.meta
Normal file
7
Assets/NavMeshPlus/package.json.meta
Normal file
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a11de58dc8c82df4a8a5db73629430c4
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/Palettes.meta
Normal file
8
Assets/Palettes.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: eb25d24ee0f5eda40842f55c27d1f64e
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
216
Assets/Palettes/New Palette.prefab
Normal file
216
Assets/Palettes/New Palette.prefab
Normal file
@@ -0,0 +1,216 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!1 &803988258233372697
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 1630288917769168245}
|
||||
- component: {fileID: 6465647657844379263}
|
||||
m_Layer: 0
|
||||
m_Name: New Palette
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &1630288917769168245
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 803988258233372697}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children:
|
||||
- {fileID: 4430871276903213397}
|
||||
m_Father: {fileID: 0}
|
||||
m_RootOrder: 3
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!156049354 &6465647657844379263
|
||||
Grid:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 803988258233372697}
|
||||
m_Enabled: 1
|
||||
m_CellSize: {x: 1, y: 1, z: 0}
|
||||
m_CellGap: {x: 0, y: 0, z: 0}
|
||||
m_CellLayout: 0
|
||||
m_CellSwizzle: 0
|
||||
--- !u!1 &4163984308392436587
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 4430871276903213397}
|
||||
- component: {fileID: 3168924415502596760}
|
||||
- component: {fileID: 854459267391234178}
|
||||
m_Layer: 0
|
||||
m_Name: Layer1
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &4430871276903213397
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 4163984308392436587}
|
||||
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 1630288917769168245}
|
||||
m_RootOrder: -1
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!1839735485 &3168924415502596760
|
||||
Tilemap:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 4163984308392436587}
|
||||
m_Enabled: 1
|
||||
m_Tiles:
|
||||
- first: {x: 2, y: 0, z: 0}
|
||||
second:
|
||||
serializedVersion: 2
|
||||
m_TileIndex: 0
|
||||
m_TileSpriteIndex: 0
|
||||
m_TileMatrixIndex: 0
|
||||
m_TileColorIndex: 0
|
||||
m_TileObjectToInstantiateIndex: 65535
|
||||
dummyAlignment: 0
|
||||
m_AllTileFlags: 1073741825
|
||||
m_AnimatedTiles: {}
|
||||
m_TileAssetArray:
|
||||
- m_RefCount: 1
|
||||
m_Data: {fileID: 11400000, guid: 64a946fc6bd1f3a45ab24ef57ba0c1f2, type: 2}
|
||||
m_TileSpriteArray:
|
||||
- m_RefCount: 1
|
||||
m_Data: {fileID: 21300000, guid: 63d816f3f3cb040418900d1c8669d804, type: 3}
|
||||
m_TileMatrixArray:
|
||||
- m_RefCount: 1
|
||||
m_Data:
|
||||
e00: 1
|
||||
e01: 0
|
||||
e02: 0
|
||||
e03: 0
|
||||
e10: 0
|
||||
e11: 1
|
||||
e12: 0
|
||||
e13: 0
|
||||
e20: 0
|
||||
e21: 0
|
||||
e22: 1
|
||||
e23: 0
|
||||
e30: 0
|
||||
e31: 0
|
||||
e32: 0
|
||||
e33: 1
|
||||
m_TileColorArray:
|
||||
- m_RefCount: 1
|
||||
m_Data: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_TileObjectToInstantiateArray: []
|
||||
m_AnimationFrameRate: 1
|
||||
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_Origin: {x: 0, y: 0, z: 0}
|
||||
m_Size: {x: 3, y: 1, z: 1}
|
||||
m_TileAnchor: {x: 0.5, y: 0.5, z: 0}
|
||||
m_TileOrientation: 0
|
||||
m_TileOrientationMatrix:
|
||||
e00: 1
|
||||
e01: 0
|
||||
e02: 0
|
||||
e03: 0
|
||||
e10: 0
|
||||
e11: 1
|
||||
e12: 0
|
||||
e13: 0
|
||||
e20: 0
|
||||
e21: 0
|
||||
e22: 1
|
||||
e23: 0
|
||||
e30: 0
|
||||
e31: 0
|
||||
e32: 0
|
||||
e33: 1
|
||||
--- !u!483693784 &854459267391234178
|
||||
TilemapRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 4163984308392436587}
|
||||
m_Enabled: 1
|
||||
m_CastShadows: 0
|
||||
m_ReceiveShadows: 0
|
||||
m_DynamicOccludee: 0
|
||||
m_StaticShadowCaster: 0
|
||||
m_MotionVectors: 1
|
||||
m_LightProbeUsage: 0
|
||||
m_ReflectionProbeUsage: 0
|
||||
m_RayTracingMode: 0
|
||||
m_RayTraceProcedural: 0
|
||||
m_RenderingLayerMask: 1
|
||||
m_RendererPriority: 0
|
||||
m_Materials:
|
||||
- {fileID: 10754, guid: 0000000000000000f000000000000000, type: 0}
|
||||
m_StaticBatchInfo:
|
||||
firstSubMesh: 0
|
||||
subMeshCount: 0
|
||||
m_StaticBatchRoot: {fileID: 0}
|
||||
m_ProbeAnchor: {fileID: 0}
|
||||
m_LightProbeVolumeOverride: {fileID: 0}
|
||||
m_ScaleInLightmap: 1
|
||||
m_ReceiveGI: 1
|
||||
m_PreserveUVs: 0
|
||||
m_IgnoreNormalsForChartDetection: 0
|
||||
m_ImportantGI: 0
|
||||
m_StitchLightmapSeams: 1
|
||||
m_SelectedEditorRenderState: 0
|
||||
m_MinimumChartSize: 4
|
||||
m_AutoUVMaxDistance: 0.5
|
||||
m_AutoUVMaxAngle: 89
|
||||
m_LightmapParameters: {fileID: 0}
|
||||
m_SortingLayerID: 0
|
||||
m_SortingLayer: 0
|
||||
m_SortingOrder: 0
|
||||
m_ChunkSize: {x: 32, y: 32, z: 32}
|
||||
m_ChunkCullingBounds: {x: 0, y: 0, z: 0}
|
||||
m_MaxChunkCount: 16
|
||||
m_MaxFrameAge: 16
|
||||
m_SortOrder: 0
|
||||
m_Mode: 0
|
||||
m_DetectChunkCullingBounds: 0
|
||||
m_MaskInteraction: 0
|
||||
--- !u!114 &2618724760817667905
|
||||
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: 12395, guid: 0000000000000000e000000000000000, type: 0}
|
||||
m_Name: Palette Settings
|
||||
m_EditorClassIdentifier:
|
||||
cellSizing: 0
|
||||
m_TransparencySortMode: 0
|
||||
m_TransparencySortAxis: {x: 0, y: 0, z: 1}
|
||||
7
Assets/Palettes/New Palette.prefab.meta
Normal file
7
Assets/Palettes/New Palette.prefab.meta
Normal file
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f07742d4d37224440903931ff41c9e65
|
||||
PrefabImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
36
Assets/Palettes/Tile.asset
Normal file
36
Assets/Palettes/Tile.asset
Normal file
@@ -0,0 +1,36 @@
|
||||
%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: 13312, guid: 0000000000000000e000000000000000, type: 0}
|
||||
m_Name: Tile
|
||||
m_EditorClassIdentifier:
|
||||
m_Sprite: {fileID: 21300000, guid: 63d816f3f3cb040418900d1c8669d804, type: 3}
|
||||
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_Transform:
|
||||
e00: 1
|
||||
e01: 0
|
||||
e02: 0
|
||||
e03: 0
|
||||
e10: 0
|
||||
e11: 1
|
||||
e12: 0
|
||||
e13: 0
|
||||
e20: 0
|
||||
e21: 0
|
||||
e22: 1
|
||||
e23: 0
|
||||
e30: 0
|
||||
e31: 0
|
||||
e32: 0
|
||||
e33: 1
|
||||
m_InstancedGameObject: {fileID: 0}
|
||||
m_Flags: 1
|
||||
m_ColliderType: 1
|
||||
8
Assets/Palettes/Tile.asset.meta
Normal file
8
Assets/Palettes/Tile.asset.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 64a946fc6bd1f3a45ab24ef57ba0c1f2
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 11400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/Scenes.meta
Normal file
8
Assets/Scenes.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 08e05ccbd5578424bafcdf9eb237cb2b
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/Scenes/SampleScene.meta
Normal file
8
Assets/Scenes/SampleScene.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 685b58c35b8c4264d949a6105acf890e
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
196778
Assets/Scenes/SampleScene.unity
Normal file
196778
Assets/Scenes/SampleScene.unity
Normal file
File diff suppressed because it is too large
Load Diff
7
Assets/Scenes/SampleScene.unity.meta
Normal file
7
Assets/Scenes/SampleScene.unity.meta
Normal file
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2cda990e2423bbf4892e6590ba056729
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Assets/Scenes/SampleScene/NavMesh-NavMesh.asset
Normal file
BIN
Assets/Scenes/SampleScene/NavMesh-NavMesh.asset
Normal file
Binary file not shown.
8
Assets/Scenes/SampleScene/NavMesh-NavMesh.asset.meta
Normal file
8
Assets/Scenes/SampleScene/NavMesh-NavMesh.asset.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2a3c5a8b2ba5e724e9e5c55585d9baac
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 23800000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/Scripts.meta
Normal file
8
Assets/Scripts.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 19b0147e0c7a79e4cacee5a9705d3b96
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
73
Assets/Scripts/City.cs
Normal file
73
Assets/Scripts/City.cs
Normal file
@@ -0,0 +1,73 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public class City : MonoBehaviour
|
||||
{
|
||||
[Header("City")]
|
||||
[SerializeField]
|
||||
string cityName;
|
||||
|
||||
[SerializeField]
|
||||
List<Person> citizens = new List<Person>();
|
||||
|
||||
[SerializeField]
|
||||
List<House> houses = new List<House>();
|
||||
|
||||
[SerializeField]
|
||||
List<Workplace> workplaces = new List<Workplace>();
|
||||
|
||||
public void AddCitizen(Person citizen)
|
||||
{
|
||||
if (!citizens.Contains(citizen))
|
||||
{
|
||||
citizens.Add(citizen);
|
||||
Debug.Log(citizen.GetFullName() + " joined " + cityName);
|
||||
}
|
||||
}
|
||||
|
||||
public void RemoveCitizen(Person citizen)
|
||||
{
|
||||
if (citizens.Contains(citizen))
|
||||
{
|
||||
citizens.Remove(citizen);
|
||||
Debug.Log(citizen.GetFullName() + " left " + cityName);
|
||||
}
|
||||
}
|
||||
|
||||
public void AddHouse(House house)
|
||||
{
|
||||
if (!houses.Contains(house))
|
||||
{
|
||||
houses.Add(house);
|
||||
Debug.Log("House built in " + cityName);
|
||||
}
|
||||
}
|
||||
|
||||
public void RemoveHouse(House house)
|
||||
{
|
||||
if (houses.Contains(house))
|
||||
{
|
||||
houses.Remove(house);
|
||||
Debug.Log("House demolished in " + cityName);
|
||||
}
|
||||
}
|
||||
|
||||
public void AddWorkplace(Workplace workplace)
|
||||
{
|
||||
if (!workplaces.Contains(workplace))
|
||||
{
|
||||
workplaces.Add(workplace);
|
||||
Debug.Log("Workplace built in " + cityName);
|
||||
}
|
||||
}
|
||||
|
||||
public void RemoveWorkplace(Workplace workplace)
|
||||
{
|
||||
if (workplaces.Contains(workplace))
|
||||
{
|
||||
workplaces.Remove(workplace);
|
||||
Debug.Log("Workplace demolished in " + cityName);
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/City.cs.meta
Normal file
11
Assets/Scripts/City.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1da1a268031cfd742a614a4d319ddc32
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
39
Assets/Scripts/House.cs
Normal file
39
Assets/Scripts/House.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public class House : MonoBehaviour
|
||||
{
|
||||
[Header("House")]
|
||||
[SerializeField]
|
||||
int space = 1;
|
||||
|
||||
[SerializeField]
|
||||
List<Person> persons = new List<Person>();
|
||||
|
||||
[SerializeField]
|
||||
City city;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
city.AddHouse(this);
|
||||
}
|
||||
|
||||
public void AddPerson(Person person)
|
||||
{
|
||||
if (!persons.Contains(person) && persons.Count < space)
|
||||
{
|
||||
persons.Add(person);
|
||||
Debug.Log(person.GetFullName() + " now lives in house");
|
||||
}
|
||||
}
|
||||
|
||||
public void RemovePerson(Person person)
|
||||
{
|
||||
if (persons.Contains(person))
|
||||
{
|
||||
persons.Remove(person);
|
||||
Debug.Log(person.GetFullName() + " does not live in house anymore");
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/House.cs.meta
Normal file
11
Assets/Scripts/House.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5efcb4abb6526ca4fbbd130512bbc14d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
66
Assets/Scripts/Person.cs
Normal file
66
Assets/Scripts/Person.cs
Normal file
@@ -0,0 +1,66 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public class Person : MonoBehaviour
|
||||
{
|
||||
[Header("Person")]
|
||||
[SerializeField]
|
||||
string firstName = "";
|
||||
|
||||
[SerializeField]
|
||||
string lastName = "";
|
||||
|
||||
[SerializeField]
|
||||
City city;
|
||||
|
||||
[SerializeField]
|
||||
House house;
|
||||
|
||||
[SerializeField]
|
||||
Workplace workplace;
|
||||
|
||||
TimeManager timeManager;
|
||||
PersonMovement movement;
|
||||
|
||||
public string GetFirstName() => firstName;
|
||||
public string GetLastName() => lastName;
|
||||
public string GetFullName() => firstName + " " + lastName;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
city.AddCitizen(this);
|
||||
house.AddPerson(this);
|
||||
workplace.AddWorker(this);
|
||||
}
|
||||
|
||||
void Start()
|
||||
{
|
||||
timeManager = GameObject.Find("GameManager").GetComponent<TimeManager>();
|
||||
movement = GetComponent<PersonMovement>();
|
||||
|
||||
TimeManager.OnTimeInterval += OnTimeInterval;
|
||||
}
|
||||
|
||||
void OnTimeInterval()
|
||||
{
|
||||
switch (timeManager.partOfDay)
|
||||
{
|
||||
case TimeManager.PartOfDay.NIGHT:
|
||||
movement.SetTarget(house.transform);
|
||||
break;
|
||||
case TimeManager.PartOfDay.MORNING:
|
||||
movement.SetTarget(workplace.transform);
|
||||
break;
|
||||
case TimeManager.PartOfDay.AFTERNOON:
|
||||
movement.SetTarget(workplace.transform);
|
||||
break;
|
||||
case TimeManager.PartOfDay.EVENING:
|
||||
movement.SetTarget(city.transform);
|
||||
break;
|
||||
default:
|
||||
movement.SetTarget(city.transform);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Person.cs.meta
Normal file
11
Assets/Scripts/Person.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8647d87746af05e41a97676f479a8da8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
21
Assets/Scripts/PersonMovement.cs
Normal file
21
Assets/Scripts/PersonMovement.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.AI;
|
||||
|
||||
public class PersonMovement : MonoBehaviour
|
||||
{
|
||||
NavMeshAgent agent;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
agent = GetComponent<NavMeshAgent>();
|
||||
agent.updateRotation = false;
|
||||
agent.updateUpAxis = false;
|
||||
}
|
||||
|
||||
public void SetTarget(Transform target)
|
||||
{
|
||||
agent.SetDestination(target.position);
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/PersonMovement.cs.meta
Normal file
11
Assets/Scripts/PersonMovement.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 92efa8c0fa40ca1429bb33b689b384ea
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
68
Assets/Scripts/TimeManager.cs
Normal file
68
Assets/Scripts/TimeManager.cs
Normal file
@@ -0,0 +1,68 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public class TimeManager : MonoBehaviour
|
||||
{
|
||||
public static Action OnTimeInterval;
|
||||
public static TimeManager instance;
|
||||
|
||||
public enum PartOfDay
|
||||
{
|
||||
MORNING,
|
||||
AFTERNOON,
|
||||
EVENING,
|
||||
NIGHT
|
||||
}
|
||||
|
||||
public PartOfDay partOfDay;
|
||||
|
||||
[SerializeField]
|
||||
float intervalTime = 1.0f; // 1.0f -> 1 real second is 1 ingame minute
|
||||
|
||||
int minutesPerInterval = 1;
|
||||
|
||||
public CultureInfo cultureInfo = new CultureInfo("en-us");
|
||||
DateTime dateTime = new DateTime(1, 1, 1, 0, 0, 0);
|
||||
float timer;
|
||||
|
||||
public DateTime GetDateTime() => dateTime;
|
||||
|
||||
public string GetTime() => dateTime.ToString("hh:mm tt", cultureInfo);
|
||||
public string GetDate() => dateTime.ToString("dd/mm/yyyy", cultureInfo);
|
||||
public float GetintervalTime() => intervalTime;
|
||||
|
||||
|
||||
void Start()
|
||||
{
|
||||
timer = intervalTime;
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
timer -= Time.deltaTime;
|
||||
|
||||
if (timer <= 0)
|
||||
{
|
||||
dateTime = dateTime.AddMinutes(minutesPerInterval);
|
||||
CheckPartsOfDay();
|
||||
OnTimeInterval?.Invoke();
|
||||
timer = intervalTime;
|
||||
}
|
||||
}
|
||||
|
||||
void CheckPartsOfDay()
|
||||
{
|
||||
if (dateTime.Hour >= 22)
|
||||
partOfDay = PartOfDay.NIGHT;
|
||||
else if (dateTime.Hour < 6)
|
||||
partOfDay = PartOfDay.NIGHT;
|
||||
else if (dateTime.Hour >= 6 && dateTime.Hour < 12)
|
||||
partOfDay = PartOfDay.MORNING;
|
||||
else if (dateTime.Hour >= 12 && dateTime.Hour < 17)
|
||||
partOfDay = PartOfDay.AFTERNOON;
|
||||
else if (dateTime.Hour >= 17 && dateTime.Hour < 22)
|
||||
partOfDay = PartOfDay.EVENING;
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/TimeManager.cs.meta
Normal file
11
Assets/Scripts/TimeManager.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 19408a8c9044fc542b7045812e07e7fa
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
25
Assets/Scripts/TimeUI.cs
Normal file
25
Assets/Scripts/TimeUI.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using TMPro;
|
||||
|
||||
public class TimeUI : MonoBehaviour
|
||||
{
|
||||
TextMeshProUGUI dateTimeText;
|
||||
TimeManager timeManager;
|
||||
|
||||
private void Start()
|
||||
{
|
||||
timeManager = GameObject.Find("GameManager").GetComponent<TimeManager>();
|
||||
TimeManager.OnTimeInterval += OnInterval;
|
||||
dateTimeText = GetComponent<TextMeshProUGUI>();
|
||||
|
||||
}
|
||||
|
||||
void OnInterval()
|
||||
{
|
||||
DateTime dateTime = timeManager.GetDateTime();
|
||||
if (dateTimeText != null)
|
||||
dateTimeText.text = dateTime.ToString("hh:mm tt / dd.MM.yyyy", timeManager.cultureInfo);
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/TimeUI.cs.meta
Normal file
11
Assets/Scripts/TimeUI.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3c60f5ffa1a5b6f4292a33377311dcb6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
42
Assets/Scripts/Workplace.cs
Normal file
42
Assets/Scripts/Workplace.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public class Workplace : MonoBehaviour
|
||||
{
|
||||
[Header("Workplace")]
|
||||
[SerializeField]
|
||||
int space = 1;
|
||||
|
||||
[SerializeField]
|
||||
float salary = 4.5f;
|
||||
|
||||
[SerializeField]
|
||||
List<Person> workers = new List<Person>();
|
||||
|
||||
[SerializeField]
|
||||
City city;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
city.AddWorkplace(this);
|
||||
}
|
||||
|
||||
public void AddWorker(Person worker)
|
||||
{
|
||||
if (!workers.Contains(worker) && workers.Count < space)
|
||||
{
|
||||
workers.Add(worker);
|
||||
Debug.Log(worker.GetFullName() + " now works");
|
||||
}
|
||||
}
|
||||
|
||||
public void RemoveWorker(Person worker)
|
||||
{
|
||||
if (workers.Contains(worker))
|
||||
{
|
||||
workers.Remove(worker);
|
||||
Debug.Log(worker.GetFullName() + " does not work anymore");
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Workplace.cs.meta
Normal file
11
Assets/Scripts/Workplace.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2b0d700ec6a861f499e0c4bf7220bb68
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/Sprites.meta
Normal file
8
Assets/Sprites.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1330d978ea888514abb6a70ae1d93ff6
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Assets/Sprites/Tile.aseprite
Normal file
BIN
Assets/Sprites/Tile.aseprite
Normal file
Binary file not shown.
7
Assets/Sprites/Tile.aseprite.meta
Normal file
7
Assets/Sprites/Tile.aseprite.meta
Normal file
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bda32a5118df9ef4db473695a146d3f2
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Assets/Sprites/Tile.png
Normal file
BIN
Assets/Sprites/Tile.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 224 B |
135
Assets/Sprites/Tile.png.meta
Normal file
135
Assets/Sprites/Tile.png.meta
Normal file
@@ -0,0 +1,135 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 63d816f3f3cb040418900d1c8669d804
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 11
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
flipGreenChannel: 0
|
||||
isReadable: 0
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
vTOnly: 0
|
||||
ignoreMasterTextureLimit: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 0
|
||||
aniso: 1
|
||||
mipBias: 0
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: 1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 1
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 64
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 8
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 0
|
||||
swizzle: 50462976
|
||||
platformSettings:
|
||||
- serializedVersion: 3
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 0
|
||||
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: Server
|
||||
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: Windows Store Apps
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID: 5e97eb03825dee720800000000000000
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
nameFileIdTable: {}
|
||||
spritePackingTag:
|
||||
pSDRemoveMatte: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/TextMesh Pro.meta
Normal file
8
Assets/TextMesh Pro.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f54d1bd14bd3ca042bd867b519fee8cc
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/TextMesh Pro/Documentation.meta
Normal file
8
Assets/TextMesh Pro/Documentation.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8e7e8f5a82a3a134e91c54efd2274ea9
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Binary file not shown.
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1b8d251f9af63b746bf2f7ffe00ebb9b
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/TextMesh Pro/Fonts.meta
Normal file
8
Assets/TextMesh Pro/Fonts.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6ab70aee4d56447429c680537fbf93ed
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
46
Assets/TextMesh Pro/Fonts/LiberationSans - OFL.txt
Normal file
46
Assets/TextMesh Pro/Fonts/LiberationSans - OFL.txt
Normal file
@@ -0,0 +1,46 @@
|
||||
Digitized data copyright (c) 2010 Google Corporation
|
||||
with Reserved Font Arimo, Tinos and Cousine.
|
||||
Copyright (c) 2012 Red Hat, Inc.
|
||||
with Reserved Font Name Liberation.
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL
|
||||
|
||||
-----------------------------------------------------------
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide development of collaborative font projects, to support the font creation efforts of academic and linguistic communities, and to provide a free and open framework in which fonts may be shared and improved in partnership with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and redistributed freely as long as they are not sold by themselves. The fonts, including any derivative works, can be bundled, embedded, redistributed and/or sold with any software provided that any reserved names are not used by derivative works. The fonts and derivatives, however, cannot be released under any other type of license. The requirement for fonts to remain under this license does not apply to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright Holder(s) under this license and clearly marked as such. This may include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components as distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting, or substituting -- in part or in whole -- any of the components of the Original Version, by changing formats or by porting the Font Software to a new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of the Font Software, to use, study, copy, merge, embed, modify, redistribute, and sell modified and unmodified copies of the Font Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components, in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled, redistributed and/or sold with any software, provided that each copy contains the above copyright notice and this license. These can be included either as stand-alone text files, human-readable headers or in the appropriate machine-readable metadata fields within text or binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font Name(s) unless explicit written permission is granted by the corresponding Copyright Holder. This restriction only applies to the primary font name as presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font Software shall not be used to promote, endorse or advertise any Modified Version, except to acknowledge the contribution(s) of the Copyright Holder(s) and the Author(s) or with their explicit written permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole, must be distributed entirely under this license, and must not be distributed under any other license. The requirement for fonts to remain under this license does not apply to any document created using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
8
Assets/TextMesh Pro/Fonts/LiberationSans - OFL.txt.meta
Normal file
8
Assets/TextMesh Pro/Fonts/LiberationSans - OFL.txt.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6e59c59b81ab47f9b6ec5781fa725d2c
|
||||
timeCreated: 1484171296
|
||||
licenseType: Pro
|
||||
TextScriptImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Assets/TextMesh Pro/Fonts/LiberationSans.ttf
Normal file
BIN
Assets/TextMesh Pro/Fonts/LiberationSans.ttf
Normal file
Binary file not shown.
19
Assets/TextMesh Pro/Fonts/LiberationSans.ttf.meta
Normal file
19
Assets/TextMesh Pro/Fonts/LiberationSans.ttf.meta
Normal file
@@ -0,0 +1,19 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e3265ab4bf004d28a9537516768c1c75
|
||||
timeCreated: 1484171297
|
||||
licenseType: Pro
|
||||
TrueTypeFontImporter:
|
||||
serializedVersion: 2
|
||||
fontSize: 16
|
||||
forceTextureCase: -2
|
||||
characterSpacing: 1
|
||||
characterPadding: 0
|
||||
includeFontData: 1
|
||||
use2xBehaviour: 0
|
||||
fontNames: []
|
||||
fallbackFontReferences: []
|
||||
customCharacters:
|
||||
fontRenderingMode: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/TextMesh Pro/Resources.meta
Normal file
8
Assets/TextMesh Pro/Resources.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 243e06394e614e5d99fab26083b707fa
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user