Created
May 15, 2016 08:03
-
-
Save DreadBoy/c407bb5afe5bf4f7bfc0f3e4e90ee25b to your computer and use it in GitHub Desktop.
Graph implementation in Unity
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UnityEngine; | |
using System.Collections; | |
using System.Collections.Generic; | |
using System; | |
[Serializable] | |
public class Graph : ScriptableObject | |
{ | |
[SerializeField] | |
public List<Node> nodes = new List<Node>(); | |
public void Reset() | |
{ | |
Debug.Log("Graph.Reset()"); | |
nodes.Clear(); | |
} | |
public Node AddNode() | |
{ | |
var node = Node.CreateInstance(); | |
nodes.Add(node); | |
return node; | |
} | |
public void RemoveNode(Node node) | |
{ | |
// Remove incoming connections to our node. | |
foreach (var n in nodes) | |
{ | |
if (n.connections.Contains(node)) | |
n.connections.Remove(node); | |
} | |
// Then remove the node itself. | |
nodes.Remove(node); | |
} | |
public void AddConnection(Node start, Node end, bool oneway = false) | |
{ | |
start.connections.Add(end); | |
if (!oneway) | |
end.connections.Add(start); | |
} | |
public void RemoveConnection(Node start, Node end) | |
{ | |
if (start.connections.Contains(end)) | |
start.connections.Remove(end); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UnityEngine; | |
using System.Collections; | |
using System.Collections.Generic; | |
using System; | |
[Serializable] | |
public class Node : ScriptableObject | |
{ | |
private string[] names = { "Interchange 285", "Exit 135A", "Interchange 18", "Interchange 12", "Tiptonville Ferry", "Interchange 72", "Babcock Crossing", "Gainesboro Ferry", "Interchange 179", "Connelly Ford", "Interchange 8A and 8B", "Roy Ford", "Stallard Ford", "Holders Ferry", "Exit 7", "Interchange 41", "Blakemans Ford", "Salem Ferry", "Fortsons Ferry", "Interchange 123", "Interchange 176", "Dead Timbers Ford", "Interchange 11", "Interchange 139", "Exit 71A", "Ellis Ford", "Interchange 81B", "Interchange Thirty-three", "Bowman Ford", "Interchange 3", "Stephen Chapel Ford", "Briggs Ford", "Exit 70", "Interchange 236A", "Meridean Ferry", "Willinghams Ferry", "Sanderson Ferry", "Cut-Off Ferry", "Interchange 348", "Interchange 165", "Interchange 36C", "Campbell Ford", "Interchange 53", "Interchange 24", "Interchange 10A", "Exit 24A", "Interchange 211", "Interchange 119", "Interchange 4B", "Young Ford" }; | |
public string Name = ""; | |
public List<Node> connections = new List<Node>(); | |
public Vector3 position = new Vector3(); | |
public void Init() | |
{ | |
Debug.Log("Node.ctor()"); | |
// Select random name for that node. | |
Name = names[UnityEngine.Random.Range(0, names.Length - 1)]; | |
} | |
public void Init(Vector3 position) | |
{ | |
Debug.Log("Node.ctor(Vector3)"); | |
Init(); | |
this.position = position; | |
} | |
public static Node CreateInstance() | |
{ | |
var node = ScriptableObject.CreateInstance<Node>(); | |
node.Init(); | |
return node; | |
} | |
public static Node CreateInstance(Vector3 position) | |
{ | |
var node = ScriptableObject.CreateInstance<Node>(); | |
node.Init(position); | |
return node; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UnityEngine; | |
using System.Collections; | |
public class Streets : MonoBehaviour | |
{ | |
public Graph graph = null; | |
void Awake() | |
{ | |
if(graph == null) | |
{ | |
graph = ScriptableObject.CreateInstance<Graph>(); | |
Debug.Log("Graph is null, creating new one"); | |
} | |
} | |
public void Reset() | |
{ | |
Debug.Log("Streets.Reset(), also calling Graph.Reset()"); | |
graph = ScriptableObject.CreateInstance<Graph>(); | |
graph.nodes.Add(Node.CreateInstance(new Vector3(1, 0, 0))); | |
graph.nodes.Add(Node.CreateInstance()); | |
graph.nodes.Add(Node.CreateInstance(new Vector3(0, 0, 1))); | |
graph.AddConnection(graph.nodes[0], graph.nodes[1]); | |
graph.AddConnection(graph.nodes[1], graph.nodes[2], true); | |
} | |
// Use this for initialization | |
void Start() | |
{ | |
} | |
// Update is called once per frame | |
void Update() | |
{ | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UnityEngine; | |
using System.Collections; | |
using UnityEditor; | |
[CustomEditor(typeof(Streets))] | |
public class StreetsInspector : Editor | |
{ | |
Streets streets; | |
Transform transform; | |
Graph graph; | |
Node selected = null; | |
bool addingConnection = false; | |
bool addingOneway = false; | |
public override void OnInspectorGUI() | |
{ | |
streets = target as Streets; | |
graph = streets.graph; | |
if (GUILayout.Button("Reset")) | |
{ | |
Undo.RecordObject(streets, "Reset streets"); | |
streets.Reset(); | |
EditorUtility.SetDirty(streets); | |
} | |
GUILayout.Space(20); | |
if (selected == null) | |
{ | |
if (GUILayout.Button("Add intersection")) | |
{ | |
Undo.RecordObject(graph, "Add intersection"); | |
graph.AddNode(); | |
EditorUtility.SetDirty(graph); | |
RefreshEditor(); | |
} | |
GUILayout.Label("Intersections:"); | |
foreach (var node in graph.nodes) | |
{ | |
GUILayout.BeginHorizontal(); | |
if (GUILayout.Button(node.Name, "Label")) | |
{ | |
selected = node; | |
RefreshEditor(); | |
} | |
if (GUILayout.Button("X")) | |
{ | |
Undo.RecordObject(graph, "Remove intersection"); | |
graph.RemoveNode(node); | |
EditorUtility.SetDirty(graph); | |
RefreshEditor(); | |
return; | |
} | |
GUILayout.EndHorizontal(); | |
EditorGUI.BeginChangeCheck(); | |
Vector3 pos = EditorGUILayout.Vector3Field("", node.position); | |
if (EditorGUI.EndChangeCheck()) | |
{ | |
Undo.RecordObject(node, "Change intersection position"); | |
node.position = pos; | |
EditorUtility.SetDirty(node); | |
} | |
} | |
} | |
else | |
{ | |
if (GUILayout.Button("Back")) | |
{ | |
selected = null; | |
RefreshEditor(); | |
return; | |
} | |
GUILayout.Box(selected.Name); | |
EditorGUI.BeginChangeCheck(); | |
Vector3 pos = EditorGUILayout.Vector3Field("", selected.position); | |
if (EditorGUI.EndChangeCheck()) | |
{ | |
Undo.RecordObject(selected, "Change intersection position"); | |
selected.position = pos; | |
EditorUtility.SetDirty(selected); | |
} | |
foreach (var connection in selected.connections) | |
{ | |
GUILayout.BeginHorizontal(); | |
if (GUILayout.Button(connection.Name, "Label")) | |
{ | |
selected = connection; | |
RefreshEditor(); | |
return; | |
} | |
else if (GUILayout.Button("X")) | |
{ | |
Undo.RecordObject(selected, "Remove connection"); | |
graph.RemoveConnection(selected, connection); | |
EditorUtility.SetDirty(selected); | |
RefreshEditor(); | |
return; | |
} | |
GUILayout.EndHorizontal(); | |
} | |
if (addingConnection) | |
{ | |
if (GUILayout.Button("Select intersection in scene")) | |
addingConnection = addingOneway = false; | |
} | |
else | |
{ | |
GUILayout.BeginHorizontal(); | |
if (GUILayout.Button("Add twoway connection")) | |
addingConnection = true; | |
if (GUILayout.Button("Add oneway connection")) | |
{ | |
addingConnection = true; | |
addingOneway = true; | |
} | |
GUILayout.EndHorizontal(); | |
} | |
} | |
} | |
void OnSceneGUI() | |
{ | |
streets = target as Streets; | |
transform = streets.transform; | |
graph = streets.graph; | |
// Removes default position handle of GameObject. | |
Tools.current = Tool.None; | |
foreach (var node in graph.nodes) | |
{ | |
ShowPoint(node); | |
foreach (var conn in node.connections) | |
{ | |
Handles.color = selected == node ? Color.blue : Color.gray; | |
var start = transform.TransformPoint(node.position); | |
var end = transform.TransformPoint(conn.position); | |
var middle = (start + end) / 2; | |
float size = HandleUtility.GetHandleSize(middle); | |
Handles.DrawLine(start, end); | |
Handles.ConeCap(0, middle, Quaternion.LookRotation(end - start), size * 0.3f); | |
} | |
} | |
} | |
private void ShowPoint(Node node) | |
{ | |
bool select = selected == node && selected != null; | |
var point = transform.TransformPoint(node.position); | |
float size = HandleUtility.GetHandleSize(point); | |
Handles.color = select ? Color.green : Color.white; | |
if (Handles.Button(point, Quaternion.identity, size * 0.15f, size * 0.15f, Handles.SphereCap)) | |
{ | |
if (addingConnection && selected != node) | |
{ | |
Undo.RecordObject(selected, "Add connection"); | |
graph.AddConnection(selected, node, addingOneway); | |
EditorUtility.SetDirty(selected); | |
addingConnection = false; | |
addingOneway = false; | |
RefreshEditor(); | |
} | |
else if (selected == node) | |
selected = null; | |
else | |
selected = node; | |
RefreshEditor(); | |
} | |
if (select) | |
{ | |
EditorGUI.BeginChangeCheck(); | |
var p0 = Handles.DoPositionHandle(point, Quaternion.identity); | |
if (EditorGUI.EndChangeCheck()) | |
{ | |
Undo.RecordObject(node, "Moved intersection"); | |
node.position = p0; | |
EditorUtility.SetDirty(node); | |
RefreshEditor(); | |
} | |
} | |
} | |
void RefreshEditor() | |
{ | |
Repaint(); | |
SceneView.RepaintAll(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment