private static string GetAreaEnumValuesAsText(ref string[] areaNames) { var increment = 0; var output = new StringBuilder(); var seenKeys = new HashSet <string>(); foreach (var name in areaNames) { var enumKey = string.Concat(name.Where(char.IsLetterOrDigit)); var value = 1 << NavMesh.GetAreaFromName(name); output.Append(seenKeys.Contains(name) ? $"{(enumKey + increment++)} = {value}, " : $"{enumKey} = {value}, "); seenKeys.Add(enumKey); } return(output.ToString()); }
void AddObstacles(List <NavMeshBuildSource> sources) { // ---------Terrain trees-- - ------ Terrain terrain = Terrain.activeTerrain; TerrainData terrainData = terrain.terrainData; Vector3 size = Terrain.activeTerrain.terrainData.size; Vector3 terrainPos = terrain.GetPosition(); //Debug.Log("terrainPos = " + terrainPos); int treesArea = NavMesh.GetAreaFromName("Not Walkable"); if (treesArea < 0) { Debug.LogError("Unrecognized area name! The default area will be used instead."); treesArea = 0; } TreePrototype[] treePrototypes = terrainData.treePrototypes; TreeInstance[] treeInstances = terrainData.treeInstances; for (int i = 0; i < treeInstances.Length; i++) { //treeInstances[i] is the current ACTUAL tree we're going over. //the tree prototype is the "template" used by this tree. TreePrototype prototype = treePrototypes[treeInstances[i].prototypeIndex]; GameObject prefab = prototype.prefab; NavMeshObstacle obstacle = prefab.GetComponent <NavMeshObstacle>(); if (obstacle == null) { continue; } //Debug.Log("treeInstances[" + i + "] info:\n" + treeInstances[i].position + " " + treeInstances[i].rotation + " " + treeInstances[i].widthScale + " " + treeInstances[i].heightScale); Vector3 worldTreePos = terrainPos + Vector3.Scale(treeInstances[i].position, size) + obstacle.center; Quaternion worldTreeRot = Quaternion.Euler(0, treeInstances[i].rotation * Mathf.Rad2Deg, 0); Vector3 worldTreeScale = new Vector3(treeInstances[i].widthScale, treeInstances[i].heightScale, treeInstances[i].widthScale); //Debug.Log("CREATED MATRIX FOR TRS:\nworldTreePos = " + worldTreePos + "\nworldTreeRot = " + worldTreeRot + "\nworldTreeScale = " + worldTreeScale); NavMeshBuildSource src = new NavMeshBuildSource(); src.transform = Matrix4x4.TRS(worldTreePos, worldTreeRot, worldTreeScale); switch (obstacle.shape) { case NavMeshObstacleShape.Capsule: src.shape = NavMeshBuildSourceShape.Capsule; //Unity 2019.2.0f1: BUG!! navMeshObstacle.height returns exactly HALF of the actual height of the obstacle. //Use the size property instead. src.size = obstacle.size; break; case NavMeshObstacleShape.Box: src.shape = NavMeshBuildSourceShape.Box; src.size = obstacle.size; break; default: Debug.LogError("Unsupported type of " + typeof(NavMeshObstacleShape).Name + " for the building of the " + typeof(NavMeshSurface).Name + "! (" + obstacle.shape + ")"); break; } src.size = Vector3.Scale(src.size, prefab.transform.localScale); //Debug.Log("src.size = " + src.size); src.area = treesArea; sources.Add(src); } // --- --- --- End of Terrain trees --- --- --- }
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); } } // --- --- --- Terrain trees --- --- --- Terrain[] terrains = GameObject.FindObjectsOfType <Terrain>(); if (terrains.Length > 0) { foreach (Terrain item in terrains) { Terrain terrain = item.GetComponent <Terrain>(); TerrainData terrainData = terrain.terrainData; Vector3 size = Terrain.activeTerrain.terrainData.size; Vector3 terrainPos = terrain.GetPosition(); if (m_Debug) { Debug.Log("terrainPos = " + terrainPos); } int treesArea = NavMesh.GetAreaFromName("Not Walkable"); if (treesArea < 0) { Debug.LogError("Unrecognized area name! The default area will be used instead."); treesArea = 0; } TreePrototype[] treePrototypes = terrainData.treePrototypes; TreeInstance[] treeInstances = terrainData.treeInstances; if (m_Debug) { Debug.Log("trees found = " + treeInstances.Length); } for (int i = 0; i < treeInstances.Length; i++) { //treeInstances[i] is the current ACTUAL tree we're going over. //the tree prototype is the "template" used by this tree. TreePrototype prototype = treePrototypes[treeInstances[i].prototypeIndex]; GameObject prefab = prototype.prefab; NavMeshObstacle obstacle = prefab.GetComponent <NavMeshObstacle>(); Collider collider = prefab.GetComponentInChildren <Collider>(); bool obstacleBool = obstacle != null && (m_SelectionType == SelectionType.All || m_SelectionType == SelectionType.Obstacles); bool colliderBool = collider != null && (m_SelectionType == SelectionType.All || m_SelectionType == SelectionType.Colliders); if (obstacleBool || colliderBool) { Vector3 center = Vector3.zero; if (obstacle != null) { center = obstacle.center; } else if (collider != null) { center = collider.bounds.center; } if (m_Debug) { Debug.Log("treeInstances[" + i + "] info:\n" + treeInstances[i].position + " " + treeInstances[i].rotation + " " + treeInstances[i].widthScale + " " + treeInstances[i].heightScale); } Vector3 worldTreePos = terrainPos + Vector3.Scale(treeInstances[i].position, size) + center; Quaternion worldTreeRot = Quaternion.Euler(0, treeInstances[i].rotation * Mathf.Rad2Deg, 0); Vector3 worldTreeScale = new Vector3(treeInstances[i].widthScale, treeInstances[i].heightScale, treeInstances[i].widthScale); if (m_Debug) { Debug.Log("CREATED MATRIX FOR TRS:\nworldTreePos = " + worldTreePos + "\nworldTreeRot = " + worldTreeRot + "\nworldTreeScale = " + worldTreeScale); } NavMeshBuildSource src = new NavMeshBuildSource(); src.transform = Matrix4x4.TRS(worldTreePos, worldTreeRot, worldTreeScale); if (obstacleBool) { switch (obstacle.shape) { case NavMeshObstacleShape.Capsule: src.shape = NavMeshBuildSourceShape.Capsule; //Unity 2019.2.0f1: BUG!! navMeshObstacle.height returns exactly HALF of the actual height of the obstacle. //Use the size property instead. src.size = obstacle.size; break; case NavMeshObstacleShape.Box: src.shape = NavMeshBuildSourceShape.Box; src.size = obstacle.size; break; default: Debug.LogError("Unsupported type of " + typeof(NavMeshObstacleShape).Name + " for the building of the " + typeof(NavMeshSurface).Name + "! (" + obstacle.shape + ")"); break; } } else if (colliderBool) { if (collider is CapsuleCollider) { src.shape = NavMeshBuildSourceShape.Capsule; //Unity 2019.2.0f1: BUG!! navMeshObstacle.height returns exactly HALF of the actual height of the obstacle. //Use the size property instead. src.size = ((CapsuleCollider)collider).radius * Vector3.one * m_ColliderTolerance; } else if (collider is BoxCollider) { src.shape = NavMeshBuildSourceShape.Box; src.size = collider.bounds.size * m_ColliderTolerance; } else { Debug.LogError("Unsupported type of " + typeof(NavMeshObstacleShape).Name + " for the building of the " + typeof(NavMeshSurface).Name + "! (" + obstacle.shape + ")"); } } // Scale size src.size = Vector3.Scale(src.size, prefab.transform.localScale); if (m_Debug) { Debug.Log("src.size = " + src.size); } src.area = treesArea; sources.Add(src); } } } } // --- --- --- End of Terrain trees --- --- --- 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); }