ClusterPrefabDrawer seems to work

This commit is contained in:
Pascal Serrarens 2026-05-08 16:59:56 +02:00
parent 8d3d6d97b2
commit daf93691c1
3 changed files with 677 additions and 52 deletions

View File

@ -6,29 +6,23 @@ namespace NanoBrain.Unity {
public class ClusterView {
private static readonly float size = 20;
private static readonly float discRadius = 20;
protected class ViewState {
public string key = null;
public Vector2 scrollPos = Vector2.zero;
public bool expandArray = false;
public Nucleus currentNucleus = null;
}
static Dictionary<string, ViewState> viewStates = new();
private static ViewState GetViewState(SerializedProperty property) {
static readonly Dictionary<string, ClusterView> viewStates = new();
private static ClusterView GetClusterView(SerializedProperty property) {
string key = property.propertyPath + "_" + property.serializedObject.targetObject.GetEntityId();
if (!viewStates.TryGetValue(key, out ViewState state))
if (!viewStates.TryGetValue(key, out ClusterView state))
state = new() { key = key };
return state;
}
private static void UpdateViewState(ViewState viewState) {
private static void UpdateViewState(ClusterView viewState) {
viewStates[viewState.key] = viewState;
}
public static void Render(Rect drawRect, Cluster cluster, SerializedProperty property) {
ViewState state = GetViewState(property);
ClusterView clusterView = GetClusterView(property);
clusterView.currentCluster ??= cluster;
// background
EditorGUI.DrawRect(drawRect, Color.black);
@ -37,10 +31,10 @@ namespace NanoBrain.Unity {
Rect contentRect = new Rect(0f, 0f, contentWidth, drawRect.height);
// Begin horizontal-only scroll view
state.scrollPos = GUI.BeginScrollView(drawRect, state.scrollPos, contentRect, true, false);
clusterView.scrollPos = GUI.BeginScrollView(drawRect, clusterView.scrollPos, contentRect, true, false);
// Local content group: draw GUI content using content-local coords (0..contentWidth)
GUI.BeginGroup(new Rect(-state.scrollPos.x, 0f, contentWidth, drawRect.height));
GUI.BeginGroup(new Rect(-clusterView.scrollPos.x, 0f, contentWidth, drawRect.height));
EditorGUI.DrawRect(new Rect(0f, 0f, contentWidth, drawRect.height), new Color(0.08f, 0.08f, 0.08f, 1f));
GUI.EndGroup();
GUI.EndScrollView();
@ -49,35 +43,372 @@ namespace NanoBrain.Unity {
GUI.BeginGroup(drawRect);
// Inner group positions content origin so local coords match content space and respect scroll
GUI.BeginGroup(new Rect(-state.scrollPos.x, 0f, contentWidth, drawRect.height));
GUI.BeginGroup(new Rect(-clusterView.scrollPos.x, 0f, contentWidth, drawRect.height));
Handles.BeginGUI();
DrawNucleus(state, cluster, new Vector2(100, 100), Color.black);
clusterView.DrawFocusGraph();
Handles.EndGUI();
GUI.EndGroup(); // end inner group
GUI.EndGroup(); // end clipping group
UpdateViewState(state);
UpdateViewState(clusterView);
}
protected static void DrawNucleus(ViewState state, Nucleus nucleus, Vector2 position, Color color) {
public string key = null;
public Vector2 scrollPos = Vector2.zero;
public bool expandArray = false;
public Cluster currentCluster;
public Nucleus currentNucleus = null;
public Nucleus selectedSynapseNeuron = null;
public Nucleus selectedOutput;
protected void DrawFocusGraph() {
float size = 20;
Vector3 position = new(150, 210, 0);
if (this.currentNucleus != null) {
DrawReceivers(this.currentNucleus, position, size);
DrawSynapses(this.currentNucleus, position, size);
// Draw selected Nucleus
if (this.expandArray) {
float maxValue = 1;
if (this.currentNucleus is Cluster cluster) {
float spacing = 400f / cluster.instanceCount;
float margin = 10 + spacing / 2;
float xMin = 150 - size;
float xMax = 150 + size;
float yMin = 10 + margin - size / 2;
float yMax = 400 - margin + size;
Vector3[] verts = new Vector3[4] {
new(xMin, yMin, 0),
new(xMax, yMin, 0),
new(xMax, yMax, 0),
new(xMin, yMax, 0)
};
Handles.color = Color.black;
Handles.DrawAAConvexPolygon(verts);
int row = 0;
if (cluster.instances == null) {
Vector2 pos = new(150, margin + row * spacing);
Handles.color = Color.white;
// The selected sibling highlight ring
Handles.DrawSolidDisc(pos, Vector3.forward, size + 2);
DrawNucleus(cluster, pos, maxValue);
row++;
}
else {
foreach (Cluster sibling in cluster.instances) {
Vector3 pos = new(150, margin + row * spacing, 0.0f);
Handles.color = Color.white;
// The selected sibling highlight ring
Handles.DrawSolidDisc(pos, Vector3.forward, size + 2);
DrawNucleus(sibling, pos, maxValue);
row++;
}
}
GUIStyle style = new(EditorStyles.label) {
alignment = TextAnchor.UpperCenter,
normal = { textColor = Color.white },
fontStyle = FontStyle.Bold,
};
Vector3 labelPos = new(150, yMax + size + 5, 0);
string clusterName = cluster.name;
int colonPos = clusterName.IndexOf(":");
if (colonPos > 0) {
string baseName = clusterName[..colonPos];
Handles.Label(labelPos, baseName, style);
}
else
Handles.Label(labelPos, clusterName, style);
}
else {
if (this.currentNucleus is Neuron neuron)
maxValue = neuron.outputMagnitude;
DrawNucleus(this.currentNucleus, position, maxValue);
}
}
else {
float maxValue = 1;
if (this.currentNucleus is Neuron neuron)
maxValue = neuron.outputMagnitude;
else if (this.currentNucleus is Cluster cluster)
maxValue = cluster.defaultOutput.outputMagnitude;
DrawNucleus(this.currentNucleus, position, maxValue);
}
}
else {
DrawAllOutputs(position);
DrawOutputs(position);
}
}
protected void DrawReceivers(Nucleus nucleus, Vector3 parentPos, float size) {
List<Nucleus> receivers;
if (nucleus is Neuron neuron)
receivers = neuron.receivers;
else if (nucleus is Cluster cluster)
receivers = cluster.CollectReceivers(true);
else
return;
// For top-level nodes, add link to previous editor and/or 'Outputs'
int nodeCount = receivers.Count;
if (nucleus == this.selectedOutput) {
// Add link to 'Outpus'
nodeCount++;
if (ClusterViewer.previousPrefab != null)
// Add link to previous editor
nodeCount++;
}
// Determine the maximum value in this layer
// This is used to 'scale' the output value colors of the nuclei
float maxValue = 0;
foreach (Nucleus receiver in receivers) {
if (receiver is Neuron neuroid) {
float value = neuroid.outputMagnitude;
if (value > maxValue)
maxValue = value;
}
}
// Determine the spacing of the nuclei in the layer
float spacing = 400f / nodeCount;
float margin = 10 + spacing / 2;
int row = 0;
foreach (Nucleus receiver in receivers) {
Nucleus receiverNucleus = receiver;
if (receiverNucleus == null)
continue;
Vector3 pos = new(50, margin + row * spacing, 0.0f);
DrawEdge(parentPos, pos);
DrawNucleus(receiverNucleus, pos, maxValue);
row++;
}
if (nucleus == this.selectedOutput) {
Vector3 pos = new(50, margin + row * spacing, 0);
if (ClusterViewer.previousPrefab != null) {
DrawEdge(parentPos, pos);
DrawClusterPrefab(ClusterViewer.previousPrefab, pos);
row++;
}
pos = new(50, margin + row * spacing, 0);
DrawEdge(parentPos, pos);
DrawAllOutputs(pos);
}
}
protected void DrawSynapses(Nucleus nucleus, Vector3 parentPos, float size) {
if (nucleus is not Neuron neuron)
return;
if (this.selectedSynapseNeuron != null) {
DrawClusterSynapses(this.selectedSynapseNeuron, parentPos);
return;
}
if (nucleus == null)
return;
if (nucleus == state.currentNucleus) {
// Determine the maximum value in this layer
// This is used to 'scale' the output value colors of the nuclei
float maxValue = 0;
int neuronCount = 0;
List<string> drawnNeuronNames = new();
foreach (Synapse synapse in neuron.synapses) {
if (synapse.neuron == null)
continue;
// Count multiple synapses to the same neuron only once
string neuronName = synapse.neuron.name;
if (synapse.neuron.parent != null)
neuronName = synapse.neuron.parent.baseName + "." + neuronName;
if (drawnNeuronNames.Contains(neuronName))
continue;
drawnNeuronNames.Add(neuronName);
float value = synapse.neuron.outputMagnitude * synapse.weight;
if (value > maxValue)
maxValue = value;
neuronCount++;
}
// Determine the spacing of the nuclei in the layer
float spacing = 400f / neuronCount;
float margin = 10 + spacing / 2;
int row = 0;
//List<Neuron> drawnNeurons = new();
drawnNeuronNames = new();
foreach (Synapse synapse in neuron.synapses) {
if (synapse.neuron is null)
continue;
// Draw multiple synapses to the same neuron only once
string neuronName = synapse.neuron.name;
if (synapse.neuron.parent != null)
neuronName = synapse.neuron.parent.baseName + "." + neuronName;
if (drawnNeuronNames.Contains(neuronName))
continue;
drawnNeuronNames.Add(neuronName);
Vector3 pos = new(250, margin + row * spacing, 0.0f);
DrawEdge(parentPos, pos);
// Handles.color = Color.white;
// Handles.DrawLine(parentPos, pos);
Color color = Color.black;
if (Application.isPlaying) {
if (maxValue == 0 || !float.IsFinite(maxValue))
maxValue = 1;
float brightness = synapse.neuron.outputMagnitude * synapse.weight / maxValue;
color = new Color(brightness, brightness, brightness, 1f);
}
DrawNucleus(synapse.neuron, pos, color);
row++;
}
}
protected void DrawClusterSynapses(Nucleus nucleus, Vector3 parentPos) {
if (nucleus == null || nucleus.parent == null || nucleus.parent.instances == null)
return;
// Hack to disable showing labels
expandArray = true;
float maxValue = 0;
foreach (Cluster sibling in nucleus.parent.instances) {
Neuron siblingNeuron = sibling.GetNucleus(nucleus.name) as Neuron;
float value = siblingNeuron.outputMagnitude; // no need to add weight as they are all the same
if (value > maxValue)
maxValue = value;
}
// Determine the spacing of the nuclei in the layer
float spacing = 400f / nucleus.parent.instanceCount;
float margin = 10 + spacing / 2;
int row = 0;
foreach (Cluster sibling in nucleus.parent.instances) {
Neuron siblingNeuron = sibling.GetNucleus(nucleus.name) as Neuron;
Vector3 position = new(250, margin + row * spacing, 0.0f);
DrawEdge(parentPos, position);
Color color = Color.black;
if (Application.isPlaying) {
if (maxValue == 0 || !float.IsFinite(maxValue))
maxValue = 1;
float brightness = siblingNeuron.outputMagnitude / maxValue;
color = new Color(brightness, brightness, brightness, 1f);
}
DrawNucleus(siblingNeuron, position, color);
GUIStyle style = new(EditorStyles.label) {
alignment = TextAnchor.UpperCenter,
normal = { textColor = Color.white },
fontStyle = FontStyle.Bold,
};
Vector3 labelPos = position - Vector3.down * (discRadius + 5); // below neuron
string name = $"{sibling.baseName}\n{nucleus.name}";
Handles.Label(labelPos, name, style);
row++;
}
expandArray = false;
}
protected void DrawOutputs(Vector2 parentPos) {
if (this.currentCluster == null)
return;
// Determine the maximum value in this layer
// This is used to 'scale' the output value colors of the nuclei
float maxValue = 0;
int neuronCount = 0;
List<Nucleus> drawnNuclei = new();
foreach (Nucleus nucleus in this.currentCluster.outputs) {
if (nucleus is not Neuron neuron)
continue;
// Draw multiple synapses to the same neuron only once
if (drawnNuclei.Contains(nucleus))
continue;
drawnNuclei.Add(nucleus);
float value = neuron.outputMagnitude;
if (value > maxValue)
maxValue = value;
neuronCount++;
}
// Determine the spacing of the nuclei in the layer
float spacing = 400f / neuronCount;
float margin = 10 + spacing / 2;
int row = 0;
drawnNuclei = new();
foreach (Nucleus nucleus in this.currentCluster.outputs) {
if (nucleus is not Neuron neuron)
continue;
// Draw multiple synapses to the same neuron only once
if (drawnNuclei.Contains(nucleus))
continue;
drawnNuclei.Add(nucleus);
Vector3 pos = new(250, margin + row * spacing, 0.0f);
DrawEdge(parentPos, pos);
Color color = Color.black;
if (Application.isPlaying) {
if (maxValue == 0 || !float.IsFinite(maxValue))
maxValue = 1;
float brightness = neuron.outputMagnitude / maxValue;
color = new Color(brightness, brightness, brightness, 1f);
}
DrawNucleus(nucleus, pos, color);
row++;
}
}
protected void DrawNucleus(Nucleus nucleus, Vector3 position, float maxValue) {
Color color;
if (Application.isPlaying) {
float brightness = 0;
if (nucleus is Neuron neuron)
brightness = neuron.outputMagnitude / maxValue;
color = new Color(brightness, brightness, brightness, 1f);
}
else
color = Color.black;
DrawNucleus(nucleus, position, color);
}
protected void DrawNucleus(Nucleus nucleus, Vector2 position, Color color) {
if (nucleus == null)
return;
if (nucleus == this.currentNucleus) {
// The selected nucleus highlight ring
Handles.color = Color.white;
Handles.DrawSolidDisc(position, Vector3.forward, size + 2);
Handles.DrawSolidDisc(position, Vector3.forward, discRadius + 2);
}
if (nucleus is MemoryCell) {
Handles.color = Color.white;
Handles.DrawWireDisc(position + Vector2.right * 10, Vector3.forward, size);
Handles.DrawWireDisc(position + Vector2.right * 10, Vector3.forward, discRadius);
}
Handles.color = color;
Handles.DrawSolidDisc(position, Vector3.forward, size);
Handles.DrawSolidDisc(position, Vector3.forward, discRadius);
Handles.color = Color.white;
// Position the label in front of the disc
@ -89,17 +420,17 @@ namespace NanoBrain.Unity {
fontStyle = FontStyle.Bold,
};
// if (nucleus.parent is Cluster parentCluster && currentNucleus != null && parentCluster != currentNucleus.parent)
// DrawCluster(parentCluster, position, color, size);
// else if (nucleus is Cluster cluster)
// DrawCluster(cluster, position, color, size);
if (nucleus.parent is Cluster parentCluster && this.currentNucleus != null && parentCluster != this.currentNucleus.parent)
DrawCluster(parentCluster, position, color);
else if (nucleus is Cluster cluster)
DrawCluster(cluster, position, color);
if (state.expandArray == false) {// || nucleus != currentNucleus) {
if (this.expandArray == false) {// || nucleus != currentNucleus) {
// put name below nucleus
Vector3 labelPos = position - Vector2.down * (size + 5); // below neuron
Vector3 labelPos = position - Vector2.down * (discRadius + 5); // below neuron
style.alignment = TextAnchor.UpperCenter;
if (nucleus.parent != null && state.currentNucleus != null && nucleus.parent != state.currentNucleus.parent && nucleus.parent is Cluster parentCluster1) {
if (nucleus.parent != null && this.currentNucleus != null && nucleus.parent != this.currentNucleus.parent && nucleus.parent is Cluster parentCluster1) {
// This neuron is part of another cluster
parentCluster1.name ??= "";
int colonPos = parentCluster1.name.IndexOf(":");
@ -124,25 +455,222 @@ namespace NanoBrain.Unity {
}
// Tooltip
// Rect neuronRect = new(position.x - size, position.y - size, size * 2, size * 2);
Rect neuronRect = new(position.x - discRadius, position.y - discRadius, discRadius * 2, discRadius * 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(nucleus, neuronRect);
// // Process click
// if (e.type == EventType.MouseDown && e.button == 0) {
// // Consume the event so the scene doesn't also handle it
// e.Use();
// if (nucleus is Cluster parentCluster2)
// OnNeuronClick(parentCluster2);
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(nucleus, neuronRect);
// Process click
if (e.type == EventType.MouseDown && e.button == 0) {
// Consume the event so the scene doesn't also handle it
e.Use();
if (nucleus is Cluster parentCluster2)
OnNeuronClick(parentCluster2);
else
OnNeuronClick(nucleus);
}
}
}
protected void DrawCluster(Cluster cluster, Vector3 position, Color color) {
GUIStyle labelTextStyle = new(EditorStyles.label) {
normal = { textColor = Color.white },
fontStyle = FontStyle.Bold,
};
if (this.expandArray) {
// Put array indices above the discs
labelTextStyle.alignment = TextAnchor.LowerCenter;
Vector3 labelPosition = position + Vector3.down * (discRadius + 5); // below disc
// Strip the instance number in the name
int colonPos1 = cluster.name.IndexOf(":");
if (colonPos1 > 0) {
string extName = cluster.name[(colonPos1 + 2)..];
Handles.Label(labelPosition, extName, labelTextStyle);
}
else
Handles.Label(labelPosition, "0", labelTextStyle);
}
else {
// Put instance count inside the disc
labelTextStyle.alignment = TextAnchor.MiddleCenter;
Vector3 labelPosition = position + (Vector3.forward * 0.1f);
// Adjust text color based on disc color
if (color.grayscale > 0.5f)
labelTextStyle.normal.textColor = Color.black;
else
labelTextStyle.normal.textColor = Color.white;
if (cluster.instanceCount > 1) {
Handles.Label(labelPosition, cluster.instanceCount.ToString(), labelTextStyle);
labelTextStyle.normal.textColor = Color.white;
}
else if (cluster.instances != null && cluster.instances.Length > 1) {
Handles.Label(labelPosition, cluster.instances.Length.ToString(), labelTextStyle);
labelTextStyle.normal.textColor = Color.white;
}
}
// Draw a circle around the disc to indicate this is a Cluster
Handles.color = Color.white;
Handles.DrawWireDisc(position, Vector3.forward, discRadius + 5);
}
protected void DrawClusterPrefab(ClusterPrefab prefab, Vector2 position) {
Handles.color = Color.black;
Handles.DrawSolidDisc(position, Vector3.forward, discRadius);
// Draw a circle around the disc to indicate this is a Cluster
Handles.color = Color.white;
Handles.DrawWireDisc(position, Vector3.forward, discRadius + 5);
// put name below nucleus
GUIStyle style = new(EditorStyles.label) {
alignment = TextAnchor.MiddleCenter,
normal = { textColor = Color.white },
fontStyle = FontStyle.Bold,
};
Vector2 labelPos = position - Vector2.down * (discRadius + 5); // below neuron
style.alignment = TextAnchor.UpperCenter;
Handles.Label(labelPos, prefab.name, style);
Rect neuronRect = new(position.x - discRadius, position.y - discRadius, discRadius * 2, discRadius * 2);
int id = GUIUtility.GetControlID(FocusType.Passive);
Event e = Event.current;
EventType et = e.GetTypeForControl(id);
if (e != null && neuronRect.Contains(e.mousePosition)) {
// Process click
if (e.type == EventType.MouseDown && e.button == 0) {
// Consume the event so the scene doesn't also handle it
e.Use();
Selection.activeObject = prefab;
EditorGUIUtility.PingObject(prefab);
ClusterViewer.previousPrefab = null;
Editor.CreateEditor(prefab);
}
}
}
protected void DrawAllOutputs(Vector2 position) {
GUIStyle labelTextStyle = new(EditorStyles.label) {
normal = { textColor = Color.white },
fontStyle = FontStyle.Bold,
alignment = TextAnchor.MiddleCenter,
};
Handles.Label(position, "Outputs", labelTextStyle);
Rect neuronRect = new(position.x - discRadius, position.y - discRadius, discRadius * 2, discRadius * 2);
Event e = Event.current;
if (e != null && neuronRect.Contains(e.mousePosition)) {
// Process click
if (e.type == EventType.MouseDown && e.button == 0) {
// Consume the event so the scene doesn't also handle it
e.Use();
OnAllOutputsClick();
}
}
}
protected void DrawEdge(Vector2 from, Vector2 to) {
Handles.color = Color.white;
// Handles.DrawLine(from, to);
Vector2 dir = to - from;
float len = dir.magnitude;
if (len <= 2f * discRadius || len <= Mathf.Epsilon)
// line too short
return;
Vector2 n = dir / len; // normalized
Vector2 a = from + n * discRadius;
Vector2 b = to - n * discRadius;
Handles.DrawLine(a, b);
}
#region Interaction
protected static void HandleMouseHover(Nucleus nucleus, Rect rect) {
GUIContent tooltip;
if (nucleus is Neuron neuron) {
tooltip = new(
$"{nucleus.name}" +
$"\nValue: {neuron.outputMagnitude}");
}
else
tooltip = new($"{nucleus.name}");
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);
}
protected void OnNeuronClick(Nucleus nucleus) {
if (nucleus == this.currentNucleus) {
this.selectedSynapseNeuron = null;
// if (Application.isPlaying) {
// if (nucleus is Cluster)
// expandArray = !expandArray;
// else
// OnNeuronClick(nucleus);
// expandArray = false;
// }
// else {
if (nucleus is Cluster cluster)
OnClusterClick(cluster);
// }
}
else if (nucleus.parent != null && this.currentNucleus != null && nucleus.parent != this.currentNucleus.parent) {
// We go to a different cluster
if (Application.isPlaying) {
if (this.selectedSynapseNeuron == null && nucleus.parent.instanceCount > 1) {
this.selectedSynapseNeuron = nucleus;
this.expandArray = false;
}
else {
this.currentNucleus = nucleus;
if (this.currentNucleus is Neuron neuron && neuron.receivers.Count == 0)
this.selectedOutput = this.currentNucleus;
this.selectedSynapseNeuron = null;
this.expandArray = false;
}
}
else {
// select the cluster, not the neuron in the cluster
this.currentNucleus = nucleus.parent;
this.expandArray = false;
}
}
else {
this.currentNucleus = nucleus;
if (this.currentNucleus is Neuron neuron && neuron.receivers.Count == 0)
this.selectedOutput = this.currentNucleus;
this.expandArray = false;
}
}
protected void OnClusterClick(Cluster subCluster) {
// May be used with storedPrefab...
Selection.activeObject = subCluster.prefab;
EditorGUIUtility.PingObject(subCluster.prefab);
ClusterViewer.previousPrefab = this.currentCluster.prefab;
Editor.CreateEditor(subCluster.prefab);
}
protected void OnAllOutputsClick() {
this.currentNucleus = null;
this.selectedOutput = null;
this.expandArray = false;
}
#endregion Interaction
}
}

View File

@ -13,14 +13,107 @@ MonoBehaviour:
m_Name: Breitenberg
m_EditorClassIdentifier: Assembly-CSharp::NanoBrain.Unity.ClusterPrefab
cluster:
name:
name: Breitenberg
parent:
rid: -2
prefab: {fileID: 0}
instanceCount: 0
nuclei: []
prefab: {fileID: 11400000}
instanceCount: 1
nuclei:
- rid: 4201949899492425781
- rid: 4201949899492425817
references:
version: 2
RefIds:
- rid: -2
type: {class: , ns: , asm: }
- rid: 4201949899492425781
type: {class: Neuron, ns: NanoBrain, asm: Assembly-CSharp}
data:
name: Output
parent:
rid: 4201949899492425816
bias: {x: 0, y: 0, z: 0}
_synapses:
- neuron:
rid: 4201949899492425817
weight: 1
combinator: 0
_activator: 0
curve:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 0
inSlope: 0
outSlope: 1
tangentMode: 0
weightedMode: 0
inWeight: 0
outWeight: 0
- serializedVersion: 3
time: 1000
value: 1000
inSlope: 1
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0
outWeight: 0
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
curveMax: 1
persistOutput: 0
lastUpdate: 0
_receivers: []
- rid: 4201949899492425816
type: {class: Cluster, ns: NanoBrain, asm: Assembly-CSharp}
data:
name: Breitenberg
parent:
rid: -2
prefab: {fileID: 11400000}
instanceCount: 1
nuclei:
- rid: 4201949899492425781
- rid: 4201949899492425817
- rid: 4201949899492425817
type: {class: Neuron, ns: NanoBrain, asm: Assembly-CSharp}
data:
name: Sensor
parent:
rid: 4201949899492425816
bias: {x: 0, y: 0, z: 0}
_synapses: []
combinator: 0
_activator: 0
curve:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 0
inSlope: 0
outSlope: 1
tangentMode: 0
weightedMode: 0
inWeight: 0
outWeight: 0
- serializedVersion: 3
time: 1000
value: 1000
inSlope: 1
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0
outWeight: 0
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
curveMax: 1
persistOutput: 0
lastUpdate: 0
_receivers:
- rid: 4201949899492425781

View File

@ -652,6 +652,10 @@ PrefabInstance:
propertyPath: m_Name
value: Vehicle
objectReference: {fileID: 0}
- target: {fileID: 8280937452374640854, guid: c0398fc7a48853d47acb42e4e3498383, type: 3}
propertyPath: brain
value:
objectReference: {fileID: 11400000, guid: f6472e5b4459918cab23832c0545c832, type: 2}
- target: {fileID: 8280937452374640854, guid: c0398fc7a48853d47acb42e4e3498383, type: 3}
propertyPath: turnTorque
value: 10