Unity 2018 Artificial Intelligence Cookbook(Second Edition)
上QQ阅读APP看书,第一时间看更新

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; 
    } 
}