initial multiple output support

This commit is contained in:
Pascal Serrarens 2026-02-06 18:06:36 +01:00
parent 278b861a84
commit 2cae7a6c41
3 changed files with 88 additions and 29 deletions

View File

@ -185,12 +185,10 @@ public class Cluster : Nucleus {
get {
if (this._inputs == null) {
this._inputs = new();
foreach (Nucleus receptor in this.nuclei) {
if (receptor is Nucleus nucleus) {
// inputs have no incoming synapses yet.
if (nucleus.synapses.Count == 0)
this._inputs.Add(nucleus);
}
foreach (Nucleus nucleus in this.nuclei) {
// inputs have no synapses
if (nucleus.synapses.Count == 0)
this._inputs.Add(nucleus);
}
}
return this._inputs;
@ -204,6 +202,20 @@ public class Cluster : Nucleus {
return null;
}
}
public List<Nucleus> _outputs = null;
public List<Nucleus> outputs {
get {
if (this._outputs == null) {
this._outputs = new();
foreach (Nucleus nucleus in this.nuclei) {
// outputs have not receivers
if (nucleus.receivers.Count == 0)
this._outputs.Add(nucleus);
}
}
return this._outputs;
}
}
public bool TryGetNucleus(string nucleusName, out Nucleus foundNucleus) {
foreach (Nucleus receptor in this.nuclei) {

View File

@ -28,6 +28,29 @@ public class ClusterPrefab : ScriptableObject {
return this._inputs;
}
}
private List<Nucleus> _outputs = null;
public List<Nucleus> outputs {
get {
if (this._outputs == null)
RefreshOutputs();
return this._outputs;
}
}
public void RefreshOutputs() {
this._outputs = new();
foreach (Nucleus nucleus in this.nuclei) {
if (nucleus.receivers.Count == 0)
this._outputs.Add(nucleus);
}
}
public Nucleus GetNucleus(string nucleusName) {
foreach (Nucleus nucleus in this.nuclei) {
if (nucleus.name == nucleusName)
return nucleus;
}
return null;
}
// Call this function to ensure that there is at least one nucleus
// This is an invariant and should be ensured before the nucleus is used

View File

@ -46,7 +46,7 @@ public class ClusterInspector : Editor {
flexDirection = FlexDirection.Row
}
};
GraphView graph = new();
GraphView graph = new(cluster);
graph.style.flexGrow = 1;
inspectorContainer = new VisualElement {
@ -61,14 +61,14 @@ public class ClusterInspector : Editor {
mainContainer.Add(inspectorContainer);
root.Add(mainContainer);
graph.SetGraph(null, cluster, cluster.output, inspectorContainer);
graph.SetGraph(null, cluster.output, inspectorContainer);
return graph;
}
public class GraphView : VisualElement {
ClusterPrefab cluster;
readonly ClusterPrefab cluster;
SerializedObject serializedBrain;
Nucleus currentNucleus;
GameObject gameObject;
@ -77,35 +77,59 @@ public class ClusterInspector : Editor {
private bool expandArray = false;
ClusterWrapper currentWrapper;
PopupField<string> outputsField;
public enum OutputNodes {
Output,
Output2,
Output3
}
public GraphView(ClusterPrefab prefab) {
this.cluster = prefab;
public GraphView() {
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);
IMGUIContainer graphContainer = new(OnIMGUI);
graphContainer.style.position = Position.Absolute;
graphContainer.style.left = 0; graphContainer.style.top = 0;
graphContainer.style.right = 0; graphContainer.style.bottom = 0;
graphContainer.pickingMode = PickingMode.Position;
graphContainer.focusable = true;
Add(graphContainer);
PopupField<OutputNodes> enumField = new(System.Enum.GetValues(typeof(OutputNodes)).Cast<OutputNodes>().ToList(), OutputNodes.Output);
enumField.RegisterValueChangedCallback(evt => OnOutputChanged(evt.newValue));
Add(enumField);
VisualElement outputContainer = new() {
style = {
flexDirection = FlexDirection.Row,
alignItems = Align.Center,
}
};
List<string> names = this.cluster.outputs.Select(output => output.name).ToList();
outputsField = new(names, names.First()) {
style = { flexGrow = 1 }
};
outputsField.RegisterValueChangedCallback(evt => OnOutputChanged(evt.newValue));
outputContainer.Add(outputsField);
Button addButton = new(() => OnAddClusterOutput()) {
text = "Add"
};
outputContainer.Add(addButton);
Add(outputContainer);
// Subscribe when added to panel (editor UI ready)
RegisterCallback<AttachToPanelEvent>(evt => Subscribe());
RegisterCallback<DetachFromPanelEvent>(evt => Unsubscribe());
}
void OnOutputChanged(OutputNodes output) {
void OnOutputChanged(string outputName) {
this.currentNucleus = this.cluster.GetNucleus(outputName);
}
void OnAddClusterOutput() {
Nucleus newOutput = new Neuron(this.cluster, "Output 2");
outputsField.choices = this.cluster.outputs.Select(output => output.name).ToList();
outputsField.value = newOutput.name;
this.currentNucleus = newOutput;
}
bool subscribed = false;
@ -122,11 +146,11 @@ public class ClusterInspector : Editor {
subscribed = false;
}
public void SetGraph(GameObject gameObject, ClusterPrefab brain, Nucleus nucleus, VisualElement inspectorContainer) {
public void SetGraph(GameObject gameObject, Nucleus nucleus, VisualElement inspectorContainer) {
this.gameObject = gameObject;
this.cluster = brain;
//this.cluster = brain;
if (Application.isPlaying == false)
this.serializedBrain = new SerializedObject(brain);
this.serializedBrain = new SerializedObject(this.cluster);
this.currentNucleus = nucleus;
Rebuild(inspectorContainer);
}