Пример #1
0
        //called whenever the inspector gui gets rendered
        public override void OnInspectorGUI()
        {
            //don't draw inspector fields if the path contains less than 2 points
            //(a path with less than 2 points really isn't a path)
            if (m_WaypointsCount.intValue < 2)
            {
                return;
            }

            //this pulls the relative variables from unity runtime and stores them in the object
            m_Object.Update();

            //create new checkboxes for path gizmo property
            m_Check1.boolValue = EditorGUILayout.Toggle("Walkable", m_Check1.boolValue);

            m_Check2.boolValue = EditorGUILayout.Toggle("Closure", m_Check2.boolValue);

            //create new property fields for editing waypoint gizmo colors
            EditorGUILayout.PropertyField(m_Color1);
            EditorGUILayout.PropertyField(m_Color2);

            //get waypoint array
            var waypoints = GetWaypointArray();

            //force naming scheme
            RenameWaypoints();

            //calculate path length of all waypoints
            Vector3[] wpPositions = new Vector3[waypoints.Length];
            for (int i = 0; i < waypoints.Length; i++)
            {
                wpPositions[i] = waypoints[i].position;
            }
            float pathLength = WaypointManager.GetPathLength(wpPositions);

            //path length label, show calculated path length
            GUILayout.Label("Path Length: " + pathLength);

            //waypoint index header
            GUILayout.Label("Waypoints: ", EditorStyles.boldLabel);

            //loop through the waypoint array
            for (int i = 0; i < waypoints.Length; i++)
            {
                GUILayout.BeginHorizontal();
                //indicate each array slot with index number in front of it
                GUILayout.Label(i + ".", GUILayout.Width(20));
                //create an object field for every waypoint
                EditorGUILayout.ObjectField(waypoints[i], typeof(Transform), true);

                //display an "Add Waypoint" button for every array row except the last one
                if (i < waypoints.Length && GUILayout.Button("+", GUILayout.Width(30f)))
                {
                    AddWaypointAtIndex(i);
                    break;
                }

                //display an "Remove Waypoint" button for every array row except the first and last one
                if (i > 0 && i < waypoints.Length - 1 && GUILayout.Button("-", GUILayout.Width(30f)))
                {
                    RemoveWaypointAtIndex(i);
                    break;
                }

                GUILayout.EndHorizontal();
            }

            EditorGUILayout.Space();

            //button to move all waypoints down to the ground
            if (GUILayout.Button("Place to Ground"))
            {
                //for each waypoint of this path
                foreach (Transform trans in waypoints)
                {
                    //define ray to cast downwards waypoint position
                    Ray ray = new Ray(trans.position + new Vector3(0, 2f, 0), -Vector3.up);
                    Undo.RecordObject(trans, "");

                    RaycastHit hit;
                    //cast ray against ground, if it hit:
                    if (Physics.Raycast(ray, out hit, 100))
                    {
                        //position y values of waypoint to hit point
                        trans.position = hit.point;
                    }

                    //also try to raycast against 2D colliders
                    RaycastHit2D hit2D = Physics2D.Raycast(ray.origin, -Vector2.up, 100);
                    if (hit2D)
                    {
                        trans.position = new Vector3(hit2D.point.x, hit2D.point.y, trans.position.z);
                    }
                }
            }

            EditorGUILayout.Space();

            //invert direction of whole path
            if (GUILayout.Button("Invert Direction"))
            {
                Undo.RecordObjects(waypoints, "");

                //to reverse the whole path we need to know where the waypoints were before
                //for this purpose a new copy must be created
                Vector3[] waypointCopy = new Vector3[waypoints.Length];
                for (int i = 0; i < waypoints.Length; i++)
                {
                    waypointCopy[i] = waypoints[i].position;
                }

                //looping over the array in reversed order
                for (int i = 0; i < waypoints.Length; i++)
                {
                    waypoints[i].position = waypointCopy[waypointCopy.Length - 1 - i];
                }
            }

            EditorGUILayout.Space();

            //draw object field for waypoint prefab
            EditorGUILayout.PropertyField(m_WaypointPref);

            //replace all waypoints with the prefab
            if (GUILayout.Button("Replace Waypoints with Object"))
            {
                if (m_WaypointPref == null)
                {
                    Debug.LogWarning("No replace object set. Cancelling.");
                    return;
                }

                ReplaceWaypoints();
            }

            //we push our modified variables back to our serialized object
            m_Object.ApplyModifiedProperties();
        }
Пример #2
0
        public override void OnInspectorGUI()
        {
            //show default variables of manager
            DrawDefaultInspector();
            //get manager reference
            script = (WaypointManager)target;
            EditorGUILayout.LabelField("", GUI.skin.horizontalSlider);

            //get sceneview to auto-detect 2D mode
            SceneView view = GetSceneView();

            mode2D = view.in2DMode;

            EditorGUILayout.Space();
            EditorGUILayout.BeginHorizontal();

            //draw path text label
            GUILayout.Label("Enter Path Name: ", GUILayout.Height(15));
            //display text field for creating a path with that name
            pathName = EditorGUILayout.TextField(pathName, GUILayout.Height(15));

            EditorGUILayout.EndHorizontal();
            EditorGUILayout.Space();
            EditorGUILayout.BeginHorizontal();

            //draw path type selection enum
            GUILayout.Label("Select Path Type: ", GUILayout.Height(15));
            pathType = (PathType)EditorGUILayout.EnumPopup(pathType);

            EditorGUILayout.EndHorizontal();
            EditorGUILayout.Space();

            //display label of current mode
            if (mode2D)
            {
                GUILayout.Label("2D Mode Detected.", GUILayout.Height(15));
            }
            else
            {
                GUILayout.Label("3D Mode Detected.", GUILayout.Height(15));
            }
            EditorGUILayout.Space();

            //draw path creation button
            if (!placing && GUILayout.Button("Start Path", GUILayout.Height(40)))
            {
                if (pathName == "")
                {
                    EditorUtility.DisplayDialog("No Path Name", "Please enter a unique name for your path.", "Ok");
                    return;
                }

                if (script.transform.FindChild(pathName) != null)
                {
                    if (EditorUtility.DisplayDialog("Path Exists Already",
                                                    "A path with this name exists already.\n\nWould you like to edit it?", "Ok", "Cancel"))
                    {
                        Selection.activeTransform = script.transform.FindChild(pathName);
                    }
                    return;
                }

                //create a new container transform which will hold all new waypoints
                path = new GameObject(pathName);
                //reset position and parent container gameobject to this manager gameobject
                path.transform.position = script.gameObject.transform.position;
                path.transform.parent   = script.gameObject.transform;
                StartPath();

                //we passed all prior checks, toggle waypoint placement
                placing = true;
                //focus sceneview for placement
                view.Focus();
            }

            GUI.backgroundColor = Color.yellow;

            //finish path button
            if (placing && GUILayout.Button("Finish Editing", GUILayout.Height(40)))
            {
                FinishPath();
            }

            GUI.backgroundColor = Color.white;
            EditorGUILayout.Space();
            //draw instructions
            GUILayout.TextArea("Hint:\nEnter a unique name for your path, "
                               + "then press 'Start Path' to begin placement mode. Press '" + script.placementKey
                               + "' on your keyboard to place new waypoints in the Scene view. In 3D Mode "
                               + "you have to place waypoints onto game objects with colliders. You can "
                               + "also place waypoints at the current scene view camera position by pressing '"
                               + script.viewPlacementKey + "'.\n\nPress 'Finish Editing' to end your path.");
        }
Пример #3
0
 //auto-add to WaypointManager
 void Awake()
 {
     WaypointManager.AddPath(gameObject);
 }
Пример #4
0
        //if this path is selected, display small info boxes above all waypoint positions
        //also display handles for the waypoints
        void OnSceneGUI()
        {
            //again, get waypoint array
            var waypoints = GetWaypointArray();

            //do not execute further code if we have no waypoints defined
            //(just to make sure, practically this can not occur)
            if (waypoints.Length == 0)
            {
                return;
            }
            Vector3 wpPos = Vector3.zero;
            float   size  = 1f;

            //loop through waypoint array
            for (int i = 0; i < waypoints.Length; i++)
            {
                if (!waypoints[i])
                {
                    continue;
                }
                wpPos = waypoints[i].position;
                size  = HandleUtility.GetHandleSize(wpPos) * 0.4f;

                //do not draw waypoint header if too far away
                if (size < 3f)
                {
                    //begin 2D GUI block
                    Handles.BeginGUI();
                    //translate waypoint vector3 position in world space into a position on the screen
                    var guiPoint = HandleUtility.WorldToGUIPoint(wpPos);
                    //create rectangle with that positions and do some offset
                    var rect = new Rect(guiPoint.x - 50.0f, guiPoint.y - 40, 100, 20);
                    //draw box at position with current waypoint name
                    GUI.Box(rect, waypoints[i].name);
                    Handles.EndGUI(); //end GUI block
                }

                //draw handles per waypoint, clamp size
                Handles.color = m_Color2.colorValue;
                size          = Mathf.Clamp(size, 0, 1.2f);
                Vector3 newPos = Handles.FreeMoveHandle(wpPos, Quaternion.identity,
                                                        size, Vector3.zero, Handles.SphereCap);
                Handles.RadiusHandle(Quaternion.identity, wpPos, size / 2);

                if (wpPos != newPos)
                {
                    Undo.RecordObject(waypoints[i], "Move Handles");
                    waypoints[i].position = newPos;
                }
            }

            //waypoint direction handles drawing
            if (!m_Check2.boolValue)
            {
                return;
            }
            Vector3[] pathPoints = new Vector3[waypoints.Length];
            for (int i = 0; i < pathPoints.Length; i++)
            {
                pathPoints[i] = waypoints[i].position;
            }

            //create list of path segments (list of Vector3 list)
            List <List <Vector3> > segments = new List <List <Vector3> >();
            int   curIndex = 0;
            float lerpVal  = 0f;

            //differ between linear and curved display
            switch (m_Check1.boolValue)
            {
            case true:
                //convert waypoints to curved path points
                pathPoints = WaypointManager.GetCurved(pathPoints);
                for (int i = 0; i < waypoints.Length - 1; i++)
                {
                    //loop over path points to find single segments
                    segments.Add(new List <Vector3>());
                    for (int j = curIndex; j < pathPoints.Length; j++)
                    {
                        //the segment ends here, continue with new segment
                        if (pathPoints[j] == waypoints[i + 1].position)
                        {
                            curIndex = j;
                            break;
                        }

                        //add path point to current segment
                        segments[i].Add(pathPoints[j]);
                    }
                }
                break;

            case false:
                //detail for arrows between waypoints
                int lerpMax = 16;
                //loop over waypoints to add intermediary points
                for (int i = 0; i < waypoints.Length - 1; i++)
                {
                    segments.Add(new List <Vector3>());
                    for (int j = 0; j < lerpMax; j++)
                    {
                        //linear lerp between waypoints to get additional points for drawing arrows at
                        segments[i].Add(Vector3.Lerp(pathPoints[i], pathPoints[i + 1], j / (float)lerpMax));
                    }
                }
                break;
            }

            //loop over segments
            for (int i = 0; i < segments.Count; i++)
            {
                //loop over single positions on the segment
                for (int j = 0; j < segments[i].Count; j++)
                {
                    //get current lerp value for interpolating rotation
                    //draw arrow handle on current position with interpolated rotation
                    size    = Mathf.Clamp(HandleUtility.GetHandleSize(segments[i][j]) * 0.4f, 0, 1.2f);
                    lerpVal = j / (float)segments[i].Count;
                    Handles.ArrowCap(0, segments[i][j], Quaternion.Lerp(waypoints[i].rotation, waypoints[i + 1].rotation, lerpVal) * Quaternion.Euler(0, 90, 0), size);
                }
            }
        }
Пример #5
0
        public override void OnInspectorGUI()
        {
            //don't draw inspector fields if the path contains less than 2 points
            //(a path with less than 2 points really isn't a path)
            if (script.bPoints.Count < 2)
            {
                return;
            }

            //checkbox field to enable editable path properties
            script.showHandles = EditorGUILayout.Toggle("Show Handles", script.showHandles);
            //checkbox field for toggling control point connectedness
            script.connectHandles = EditorGUILayout.Toggle("Connect Handles", script.connectHandles);
            //checkbox field for drawing gizmo path lines
            script.drawCurved = EditorGUILayout.Toggle("Draw Smooth Lines", script.drawCurved);

            //create new color fields for editing path gizmo colors
            script.color1 = EditorGUILayout.ColorField("Color1", script.color1);
            script.color2 = EditorGUILayout.ColorField("Color2", script.color2);
            script.color3 = EditorGUILayout.ColorField("Color3", script.color3);

            //calculate path length of all waypoints
            float pathLength = WaypointManager.GetPathLength(script.pathPoints);

            //path length label, show calculated path length
            GUILayout.Label("Path Length: " + pathLength);

            float thisDetail = script.pathDetail;

            //slider to modify the smoothing factor of the final path,
            //round because of path point imprecision placement (micro loops)
            script.pathDetail = EditorGUILayout.Slider("Path Detail", script.pathDetail, 0.5f, 10);
            script.pathDetail = Mathf.Round(script.pathDetail * 10f) / 10f;
            //toggle custom detail when modifying the whole path
            if (thisDetail != script.pathDetail)
            {
                script.customDetail = false;
            }

            //draw custom detail settings
            EditorGUILayout.Space();
            DetailSettings();
            EditorGUILayout.Space();

            //waypoint index header
            GUILayout.Label("Waypoints: ", EditorStyles.boldLabel);

            //loop through the waypoint array
            for (int i = 0; i < script.bPoints.Count; i++)
            {
                GUILayout.BeginHorizontal();
                //indicate each array slot with index number in front of it
                GUILayout.Label(i + ".", GUILayout.Width(20));

                //create an object field for every waypoint
                EditorGUILayout.ObjectField(script.bPoints[i].wp, typeof(Transform), true);

                //display an "Add Waypoint" button for every array row except the last one
                //on click we call AddWaypointAtIndex() to insert a new waypoint slot AFTER the selected slot
                if (i < script.bPoints.Count && GUILayout.Button("+", GUILayout.Width(30f)))
                {
                    AddWaypointAtIndex(i);
                    break;
                }

                //display an "Remove Waypoint" button for every array row except the first and last one
                //on click we call RemoveWaypointAtIndex() to delete the selected waypoint slot
                if (i > 0 && i < script.bPoints.Count - 1 && GUILayout.Button("-", GUILayout.Width(30f)))
                {
                    RemoveWaypointAtIndex(i);
                    break;
                }

                GUILayout.EndHorizontal();
            }

            EditorGUILayout.Space();

            EditorGUILayout.BeginHorizontal();
            //button to rename waypoints to current index order
            if (GUILayout.Button("Rename Waypoints"))
            {
                string   wpName = string.Empty;
                string[] nameSplit;

                for (int i = 0; i < script.bPoints.Count; i++)
                {
                    //cache name and split into strings
                    wpName    = script.bPoints[i].wp.name;
                    nameSplit = wpName.Split(' ');

                    //ignore custom names and just rename
                    if (!script.skipCustomNames)
                    {
                        wpName = "Waypoint " + i;
                    }
                    else if (nameSplit.Length == 2 && nameSplit[0] == "Waypoint")
                    {
                        //try parsing the current index and rename,
                        //not ignoring custom names here
                        int index;
                        if (int.TryParse(nameSplit[1], out index))
                        {
                            wpName = nameSplit[0] + " " + i;
                        }
                    }

                    //set the desired index or leave it
                    script.bPoints[i].wp.name = wpName;
                }
            }

            EditorGUILayout.LabelField("Skip Custom", GUILayout.Width(80));
            script.skipCustomNames = EditorGUILayout.Toggle(script.skipCustomNames, GUILayout.Width(20));
            EditorGUILayout.EndHorizontal();

            //button to move all waypoints down to the ground
            if (GUILayout.Button("Place to Ground"))
            {
                //for each waypoint of this path
                foreach (BezierPoint bp in script.bPoints)
                {
                    //define ray to cast downwards waypoint position
                    Ray ray = new Ray(bp.wp.position + new Vector3(0, 2f, 0), -Vector3.up);
                    Undo.RecordObject(bp.wp, "PlaceToGround");

                    RaycastHit hit;
                    //cast ray against ground, if it hit:
                    if (Physics.Raycast(ray, out hit, 100))
                    {
                        //position waypoint to hit point
                        bp.wp.position = hit.point;
                    }

                    //also try to raycast against 2D colliders
                    RaycastHit2D hit2D = Physics2D.Raycast(ray.origin, -Vector2.up, 100);
                    if (hit2D)
                    {
                        bp.wp.position = new Vector3(hit2D.point.x, hit2D.point.y, bp.wp.position.z);
                    }
                }
            }

            //invert direction of whole path
            if (GUILayout.Button("Invert Direction"))
            {
                Undo.RecordObject(script, "Invert");

                //to reverse the whole path we need to know where the waypoints were before
                //for this purpose a new copy must be created
                BezierPoint[] waypointCache = new BezierPoint[script.bPoints.Count];
                for (int i = 0; i < waypointCache.Length; i++)
                {
                    waypointCache[i] = script.bPoints[i];
                }

                //reverse order based on the old list
                for (int i = 0; i < waypointCache.Length; i++)
                {
                    BezierPoint currentPoint = script.bPoints[waypointCache.Length - 1 - i];
                    script.bPoints[waypointCache.Length - 1 - i] = waypointCache[i];
                    Vector3 leftHandle = currentPoint.cp[0].position;

                    Undo.RecordObject(currentPoint.cp[0], "Invert");
                    Undo.RecordObject(currentPoint.cp[1], "Invert");

                    currentPoint.cp[0].position = currentPoint.cp[1].position;
                    currentPoint.cp[1].position = leftHandle;
                }
            }

            EditorGUILayout.Space();

            //draw object field for new waypoint object
            script.replaceObject = (GameObject)EditorGUILayout.ObjectField("Replace Object", script.replaceObject, typeof(GameObject), true);

            //replace all waypoints with the prefab
            if (GUILayout.Button("Replace Waypoints with Object"))
            {
                ReplaceWaypoints();
            }

            //recalculate on inspector changes
            if (GUI.changed)
            {
                script.CalculatePath();
                EditorUtility.SetDirty(target);
            }
        }
Пример #6
0
        public override void OnInspectorGUI()
        {
            //show default variables of manager
            DrawDefaultInspector();
            //get manager reference
            script = (WaypointManager)target;

            //get sceneview to auto-detect 2D mode
            SceneView view = GetSceneView();

            mode2D = view.in2DMode;

            EditorGUILayout.Space();
            EditorGUILayout.BeginHorizontal();

            //draw path text label
            GUILayout.Label("Enter Path Name: ", GUILayout.Height(15));
            //display text field for creating a path with that name
            pathName = EditorGUILayout.TextField(pathName, GUILayout.Height(15));

            EditorGUILayout.EndHorizontal();
            EditorGUILayout.Space();
            EditorGUILayout.BeginHorizontal();

            //draw path type selection enum
            GUILayout.Label("Select Path Type: ", GUILayout.Height(15));
            pathType = (PathType)EditorGUILayout.EnumPopup(pathType);

            EditorGUILayout.EndHorizontal();
            EditorGUILayout.Space();

            //display label of current mode
            if (mode2D)
            {
                GUILayout.Label("2D Mode Detected.", GUILayout.Height(15));
            }
            else
            {
                GUILayout.Label("3D Mode Detected.", GUILayout.Height(15));
            }
            EditorGUILayout.Space();

            //draw path creation button
            if (!placing && GUILayout.Button("Start Path", GUILayout.Height(40)))
            {
                if (pathName == "")
                {
                    Debug.LogWarning("No path name defined. Cancelling.");
                    return;
                }

                if (script.transform.Find(pathName) != null)
                {
                    Debug.LogWarning("Path name already given. Cancelling.");
                    return;
                }

                //create a new container transform which will hold all new waypoints
                path = new GameObject(pathName);
                //reset position and parent container gameobject to this manager gameobject
                path.transform.position = script.gameObject.transform.position;
                path.transform.parent   = script.gameObject.transform;
                StartPath();

                //we passed all prior checks, toggle waypoint placement
                placing = true;
                //focus sceneview for placement
                view.Focus();
            }

            GUI.backgroundColor = Color.yellow;

            //finish path button
            if (placing && GUILayout.Button("Finish Editing", GUILayout.Height(40)))
            {
                if (wpList.Count < 2)
                {
                    Debug.LogWarning("Not enough waypoints placed. Cancelling.");
                    //if we have created a path already, destroy it again
                    if (path)
                    {
                        DestroyImmediate(path);
                    }
                }

                //toggle placement off
                placing = false;
                //clear list with temporary waypoint references,
                //we only needed this for getting the waypoint count
                wpList.Clear();
                //reset path name input field
                pathName = "";
                //make the new path the active selection
                Selection.activeGameObject = path;
            }

            GUI.backgroundColor = Color.white;
            EditorGUILayout.Space();
            //draw instructions
            GUILayout.TextArea("Hint:\nPress 'Start Path' to begin a new path, then press 'p' on "
                               + "your keyboard to place new waypoints in the SceneView. In 3D Mode "
                               + "you have to place waypoints onto objects with colliders. You can "
                               + "also place waypoints at the scene view position by pressing 'c'."
                               + "\n\nPress 'Finish Editing' to end your path.");
        }
Пример #7
0
        //called whenever the inspector gui gets rendered
        public override void OnInspectorGUI()
        {
            //don't draw inspector fields if the path contains less than 2 points
            //(a path with less than 2 points really isn't a path)
            if (m_WaypointsCount.intValue < 2)
            {
                return;
            }

            //this pulls the relative variables from unity runtime and stores them in the object
            m_Object.Update();

            //create new checkboxes for path gizmo property
            m_Check1.boolValue = EditorGUILayout.Toggle("Draw Smooth Lines", m_Check1.boolValue);
            //m_Check2.boolValue = EditorGUILayout.Toggle("Draw Direction Handles", m_Check2.boolValue);

            //create new property fields for editing waypoint gizmo colors
            EditorGUILayout.PropertyField(m_Color1);
            EditorGUILayout.PropertyField(m_Color2);

            //get waypoint array
            var waypoints = GetWaypointArray();

            //calculate path length of all waypoints
            Vector3[] wpPositions = new Vector3[waypoints.Length];
            for (int i = 0; i < waypoints.Length; i++)
            {
                wpPositions[i] = waypoints[i].position;
            }
            float pathLength = WaypointManager.GetPathLength(wpPositions);

            //path length label, show calculated path length
            GUILayout.Label("Path Length: " + pathLength);

            //waypoint index header
            GUILayout.Label("Waypoints: ", EditorStyles.boldLabel);

            //loop through the waypoint array
            for (int i = 0; i < waypoints.Length; i++)
            {
                GUILayout.BeginHorizontal();
                //indicate each array slot with index number in front of it
                GUILayout.Label(i + ".", GUILayout.Width(20));
                //create an object field for every waypoint
                EditorGUILayout.ObjectField(waypoints[i], typeof(Transform), true);

                //display an "Add Waypoint" button for every array row except the last one
                if (i < waypoints.Length && GUILayout.Button("+", GUILayout.Width(30f)))
                {
                    AddWaypointAtIndex(i);
                    break;
                }

                //display an "Remove Waypoint" button for every array row except the first and last one
                if (i > 0 && i < waypoints.Length - 1 && GUILayout.Button("-", GUILayout.Width(30f)))
                {
                    RemoveWaypointAtIndex(i);
                    break;
                }

                GUILayout.EndHorizontal();
            }

            EditorGUILayout.Space();

            EditorGUILayout.BeginHorizontal();
            //button to rename waypoints to current index order
            if (GUILayout.Button("Rename Waypoints"))
            {
                //disabled because of a Unity bug that crashes the editor
                //this is taken directly from the docs, thank you Unity.
                //http://docs.unity3d.com/ScriptReference/Undo.RegisterCompleteObjectUndo.html
                //Undo.RegisterCompleteObjectUndo(waypoints[0].gameObject, "Rename Waypoints");

                string   wpName = string.Empty;
                string[] nameSplit;

                for (int i = 0; i < waypoints.Length; i++)
                {
                    //cache name and split into strings
                    wpName    = waypoints[i].name;
                    nameSplit = wpName.Split(' ');

                    //ignore custom names and just rename
                    if (!m_SkipNames.boolValue)
                    {
                        wpName = "Waypoint " + i;
                    }
                    else if (nameSplit.Length == 2 && nameSplit[0] == "Waypoint")
                    {
                        //try parsing the current index and rename,
                        //not ignoring custom names here
                        int index;
                        if (int.TryParse(nameSplit[1], out index))
                        {
                            wpName = nameSplit[0] + " " + i;
                        }
                    }

                    //set the desired index or leave it
                    waypoints[i].name = wpName;
                }
            }

            EditorGUILayout.LabelField("Skip Custom", GUILayout.Width(80));
            m_SkipNames.boolValue = EditorGUILayout.Toggle(m_SkipNames.boolValue, GUILayout.Width(20));
            EditorGUILayout.EndHorizontal();

            //button to move all waypoints down to the ground
            if (GUILayout.Button("Place to Ground"))
            {
                //for each waypoint of this path
                foreach (Transform trans in waypoints)
                {
                    //define ray to cast downwards waypoint position
                    Ray ray = new Ray(trans.position + new Vector3(0, 2f, 0), -Vector3.up);
                    Undo.RecordObject(trans, "Place To Ground");

                    RaycastHit hit;
                    //cast ray against ground, if it hit:
                    if (Physics.Raycast(ray, out hit, 100))
                    {
                        //position y values of waypoint to hit point
                        trans.position = hit.point;
                    }

                    //also try to raycast against 2D colliders
                    RaycastHit2D hit2D = Physics2D.Raycast(ray.origin, -Vector2.up, 100);
                    if (hit2D)
                    {
                        trans.position = new Vector3(hit2D.point.x, hit2D.point.y, trans.position.z);
                    }
                }
            }

            //invert direction of whole path
            if (GUILayout.Button("Invert Direction"))
            {
                Undo.RecordObjects(waypoints, "Invert Direction");

                //to reverse the whole path we need to know where the waypoints were before
                //for this purpose a new copy must be created
                Vector3[] waypointCopy = new Vector3[waypoints.Length];
                for (int i = 0; i < waypoints.Length; i++)
                {
                    waypointCopy[i] = waypoints[i].position;
                }

                //looping over the array in reversed order
                for (int i = 0; i < waypoints.Length; i++)
                {
                    waypoints[i].position = waypointCopy[waypointCopy.Length - 1 - i];
                }
            }

            EditorGUILayout.Space();

            //draw object field for waypoint prefab
            EditorGUILayout.PropertyField(m_WaypointPref);

            //replace all waypoints with the prefab
            if (GUILayout.Button("Replace Waypoints with Object"))
            {
                if (m_WaypointPref == null)
                {
                    Debug.LogWarning("No replace object set. Cancelling.");
                    return;
                }

                ReplaceWaypoints();
            }

            //we push our modified variables back to our serialized object
            m_Object.ApplyModifiedProperties();
        }
Пример #8
0
        public override void OnInspectorGUI()
        {
            //don't draw inspector fields if the path contains less than 2 points
            //(a path with less than 2 points really isn't a path)
            if (script.bPoints.Count < 2)
            {
                //button to create path manually
                if (GUILayout.Button("Create Path from Children"))
                {
                    Undo.RecordObject(script, "Create Path");
                    script.Create();
                    SceneView.RepaintAll();
                }

                return;
            }

            //create new checkboxes for path gizmo property
            script.showHandles    = EditorGUILayout.Toggle("Show Handles", script.showHandles);
            script.connectHandles = EditorGUILayout.Toggle("Connect Handles", script.connectHandles);
            script.drawCurved     = EditorGUILayout.Toggle("Draw Smooth Lines", script.drawCurved);
            script.drawDirection  = EditorGUILayout.Toggle("Draw Direction", script.drawDirection);

            //create new color fields for editing path gizmo colors
            script.color1 = EditorGUILayout.ColorField("Color1", script.color1);
            script.color2 = EditorGUILayout.ColorField("Color2", script.color2);
            script.color3 = EditorGUILayout.ColorField("Color3", script.color3);

            //calculate path length of all waypoints
            float pathLength = WaypointManager.GetPathLength(script.pathPoints);

            GUILayout.Label("Path Length: " + pathLength);

            float thisDetail = script.pathDetail;

            //slider to modify the smoothing factor of the final path,
            //round because of path point imprecision placement (micro loops)
            script.pathDetail = EditorGUILayout.Slider("Path Detail", script.pathDetail, 0.5f, 10);
            script.pathDetail = Mathf.Round(script.pathDetail * 10f) / 10f;
            //toggle custom detail when modifying the whole path
            if (thisDetail != script.pathDetail)
            {
                script.customDetail = false;
            }
            //draw custom detail settings
            DetailSettings();

            //button for switching over to the WaypointManager for further path editing
            if (GUILayout.Button("Continue Editing"))
            {
                Selection.activeGameObject = (GameObject.FindObjectOfType(typeof(WaypointManager)) as WaypointManager).gameObject;
                WaypointEditor.ContinuePath(script);
            }

            //more path modifiers
            DrawPathOptions();
            EditorGUILayout.Space();

            //waypoint index header
            GUILayout.Label("Waypoints: ", EditorStyles.boldLabel);

            //loop through the waypoint array
            for (int i = 0; i < script.bPoints.Count; i++)
            {
                GUILayout.BeginHorizontal();
                //indicate each array slot with index number in front of it
                GUILayout.Label(i + ".", GUILayout.Width(20));

                //create an object field for every waypoint
                EditorGUILayout.ObjectField(script.bPoints[i].wp, typeof(Transform), true);

                //display an "Add Waypoint" button for every array row except the last one
                //on click we call AddWaypointAtIndex() to insert a new waypoint slot AFTER the selected slot
                if (i < script.bPoints.Count && GUILayout.Button("+", GUILayout.Width(30f)))
                {
                    AddWaypointAtIndex(i);
                    break;
                }

                //display an "Remove Waypoint" button for every array row except the first and last one
                //on click we call RemoveWaypointAtIndex() to delete the selected waypoint slot
                if (i > 0 && i < script.bPoints.Count - 1 && GUILayout.Button("-", GUILayout.Width(30f)))
                {
                    RemoveWaypointAtIndex(i);
                    break;
                }

                GUILayout.EndHorizontal();
            }

            //recalculate on inspector changes
            if (GUI.changed)
            {
                script.CalculatePath();
                EditorUtility.SetDirty(target);
            }
        }
Пример #9
0
        public override void OnInspectorGUI()
        {
            //show default variables of manager
            DrawDefaultInspector();
            //get manager reference
            script = (WaypointManager)target;

            //get sceneview to auto-detect 2D mode
            SceneView view = SceneView.currentDrawingSceneView;

            if (view == null)
            {
                view = EditorWindow.GetWindow <SceneView>("Scene", false);
            }
            mode2D = view.in2DMode;

            EditorGUIUtility.LookLikeControls();
            EditorGUILayout.Space();
            EditorGUILayout.BeginHorizontal();

            //draw path text label
            GUILayout.Label("Enter Path Name: ", GUILayout.Height(15));
            //display text field for creating a path with that name
            pathName = EditorGUILayout.TextField(pathName, GUILayout.Height(15));

            EditorGUILayout.EndHorizontal();
            EditorGUILayout.Space();
            EditorGUILayout.BeginHorizontal();

            //draw path type selection enum
            GUILayout.Label("Select Path Type: ", GUILayout.Height(15));
            pathType = (PathType)EditorGUILayout.EnumPopup(pathType);

            EditorGUILayout.EndHorizontal();
            EditorGUILayout.Space();

            //display label of current mode
            if (mode2D)
            {
                GUILayout.Label("2D Mode Detected.", GUILayout.Height(15));
            }
            else
            {
                GUILayout.Label("3D Mode Detected.", GUILayout.Height(15));
            }
            EditorGUILayout.Space();

            //draw path creation button
            if (!placing && GUILayout.Button("Start Path", GUILayout.Height(40)))
            {
                if (pathName == "")
                {
                    Debug.LogWarning("No path name defined. Cancelling.");
                    return;
                }

                if (script.transform.Find(pathName) != null)
                {
                    Debug.LogWarning("Path name already given. Cancelling.");
                    return;
                }

                //create a new container transform which will hold all new waypoints
                path = new GameObject(pathName);
                //reset position and parent container gameobject to this manager gameobject
                path.transform.position = script.gameObject.transform.position;
                path.transform.parent   = script.gameObject.transform;
                StartPath();

                //we passed all prior checks, toggle waypoint placement
                placing = true;
                //focus sceneview for placement
                if (view != null)
                {
                    view.Focus();
                }
                //   SceneView.currentDrawingSceneView.Focus();
            }

            if (!placing && GUILayout.Button("Export Path", GUILayout.Height(40)))
            {
                string filepath = EditorUtility.SaveFilePanelInProject("Save Path", "PathInfo", "csv", "OKOK");
                LogManager.Log(filepath);
                string fileName = filepath;                //文件名字

                StringBuilder sb = new StringBuilder();
                //offset
                sb.Append("patrolId").Append(',');
                sb.Append("patrolPlan").Append(',');
                sb.Append("patrolX").Append(',');
                sb.Append("patrolY").Append("\r\n");
                int           totalCount = 0;
                PathManager[] pathes     = script.GetComponentsInChildren <PathManager>();
                for (int i = 0; i < pathes.Length; ++i)
                {
                    sb.Append('#').Append(pathes[i].name).Append(',').Append(pathes[i].transform.position.y).Append("\r\n");
                    Vector3[] points = pathes[i].GetPathPoints();
                    for (int j = 0; j < points.Length; ++j)
                    {
                        totalCount++;
                        sb.Append(totalCount).Append(',');
                        sb.Append(i).Append(',');
                        sb.Append(points[j].x).Append(',');
                        sb.Append(points[j].z).Append("\r\n");
                    }
                }

                //要写的数据源
                SaveTextFile(filepath, sb.ToString());
            }

            if (!placing && GUILayout.Button("Import", GUILayout.Height(40)))
            {
                string filepath = EditorUtility.OpenFilePanel("Load pathes", Application.dataPath, "csv");
                if (filepath != null)
                {
                    StreamReader reader = new StreamReader(filepath, new UTF8Encoding(false));
                    if (reader != null)
                    {
                        string content = reader.ReadToEnd();
                        int    readPos = 0;
                        //skip the first line
                        string        skipLine   = EditorUtils.readLine(content, ref readPos);
                        List <string> kv         = null;
                        PathManager   manager    = null;
                        int           pointCount = 0;
                        float         currentY   = 0f;
                        while (readPos < content.Length)
                        {
                            string lineNew = EditorUtils.readLine(content, ref readPos);
                            //new path
                            if (lineNew[0] == '#')
                            {
                                int noUse = 0;
                                kv = GameAssist.readCsvLine(lineNew, ref noUse);
                                string readpathName = kv[0].Substring(1);
                                float.TryParse(kv[1], out currentY);
                                path = new GameObject(readpathName);
                                //reset position and parent container gameobject to this manager gameobject
                                path.transform.position = script.gameObject.transform.position;
                                path.transform.parent   = script.gameObject.transform;
                                StartPath();
                                wpList.Clear();
                            }
                            else
                            {
                                int a = 0;
                                kv = GameAssist.readCsvLine(lineNew, ref a);
                                float x = 0f;
                                float.TryParse(kv[2], out x);
                                float z = 0f;
                                float.TryParse(kv[3], out z);
                                PlaceWaypoint(new Vector3(x, currentY, z));
                            }
                        }
                    }
                }
            }

            if (!placing && GUILayout.Button("CreateColliders", GUILayout.Height(40)))
            {
                UnityEngine.Object prefab = AssetDatabase.LoadAssetAtPath("Assets/PathEditor/Cube.prefab", typeof(UnityEngine.Object));
                GameObject         parent = GameObject.Find("WalkColliders");
                Texture2D          tex    = (Texture2D)AssetDatabase.LoadAssetAtPath("Assets/CameraPath3/Icons/options.png", typeof(Texture2D));
                if (parent == null)
                {
                    parent = new GameObject("WalkColliders");
                }
                PathManager[] pathes = script.GetComponentsInChildren <PathManager>();
                for (int i = 0; i < pathes.Length; ++i)
                {
                    Vector3[] points    = pathes[i].GetPathPoints();
                    int       pointC    = points.Length;
                    int       loopcount = pointC;
                    //不是关闭类型的,不生成最后一个点到初始点的连线
                    if (pathes[i].closure == false)
                    {
                        loopcount = pointC - 1;
                    }
                    for (int j = 0; j < loopcount; ++j)
                    {
                        Vector3    nextPos   = points[(j + 1) % pointC];
                        Vector3    middlePos = (points[j] + nextPos) * 0.5f;
                        GameObject collider  = GameObject.Instantiate(prefab, middlePos, Quaternion.identity) as GameObject;
                        Vector3    lookPos   = nextPos;
                        lookPos.y = middlePos.y;
                        collider.transform.LookAt(lookPos);
                        collider.transform.parent = parent.transform;
                        Vector3 setScale = collider.transform.localScale;
                        setScale.z = (nextPos - points[j]).magnitude;
                        collider.transform.localScale = setScale;
                    }
                }
            }
            GUI.backgroundColor = Color.yellow;

            //finish path button
            if (placing && GUILayout.Button("Finish Editing", GUILayout.Height(40)))
            {
                if (wpList.Count < 2)
                {
                    Debug.LogWarning("Not enough waypoints placed. Cancelling.");
                    //if we have created a path already, destroy it again
                    if (path)
                    {
                        DestroyImmediate(path);
                    }
                }

                //toggle placement off
                placing = false;
                //clear list with temporary waypoint references,
                //we only needed this for getting the waypoint count
                wpList.Clear();
                //reset path name input field
                pathName = "";
                //make the new path the active selection
                Selection.activeGameObject = path;
            }

            GUI.backgroundColor = Color.white;
            EditorGUILayout.Space();
            //draw instructions
            GUILayout.TextArea("Hint:\nPress 'Start Path' to begin a new path, then press 'p' "
                               + "on your keyboard to place waypoints in the SceneView. In 3D Mode "
                               + "you have to place waypoints onto objects with colliders."
                               + "\n\nPress 'Finish Editing' to end your path.");
        }
Пример #10
0
        //if this path is selected, display small info boxes above all waypoint positions
        //also display handles for the waypoints
        void OnSceneGUI()
        {
            //again, get waypoint array
            var waypoints = GetWaypointArray();

            //do not execute further code if we have no waypoints defined
            //(just to make sure, practically this can not occur)
            if (waypoints.Length == 0)
            {
                return;
            }
            Vector3 wpPos = Vector3.zero;
            float   size  = 1f;

            //loop through waypoint array
            for (int i = 0; i < waypoints.Length; i++)
            {
                if (!waypoints[i])
                {
                    continue;
                }
                wpPos = waypoints[i].position;

                size = HandleUtility.GetHandleSize(wpPos) * 0.4f;

                //do not draw waypoint header if too far away
                if (size < 3f)
                {
                    //begin 2D GUI block
                    Handles.BeginGUI();
                    //translate waypoint vector3 position in world space into a position on the screen
                    var guiPoint = HandleUtility.WorldToGUIPoint(wpPos);
                    //create rectangle with that positions and do some offset
                    var rect = new Rect(guiPoint.x - 50.0f, guiPoint.y - 40, 100, 20);
                    //draw box at position with current waypoint name
                    GUI.Box(rect, waypoints[i].name);
                    Handles.EndGUI(); //end GUI block
                }

                //draw handles per waypoint, clamp size
                Handles.color = m_Color2.colorValue;
                size          = Mathf.Clamp(size, 0, 1.2f);

                Handles.FreeMoveHandle(wpPos, Quaternion.identity, size, Vector3.zero, (controlID, position, rotation, hSize, eventType) =>
                {
                    Handles.SphereHandleCap(controlID, position, rotation, hSize, eventType);
                    if (controlID == GUIUtility.hotControl && GUIUtility.hotControl != 0)
                    {
                        activeNode = i;
                    }
                });
                Handles.RadiusHandle(waypoints[i].rotation, wpPos, size / 2);
            }

            if (activeNode > -1)
            {
                wpPos = waypoints[activeNode].position;
                Quaternion wpRot = waypoints[activeNode].rotation;
                switch (Tools.current)
                {
                case Tool.Move:
                    if (Tools.pivotRotation == PivotRotation.Global)
                    {
                        wpRot = Quaternion.identity;
                    }

                    Vector3 newPos = Handles.PositionHandle(wpPos, wpRot);
                    if (wpPos != newPos)
                    {
                        Undo.RecordObject(waypoints[activeNode], "Move Handle");
                        waypoints[activeNode].position = newPos;
                    }
                    break;

                case Tool.Rotate:
                    Quaternion newRot = Handles.RotationHandle(wpRot, wpPos);

                    if (wpRot != newRot)
                    {
                        Undo.RecordObject(waypoints[activeNode], "Rotate Handle");
                        waypoints[activeNode].rotation = newRot;
                    }
                    break;
                }
            }

            //waypoint direction handles drawing
            if (!m_Check2.boolValue)
            {
                return;
            }
            Vector3[] pathPoints = new Vector3[waypoints.Length];
            for (int i = 0; i < pathPoints.Length; i++)
            {
                pathPoints[i] = waypoints[i].position;
            }

            //create list of path segments (list of Vector3 list)
            List <List <Vector3> > segments = new List <List <Vector3> >();
            int   curIndex = 0;
            float lerpVal  = 0f;

            //differ between linear and curved display
            switch (m_Check1.boolValue)
            {
            case true:
                //convert waypoints to curved path points
                pathPoints = WaypointManager.GetCurved(pathPoints);
                //calculate approximate path point amount per segment
                int detail = Mathf.FloorToInt((pathPoints.Length - 1f) / (waypoints.Length - 1f));

                for (int i = 0; i < waypoints.Length - 1; i++)
                {
                    float dist = Mathf.Infinity;
                    //loop over path points to find single segments
                    segments.Add(new List <Vector3>());

                    //we are not checking for absolute path points on standard paths, because
                    //path points could also be located before or after waypoint positions.
                    //instead a minimum distance is searched which marks the nearest path point
                    for (int j = curIndex; j < pathPoints.Length; j++)
                    {
                        //add path point to current segment
                        segments[i].Add(pathPoints[j]);

                        //start looking for distance after a certain amount of path points of this segment
                        if (j >= (i + 1) * detail)
                        {
                            //calculate distance of current path point to waypoint
                            float pointDist = Vector3.Distance(waypoints[i].position, pathPoints[j]);
                            //we are getting closer to the waypoint
                            if (pointDist < dist)
                            {
                                dist = pointDist;
                            }
                            else
                            {
                                //current path point is more far away than the last one
                                //the segment ends here, continue with new segment
                                curIndex = j + 1;
                                break;
                            }
                        }
                    }
                }
                break;

            case false:
                //detail for arrows between waypoints
                int lerpMax = 16;
                //loop over waypoints to add intermediary points
                for (int i = 0; i < waypoints.Length - 1; i++)
                {
                    segments.Add(new List <Vector3>());
                    for (int j = 0; j < lerpMax; j++)
                    {
                        //linear lerp between waypoints to get additional points for drawing arrows at
                        segments[i].Add(Vector3.Lerp(pathPoints[i], pathPoints[i + 1], j / (float)lerpMax));
                    }
                }
                break;
            }

            //loop over segments
            for (int i = 0; i < segments.Count; i++)
            {
                //loop over single positions on the segment
                for (int j = 0; j < segments[i].Count; j++)
                {
                    //get current lerp value for interpolating rotation
                    //draw arrow handle on current position with interpolated rotation
                    size    = Mathf.Clamp(HandleUtility.GetHandleSize(segments[i][j]) * 0.4f, 0, 1.2f);
                    lerpVal = j / (float)segments[i].Count;
                    Handles.ArrowHandleCap(0, segments[i][j], Quaternion.Lerp(waypoints[i].rotation, waypoints[i + 1].rotation, lerpVal), size, EventType.Repaint);
                }
            }
        }
Пример #11
0
        //called whenever the inspector gui gets rendered
        public override void OnInspectorGUI()
        {
            //this pulls the relative variables from unity runtime and stores them in the object
            m_Object.Update();

            //get waypoint array
            var waypoints = GetWaypointArray();

            //don't draw inspector fields if the path contains less than 2 points
            //(a path with less than 2 points really isn't a path)
            if (m_WaypointsCount.intValue < 2)
            {
                //button to create path manually
                if (GUILayout.Button("Create Path from Children"))
                {
                    Undo.RecordObjects(waypoints, "Create Path");
                    (m_Object.targetObject as PathManager).Create();
                    SceneView.RepaintAll();
                }

                return;
            }

            //create new checkboxes for path gizmo property
            m_Check1.boolValue = EditorGUILayout.Toggle("Draw Smooth Lines", m_Check1.boolValue);
            m_Check2.boolValue = EditorGUILayout.Toggle("Draw Direction", m_Check2.boolValue);

            //create new property fields for editing waypoint gizmo colors
            EditorGUILayout.PropertyField(m_Color1);
            EditorGUILayout.PropertyField(m_Color2);

            //calculate path length of all waypoints
            Vector3[] wpPositions = new Vector3[waypoints.Length];
            for (int i = 0; i < waypoints.Length; i++)
            {
                wpPositions[i] = waypoints[i].position;
            }

            float pathLength = WaypointManager.GetPathLength(wpPositions);

            //path length label, show calculated path length
            GUILayout.Label("Path Length: " + pathLength);

            //button for switching over to the WaypointManager for further path editing
            if (GUILayout.Button("Continue Editing"))
            {
                Selection.activeGameObject = (GameObject.FindObjectOfType(typeof(WaypointManager)) as WaypointManager).gameObject;
                WaypointEditor.ContinuePath(m_Object.targetObject as PathManager);
            }

            //more path modifiers
            DrawPathOptions();
            EditorGUILayout.Space();

            //waypoint index header
            GUILayout.Label("Waypoints: ", EditorStyles.boldLabel);

            //loop through the waypoint array
            for (int i = 0; i < waypoints.Length; i++)
            {
                GUILayout.BeginHorizontal();
                //indicate each array slot with index number in front of it
                GUILayout.Label(i + ".", GUILayout.Width(20));
                //create an object field for every waypoint
                EditorGUILayout.ObjectField(waypoints[i], typeof(Transform), true);

                //display an "Add Waypoint" button for every array row except the last one
                if (i < waypoints.Length && GUILayout.Button("+", GUILayout.Width(30f)))
                {
                    AddWaypointAtIndex(i);
                    break;
                }

                //display an "Remove Waypoint" button for every array row except the first and last one
                if (i > 0 && i < waypoints.Length - 1 && GUILayout.Button("-", GUILayout.Width(30f)))
                {
                    RemoveWaypointAtIndex(i);
                    break;
                }

                GUILayout.EndHorizontal();
            }

            //we push our modified variables back to our serialized object
            m_Object.ApplyModifiedProperties();
        }
        public override void OnInspectorGUI()
        {
            editPlane = target as GridPlane;
            //show default variables of manager
            DrawDefaultInspector();
            //get manager reference
            EditorGUIUtility.LookLikeControls();
            EditorGUILayout.Space();

            EditorGUILayout.BeginHorizontal();

            if (GUILayout.Button("One Point", GUILayout.Height(40)))
            {
                editPlane.SetBrushType(0);
                SceneView.currentDrawingSceneView.Focus();
            }
            if (GUILayout.Button("three Point", GUILayout.Height(40)))
            {
                editPlane.SetBrushType(1);
                SceneView.currentDrawingSceneView.Focus();
            }
            EditorGUILayout.EndHorizontal();
            EditorGUILayout.Space();

            if (GUILayout.Button("Generate", GUILayout.Height(40)))
            {
                editPlane.GenerateMesh();
            }
            //draw path creation button
            GUI.backgroundColor = Color.yellow;
            if (!placing && GUILayout.Button("Brush", GUILayout.Height(40)))
            {
                //we passed all prior checks, toggle waypoint placement
                placing = true;
                //focus sceneview for placement
                SceneView.currentDrawingSceneView.Focus();
            }

            if (placing && GUILayout.Button("Erase", GUILayout.Height(40)))
            {
                //we passed all prior checks, toggle waypoint placement
                placing = false;
                //focus sceneview for placement
                SceneView.currentDrawingSceneView.Focus();
            }
            GUI.backgroundColor = Color.white;
            if (GUILayout.Button("ExportCollision", GUILayout.Height(40)))
            {
                string filepath = EditorUtility.SaveFilePanelInProject("Save Map", "CollisionInfo", "bytes", "OKOK");
                LogManager.Log(filepath);
                FileStream   fs = new FileStream(filepath, FileMode.Create, FileAccess.Write);
                BinaryWriter bw = new BinaryWriter(fs);
                //	string fileName = filepath;//文件名字
                Vector3 offset = editPlane.transform.position;
                //write offset x
                FP offsetX = (FP)(offset.x);
                bw.Write(offsetX.RawValue);
                //write offset z
                FP offsetZ = (FP)offset.z;
                bw.Write(offsetZ.RawValue);
                //write width
                bw.Write(editPlane.width);
                //write height
                bw.Write(editPlane.height);
                //write size
                bw.Write(editPlane.gridsize);
                int []   gridInfo  = editPlane.GetGridInfo();
                int      len       = gridInfo.Length;
                BitArray bitarray  = new BitArray(len);
                int      byteCount = (len + 7) / 8;
                byte[]   data      = new byte[byteCount];
                for (int i = 0; i < editPlane.height; ++i)
                {
                    for (int j = 0; j < editPlane.width; ++j)
                    {
                        int index = i * editPlane.width + j;
                        if (gridInfo[i * editPlane.width + j] == 0)
                        {
                            bitarray.Set(index, false);
                        }
                        else
                        {
                            bitarray.Set(index, true);
                        }
                    }
                }
                //要写的数据源
                bitarray.CopyTo(data, 0);
                for (int i = 0; i < data.Length; ++i)
                {
                    bw.Write(data[i]);
                }
                bw.Flush();
                bw.Close();
                fs.Close();
            }
            if (GUILayout.Button("Export", GUILayout.Height(40)))
            {
                string filepath = EditorUtility.SaveFilePanelInProject("Save Map", "GridInfo", "txt", "OKOK");
                LogManager.Log(filepath);
                string fileName = filepath;                //文件名字

                StringBuilder sb = new StringBuilder();
                //offset
                sb.Append("type octile").Append("\r\n");
                Vector3 offset = editPlane.transform.position;
                FP      x      = (FP)offset.x;
                sb.Append("X ").Append(x.RawValue).Append("\r\n");
                FP z = (FP)offset.z;
                sb.Append("Z ").Append(z.RawValue).Append("\r\n");
                sb.Append("width ").Append(editPlane.width).Append("\r\n");
                sb.Append("height ").Append(editPlane.height).Append("\r\n");
                FP size = (FP)editPlane.gridsize;
                sb.Append("size ").Append(size.RawValue).Append("\r\n");
                sb.Append("map").Append("\r\n");
                int [] gridInfo = editPlane.GetGridInfo();
                //	int len = gridInfo.Length;
                for (int i = 0; i < editPlane.height; ++i)
                {
                    for (int j = 0; j < editPlane.width; ++j)
                    {
                        if (gridInfo[i * editPlane.width + j] == 0)
                        {
                            sb.Append('@');
                        }
                        else
                        {
                            sb.Append('.');
                        }
                    }
                    sb.Append("\r\n");
                }
                //要写的数据源
                EditorUtils.SaveTextFile(filepath, sb.ToString());
            }

            if (GUILayout.Button("Import", GUILayout.Height(40)))
            {
                string filepath = EditorUtility.OpenFilePanel("Load map", Application.dataPath, "txt");
                if (filepath != null)
                {
                    StreamReader reader = new StreamReader(filepath, new UTF8Encoding(false));
                    if (reader != null)
                    {
                        MapGridT      myGrid  = new MapGridT();
                        string        content = reader.ReadToEnd();
                        int           readPos = 0;
                        List <string> kv      = null;
                        while (readPos < content.Length)
                        {
                            string line = EditorUtils.readLine(content, ref readPos);
                            kv = EditorUtils.splitLine(line);
                            if (kv.Count == 0)
                            {
                                continue;
                            }
                            if (kv[0] == "map")
                            {
                                break;
                            }
                            if (kv[0] == "X")
                            {
                                if (kv.Count > 1)
                                {
                                    myGrid.X = float.Parse(kv[1]);
                                }
                            }
                            if (kv[0] == "Z")
                            {
                                if (kv.Count > 1)
                                {
                                    myGrid.Z = float.Parse(kv[1]);
                                }
                            }
                            if (kv[0] == "width")
                            {
                                if (kv.Count > 1)
                                {
                                    myGrid.Width = int.Parse(kv[1]);
                                }
                            }
                            if (kv[0] == "height")
                            {
                                if (kv.Count > 1)
                                {
                                    myGrid.Height = int.Parse(kv[1]);
                                }
                            }
                            if (kv[0] == "size")
                            {
                                if (kv.Count > 1)
                                {
                                    myGrid.GridSize = float.Parse(kv[1]);
                                }
                            }
                        }
                        if (myGrid.Width == 0 || myGrid.Height == 0)
                        {
                            StringBuilder log = new StringBuilder();
                            log.Append("invlid width").Append(myGrid.Width).Append("or height").Append(myGrid.Height);
                            LogManager.Log(log.ToString());
                            return;
                        }
                        editPlane.transform.position = new Vector3((float)myGrid.X, 0f, (float)myGrid.Z);
                        editPlane.width    = myGrid.Width;
                        editPlane.height   = myGrid.Height;
                        editPlane.gridsize = (float)myGrid.GridSize;
                        editPlane.GenerateMesh();
                        int[] gridData = editPlane.GetGridInfo();

                        for (int i = 0; i < myGrid.Height; i++)
                        {
                            string line = EditorUtils.readLine(content, ref readPos);
                            if (line.Length < myGrid.Width + 1)
                            {
                                StringBuilder log = new StringBuilder();
                                log.Append("line").Append(i).Append("length is less than").Append(myGrid.Width);
                                LogManager.Log(log.ToString());
                                return;
                            }
                            for (int w = 0; w < myGrid.Width; w++)
                            {
                                if (line[w] == '.')
                                {
                                    gridData[i * myGrid.Width + w] = 1;
                                }
                                else
                                {
                                    gridData[i * myGrid.Width + w] = 0;
                                }
                            }
                        }
                    }
                }
            }
            if (GUILayout.Button("ImportCollision", GUILayout.Height(40)))
            {
                string filepath = EditorUtility.OpenFilePanel("Load collision", Application.dataPath, "bytes");
                if (filepath != null)
                {
                    FileStream fs = new FileStream(filepath, FileMode.Open, FileAccess.Read);
                    if (fs != null)
                    {
                        BinaryReader br     = new BinaryReader(fs);
                        MapGridT     myGrid = new MapGridT();
                        //read offset x
                        myGrid.X = br.ReadSingle();
                        //read offset z
                        myGrid.Z = br.ReadSingle();
                        //read width
                        myGrid.Width = br.ReadInt32();
                        //read height
                        myGrid.Height = br.ReadInt32();
                        //read size
                        myGrid.GridSize = br.ReadSingle();
                        if (myGrid.Width == 0 || myGrid.Height == 0)
                        {
                            StringBuilder log = new StringBuilder();
                            log.Append("invlid width").Append(myGrid.Width).Append("or height").Append(myGrid.Height);
                            LogManager.Log(log.ToString());
                            return;
                        }
                        editPlane.transform.position = new Vector3((float)myGrid.X, 0f, (float)myGrid.Z);
                        editPlane.width    = myGrid.Width;
                        editPlane.height   = myGrid.Height;
                        editPlane.gridsize = (float)myGrid.GridSize;
                        editPlane.GenerateMesh();
                        int []   gridInfo  = editPlane.GetGridInfo();
                        int      len       = gridInfo.Length;
                        int      byteCount = (len + 7) / 8;
                        byte[]   data      = br.ReadBytes(byteCount);
                        BitArray bitarray  = new BitArray(data);
                        for (int i = 0; i < myGrid.Height; i++)
                        {
                            for (int w = 0; w < myGrid.Width; w++)
                            {
                                gridInfo[i * myGrid.Width + w] = bitarray.Get(i * myGrid.Width + w) == true ? 1:0;
                            }
                        }
                    }
                }
            }


            if (GUILayout.Button("CreateFromPath", GUILayout.Height(40)))
            {
                int       walkNum = 0, nonWalkNum = 0;
                Polygon[] walkables = new Polygon[16];
                for (int a = 0; a < walkables.Length; ++a)
                {
                    walkables[a] = new Polygon();
                }
                Polygon[] nonWalkables = new Polygon[32];
                for (int b = 0; b < nonWalkables.Length; ++b)
                {
                    nonWalkables[b] = new Polygon();
                }
                //get all pathes
                WaypointManager manager = GameObject.FindObjectOfType <WaypointManager>();
                if (manager)
                {
                    Vector3       offset = editPlane.transform.position;
                    PathManager[] pathes = manager.GetComponentsInChildren <PathManager>();
                    foreach (PathManager path in pathes)
                    {
                        if (path.walkable)
                        {
                            for (int i = 0; i < path.waypoints.Length; ++i)
                            {
                                Vector3 pos = path.waypoints[i].position;
                                walkables[walkNum].m_Points.Add(new Vector2(pos.x - offset.x, pos.z - offset.z));
                            }
                            Vector3 firstPos = path.waypoints[0].position;
                            walkables[walkNum].m_Points.Add(new Vector2(firstPos.x - offset.x, firstPos.z - offset.z));
                            walkNum++;
                        }
                        else
                        {
                            for (int i = 0; i < path.waypoints.Length; ++i)
                            {
                                Vector3 pos = path.waypoints[i].position;
                                nonWalkables[nonWalkNum].m_Points.Add(new Vector2(pos.x - offset.x, pos.z - offset.z));
                            }
                            Vector3 firstPos = path.waypoints[0].position;
                            nonWalkables[nonWalkNum].m_Points.Add(new Vector2(firstPos.x - offset.x, firstPos.z - offset.z));
                            nonWalkNum++;
                        }
                    }
                }
                int[] gridData = editPlane.GetGridInfo();

                for (int i = 0; i < editPlane.height; i++)
                {
                    for (int w = 0; w < editPlane.width; w++)
                    {
                        bool    processed = false;
                        Vector2 pos       = new Vector2(w * editPlane.gridsize + editPlane.gridsize * 0.5f, i * editPlane.gridsize + editPlane.gridsize * 0.5f);
                        for (int nonWalkIndex = 0; nonWalkIndex < nonWalkNum; ++nonWalkIndex)
                        {
                            if (PtInPolygon(pos, nonWalkables[nonWalkIndex].m_Points))
                            {
                                processed = true;
                                gridData[i * editPlane.width + w] = 0;
                            }
                        }
                        if (!processed)
                        {
                            for (int walkIndex = 0; walkIndex < walkNum; ++walkIndex)
                            {
                                if (PtInPolygon(pos, walkables[walkIndex].m_Points))
                                {
                                    processed = true;
                                    gridData[i * editPlane.width + w] = 1;
                                }
                            }
                        }
                    }
                }
            }
            EditorGUILayout.Space();
            //draw instructions
            GUILayout.TextArea("Hint:\nPress 'Brush' to begin a new path, then press 'p' "
                               + "on your keyboard to place green points in the SceneView "
                               + "\n\nPress 'Erase' to do the opposite operation.");
        }