Scriptable Object nanobrain editor
This commit is contained in:
parent
69c6b1e2b7
commit
5a9aa7161b
@ -48,6 +48,7 @@
|
||||
<Analyzer Include="/home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Tools/Unity.SourceGenerators/Unity.UIToolkit.SourceGenerator.dll" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Assets/NanoBrain/VisualEditor/Editor/NanoBrainEditor.cs" />
|
||||
<Compile Include="Assets/NanoBrain/Editor/NanoBrain_Editor.cs" />
|
||||
<Compile Include="Assets/NanoBrain/Editor/NeuroidWindow.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
@ -48,6 +48,7 @@
|
||||
<Analyzer Include="/home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Tools/Unity.SourceGenerators/Unity.UIToolkit.SourceGenerator.dll" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Assets/NanoBrain/VisualEditor/NanoBrainObj.cs" />
|
||||
<Compile Include="Assets/Scenes/Boids/Scripts/SwarmSpawner.cs" />
|
||||
<Compile Include="Assets/NanoBrain/NeuroidBehaviour.cs" />
|
||||
<Compile Include="Assets/NanoBrain/NanoBrain.cs" />
|
||||
@ -57,9 +58,14 @@
|
||||
<Compile Include="Assets/NanoBrain/Perception.cs" />
|
||||
<Compile Include="Assets/Scenes/Boids/Scripts/SwarmingNucleus.cs" />
|
||||
<Compile Include="Assets/Scenes/Boids/Scripts/Boid.cs" />
|
||||
<Compile Include="Assets/NanoBrain/VisualEditor/NucleusObject.cs" />
|
||||
<Compile Include="Assets/NanoBrain/Neuroid.cs" />
|
||||
<Compile Include="Assets/NanoBrain/VisualEditor/NeuroidObject.cs" />
|
||||
<Compile Include="Assets/NanoBrain/Nucleus.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="Assets/NanoBrain/VisualEditor/Resources/GraphStyles.uss" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="UnityEngine">
|
||||
<HintPath>/home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.dll</HintPath>
|
||||
|
||||
@ -13,6 +13,15 @@ public class NanoBrain_Editor : Editor {
|
||||
#region Start
|
||||
|
||||
private void OnEnable() {
|
||||
// NanoBrain brain = target as NanoBrain;
|
||||
// if (brain == null)
|
||||
// return;
|
||||
|
||||
// if (brain.rootNucleus == null) {
|
||||
// brain.rootNucleus = CreateInstance<NucleusObj>();
|
||||
// EditorUtility.SetDirty(brain.rootNucleus);
|
||||
// }
|
||||
|
||||
SelectNeuron();
|
||||
}
|
||||
|
||||
@ -44,7 +53,6 @@ public class NanoBrain_Editor : Editor {
|
||||
|
||||
DrawGraph();
|
||||
|
||||
//DrawDefaultInspector();
|
||||
EditorGUILayout.TextField("Name", currentNucleus.name);
|
||||
EditorGUILayout.Vector3Field("Output Value", currentNucleus.outputValue);
|
||||
if (currentNucleus.synapses.Count > 0) {
|
||||
@ -62,6 +70,7 @@ public class NanoBrain_Editor : Editor {
|
||||
}
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
DrawDefaultInspector();
|
||||
}
|
||||
|
||||
private void BuildLayers() {
|
||||
|
||||
@ -40,7 +40,7 @@ public class GraphEditorWindow : EditorWindow {
|
||||
return;
|
||||
NeuroidLayer currentLayer = new() { ix = layerIx };
|
||||
|
||||
foreach (Neuroid outputNeuroid in selectedNucleus.receivers) {
|
||||
foreach (Nucleus outputNeuroid in selectedNucleus.receivers) {
|
||||
if (outputNeuroid != null) {
|
||||
AddToLayer(currentLayer, outputNeuroid);
|
||||
Debug.Log($"layer {layerIx} nucleus {outputNeuroid.name}");
|
||||
|
||||
@ -2,6 +2,9 @@ using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public class NanoBrain : MonoBehaviour {
|
||||
|
||||
// public NucleusObj rootNucleus;
|
||||
|
||||
public List<Neuroid> neuroids = new();
|
||||
|
||||
public Neuroid AddNeuron(string name) {
|
||||
|
||||
@ -13,6 +13,14 @@ public class Neuroid : Nucleus {
|
||||
Debug.LogError("No neuroid network");
|
||||
}
|
||||
|
||||
public Neuroid(NanoBrainObj brain, string name) : base(name) {
|
||||
this.newBrain = brain;
|
||||
if (this.newBrain != null)
|
||||
this.newBrain.neuroids.Add(this);
|
||||
else
|
||||
Debug.LogError("No neuroid network");
|
||||
}
|
||||
|
||||
public void SetWeight(Neuroid input, float weight) {
|
||||
this.synapses[input] = weight;
|
||||
}
|
||||
|
||||
@ -5,11 +5,12 @@ public class Nucleus {
|
||||
public int stale = 0;
|
||||
|
||||
public NanoBrain brain { get; protected set; }
|
||||
public NanoBrainObj newBrain { get; protected set; }
|
||||
|
||||
public virtual string name { get; set; }
|
||||
|
||||
public readonly Dictionary<Nucleus, float> synapses = new();
|
||||
public HashSet<Neuroid> receivers = new();
|
||||
public HashSet<Nucleus> receivers = new();
|
||||
public virtual Vector3 outputValue { get; set; }
|
||||
|
||||
public int layerIx;
|
||||
@ -18,7 +19,7 @@ public class Nucleus {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public virtual void AddReceiver(Neuroid receiver) {
|
||||
public virtual void AddReceiver(Nucleus receiver) {
|
||||
//Debug.Log($"add receiver to {this} for {receiver} {receiver.GetHashCode()} {this.receivers.Count} {receiver.synapses.Count}");
|
||||
this.receivers.Add(receiver);
|
||||
receiver.synapses[this] = 1.0f; // new(this);
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 895037c7e323e03ada7f43d011f1390b
|
||||
guid: 62a58c801eda0c9eab7a49fb1d0840cb
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
@ -1,5 +1,6 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e5398245724c5668992c64c27db35040
|
||||
guid: e47ea55fc051fcdcb8ae6197d1105cc0
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
477
Assets/NanoBrain/VisualEditor/Editor/NanoBrainEditor.cs
Normal file
477
Assets/NanoBrain/VisualEditor/Editor/NanoBrainEditor.cs
Normal file
@ -0,0 +1,477 @@
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
|
||||
public class NucleusLayer {
|
||||
public int ix = 0;
|
||||
public List<Nucleus> neuroids = new();
|
||||
}
|
||||
|
||||
public class NanoBrainEditor : EditorWindow {
|
||||
public static NanoBrainObj brain;
|
||||
|
||||
public static VisualElement inspectorContainer;
|
||||
|
||||
[MenuItem("Window/NanoBrain Editor")]
|
||||
public static void ShowWindow() {
|
||||
GetWindow<NanoBrainEditor>("NanoBrain Editor");
|
||||
}
|
||||
|
||||
GraphBoardView board;
|
||||
|
||||
private void OnEnable() {
|
||||
if (brain == null) {
|
||||
brain = CreateInstance<NanoBrainObj>();
|
||||
EditorUtility.SetDirty(brain);
|
||||
}
|
||||
|
||||
VisualElement root = rootVisualElement;
|
||||
root.styleSheets.Add(Resources.Load<StyleSheet>("GraphStyles"));
|
||||
|
||||
root.Add(board);
|
||||
root.Add(inspectorContainer);
|
||||
|
||||
VisualElement main = new() {
|
||||
name = "main",
|
||||
style = {
|
||||
flexDirection = FlexDirection.Row,
|
||||
flexGrow = 1
|
||||
}
|
||||
};
|
||||
board = new GraphBoardView();
|
||||
board.style.flexGrow = 1;
|
||||
inspectorContainer = new VisualElement {
|
||||
name = "inspector",
|
||||
style = {
|
||||
width = 400
|
||||
}
|
||||
};
|
||||
|
||||
main.Add(board);
|
||||
main.Add(inspectorContainer);
|
||||
root.Add(main);
|
||||
|
||||
board.SetGraph(brain.rootNucleus);
|
||||
}
|
||||
}
|
||||
|
||||
public class GraphBoardView : VisualElement {
|
||||
Nucleus currentNucleus;
|
||||
private List<NeuroidLayer> layers = new();
|
||||
private Dictionary<Nucleus, Vector2Int> neuroidPositions = new();
|
||||
|
||||
Vector2 pan = Vector2.zero;
|
||||
//float zoom = 1f;
|
||||
bool draggingCanvas = false;
|
||||
Vector2 lastMouse;
|
||||
GraphNodeWrapper currentWrapper;
|
||||
|
||||
public GraphBoardView() {
|
||||
name = "content";
|
||||
style.flexGrow = 1;
|
||||
|
||||
IMGUIContainer imguiContainer = new(OnIMGUI);
|
||||
imguiContainer.style.position = Position.Absolute;
|
||||
imguiContainer.style.left = 0; imguiContainer.style.top = 0;
|
||||
imguiContainer.style.right = 0; imguiContainer.style.bottom = 0;
|
||||
imguiContainer.pickingMode = PickingMode.Position;
|
||||
imguiContainer.focusable = true;
|
||||
Add(imguiContainer);
|
||||
|
||||
//RegisterCallback<WheelEvent>(OnWheel);
|
||||
RegisterCallback<MouseDownEvent>(OnMouseDown);
|
||||
RegisterCallback<MouseMoveEvent>(OnMouseMove);
|
||||
RegisterCallback<MouseUpEvent>(OnMouseUp);
|
||||
}
|
||||
|
||||
public void SetGraph(Nucleus nucleus) {
|
||||
this.currentNucleus = nucleus;
|
||||
Rebuild();
|
||||
}
|
||||
|
||||
void Rebuild() {
|
||||
BuildLayers();
|
||||
|
||||
if (currentNucleus == null) {
|
||||
NanoBrainEditor.inspectorContainer.Clear();
|
||||
return;
|
||||
}
|
||||
|
||||
if (currentWrapper != null)
|
||||
Object.DestroyImmediate(currentWrapper);
|
||||
currentWrapper = ScriptableObject.CreateInstance<GraphNodeWrapper>().Init(currentNucleus, NanoBrainEditor.brain);
|
||||
DrawInspector();
|
||||
}
|
||||
|
||||
private void BuildLayers() {
|
||||
// A temporary list to track what's been added to layers
|
||||
this.layers = new();
|
||||
int layerIx = 0;
|
||||
|
||||
Nucleus selectedNucleus = this.currentNucleus;
|
||||
if (selectedNucleus == null)
|
||||
return;
|
||||
NeuroidLayer currentLayer = new() { ix = layerIx };
|
||||
|
||||
foreach (Nucleus outputNeuroid in selectedNucleus.receivers) {
|
||||
if (outputNeuroid != null) {
|
||||
AddToLayer(currentLayer, outputNeuroid);
|
||||
// Debug.Log($"layer {layerIx} nucleus {outputNeuroid.name}");
|
||||
}
|
||||
}
|
||||
if (currentLayer.neuroids.Count > 0) {
|
||||
this.layers.Add(currentLayer);
|
||||
layerIx++;
|
||||
currentLayer = new() { ix = layerIx };
|
||||
}
|
||||
|
||||
AddToLayer(currentLayer, selectedNucleus);
|
||||
this.layers.Add(currentLayer);
|
||||
// Debug.Log($"layer {layerIx} nucleus {selectedNucleus.name}");
|
||||
|
||||
layerIx++;
|
||||
currentLayer = new() { ix = layerIx };
|
||||
|
||||
foreach (Nucleus input in selectedNucleus.synapses.Keys) {
|
||||
AddToLayer(currentLayer, input);
|
||||
// Debug.Log($"layer {layerIx} nucleus {input.name}");
|
||||
}
|
||||
if (currentLayer.neuroids.Count > 0) {
|
||||
this.layers.Add(currentLayer);
|
||||
}
|
||||
}
|
||||
|
||||
private void AddToLayer(NeuroidLayer layer, Nucleus nucleus) {
|
||||
layer.neuroids.Add(nucleus);
|
||||
nucleus.layerIx = layer.ix;
|
||||
// Store its position
|
||||
Vector2Int neuroidPosition = new(layer.ix, layer.neuroids.Count - 1);
|
||||
neuroidPositions[nucleus] = neuroidPosition;
|
||||
|
||||
}
|
||||
|
||||
// basic pan/zoom handling
|
||||
// void OnWheel(WheelEvent e) {
|
||||
// if (e.ctrlKey) {
|
||||
// float delta = -e.delta.y * 0.001f;
|
||||
// zoom = Mathf.Clamp(zoom + delta, 0.25f, 2f);
|
||||
// content.transform.rotation = Quaternion.identity; // keep transform accessible
|
||||
// content.transform.scale = new Vector3(zoom, zoom, 1);
|
||||
// e.StopPropagation();
|
||||
// }
|
||||
// else {
|
||||
// pan += e.delta;
|
||||
// content.style.left = pan.x;
|
||||
// content.style.top = pan.y;
|
||||
// }
|
||||
// }
|
||||
|
||||
void OnMouseDown(MouseDownEvent e) {
|
||||
if (e.button == 2) { draggingCanvas = true; lastMouse = e.mousePosition; e.StopPropagation(); }
|
||||
}
|
||||
void OnMouseMove(MouseMoveEvent e) {
|
||||
if (draggingCanvas) {
|
||||
var delta = e.mousePosition - lastMouse;
|
||||
pan += delta;
|
||||
//content.style.left = pan.x;
|
||||
//content.style.top = pan.y;
|
||||
lastMouse = e.mousePosition;
|
||||
}
|
||||
}
|
||||
void OnMouseUp(MouseUpEvent e) { if (e.button == 2) draggingCanvas = false; }
|
||||
|
||||
void OnIMGUI() {
|
||||
if (currentNucleus == null)
|
||||
return;
|
||||
|
||||
Handles.BeginGUI();
|
||||
foreach (NeuroidLayer layer in layers)
|
||||
DrawLayer(layer);
|
||||
Handles.EndGUI();
|
||||
}
|
||||
|
||||
private void DrawLayer(NeuroidLayer layer) {
|
||||
int nodeCount = layer.neuroids.Count;
|
||||
float maxValue = 0;
|
||||
foreach (Nucleus nucleus in layer.neuroids) {
|
||||
if (nucleus is Neuroid neuroid) {
|
||||
float value = neuroid.outputValue.magnitude;
|
||||
if (value > maxValue)
|
||||
maxValue = value;
|
||||
}
|
||||
}
|
||||
float spacing = 400f / nodeCount;
|
||||
float margin = 10 + spacing / 2;
|
||||
foreach (Nucleus layerNucleus in layer.neuroids) {
|
||||
Vector2Int layerNeuroidPos = this.neuroidPositions[layerNucleus];
|
||||
Vector3 parentPos = new(100 + layerNeuroidPos.x * 100, margin + layerNeuroidPos.y * spacing, 0.1f);
|
||||
|
||||
//int i = 0;
|
||||
float inputSpacing = 400f / layerNucleus.synapses.Count;
|
||||
float inputMargin = 10 + inputSpacing / 2;
|
||||
int minStale = 10000;
|
||||
foreach ((Nucleus nucleus, float weight) in layerNucleus.synapses) {
|
||||
if (this.neuroidPositions.ContainsKey(nucleus)) {
|
||||
Vector2Int inputNeuroidPos = this.neuroidPositions[nucleus];
|
||||
if (inputNeuroidPos.x == layerNeuroidPos.x + 1) {
|
||||
Vector3 pos = new(100 + inputNeuroidPos.x * 100, inputMargin + inputNeuroidPos.y * inputSpacing, 0.0f);
|
||||
|
||||
float brightness = weight / 10.0f;
|
||||
Handles.color = new Color(brightness, brightness, brightness);
|
||||
Handles.DrawLine(parentPos, pos);
|
||||
}
|
||||
}
|
||||
if (nucleus is Neuroid neuroid && neuroid.stale < minStale)
|
||||
minStale = neuroid.stale;
|
||||
}
|
||||
|
||||
if (layerNucleus.synapses.Count > 0 && minStale > 2 && layerNucleus.stale < 3)
|
||||
Debug.LogWarning($"Strange {minStale} is big duing update");
|
||||
|
||||
|
||||
float size = 20;
|
||||
if (layerNucleus.isSleeping)
|
||||
Handles.color = Color.darkRed;
|
||||
else {
|
||||
float brightness = layerNucleus.outputValue.magnitude / maxValue;
|
||||
Handles.color = new Color(brightness, brightness, brightness);
|
||||
}
|
||||
Handles.DrawSolidDisc(parentPos, Vector3.forward, size);
|
||||
Vector3 labelPos = parentPos - Vector3.down * (size + 0.2f); // below disc along up axis
|
||||
GUIStyle style = new GUIStyle(EditorStyles.label) {
|
||||
alignment = TextAnchor.UpperCenter,
|
||||
normal = { textColor = Color.white },
|
||||
fontStyle = FontStyle.Bold
|
||||
};
|
||||
Handles.Label(labelPos, layerNucleus.name, style);
|
||||
|
||||
Rect neuronRect = new(parentPos.x - size, parentPos.y - size, size * 2, size * 2);
|
||||
int id = GUIUtility.GetControlID(FocusType.Passive);
|
||||
Event e = Event.current;
|
||||
EventType et = e.GetTypeForControl(id);
|
||||
if (e != null && neuronRect.Contains(e.mousePosition)) {
|
||||
// Process Hover
|
||||
HandleMouseHover(layerNucleus, neuronRect);
|
||||
// Process click
|
||||
Debug.Log($"{et} {e.type}");
|
||||
if (e.type == EventType.MouseDown && e.button == 0) {
|
||||
// Consume the event so the scene doesn't also handle it
|
||||
e.Use();
|
||||
HandleDiscClicked(layerNucleus);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleMouseHover(Nucleus neuroid, Rect rect) {
|
||||
GUIContent tooltip;
|
||||
if (neuroid is SensoryNeuroid sensoryNeuroid) {
|
||||
tooltip = new(
|
||||
$"{sensoryNeuroid.name}" +
|
||||
$"\nThing {sensoryNeuroid.receptor.thingId}" +
|
||||
$"\nValue: {neuroid.outputValue}" +
|
||||
$"\nStale: {neuroid.stale}");
|
||||
}
|
||||
else {
|
||||
tooltip = new(
|
||||
$"{neuroid.name}" +
|
||||
$"\nsynapse count {neuroid.synapses.Count}" +
|
||||
$"\nValue: {neuroid.outputValue}" +
|
||||
$"\nStale: {neuroid.stale}");
|
||||
}
|
||||
|
||||
Vector2 mousePosition = Event.current.mousePosition;
|
||||
|
||||
// Display tooltip with some offset
|
||||
Vector2 tooltipSize = GUI.skin.box.CalcSize(tooltip);
|
||||
Rect tooltipRect = new Rect(mousePosition.x + 10, mousePosition.y + 10, tooltipSize.x, tooltipSize.y);
|
||||
|
||||
GUI.Box(tooltipRect, tooltip);
|
||||
}
|
||||
|
||||
private void HandleDiscClicked(Nucleus nucleus) {
|
||||
this.currentNucleus = nucleus;
|
||||
BuildLayers();
|
||||
}
|
||||
|
||||
|
||||
void DrawInspector() {
|
||||
NanoBrainEditor.inspectorContainer.Clear();
|
||||
if (this.currentNucleus == null)
|
||||
return;
|
||||
|
||||
// create a SerializedObject wrapper so Unity inspector controls work (and Undo)
|
||||
SerializedObject so = new SerializedObject(currentWrapper);
|
||||
IMGUIContainer container = new IMGUIContainer(() => {
|
||||
so.Update();
|
||||
currentNucleus.name = EditorGUILayout.TextField(currentNucleus.name);
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
EditorGUILayout.LabelField("Output Value", GUILayout.Width(100));
|
||||
EditorGUILayout.Vector3Field(GUIContent.none, currentNucleus.outputValue);
|
||||
EditorGUILayout.EndHorizontal();
|
||||
if (currentNucleus.synapses.Count > 0) {
|
||||
EditorGUILayout.LabelField("Synapses");
|
||||
EditorGUI.indentLevel++;
|
||||
|
||||
List<Nucleus> nuclei = currentNucleus.synapses.Keys.ToList();
|
||||
foreach (Nucleus nucleus in nuclei) {
|
||||
EditorGUI.BeginDisabledGroup(nucleus.isSleeping);
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
EditorGUILayout.LabelField(nucleus.name, GUILayout.Width(120));
|
||||
EditorGUI.indentLevel--;
|
||||
EditorGUILayout.LabelField("Weight", GUILayout.Width(45));
|
||||
float weight = currentNucleus.synapses[nucleus];
|
||||
currentNucleus.synapses[nucleus] = EditorGUILayout.FloatField(weight, GUILayout.Width(40));
|
||||
EditorGUI.indentLevel++;
|
||||
EditorGUILayout.Vector3Field(GUIContent.none, nucleus.outputValue, GUILayout.Width(180));
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
EditorGUI.EndDisabledGroup();
|
||||
}
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
if (GUILayout.Button("Add Neuron"))
|
||||
AddInputNeuron(currentNucleus);
|
||||
|
||||
});
|
||||
NanoBrainEditor.inspectorContainer.Add(container);
|
||||
}
|
||||
|
||||
protected virtual void AddInputNeuron(Nucleus receiver) {
|
||||
Neuroid newNeuroid = new(NanoBrainEditor.brain, "New neuron");
|
||||
newNeuroid.AddReceiver(receiver);
|
||||
Rebuild();
|
||||
}
|
||||
|
||||
private Vector3 NodePosition(Nucleus nucleus, int layerNodeCount = 1) {
|
||||
if (this.neuroidPositions.ContainsKey(nucleus)) {
|
||||
Vector2Int nucleusPos = this.neuroidPositions[nucleus];
|
||||
return NodePosition(nucleusPos, layerNodeCount);
|
||||
}
|
||||
else {
|
||||
return Vector3.zero;
|
||||
}
|
||||
}
|
||||
private Vector3 NodePosition(Vector2Int location, int layerNodeCount = 1) {
|
||||
float spacing = 400f / layerNodeCount;
|
||||
float margin = 10 + spacing / 2;
|
||||
float size = 20;
|
||||
Vector3 parentPos = new(100 + location.x * 100 - size, margin + location.y * spacing - size, 0.1f);
|
||||
return parentPos;
|
||||
}
|
||||
|
||||
// helper to save node position back to graph
|
||||
// public void UpdateNodePosition(NucleusObj node, Vector2 worldPos) {
|
||||
// Undo.RecordObject(graph, "Move Node");
|
||||
// node.position = (worldPos - pan) / zoom;
|
||||
// EditorUtility.SetDirty(graph);
|
||||
// }
|
||||
|
||||
// create & delete APIs called by NodeView or toolbar
|
||||
public void CreateNode(Vector2 worldPos) {
|
||||
// Undo.RecordObject(graph, "Create Node");
|
||||
// var n = new NucleusObj("New Node"); //, position = (worldPos - pan) / zoom };
|
||||
// graph.nodes.Add(n);
|
||||
// EditorUtility.SetDirty(graph);
|
||||
// Rebuild();
|
||||
}
|
||||
|
||||
// public void CreateEdge(string fromId, string toId) {
|
||||
// if (fromId == toId) return;
|
||||
// Undo.RecordObject(graph, "Create Edge");
|
||||
// graph.edges.Add(new GraphEdge { fromNodeId = fromId, toNodeId = toId });
|
||||
// EditorUtility.SetDirty(graph);
|
||||
// Rebuild();
|
||||
// }
|
||||
}
|
||||
|
||||
/*
|
||||
public class NodeView : VisualElement {
|
||||
Nucleus data;
|
||||
GraphBoardView board;
|
||||
Label titleLabel;
|
||||
//bool dragging = false;
|
||||
Vector2 localDragStart;
|
||||
|
||||
public NodeView(Nucleus node, GraphBoardView boardView) {
|
||||
data = node;
|
||||
board = boardView;
|
||||
name = "node";
|
||||
style.width = 20; //node.size.x;
|
||||
style.height = 20; //node.size.y;
|
||||
|
||||
titleLabel = new Label(node.name) { name = "title" };
|
||||
Add(titleLabel);
|
||||
|
||||
// ports
|
||||
// var outPort = new Button(() => StartEdgeDrag(true)) { text = "◀", name = "out" };
|
||||
// var inPort = new Button(() => StartEdgeDrag(false)) { text = "▶", name = "in" };
|
||||
// Add(outPort);
|
||||
// Add(inPort);
|
||||
|
||||
RegisterCallback<MouseDownEvent>(OnMouseDown);
|
||||
// RegisterCallback<MouseMoveEvent>(OnMouseMove);
|
||||
RegisterCallback<MouseUpEvent>(OnMouseUp);
|
||||
//RegisterCallback<MouseLeaveEvent>(e => dragging = false);
|
||||
}
|
||||
|
||||
// void StartEdgeDrag(bool isOutput) {
|
||||
// // simplified: on first click store source; on second click on target port call board.CreateEdge
|
||||
// if (EdgeDragState.active == null) EdgeDragState.active = new EdgeDragState { fromNode = data, fromIsOutput = isOutput };
|
||||
// else {
|
||||
// var src = EdgeDragState.active.fromNode;
|
||||
// if (src != null && src.id != data.id) board.CreateEdge(src.id, data.id);
|
||||
// EdgeDragState.active = null;
|
||||
// }
|
||||
// }
|
||||
|
||||
void OnMouseDown(MouseDownEvent e) {
|
||||
if (e.button == 0 && e.target == this) {
|
||||
//dragging = true;
|
||||
localDragStart = e.mousePosition;
|
||||
e.StopPropagation();
|
||||
}
|
||||
}
|
||||
// void OnMouseMove(MouseMoveEvent e) {
|
||||
// if (!dragging) return;
|
||||
// var delta = e.mousePosition - localDragStart;
|
||||
// var worldPos = new Vector2(layout.x + delta.x, layout.y + delta.y);
|
||||
// style.left = worldPos.x;
|
||||
// style.top = worldPos.y;
|
||||
// // commit on every move
|
||||
// board.UpdateNodePosition(data, worldPos);
|
||||
// }
|
||||
void OnMouseUp(MouseUpEvent e) {
|
||||
//dragging = false;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
public class GraphNodeWrapper : ScriptableObject {
|
||||
// expose fields that map to GraphNode
|
||||
public string title;
|
||||
public Vector2 position;
|
||||
Nucleus node;
|
||||
NanoBrainObj graph; // needed to write back and mark dirty
|
||||
|
||||
public GraphNodeWrapper Init(Nucleus node, NanoBrainObj graphAsset) {
|
||||
this.node = node;
|
||||
this.graph = graphAsset;
|
||||
this.title = " A " + node.name;
|
||||
//position = node.position;
|
||||
return this;
|
||||
}
|
||||
void OnValidate() {
|
||||
if (node != null) {
|
||||
node.name = title;
|
||||
//node.position = position;
|
||||
#if UNITY_EDITOR
|
||||
UnityEditor.EditorUtility.SetDirty(graph);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
//static class EdgeDragState { public static EdgeDragState active; public GraphNode fromNode; public bool fromIsOutput; }
|
||||
@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c57f78e25f0e55b96a50fd5592b26317
|
||||
22
Assets/NanoBrain/VisualEditor/NanoBrainObj.cs
Normal file
22
Assets/NanoBrain/VisualEditor/NanoBrainObj.cs
Normal file
@ -0,0 +1,22 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public class NanoBrainObj : ScriptableObject {
|
||||
public Nucleus rootNucleus = new("root");
|
||||
|
||||
public List<Neuroid> neuroids = new();
|
||||
|
||||
public Neuroid AddNeuron(string name) {
|
||||
Neuroid neuroid = new(this, name);
|
||||
return neuroid;
|
||||
}
|
||||
|
||||
public void UpdateNeurons() {
|
||||
foreach (Neuroid neuroid in neuroids) {
|
||||
neuroid.stale++;
|
||||
if (neuroid.isSleeping)
|
||||
neuroid.outputValue = Vector3.zero;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
2
Assets/NanoBrain/VisualEditor/NanoBrainObj.cs.meta
Normal file
2
Assets/NanoBrain/VisualEditor/NanoBrainObj.cs.meta
Normal file
@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 36081359186edfec998d891a1feeb17b
|
||||
0
Assets/NanoBrain/VisualEditor/NeuroidObject.cs
Normal file
0
Assets/NanoBrain/VisualEditor/NeuroidObject.cs
Normal file
2
Assets/NanoBrain/VisualEditor/NeuroidObject.cs.meta
Normal file
2
Assets/NanoBrain/VisualEditor/NeuroidObject.cs.meta
Normal file
@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d14e756f390f41a1c9923a0015329389
|
||||
28
Assets/NanoBrain/VisualEditor/NucleusObject.cs
Normal file
28
Assets/NanoBrain/VisualEditor/NucleusObject.cs
Normal file
@ -0,0 +1,28 @@
|
||||
// using System.Collections.Generic;
|
||||
// using UnityEngine;
|
||||
|
||||
// public class NucleusObj : ScriptableObject {
|
||||
// public virtual string objName { get; set; }
|
||||
|
||||
// public readonly Dictionary<NucleusObj, float> synapses = new();
|
||||
// public HashSet<NucleusObj> receivers = new();
|
||||
// public virtual Vector3 outputValue { get; set; }
|
||||
|
||||
// public int stale = 0;
|
||||
|
||||
// public NucleusObj(string name) {
|
||||
// this.objName = name;
|
||||
// }
|
||||
|
||||
// public virtual void AddReceiver(NucleusObj receiver) {
|
||||
// this.receivers.Add(receiver);
|
||||
// receiver.synapses[this] = 1.0f;
|
||||
// }
|
||||
|
||||
// public bool isSleeping {
|
||||
// get {
|
||||
// return this.stale > 2;
|
||||
// }
|
||||
// }
|
||||
|
||||
// }
|
||||
2
Assets/NanoBrain/VisualEditor/NucleusObject.cs.meta
Normal file
2
Assets/NanoBrain/VisualEditor/NucleusObject.cs.meta
Normal file
@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ca2a41cdae50b5005b5cf10cebb28de6
|
||||
8
Assets/NanoBrain/VisualEditor/Resources.meta
Normal file
8
Assets/NanoBrain/VisualEditor/Resources.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7b61a93fc9332d2adae74fe4abe92d53
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
15
Assets/NanoBrain/VisualEditor/Resources/GraphStyles.uss
Normal file
15
Assets/NanoBrain/VisualEditor/Resources/GraphStyles.uss
Normal file
@ -0,0 +1,15 @@
|
||||
#main {
|
||||
|
||||
}
|
||||
#content {
|
||||
background-color: #2b2b2b,
|
||||
position: absolute;
|
||||
}
|
||||
#inspector {
|
||||
border-left-width: 1px;
|
||||
border-left-color: #000;
|
||||
border-left_style: solid;
|
||||
padding: 3px;
|
||||
}
|
||||
.node { background-color: #222; border-radius:4px; padding:6px; }
|
||||
#title { unity-font-style: bold; color: white; }
|
||||
11
Assets/NanoBrain/VisualEditor/Resources/GraphStyles.uss.meta
Normal file
11
Assets/NanoBrain/VisualEditor/Resources/GraphStyles.uss.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 28268b644fa8f3948851b25e41f5b03b
|
||||
ScriptedImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0}
|
||||
disableValidation: 0
|
||||
@ -11,7 +11,7 @@ public class Roaming : Nucleus {
|
||||
output.GetInputFrom(avoidance, -sc.avoidanceForce);
|
||||
}
|
||||
|
||||
public override void AddReceiver(Neuroid receiver) {
|
||||
public override void AddReceiver(Nucleus receiver) {
|
||||
output.AddReceiver(receiver);
|
||||
}
|
||||
}
|
||||
@ -30,7 +30,7 @@ public class Swarming : Nucleus {
|
||||
this.output.GetInputFrom(boundary, -sc.avoidanceForce);
|
||||
}
|
||||
|
||||
public override void AddReceiver(Neuroid receiver) {
|
||||
public override void AddReceiver(Nucleus receiver) {
|
||||
this.output.AddReceiver(receiver);
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,4 +1,4 @@
|
||||
<Solution>
|
||||
<Project Path="Assembly-CSharp.csproj" />
|
||||
<Project Path="Assembly-CSharp-Editor.csproj" />
|
||||
<Project Path="Assembly-CSharp.csproj" />
|
||||
</Solution>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user