Each boid now has its own brain (but output is still not correct)

This commit is contained in:
Pascal Serrarens 2026-01-30 10:10:37 +01:00
parent 5cb9e788a4
commit 728ef1767c
5 changed files with 161 additions and 64 deletions

View File

@ -7,22 +7,61 @@ using static Unity.Mathematics.math;
[System.Serializable] [System.Serializable]
public class Cluster : INucleus { public class Cluster : INucleus {
// The ScriptableObject asset from which the runtime object has been created // The ScriptableObject asset from which the runtime object has been created
[SerializeField]
protected string _name;
public virtual string name {
get => _name;
set => _name = value;
}
public ClusterPrefab storedPrefab; public ClusterPrefab storedPrefab;
//public ClusterPrefab prefab; //public ClusterPrefab prefab;
public Cluster() { // public Cluster() {
} // }
public Cluster(Cluster parent) { public Cluster(Cluster parent, ClusterPrefab realPrefab) {
this.storedPrefab = realPrefab;
this.parent = parent; this.parent = parent;
this.parent?.nuclei.Add(this);
ClonePrefab();
} }
public Cluster(ClusterPrefab prefab) { public Cluster(ClusterPrefab realPrefab) {
this.storedPrefab = prefab; this.storedPrefab = realPrefab;
//this.prefab = prefab.Clone(); //this.prefab = prefab.Clone();
this.name = prefab.name; this.name = realPrefab.name;
this.cluster = null; this.cluster = null;
if (this.cluster != null) if (this.cluster != null)
this.cluster.nuclei.Add(this); this.cluster.nuclei.Add(this);
ClonePrefab();
// IReceptor[] nucleiArray = this.storedPrefab.nuclei.ToArray();
// // first clone the nuclei without their connections
// foreach (IReceptor nucleus in this.storedPrefab.nuclei)
// nucleus.ShallowCloneTo(this);
// IReceptor[] clonedNuclei = this.nuclei.ToArray();
// // Now clone the connections
// for (int nucleusIx = 0; nucleusIx < nucleiArray.Length; nucleusIx++) {
// //IReceptor receptor = nucleiArray[nucleusIx];
// IReceptor clonedReceptor = clonedNuclei[nucleusIx];
// if (clonedReceptor == null)
// continue;
// // Copy the receivers, which will also create the synapses
// foreach (INucleus receiver in nucleiArray[nucleusIx].receivers) {
// int ix = GetNucleusIndex(nucleiArray, receiver);
// if (ix < 0)
// continue;
// if (clonedNuclei[ix] is not INucleus clonedReceiver)
// continue;
// clonedReceptor.AddReceiver(clonedReceiver);
// }
// }
} }
public Cluster(ClusterPrefab parent, ClusterPrefab realPrefab) { public Cluster(ClusterPrefab parent, ClusterPrefab realPrefab) {
@ -32,6 +71,61 @@ public class Cluster : INucleus {
this.cluster = parent; this.cluster = parent;
if (this.cluster != null) if (this.cluster != null)
this.cluster.nuclei.Add(this); this.cluster.nuclei.Add(this);
ClonePrefab();
// IReceptor[] nucleiArray = this.storedPrefab.nuclei.ToArray();
// // first clone the nuclei without their connections
// foreach (IReceptor nucleus in this.storedPrefab.nuclei)
// nucleus.ShallowCloneTo(this);
// IReceptor[] clonedNuclei = this.nuclei.ToArray();
// // Now clone the connections
// for (int nucleusIx = 0; nucleusIx < nucleiArray.Length; nucleusIx++) {
// IReceptor receptor = nucleiArray[nucleusIx];
// IReceptor clonedReceptor = clonedNuclei[nucleusIx];
// if (clonedReceptor == null)
// continue;
// // Copy the receivers, which will also create the synapses
// foreach (INucleus receiver in nucleiArray[nucleusIx].receivers) {
// int ix = GetNucleusIndex(nucleiArray, receiver);
// if (ix < 0)
// continue;
// if (clonedNuclei[ix] is not INucleus clonedReceiver)
// continue;
// clonedReceptor.AddReceiver(clonedReceiver);
// }
// }
}
private void ClonePrefab() {
IReceptor[] nucleiArray = this.storedPrefab.nuclei.ToArray();
// first clone the nuclei without their connections
foreach (IReceptor nucleus in this.storedPrefab.nuclei)
nucleus.ShallowCloneTo(this);
IReceptor[] clonedNuclei = this.nuclei.ToArray();
// Now clone the connections
for (int nucleusIx = 0; nucleusIx < nucleiArray.Length; nucleusIx++) {
IReceptor receptor = nucleiArray[nucleusIx];
IReceptor clonedReceptor = clonedNuclei[nucleusIx];
if (clonedReceptor == null)
continue;
// Copy the receivers, which will also create the synapses
foreach (INucleus receiver in nucleiArray[nucleusIx].receivers) {
int ix = GetNucleusIndex(nucleiArray, receiver);
if (ix < 0)
continue;
if (clonedNuclei[ix] is not INucleus clonedReceiver)
continue;
clonedReceptor.AddReceiver(clonedReceiver);
}
}
} }
public virtual IReceptor Clone() { public virtual IReceptor Clone() {
@ -55,7 +149,9 @@ public class Cluster : INucleus {
// } // }
public IReceptor ShallowCloneTo(Cluster parent) { public IReceptor ShallowCloneTo(Cluster parent) {
Cluster clone = new(parent); Cluster clone = new(parent, this.storedPrefab) {
name = this.name,
};
return clone; return clone;
} }
@ -65,55 +161,55 @@ public class Cluster : INucleus {
// } // }
// Deep clone a nucleus with its connections // Deep clone a nucleus with its connections
public virtual Cluster InstantiatePrefab(ClusterPrefab prefab) { // public virtual Cluster InstantiatePrefab(ClusterPrefab prefab) {
Cluster clone = new Cluster { // Cluster clone = new Cluster {
nuclei = new() // nuclei = new()
}; // };
IReceptor[] nucleiArray = this.nuclei.ToArray(); // IReceptor[] nucleiArray = this.nuclei.ToArray();
// first clone the nuclei without their connections // // first clone the nuclei without their connections
foreach (IReceptor nucleus in this.nuclei) // foreach (IReceptor nucleus in this.nuclei)
nucleus.ShallowCloneTo(clone); // nucleus.ShallowCloneTo(clone);
IReceptor[] clonedNuclei = clone.nuclei.ToArray(); // IReceptor[] clonedNuclei = clone.nuclei.ToArray();
// Now clone the connections // // Now clone the connections
for (int nucleusIx = 0; nucleusIx < nucleiArray.Length; nucleusIx++) { // for (int nucleusIx = 0; nucleusIx < nucleiArray.Length; nucleusIx++) {
IReceptor receptor = nucleiArray[nucleusIx]; // IReceptor receptor = nucleiArray[nucleusIx];
IReceptor clonedReceptor = clonedNuclei[nucleusIx]; // IReceptor clonedReceptor = clonedNuclei[nucleusIx];
if (clonedReceptor == null) // if (clonedReceptor == null)
continue; // continue;
// Copy the synapses // // Copy the synapses
if (receptor is INucleus nucleus) { // if (receptor is INucleus nucleus) {
foreach (Synapse synapse in nucleus.synapses) { // foreach (Synapse synapse in nucleus.synapses) {
if (clonedReceptor is not INucleus clonedNucleus) // if (clonedReceptor is not INucleus clonedNucleus)
continue; // continue;
int ix = GetNucleusIndex(nucleiArray, synapse.nucleus); // int ix = GetNucleusIndex(nucleiArray, synapse.nucleus);
if (ix < 0) // if (ix < 0)
continue; // continue;
IReceptor clonedSynapseNucleus = clonedNuclei[ix]; // IReceptor clonedSynapseNucleus = clonedNuclei[ix];
if (clonedSynapseNucleus == null) // if (clonedSynapseNucleus == null)
continue; // continue;
clonedNucleus.AddSynapse(clonedSynapseNucleus, synapse.weight); // clonedNucleus.AddSynapse(clonedSynapseNucleus, synapse.weight);
} // }
} // }
// Copy the receivers // // Copy the receivers
foreach (INucleus receiver in nucleiArray[nucleusIx].receivers) { // foreach (INucleus receiver in nucleiArray[nucleusIx].receivers) {
int ix = GetNucleusIndex(nucleiArray, receiver); // int ix = GetNucleusIndex(nucleiArray, receiver);
if (ix < 0) // if (ix < 0)
continue; // continue;
if (clonedNuclei[ix] is not INucleus clonedReceiver) // if (clonedNuclei[ix] is not INucleus clonedReceiver)
continue; // continue;
clonedReceptor.AddReceiver(clonedReceiver); // clonedReceptor.AddReceiver(clonedReceiver);
} // }
} // }
return clone; // return clone;
} // }
private int GetNucleusIndex(IReceptor[] nucleiArray, IReceptor nucleus) { private int GetNucleusIndex(IReceptor[] nucleiArray, IReceptor nucleus) {
for (int i = 0; i < nucleiArray.Length; i++) { for (int i = 0; i < nucleiArray.Length; i++) {
@ -129,13 +225,6 @@ public class Cluster : INucleus {
[SerializeReference] [SerializeReference]
public List<IReceptor> nuclei = new(); public List<IReceptor> nuclei = new();
[SerializeField]
protected string _name;
public virtual string name {
get => _name;
set => _name = value;
}
public List<INucleus> _inputs = null; public List<INucleus> _inputs = null;
public virtual List<INucleus> inputs { public virtual List<INucleus> inputs {
get { get {
@ -154,7 +243,13 @@ public class Cluster : INucleus {
} }
//public INucleus output => prefab.output; //public INucleus output => prefab.output;
public virtual INucleus output => this.nuclei[0] as INucleus; public virtual INucleus output {//=> this.nuclei[0] as INucleus;
get {
if (this.nuclei.Count > 0)
return this.nuclei[0] as INucleus;
return null;
}
}
// Not sure if this belongs here... // Not sure if this belongs here...
[SerializeReference] [SerializeReference]

View File

@ -169,9 +169,7 @@ public class Neuron : INucleus {
public Neuron(Cluster parent, string name) { public Neuron(Cluster parent, string name) {
this.parent = parent; this.parent = parent;
this.name = name; this.name = name;
if (this.cluster != null) { this.parent?.nuclei.Add(this);
this.cluster.nuclei.Add(this);
}
} }
public Neuron(ClusterPrefab parent, string name) { public Neuron(ClusterPrefab parent, string name) {
this.cluster = parent; this.cluster = parent;

View File

@ -4,7 +4,6 @@ using UnityEngine;
using Unity.Mathematics; using Unity.Mathematics;
using static Unity.Mathematics.math; using static Unity.Mathematics.math;
[Serializable]
public class Receptor : IReceptor { public class Receptor : IReceptor {
private ClusterPrefab cluster; private ClusterPrefab cluster;
@ -141,6 +140,8 @@ public class Receptor : IReceptor {
public virtual void ProcessStimulus(int thingId, Vector3 newLocalPositionVector, string thingName = null) { public virtual void ProcessStimulus(int thingId, Vector3 newLocalPositionVector, string thingName = null) {
this.localPosition = newLocalPositionVector; this.localPosition = newLocalPositionVector;
if (this._receivers == null)
return;
thingIds ??= new int[this._receivers.Count]; thingIds ??= new int[this._receivers.Count];

View File

@ -623,6 +623,9 @@ public class ClusterInspector : Editor {
private void OnClusterPicked(INucleus nucleus, ClusterPrefab prefab) { private void OnClusterPicked(INucleus nucleus, ClusterPrefab prefab) {
Cluster subclusterInstance = new(this.cluster, prefab); Cluster subclusterInstance = new(this.cluster, prefab);
subclusterInstance.AddReceiver(nucleus); subclusterInstance.AddReceiver(nucleus);
// This does not work somehow
// this.currentNucleus = subclusterInstance;
// BuildLayers();
} }
private void EditCluster(Cluster subCluster) { private void EditCluster(Cluster subCluster) {

View File

@ -1,11 +1,11 @@
using System;
using UnityEngine; using UnityEngine;
public class NanoBrainComponent : MonoBehaviour { public class NanoBrainComponent : MonoBehaviour {
[SerializeField]
public ClusterPrefab defaultBrain; public ClusterPrefab defaultBrain;
private Cluster brainInstance;
//public INucleus root => brainInstance.output; [NonSerialized]
private Cluster brainInstance;
public Cluster brain { public Cluster brain {
get { get {
if (brainInstance == null && defaultBrain != null) { if (brainInstance == null && defaultBrain != null) {