How to do it...

We will create an editor window for easily handling the automation process without weighing down the graph's Start function, thereby delaying the scene loading:

  1. Create the CustomNavMeshWindow class and place it in a directory called Editor:
using UnityEngine; 
using UnityEditor; 
using System.Collections; 
using System.Collections.Generic; 
 
public class CustomNavMeshWindow : EditorWindow 
{ 
    // next steps here 
} 
  1. Add the attributes to the editor window:
static bool isEnabled = false; 
static GameObject graphObj; 
static CustomNavMesh graph; 
static CustomNavMeshWindow window; 
static GameObject graphVertex; 
  1. Implement the function for initializing and showing the window:
[MenuItem("UAIPC/Ch02/CustomNavMeshWindow")] 
static void Init() 
{ 
    window = EditorWindow.GetWindow<CustomNavMeshWindow>(); 
    window.title = "CustomNavMeshWindow"; 
    SceneView.onSceneGUIDelegate += OnScene; 
    graphObj = GameObject.Find("CustomNavMesh"); 
    if (graphObj == null) 
    { 
        graphObj = new GameObject("CustomNavMesh"); 
        graphObj.AddComponent<CustomNavMesh>(); 
        graph = graphObj.GetComponent<CustomNavMesh>(); 
    } 
    else 
    { 
        graph = graphObj.GetComponent<CustomNavMesh>(); 
        if (graph == null) 
            graphObj.AddComponent<CustomNavMesh>(); 
        graph = graphObj.GetComponent<CustomNavMesh>(); 
    } 
} 
  1. Define the OnDestroy function:
void OnDestroy() 
{ 
    SceneView.onSceneGUIDelegate -= OnScene; 
} 
  1. Implement the OnGUI function for drawing the window's interior:
void OnGUI() 
{ 
    isEnabled = EditorGUILayout.Toggle("Enable Mesh Picking", isEnabled); 
    if (GUILayout.Button("Build Edges")) 
    { 
        if (graph != null) 
            graph.LoadGraph(); 
    } 
} 
  1. Implement the first half of the OnScene function for handling the left-click on the scene window:
private static void OnScene(SceneView sceneView) 
{ 
    if (!isEnabled) 
        return; 
    if (Event.current.type == EventType.MouseDown) 
    { 
        graphVertex = graph.vertexPrefab; 
        if (graphVertex == null) 
        { 
            Debug.LogError("No Vertex Prefab assigned"); 
            return; 
        } 
        Event e = Event.current; 
        Ray ray = HandleUtility.GUIPointToWorldRay(e.mousePosition); 
        RaycastHit hit; 
        GameObject newV; 
        // next step 
    }        
} 
  1. Implement the second half for implementing the behavior when clicking on the mesh:
if (Physics.Raycast(ray, out hit)) 
{ 
    GameObject obj = hit.collider.gameObject; 
    Mesh mesh = obj.GetComponent<MeshFilter>().sharedMesh; 
    Vector3 pos; 
    int i; 
    for (i = 0; i < mesh.triangles.Length; i += 3) 
    { 
        int i0 = mesh.triangles[i]; 
        int i1 = mesh.triangles[i + 1]; 
        int i2 = mesh.triangles[i + 2]; 
        pos = mesh.vertices[i0]; 
        pos += mesh.vertices[i1]; 
        pos += mesh.vertices[i2]; 
        pos /= 3; 
        newV = (GameObject)Instantiate(graphVertex, pos, Quaternion.identity); 
        newV.transform.Translate(obj.transform.position); 
        newV.transform.parent = graphObj.transform; 
        graphObj.transform.parent = obj.transform; 
    } 
}