Skip to content

Instantly share code, notes, and snippets.

@MattRix
Created March 1, 2021 15:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save MattRix/bfeb6f23b5cd6edfe93cee66f163993f to your computer and use it in GitHub Desktop.
Save MattRix/bfeb6f23b5cd6edfe93cee66f163993f to your computer and use it in GitHub Desktop.
Example of using EditorZoomer.cs
using System.IO;
using System.Collections;
using UnityEngine;
using UnityEditor;
using UnityEditor.Callbacks;
using System.Collections.Generic;
using System;
using NS = System.NonSerializedAttribute;
using System.Linq;
public class VizWindow : EditorWindow
{
[NS] bool hasInited = false;
List<VizNode> nodes = new List<VizNode>();
Vector2 scrollPos = Vector2.zero;
public Demand selectedDemand = null;
[NS] float ratioY = 1f;
[NS] float wireLength = 125;
EditorZoomer zoomer = new EditorZoomer();
public void Update()
{
if (!hasInited) Init();
if (!Application.isPlaying) hasInited = false;
DoMovement();
this.Repaint(); //always redraw
}
private void DoMovement()
{
if (nodes.Count == 0) return;
ratioY = Mathf.Clamp(ratioY, 0.5f, 3f);
wireLength = Mathf.Clamp(wireLength, 50f, 1000f);
Vector2 midPoint = Vector2.zero;
foreach (var nodeA in nodes)
{
midPoint += nodeA.pos;
foreach (var nodeB in nodes)
{
if (nodeA != nodeB)
{
bool isConnected = nodeA.connectedNodes.Contains(nodeB) || nodeB.connectedNodes.Contains(nodeA);
var delta = nodeA.pos - nodeB.pos;
delta.y /= ratioY;
delta.x *= ratioY;
float dist = delta.magnitude + 0.1f; //add 0.1 to prevent divide by zero
float force = 100000f / delta.sqrMagnitude * 100f;
if (isConnected)
{
float distFromWire = (delta.magnitude - wireLength) / wireLength;
force = -1000f * distFromWire;
}
force = Mathf.Clamp(force, -1000f, 1000f);
var dir = delta.normalized;
//dir.y *= 0.5f;
nodeA.velocity += 0.01f * force * new Vector2(dir.x, dir.y);
}
}
nodeA.pos += nodeA.velocity;
nodeA.velocity *= 0.8f;
}
//move nodes back to the midpoint being at 0,0,0;
midPoint = midPoint / nodes.Count;
midPoint += zoomer.GetContentOffset();
foreach (var nodeA in nodes)
{
nodeA.pos -= midPoint;
}
}
public void Init()
{
hasInited = true;
nodes.Clear();
if (!Application.isPlaying) return;
}
public void OnGUI()
{
if (!hasInited || !Application.isPlaying)
{
GUILayout.Label("Only works while game is running...");
return;
}
float leftPanelWidth = 100f;
EditorGUILayout.BeginHorizontal();
//GUI.backgroundColor = Color.blue;
EditorGUILayout.BeginVertical(GUILayout.Width(leftPanelWidth));
GUILayout.Label("Demands:");
var demands = SimCore.instance.graph.spots.SelectMany(s=>s.demands).ToList();
foreach(var demand in demands)
{
if(GUILayout.Button(new GUIContent(demand.spot.name + ": " + demand.name)))
{
SelectDemand(demand);
}
}
EditorGUILayout.EndVertical();
//GUI.backgroundColor = Color.white;
//get the size of the rect
zoomer.Begin();
BeginWindows();
for(int n = 0; n<nodes.Count; n++)
{
nodes[n].Draw(n);
}
//draw wires
foreach (var nodeA in nodes)
{
foreach (var nodeB in nodeA.connectedNodes)
{
Handles.DrawLine(nodeA.pos, nodeB.pos);
//draw the arrow
var size = 5;
var center = (nodeA.pos + nodeB.pos)/ 2f;
var forward = (nodeB.pos - nodeA.pos).normalized;
var ortho = new Vector2(-forward.y, forward.x);
Handles.DrawLine(center + forward*size, center - forward*size + ortho*size);
Handles.DrawLine(center + forward*size, center - forward*size - ortho*size);
Handles.DrawLine(center - forward*size + ortho*size, center - forward*size - ortho*size);
}
}
EndWindows();
zoomer.End();
//EditorGUILayout.EndScrollView();
EditorGUILayout.EndHorizontal();
}
private void SelectDemand(Demand demand)
{
selectedDemand = demand;
nodes.Clear();
VisualizeActs();
}
private void VisualizeActs()
{
SimCore.instance.agentManager.Update();
var demandsToAdd = new List<Demand>();
demandsToAdd.Add(selectedDemand);
while (demandsToAdd.Count > 0)
{
var demand = demandsToAdd.Pop();
for (int a = 0; a < demand.acts.Count; a++)
{
var act = demand.acts[a];
var node = new VizNode(demand.name, act.GetDesc());
nodes.Add(node);
node.updater = (n) =>
{
GUI.backgroundColor = act.hasStarted ? (act.isComplete ? new Color(0.0f, 0.8f, 0f) : new Color(1f, 1f, 0f)) : new Color(0.8f, 0f, 0f);
n.title = act.hasStarted ? (act.isComplete ? "COMPLETE" : "IN PROGRESS") : "UNSTARTED";
n.message = act.GetDesc();
};
node.source = act;
if (a == demand.acts.Count - 1)
{
if (demand.parentDemand != null)
{
//last act of previous demand
node.sourceParent = demand.parentDemand.acts[0];
}
}
else
{
//previous act
node.sourceParent = demand.acts[a + 1];
}
}
foreach (var childDemand in demand.childDemands)
{
demandsToAdd.Add(childDemand);
}
}
ConnectSourceParents();
}
private void ConnectSourceParents()
{
foreach (var nodeA in nodes)
{
foreach (var nodeB in nodes)
{
if (nodeA == nodeB) continue;
if (nodeA.sourceChildren.Contains(nodeB.source))
{
nodeB.Connect(nodeA);
}
if (nodeA.sourceParent == nodeB.source)
{
nodeA.Connect(nodeB);
}
}
}
}
[MenuItem("Worktown/Open Window")]
static void OpenWindow()
{
// Get existing open window or if none, make a new one:
VizWindow window = (VizWindow)EditorWindow.GetWindow(typeof(VizWindow));
window.position = new Rect(100, 100, 300, 500);
window.titleContent = new GUIContent("VizWindow");
window.Show();
}
}
public class VizNode
{
public Vector2 pos;
public float width = 120;
public float height = 120;
public string title;
public string message;
public List<VizNode> connectedNodes = new List<VizNode>();
public object source = null;
public object sourceParent = null;
public List<object> sourceChildren = new List<object>();
public Vector2 velocity = new Vector2(0, 0);
public Action<VizNode> updater = null;
public VizNode(string title, string message = "")
{
this.title = title;
this.message = message;
pos = new Vector2(200f, 200f) + RXRandom.Vector2Normalized() * 100f;
}
public Rect GetRect()
{
return new Rect(pos.x-width/2, pos.y-height/2, width, height);
}
public void Draw(int id)
{
updater?.Invoke(this);
var resultRect = GUI.Window(id, GetRect(), DrawGUI, title);
pos = resultRect.center;
}
private void DrawGUI(int id)
{
EditorStyles.label.wordWrap = true;
EditorGUILayout.LabelField(message);
//disable this soon
GUI.DragWindow(); //this MUST be at the end (for them to be draggable)
}
public void Connect(VizNode otherNode)
{
connectedNodes.Add(otherNode);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment