Brain object
This commit is contained in:
parent
86b5053383
commit
21751f8cea
@ -50,6 +50,7 @@
|
||||
<ItemGroup>
|
||||
<Compile Include="Assets/NanoBrain/VisualEditor/NanoBrainObj.cs" />
|
||||
<Compile Include="Assets/Scenes/Boids/Scripts/SwarmSpawner.cs" />
|
||||
<Compile Include="Assets/NanoBrain/Perceptoid.cs" />
|
||||
<Compile Include="Assets/NanoBrain/NeuroidBehaviour.cs" />
|
||||
<Compile Include="Assets/NanoBrain/NanoBrain.cs" />
|
||||
<Compile Include="Assets/NanoBrain/SensoryNeuroid.cs" />
|
||||
|
||||
@ -221,7 +221,7 @@ public class NanoBrain_Editor : Editor {
|
||||
if (neuroid is SensoryNeuroid sensoryNeuroid) {
|
||||
tooltip = new(
|
||||
$"{sensoryNeuroid.name}" +
|
||||
$"\nThing {sensoryNeuroid.receptor.thingId}" +
|
||||
$"\nThing {sensoryNeuroid.receptor.thingType}" +
|
||||
$"\nValue: {neuroid.outputValue}" +
|
||||
$"\nStale: {neuroid.stale}");
|
||||
}
|
||||
|
||||
@ -244,7 +244,7 @@ public class GraphEditorWindow : EditorWindow {
|
||||
if (neuroid is SensoryNeuroid sensoryNeuroid) {
|
||||
tooltip = new(
|
||||
$"{sensoryNeuroid.name}" +
|
||||
$"\nThing {sensoryNeuroid.receptor.thingId}" +
|
||||
$"\nThing {sensoryNeuroid.receptor.thingType}" +
|
||||
$"\nValue: {neuroid.outputValue}" +
|
||||
$"\nStale: {neuroid.stale}");
|
||||
}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
using UnityEngine;
|
||||
|
||||
[System.Serializable]
|
||||
public class Neuroid : Nucleus {
|
||||
public bool average = false;
|
||||
public bool inverse = false;
|
||||
@ -13,9 +14,17 @@ public class Neuroid : Nucleus {
|
||||
// Debug.LogError("No neuroid network");
|
||||
// }
|
||||
|
||||
public Neuroid(NanoBrainObj brain, string name) : base(brain, name) {
|
||||
public Neuroid(NanoBrainObj brain, string name) : base(name) {
|
||||
this.brain = brain;
|
||||
if (this.brain != null) {
|
||||
this.brain.nuclei.Add(this);
|
||||
}
|
||||
else
|
||||
Debug.LogError("No neuroid network");
|
||||
}
|
||||
|
||||
public Neuroid(string name): base(name) {}
|
||||
|
||||
public void SetWeight(Neuroid input, float weight) {
|
||||
//this.synapses[input] = weight;
|
||||
this.SetWeight((Nucleus)input, weight);
|
||||
@ -30,7 +39,7 @@ public class Neuroid : Nucleus {
|
||||
public void SetInput(Neuroid input) {
|
||||
// if (this.synapses.ContainsKey(input) == false)
|
||||
// this.synapses[input] = 1.0f;
|
||||
if (this.SynapseExists(input))
|
||||
if (this.SynapseExists(input) == false)
|
||||
this.SetWeight(input, 1.0f);
|
||||
UpdateState();
|
||||
}
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
@ -13,33 +14,53 @@ public class Nucleus {
|
||||
set => _name = value;
|
||||
}
|
||||
|
||||
//public readonly Dictionary<Nucleus, float> synapses = new();
|
||||
[SerializeField]
|
||||
public List<Synapse> synapses = new();
|
||||
//public HashSet<Nucleus> receivers = new();
|
||||
public List<Synapse> synapses = new();
|
||||
[SerializeField]
|
||||
public List<Receiver> receivers = new();
|
||||
|
||||
#region Serialization
|
||||
|
||||
public void Rebuild(NanoBrainObj brain) {
|
||||
[SerializeField]
|
||||
protected string nucleusType;
|
||||
|
||||
public virtual void Rebuild(NanoBrainObj brain) {
|
||||
if (this.synapses != null) {
|
||||
foreach (Synapse synapse in synapses)
|
||||
synapse.Rebuild(brain);
|
||||
}
|
||||
if (this.receivers == null)
|
||||
this.receivers = new();
|
||||
else
|
||||
foreach (Receiver receiver in receivers)
|
||||
receiver.Rebuild(brain);
|
||||
else {
|
||||
foreach (Receiver receiver in receivers.ToArray()) {
|
||||
if (receiver.Rebuild(brain) == false) {
|
||||
Debug.Log("Rebuilding failed, removing receiver.");
|
||||
receivers.Remove(receiver);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
public static Nucleus RebuildType(NanoBrainObj brain, Nucleus nucleus) {
|
||||
if (string.IsNullOrEmpty(nucleus.nucleusType) == false) {
|
||||
Type nucleusType = Type.GetType(nucleus.nucleusType);
|
||||
if (nucleusType != null) {
|
||||
object[] args = new object[] { brain, nucleus.name };
|
||||
Nucleus rebuiltNucleus = (Nucleus)Activator.CreateInstance(nucleusType, args);
|
||||
rebuiltNucleus.Deserialize(nucleus);
|
||||
return rebuiltNucleus;
|
||||
}
|
||||
}
|
||||
return nucleus;
|
||||
}
|
||||
|
||||
public virtual void Deserialize(Nucleus nucleus) { }
|
||||
|
||||
#endregion Serialization
|
||||
|
||||
#region Runtime state (not serialized)
|
||||
|
||||
// public NanoBrain brain { get; protected set; }
|
||||
public NanoBrainObj newBrain { get; protected set; }
|
||||
public NanoBrainObj brain { get; protected set; }
|
||||
|
||||
public virtual Vector3 outputValue { get; set; }
|
||||
|
||||
@ -50,12 +71,13 @@ public class Nucleus {
|
||||
|
||||
#endregion Runtime state
|
||||
|
||||
public Nucleus(NanoBrainObj brain, string name) {
|
||||
this.newBrain = brain;
|
||||
if (this.newBrain != null)
|
||||
this.newBrain.nuclei.Add(this);
|
||||
else
|
||||
Debug.LogError("No neuroid network");
|
||||
public Nucleus(string name) {
|
||||
// this.brain = brain;
|
||||
// if (this.brain != null) {
|
||||
// this.brain.nuclei.Add(this);
|
||||
// }
|
||||
// else
|
||||
// Debug.LogError("No neuroid network");
|
||||
|
||||
this._name = name;
|
||||
this.id = this.GetHashCode();
|
||||
@ -63,9 +85,7 @@ public class Nucleus {
|
||||
|
||||
public virtual void AddReceiver(Nucleus receiver) {
|
||||
this.receivers.Add(new Receiver(receiver));
|
||||
//receiver.synapses[this] = 1.0f; // new(this);
|
||||
receiver.SetWeight(this, 1.0f);
|
||||
//Debug.Log($"receiver # {this.receivers.Count} synapse count {receiver.synapses.Count}");
|
||||
}
|
||||
|
||||
public static void Delete(Nucleus nucleus) {
|
||||
@ -73,15 +93,19 @@ public class Nucleus {
|
||||
if (synapse.nucleus.receivers.Count > 1) {
|
||||
// there is another nucleus feeding into this input nucleus
|
||||
synapse.nucleus.receivers.RemoveAll(r => r.nucleus == nucleus);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
// No other links, delete it.
|
||||
Nucleus.Delete(synapse.nucleus);
|
||||
}
|
||||
}
|
||||
foreach (Receiver receiver in nucleus.receivers)
|
||||
receiver.nucleus.synapses.RemoveAll(s => s.nucleus == nucleus);
|
||||
foreach (Receiver receiver in nucleus.receivers) {
|
||||
if (receiver.nucleus != null && receiver.nucleus.synapses != null)
|
||||
receiver.nucleus.synapses.RemoveAll(s => s.nucleus == nucleus);
|
||||
}
|
||||
|
||||
nucleus.newBrain.nuclei.RemoveAll(n => n == nucleus);
|
||||
nucleus.brain.nuclei.RemoveAll(n => n == nucleus);
|
||||
nucleus.brain.GarbageCollection();
|
||||
}
|
||||
|
||||
public void GetInputFrom(Nucleus input, float weight = 1.0f) {
|
||||
@ -113,6 +137,7 @@ public class Nucleus {
|
||||
Synapse newSynapse = new(nucleus, weight);
|
||||
synapses.Add(newSynapse);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[System.Serializable]
|
||||
@ -139,6 +164,12 @@ public class Synapse {
|
||||
return;
|
||||
}
|
||||
}
|
||||
foreach (Perceptoid perceptoid in brain.perceptei) {
|
||||
if (perceptoid.id == this.nucleusId) {
|
||||
this.nucleus = perceptoid;
|
||||
return;
|
||||
}
|
||||
}
|
||||
Debug.LogError($"Synapse deserialization error: could not find nucleus with id {this.nucleusId}");
|
||||
}
|
||||
}
|
||||
@ -154,16 +185,18 @@ public class Receiver {
|
||||
this.nucleusId = nucleus.id;
|
||||
}
|
||||
|
||||
public void Rebuild(NanoBrainObj brain) {
|
||||
if (brain == null)
|
||||
return;
|
||||
public bool Rebuild(NanoBrainObj brain) {
|
||||
if (brain == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach (Nucleus nucleus in brain.nuclei) {
|
||||
if (nucleus.id == this.nucleusId) {
|
||||
this.nucleus = nucleus;
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Debug.LogError($"Synapse deserialization error: could not find nucleus with id {this.nucleusId}");
|
||||
Debug.LogWarning($"Receiver deserialization error: could not find nucleus with id {this.nucleusId}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -16,11 +16,18 @@ public class Perception : Nucleus {
|
||||
//public HashSet<Receiver> velocityReceivers { get; protected set; }
|
||||
public List<Receiver> velocityReceivers;
|
||||
|
||||
public Perception(NanoBrainObj brain) : base(brain, "Perception") {
|
||||
public Perception(NanoBrainObj brain) : base("Perception") {
|
||||
this.positionReceivers = new();
|
||||
this.velocityReceivers = new();
|
||||
}
|
||||
|
||||
public Perceptoid GetPerception(int thingType = 0) {
|
||||
foreach (Nucleus nucleus in this.brain.nuclei) {
|
||||
if (nucleus is Perceptoid perceptoid && (thingType == 0 || perceptoid.receptor.thingType == thingType))
|
||||
return perceptoid;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void SendPositions(Nucleus receivingNeuroid, int thingType = 0, float weight = 1.0f) {
|
||||
Receiver receiver = new() {
|
||||
@ -55,7 +62,7 @@ public class Perception : Nucleus {
|
||||
for (int i = 0; i < sensoryNeuroids.Length; i++) {
|
||||
if (sensoryNeuroids[i] == null)
|
||||
availableIx = i;
|
||||
else if (sensoryNeuroids[i].receptor.thingId == thingId) {
|
||||
else if (sensoryNeuroids[i].receptor.thingType == thingId) {
|
||||
sensoryNeuroids[i].receptor.position = localPosition;
|
||||
return;
|
||||
}
|
||||
@ -80,7 +87,7 @@ public class Perception : Nucleus {
|
||||
}
|
||||
else {
|
||||
Debug.Log($"new receptor for {thingId} at {availableIx}");
|
||||
neuroid = new(newBrain, thingId, name);
|
||||
neuroid = new(brain, thingId, name);
|
||||
sensoryNeuroids[availableIx] = neuroid;
|
||||
}
|
||||
foreach (Receiver receiver in positionReceivers) {
|
||||
|
||||
156
Assets/NanoBrain/Perceptoid.cs
Normal file
156
Assets/NanoBrain/Perceptoid.cs
Normal file
@ -0,0 +1,156 @@
|
||||
using UnityEngine;
|
||||
|
||||
[System.Serializable]
|
||||
public class Perceptoid : Neuroid {
|
||||
// A neuroid which has no neurons as input
|
||||
// But receives value from a receptor
|
||||
public Receptor receptor;
|
||||
public VelocityNeuroid velocityNeuroid;
|
||||
|
||||
#region Serialization
|
||||
|
||||
[SerializeField]
|
||||
public int thingType;
|
||||
|
||||
public override void Rebuild(NanoBrainObj brain) {
|
||||
base.Rebuild(brain);
|
||||
this.receptor = new Receptor() {
|
||||
neuroid = this
|
||||
};
|
||||
}
|
||||
|
||||
public override void Deserialize(Nucleus nucleus) {
|
||||
base.Deserialize(nucleus);
|
||||
|
||||
if (nucleus is Perceptoid perceptoid)
|
||||
this.receptor.thingType = perceptoid.thingType;
|
||||
|
||||
// Point all receivers to this perceptoid instead of the default nucleus
|
||||
foreach (Receiver receiver in nucleus.receivers) {
|
||||
foreach (Synapse synapse in receiver.nucleus.synapses) {
|
||||
if (synapse.nucleus == nucleus)
|
||||
synapse.nucleus = this;
|
||||
}
|
||||
}
|
||||
// Point all synapses to this perceptoid instead of the default nucleus
|
||||
foreach (Synapse synapse in nucleus.synapses) {
|
||||
foreach (Receiver receiver in synapse.nucleus.receivers) {
|
||||
if (receiver.nucleus == nucleus)
|
||||
receiver.nucleus = this;
|
||||
}
|
||||
}
|
||||
// Copy all the synapses
|
||||
this.synapses = nucleus.synapses;
|
||||
// Copy all receivers
|
||||
this.receivers = nucleus.receivers;
|
||||
}
|
||||
|
||||
#endregion Serialization
|
||||
|
||||
public Perceptoid(NanoBrainObj brain, string name) : base(name) {
|
||||
this.brain = brain;
|
||||
if (this.brain != null) {
|
||||
this.brain.perceptei.Add(this);
|
||||
}
|
||||
else
|
||||
Debug.LogError("No neuroid network");
|
||||
|
||||
this.nucleusType = nameof(Perceptoid);
|
||||
this.name = name;
|
||||
this.receptor = new Receptor {
|
||||
neuroid = this
|
||||
};
|
||||
}
|
||||
|
||||
public Perceptoid(NanoBrainObj brain, int thingType, string name = "sensor") : base(name) {
|
||||
this.brain = brain;
|
||||
if (this.brain != null) {
|
||||
this.brain.perceptei.Add(this);
|
||||
}
|
||||
else
|
||||
Debug.LogError("No neuroid network");
|
||||
|
||||
this.nucleusType = nameof(Perceptoid);
|
||||
this.name = name;
|
||||
this.thingType = thingType;
|
||||
this.receptor = new Receptor {
|
||||
neuroid = this,
|
||||
thingType = thingType
|
||||
};
|
||||
this.velocityNeuroid = new(brain, name + ": velocity");
|
||||
// The velocity neuroid received position data from this
|
||||
this.AddReceiver(velocityNeuroid);
|
||||
}
|
||||
|
||||
public void Replace(int thingType, string name = "sensor") {
|
||||
this.name = name;
|
||||
|
||||
this.thingType = thingType;
|
||||
this.receptor.thingType = thingType;
|
||||
this.receptor.localPosition = Vector3.zero;
|
||||
|
||||
this.outputValue = Vector3.zero;
|
||||
this.receivers = new();
|
||||
this.AddReceiver(velocityNeuroid);
|
||||
|
||||
this.velocityNeuroid.Replace(name + ": velocity");
|
||||
}
|
||||
|
||||
public override void UpdateState() {
|
||||
Vector3 result = receptor.localPosition;
|
||||
foreach (Synapse synapse in this.synapses) {
|
||||
Nucleus nucleus = synapse.nucleus;
|
||||
float weight = synapse.weight;
|
||||
Vector3 direction = nucleus.outputValue.normalized;
|
||||
float magnitude = nucleus.outputValue.magnitude;
|
||||
|
||||
magnitude = weight * Mathf.Pow(magnitude, exponent);
|
||||
if (inverse)
|
||||
magnitude = 1 / magnitude;
|
||||
result += direction * magnitude;
|
||||
}
|
||||
if (average && this.synapses.Count > 0)
|
||||
result /= this.synapses.Count + 1;
|
||||
|
||||
this.outputValue = result;
|
||||
foreach (Receiver receiver in this.receivers)
|
||||
if (receiver.nucleus is Neuroid neuroid)
|
||||
neuroid.SetInput(this);
|
||||
this.stale = 0;
|
||||
}
|
||||
|
||||
public static Perceptoid GetPerception(NanoBrainObj brain, int thingType = 0) {
|
||||
foreach (Nucleus nucleus in brain.nuclei) {
|
||||
if (nucleus is Perceptoid perceptoid && (thingType == 0 || perceptoid.thingType == thingType))
|
||||
return perceptoid;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void ProcessStimulus(NanoBrainObj brain, int thingType, Vector3 lcoalPosition) {
|
||||
Perceptoid selectedPerceptoid = null;
|
||||
foreach (Perceptoid nucleus in brain.perceptei) {
|
||||
if (nucleus is Perceptoid perceptoid && (thingType == 0 || perceptoid.thingType == thingType))
|
||||
if (selectedPerceptoid == null) {
|
||||
selectedPerceptoid = perceptoid;
|
||||
if (perceptoid.isSleeping) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (perceptoid.receptor.position.magnitude < selectedPerceptoid.receptor.position.magnitude)
|
||||
selectedPerceptoid = perceptoid;
|
||||
}
|
||||
if (selectedPerceptoid == null) {
|
||||
Debug.Log("No perceptoid selected, stimulus is ignored");
|
||||
return;
|
||||
}
|
||||
selectedPerceptoid.receptor.position = lcoalPosition;
|
||||
}
|
||||
public static Receptor GetReceptor(NanoBrainObj brain, int thingType) {
|
||||
foreach (Perceptoid perceptoid in brain.perceptei) {
|
||||
if (thingType == 0 || perceptoid.thingType == thingType)
|
||||
return perceptoid.receptor;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
2
Assets/NanoBrain/Perceptoid.cs.meta
Normal file
2
Assets/NanoBrain/Perceptoid.cs.meta
Normal file
@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 702f634001a21a9d7ae1057c8ce356e9
|
||||
@ -1,12 +1,11 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
public class Receptor {
|
||||
|
||||
public SensoryNeuroid neuroid;
|
||||
public Neuroid neuroid;
|
||||
|
||||
public int thingId;
|
||||
public int thingType;
|
||||
public Vector3 localPosition;
|
||||
|
||||
/// <summary>
|
||||
@ -33,7 +32,7 @@ public class SensoryNeuroid : Neuroid {
|
||||
this.name = name + ": position";
|
||||
this.receptor = new Receptor {
|
||||
neuroid = this,
|
||||
thingId = thingId
|
||||
thingType = thingId
|
||||
};
|
||||
this.velocityNeuroid = new(brain, name + ": velocity");
|
||||
// The velocity neuroid received position data from this
|
||||
@ -43,7 +42,7 @@ public class SensoryNeuroid : Neuroid {
|
||||
public void Replace(int thingId, string name = "sensor") {
|
||||
this.name = name + ": position";
|
||||
|
||||
this.receptor.thingId = thingId;
|
||||
this.receptor.thingType = thingId;
|
||||
this.receptor.localPosition = Vector3.zero;
|
||||
|
||||
this.outputValue = Vector3.zero;
|
||||
|
||||
@ -11,14 +11,16 @@ public class NanoBrainComponent_Editor : Editor {
|
||||
private SerializedProperty brainProp;
|
||||
|
||||
public void OnEnable() {
|
||||
brainProp = serializedObject.FindProperty(nameof(NanoBrainComponent.brain));
|
||||
if (Application.isPlaying == false)
|
||||
brainProp = serializedObject.FindProperty(nameof(NanoBrainComponent.defaultBrain));
|
||||
}
|
||||
|
||||
public override VisualElement CreateInspectorGUI() {
|
||||
NanoBrainComponent component = target as NanoBrainComponent;
|
||||
NanoBrainObj brain = component.brain;
|
||||
NanoBrainObj brain = Application.isPlaying ? component.brain : component.defaultBrain;
|
||||
|
||||
serializedObject.Update();
|
||||
if (Application.isPlaying == false)
|
||||
serializedObject.Update();
|
||||
|
||||
|
||||
VisualElement root = new();
|
||||
@ -32,9 +34,11 @@ public class NanoBrainComponent_Editor : Editor {
|
||||
|
||||
root.styleSheets.Add(Resources.Load<StyleSheet>("GraphStyles"));
|
||||
|
||||
PropertyField brainField = new(brainProp);
|
||||
brainField.label = "Nano Brain";
|
||||
root.Add(brainField);
|
||||
if (Application.isPlaying == false) {
|
||||
PropertyField brainField = new(brainProp);
|
||||
brainField.label = "Nano Brain";
|
||||
root.Add(brainField);
|
||||
}
|
||||
|
||||
mainContainer = new() {
|
||||
name = "main",
|
||||
@ -70,14 +74,15 @@ public class NanoBrainComponent_Editor : Editor {
|
||||
|
||||
if (brain != null)
|
||||
board.SetGraph(brain, brain.root, inspectorContainer);
|
||||
else
|
||||
Debug.LogWarning(" No brain!");
|
||||
// else
|
||||
// Debug.LogWarning(" No brain!");
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
if (Application.isPlaying == false)
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
return root;
|
||||
}
|
||||
|
||||
private void UpdateLayout(float containerWidth) {
|
||||
private void UpdateLayout(float containerWidth) {
|
||||
if (containerWidth > 800f) {
|
||||
mainContainer.style.flexDirection = FlexDirection.Row;
|
||||
inspectorContainer.style.width = 400; // fixed sidebar width
|
||||
|
||||
@ -299,7 +299,7 @@ public class GraphBoardView : VisualElement {
|
||||
if (neuroid is SensoryNeuroid sensoryNeuroid) {
|
||||
tooltip = new(
|
||||
$"{sensoryNeuroid.name}" +
|
||||
$"\nThing {sensoryNeuroid.receptor.thingId}" +
|
||||
$"\nThing {sensoryNeuroid.receptor.thingType}" +
|
||||
$"\nValue: {neuroid.outputValue}" +
|
||||
$"\nStale: {neuroid.stale}");
|
||||
}
|
||||
|
||||
@ -104,7 +104,8 @@ public class NanoBrainInspector : Editor {
|
||||
|
||||
public void SetGraph(NanoBrainObj brain, Nucleus nucleus, VisualElement inspectorContainer) {
|
||||
this.brain = brain;
|
||||
this.serializedBrain = new SerializedObject(brain);
|
||||
if (Application.isPlaying == false)
|
||||
this.serializedBrain = new SerializedObject(brain);
|
||||
this.currentNucleus = nucleus;
|
||||
Rebuild(inspectorContainer);
|
||||
}
|
||||
@ -212,17 +213,130 @@ public class NanoBrainInspector : Editor {
|
||||
if (currentNucleus == null)
|
||||
return;
|
||||
|
||||
serializedBrain.Update();
|
||||
if (Application.isPlaying == false)
|
||||
serializedBrain.Update();
|
||||
|
||||
Handles.BeginGUI();
|
||||
foreach (NeuroidLayer layer in layers)
|
||||
DrawLayer(layer);
|
||||
DrawGraph();
|
||||
// foreach (NeuroidLayer layer in layers)
|
||||
// DrawLayer(layer);
|
||||
Handles.EndGUI();
|
||||
|
||||
}
|
||||
|
||||
private void DrawGraph() {
|
||||
float size = 20;
|
||||
Vector3 position = new(200, 210, 0);
|
||||
|
||||
DrawReceivers(this.currentNucleus, position, size);
|
||||
DrawSynapses(this.currentNucleus, position, size);
|
||||
|
||||
// Draw selected Nucleus
|
||||
Handles.color = Color.white;
|
||||
Handles.DrawSolidDisc(position, Vector3.forward, size + 2);
|
||||
DrawNucleus(this.currentNucleus, position, this.currentNucleus.outputValue.magnitude, 20);
|
||||
}
|
||||
|
||||
private void DrawNucleus(Nucleus nucleus, Vector3 position, float maxValue, float size) {
|
||||
if (nucleus.isSleeping)
|
||||
Handles.color = Color.darkRed;
|
||||
else {
|
||||
float brightness = nucleus.outputValue.magnitude / maxValue;
|
||||
Handles.color = new Color(brightness, brightness, brightness);
|
||||
}
|
||||
Handles.DrawSolidDisc(position, Vector3.forward, size);
|
||||
Vector3 labelPos = position - 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, nucleus.name, style);
|
||||
|
||||
Rect neuronRect = new(position.x - size, position.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(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();
|
||||
HandleClicked(nucleus);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawReceivers(Nucleus nucleus, Vector3 parentPos, float size) {
|
||||
int nodeCount = nucleus.receivers.Count;
|
||||
|
||||
// Determine the maximum value in this layer
|
||||
// This is used to 'scale' the output value colors of the nuclei
|
||||
float maxValue = 0;
|
||||
foreach (Receiver receiver in nucleus.receivers) {
|
||||
if (receiver.nucleus is Neuroid neuroid) {
|
||||
float value = neuroid.outputValue.magnitude;
|
||||
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 (Receiver receiver in nucleus.receivers) {
|
||||
Nucleus receiverNucleus = receiver.nucleus;
|
||||
|
||||
Vector3 pos = new(100, margin + row * spacing, 0.0f);
|
||||
Handles.color = Color.white;
|
||||
Handles.DrawLine(parentPos, pos);
|
||||
|
||||
DrawNucleus(receiverNucleus, pos, maxValue, size);
|
||||
row++;
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawSynapses(Nucleus nucleus, Vector3 parentPos, float size) {
|
||||
int nodeCount = nucleus.synapses.Count;
|
||||
|
||||
// Determine the maximum value in this layer
|
||||
// This is used to 'scale' the output value colors of the nuclei
|
||||
float maxValue = 0;
|
||||
foreach (Synapse receiver in nucleus.synapses) {
|
||||
if (receiver.nucleus is Neuroid neuroid) {
|
||||
float value = neuroid.outputValue.magnitude;
|
||||
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 (Synapse receiver in nucleus.synapses) {
|
||||
Nucleus receiverNucleus = receiver.nucleus;
|
||||
|
||||
Vector3 pos = new(300, margin + row * spacing, 0.0f);
|
||||
Handles.color = Color.white;
|
||||
Handles.DrawLine(parentPos, pos);
|
||||
|
||||
DrawNucleus(receiverNucleus, pos, maxValue, size);
|
||||
row++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
private void DrawLayer(NeuroidLayer layer) {
|
||||
int nodeCount = layer.neuroids.Count;
|
||||
|
||||
// Determine the maximum value in this layer
|
||||
// This is used to 'scale' the output value colors of the nuclei
|
||||
float maxValue = 0;
|
||||
foreach (Nucleus nucleus in layer.neuroids) {
|
||||
if (nucleus is Neuroid neuroid) {
|
||||
@ -231,8 +345,11 @@ public class NanoBrainInspector : Editor {
|
||||
maxValue = value;
|
||||
}
|
||||
}
|
||||
|
||||
// Determine the spacing of the nuclei in the layer
|
||||
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);
|
||||
@ -240,11 +357,9 @@ public class NanoBrainInspector : Editor {
|
||||
float inputSpacing = 400f / layerNucleus.synapses.Count;
|
||||
float inputMargin = 10 + inputSpacing / 2;
|
||||
int minStale = 10000;
|
||||
Debug.Log($"layer neuron {layerNucleus.name} has {layerNucleus.synapses.Count} synapses");
|
||||
foreach (Synapse synapse in layerNucleus.synapses) {
|
||||
Nucleus nucleus = synapse.nucleus;
|
||||
if (nucleus != null) {
|
||||
Debug.Log($"Synapse to {nucleus.name} is valid"); float weight = synapse.weight;
|
||||
if (this.neuroidPositions.ContainsKey(nucleus)) {
|
||||
Vector2Int inputNeuroidPos = this.neuroidPositions[nucleus];
|
||||
if (inputNeuroidPos.x == layerNeuroidPos.x + 1) {
|
||||
@ -265,20 +380,21 @@ public class NanoBrainInspector : Editor {
|
||||
Handles.color = Color.white;
|
||||
Handles.DrawSolidDisc(parentPos, Vector3.forward, size + 2);
|
||||
}
|
||||
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);
|
||||
DrawNucleus(layerNucleus, parentPos, maxValue, size);
|
||||
// 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);
|
||||
@ -296,13 +412,14 @@ public class NanoBrainInspector : Editor {
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
private void HandleMouseHover(Nucleus neuroid, Rect rect) {
|
||||
GUIContent tooltip;
|
||||
if (neuroid is SensoryNeuroid sensoryNeuroid) {
|
||||
tooltip = new(
|
||||
$"{sensoryNeuroid.name}" +
|
||||
$"\nThing {sensoryNeuroid.receptor.thingId}" +
|
||||
$"\nThing {sensoryNeuroid.receptor.thingType}" +
|
||||
$"\nValue: {neuroid.outputValue}" +
|
||||
$"\nStale: {neuroid.stale}");
|
||||
}
|
||||
@ -343,7 +460,11 @@ public class NanoBrainInspector : Editor {
|
||||
if (so.targetObject == null)
|
||||
return;
|
||||
so.Update();
|
||||
if (this.currentNucleus == null)
|
||||
return;
|
||||
this.currentNucleus.name = EditorGUILayout.TextField(this.currentNucleus.name);
|
||||
if (this.currentNucleus is Perceptoid currentPerceptoid)
|
||||
currentPerceptoid.thingType = EditorGUILayout.IntField("Thing Type", currentPerceptoid.thingType);
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
EditorGUILayout.LabelField("Output Value", GUILayout.Width(100));
|
||||
EditorGUILayout.Vector3Field(GUIContent.none, this.currentNucleus.outputValue);
|
||||
@ -359,8 +480,15 @@ public class NanoBrainInspector : Editor {
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
EditorGUILayout.LabelField(synapse.nucleus.name, GUILayout.Width(120));
|
||||
EditorGUI.indentLevel--;
|
||||
// if (synapse.nucleus is Perceptoid perceptoid) {
|
||||
// EditorGUILayout.LabelField("Thing", GUILayout.Width(45));
|
||||
// perceptoid.thingType = EditorGUILayout.IntField(perceptoid.thingType, GUILayout.Width(40));
|
||||
|
||||
// }
|
||||
// else {
|
||||
EditorGUILayout.LabelField("Weight", GUILayout.Width(45));
|
||||
synapse.weight = EditorGUILayout.FloatField(synapse.weight, GUILayout.Width(40));
|
||||
// }
|
||||
EditorGUI.indentLevel++;
|
||||
EditorGUILayout.Vector3Field(GUIContent.none, synapse.nucleus.outputValue, GUILayout.Width(180));
|
||||
EditorGUILayout.EndHorizontal();
|
||||
@ -372,10 +500,8 @@ public class NanoBrainInspector : Editor {
|
||||
}
|
||||
if (GUILayout.Button("Add Neuron"))
|
||||
AddInputNeuron(this.currentNucleus);
|
||||
if (GUILayout.Button("Add Position Perception"))
|
||||
AddPositionPerception(this.currentNucleus);
|
||||
if (GUILayout.Button("Add Velocity Perception"))
|
||||
AddVelocityPerception(this.currentNucleus);
|
||||
if (GUILayout.Button("Add Perceptoid"))
|
||||
AddPerceptoid(this.currentNucleus);
|
||||
if (GUILayout.Button("Delete this neuron"))
|
||||
DeleteNeuron(this.currentNucleus);
|
||||
|
||||
@ -384,9 +510,9 @@ public class NanoBrainInspector : Editor {
|
||||
inspectorContainer.Add(container);
|
||||
}
|
||||
|
||||
protected virtual void AddInputNeuron(Nucleus receiver) {
|
||||
protected virtual void AddInputNeuron(Nucleus nucleus) {
|
||||
Neuroid newNeuroid = new(this.brain, "New neuron");
|
||||
newNeuroid.AddReceiver(receiver);
|
||||
newNeuroid.AddReceiver(nucleus);
|
||||
//Rebuild(inspectorContainer);
|
||||
BuildLayers();
|
||||
}
|
||||
@ -398,13 +524,19 @@ public class NanoBrainInspector : Editor {
|
||||
BuildLayers();
|
||||
}
|
||||
|
||||
protected virtual void AddPositionPerception(Nucleus receiver) {
|
||||
this.brain.perception.SendPositions(receiver);
|
||||
}
|
||||
protected virtual void AddVelocityPerception(Nucleus receiver) {
|
||||
this.brain.perception.SendVelocities(receiver);
|
||||
protected virtual void AddPerceptoid(Nucleus nucleus) {
|
||||
Perceptoid newPerceptoid = new(this.brain, 0, "New Perceptoid");
|
||||
newPerceptoid.AddReceiver(nucleus);
|
||||
BuildLayers();
|
||||
}
|
||||
|
||||
// protected virtual void AddPositionPerception(Nucleus receiver) {
|
||||
// this.brain.perception.SendPositions(receiver);
|
||||
// }
|
||||
// protected virtual void AddVelocityPerception(Nucleus receiver) {
|
||||
// this.brain.perception.SendVelocities(receiver);
|
||||
// }
|
||||
|
||||
private Vector3 NodePosition(Nucleus nucleus, int layerNodeCount = 1) {
|
||||
if (this.neuroidPositions.ContainsKey(nucleus)) {
|
||||
Vector2Int nucleusPos = this.neuroidPositions[nucleus];
|
||||
|
||||
@ -1,15 +1,21 @@
|
||||
using UnityEngine;
|
||||
|
||||
public class NanoBrainComponent : MonoBehaviour {
|
||||
public NanoBrainObj brain;
|
||||
public NanoBrainObj defaultBrain;
|
||||
private NanoBrainObj brainInstance;
|
||||
|
||||
public Nucleus root {
|
||||
get {
|
||||
return brain.root;
|
||||
return brainInstance.root;
|
||||
}
|
||||
}
|
||||
public Perception perception {
|
||||
public NanoBrainObj brain {
|
||||
get {
|
||||
return brain.perception;
|
||||
if (brainInstance == null && defaultBrain != null) {
|
||||
brainInstance = Instantiate(defaultBrain);
|
||||
brainInstance.name = defaultBrain.name + " (Instance)";
|
||||
}
|
||||
return brainInstance;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -9,18 +9,19 @@ public class NanoBrainObj : ScriptableObject, ISerializationCallbackReceiver {
|
||||
public Color color = Color.white;
|
||||
public Texture2D texture;
|
||||
|
||||
public List<Nucleus> nuclei = new();
|
||||
public List<Neuroid> nuclei = new();
|
||||
public List<Perceptoid> perceptei = new();
|
||||
|
||||
// This is probably always the first element in the nuclei list...
|
||||
[System.NonSerialized]
|
||||
public Nucleus root;
|
||||
public int rootId;
|
||||
|
||||
public Perception perception;
|
||||
// public Perception perception;
|
||||
|
||||
public NanoBrainObj() {
|
||||
this.root = new(this, "Root");
|
||||
this.perception = new Perception(this);
|
||||
this.root = new Neuroid(this, "Root");
|
||||
// this.perception = new Perception(this);
|
||||
}
|
||||
|
||||
public Neuroid AddNeuron(string name) {
|
||||
@ -40,10 +41,48 @@ public class NanoBrainObj : ScriptableObject, ISerializationCallbackReceiver {
|
||||
this.rootId = root.id;
|
||||
}
|
||||
public void OnAfterDeserialize() {
|
||||
foreach (Nucleus nucleus in nuclei) {
|
||||
if (this.rootId == nucleus.id)
|
||||
this.root = nucleus;
|
||||
nucleus.Rebuild(this);
|
||||
try {
|
||||
foreach (Nucleus nucleus in this.nuclei.ToArray()) {
|
||||
if (this.rootId == nucleus.id)
|
||||
this.root = nucleus;
|
||||
nucleus.Rebuild(this);
|
||||
}
|
||||
|
||||
// List<Nucleus> rebuildNuclei = new();
|
||||
// foreach (Nucleus nucleus in this.nuclei.ToArray()) {
|
||||
// rebuildNuclei.Add(Nucleus.RebuildType(this, nucleus));
|
||||
// }
|
||||
// this.nuclei = rebuildNuclei;
|
||||
foreach (Perceptoid perceptoid in this.perceptei.ToArray()) {
|
||||
perceptoid.Rebuild(this);
|
||||
}
|
||||
}
|
||||
catch (System.Exception) { }
|
||||
this.GarbageCollection();
|
||||
}
|
||||
|
||||
public void GarbageCollection() {
|
||||
HashSet<Nucleus> visitedNuclei = new();
|
||||
MarkNuclei(visitedNuclei, this.root);
|
||||
Debug.Log($"Garbage collection found {visitedNuclei.Count} Nuclei");
|
||||
this.nuclei.RemoveAll(nucleus => visitedNuclei.Contains(nucleus) == false);
|
||||
this.perceptei.RemoveAll(perceptoid => visitedNuclei.Contains(perceptoid) == false);
|
||||
}
|
||||
|
||||
public void MarkNuclei(HashSet<Nucleus> visitedNuclei, Nucleus nucleus) {
|
||||
if (nucleus is null)
|
||||
return;
|
||||
|
||||
visitedNuclei.Add(nucleus);
|
||||
if (nucleus.synapses != null) {
|
||||
HashSet<Synapse> visitedSynapses = new();
|
||||
foreach (Synapse synapse in nucleus.synapses) {
|
||||
if (synapse != null && synapse.nucleus != null) {
|
||||
visitedSynapses.Add(synapse);
|
||||
MarkNuclei(visitedNuclei, synapse.nucleus);
|
||||
}
|
||||
}
|
||||
nucleus.synapses.RemoveAll(synapse => visitedSynapses.Contains(synapse) == false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -393,7 +393,7 @@ MonoBehaviour:
|
||||
m_Script: {fileID: 11500000, guid: ec888ca5333d45a438f9f417fa5ce135, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: Assembly-CSharp::SwarmSpawn
|
||||
count: 1
|
||||
count: 3
|
||||
boidPrefab: {fileID: 8702527964058765413, guid: f9c706268554ce449a8773675b2864b8, type: 3}
|
||||
spawnAreaSize: {x: 0.5, y: 0.5, z: 0.5}
|
||||
minDelay: 0.05
|
||||
|
||||
@ -1,60 +0,0 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!114 &11400000
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 36081359186edfec998d891a1feeb17b, type: 3}
|
||||
m_Name: New Nano Brain Obj
|
||||
m_EditorClassIdentifier: Assembly-CSharp::NanoBrainObj
|
||||
title:
|
||||
count: -26
|
||||
color: {r: 1, g: 1, b: 1, a: 1}
|
||||
texture: {fileID: 0}
|
||||
nuclei:
|
||||
- id: 257807948
|
||||
_name: Root
|
||||
synapses:
|
||||
- nucleusId: -651011940
|
||||
weight: 1
|
||||
- nucleusId: -1689048724
|
||||
weight: 1
|
||||
receivers: []
|
||||
- id: -1868865374
|
||||
_name: Perception
|
||||
synapses: []
|
||||
receivers: []
|
||||
- id: -651011940
|
||||
_name: Neuron 1
|
||||
synapses: []
|
||||
receivers:
|
||||
- nucleusId: 257807948
|
||||
- id: -1689048724
|
||||
_name: New neuron
|
||||
synapses: []
|
||||
receivers:
|
||||
- nucleusId: 257807948
|
||||
- id: -152927560
|
||||
_name: 'Boundary: position'
|
||||
synapses: []
|
||||
receivers:
|
||||
- nucleusId: -1462684836
|
||||
- id: -1462684836
|
||||
_name: 'Boundary: velocity'
|
||||
synapses:
|
||||
- nucleusId: -152927560
|
||||
weight: 1
|
||||
receivers: []
|
||||
rootId: 257807948
|
||||
perception:
|
||||
id: 1565766940
|
||||
_name: Perception
|
||||
synapses: []
|
||||
receivers: []
|
||||
positionReceivers: []
|
||||
velocityReceivers: []
|
||||
@ -176,4 +176,4 @@ MonoBehaviour:
|
||||
m_Script: {fileID: 11500000, guid: 92f34a5e4027a1dc39efd8ce63cf6aba, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: Assembly-CSharp::NanoBrainComponent
|
||||
brain: {fileID: 11400000, guid: af8d90b8b4b9dcad7837130c4143d91c, type: 2}
|
||||
defaultBrain: {fileID: 11400000, guid: fc1a4800a8c531eb4855b436bc9084ae, type: 2}
|
||||
|
||||
@ -17,86 +17,36 @@ MonoBehaviour:
|
||||
color: {r: 1, g: 1, b: 1, a: 1}
|
||||
texture: {fileID: 0}
|
||||
nuclei:
|
||||
- id: -1753291412
|
||||
- id: -1707533328
|
||||
_name: Root
|
||||
synapses:
|
||||
- nucleusId: 237822944
|
||||
- nucleusId: -112538112
|
||||
weight: 1
|
||||
receivers: []
|
||||
- id: 472852910
|
||||
_name: Perception
|
||||
synapses: []
|
||||
receivers: []
|
||||
- id: 237822944
|
||||
nucleusType:
|
||||
average: 0
|
||||
inverse: 0
|
||||
exponent: 1
|
||||
- id: -112538112
|
||||
_name: Avoidance
|
||||
synapses: []
|
||||
receivers:
|
||||
- nucleusId: -1753291412
|
||||
- id: 983561152
|
||||
_name: 'Boundary: position'
|
||||
synapses: []
|
||||
receivers:
|
||||
- nucleusId: -1818801134
|
||||
- id: -1818801134
|
||||
_name: 'Boundary: velocity'
|
||||
synapses:
|
||||
- nucleusId: 983561152
|
||||
weight: 1
|
||||
receivers: []
|
||||
- id: 1386590800
|
||||
_name: 'Boundary: position'
|
||||
- nucleusId: 407735232
|
||||
weight: -1
|
||||
receivers:
|
||||
- nucleusId: -1707533328
|
||||
nucleusType:
|
||||
average: 0
|
||||
inverse: 0
|
||||
exponent: 1
|
||||
perceptei:
|
||||
- id: 407735232
|
||||
_name: Boundary
|
||||
synapses: []
|
||||
receivers:
|
||||
- nucleusId: -1415771486
|
||||
- nucleusId: 237822944
|
||||
- id: -1415771486
|
||||
_name: 'Boundary: velocity'
|
||||
synapses:
|
||||
- nucleusId: 1386590800
|
||||
weight: 1
|
||||
receivers: []
|
||||
- id: -213085248
|
||||
_name: 'Boundary: position'
|
||||
synapses: []
|
||||
receivers:
|
||||
- nucleusId: 1279519762
|
||||
- nucleusId: 237822944
|
||||
- id: 1279519762
|
||||
_name: 'Boundary: velocity'
|
||||
synapses:
|
||||
- nucleusId: -213085248
|
||||
weight: 1
|
||||
receivers: []
|
||||
- id: 1783940116
|
||||
_name: 'Boundary: position'
|
||||
synapses: []
|
||||
receivers:
|
||||
- nucleusId: -1018422170
|
||||
- nucleusId: 237822944
|
||||
- id: -1018422170
|
||||
_name: 'Boundary: velocity'
|
||||
synapses:
|
||||
- nucleusId: 1783940116
|
||||
weight: 1
|
||||
receivers: []
|
||||
rootId: -1753291412
|
||||
perception:
|
||||
id: 2139386530
|
||||
_name: Perception
|
||||
synapses: []
|
||||
receivers: []
|
||||
positionReceivers:
|
||||
- thingType: 0
|
||||
neuroid:
|
||||
id: 237822944
|
||||
_name: Avoidance
|
||||
synapses:
|
||||
- nucleusId: 1386590800
|
||||
weight: 1
|
||||
- nucleusId: -213085248
|
||||
weight: 1
|
||||
- nucleusId: 1783940116
|
||||
weight: 1
|
||||
receivers:
|
||||
- nucleusId: -1753291412
|
||||
velocityReceivers: []
|
||||
- nucleusId: -112538112
|
||||
nucleusType: Perceptoid
|
||||
average: 0
|
||||
inverse: 0
|
||||
exponent: 1
|
||||
thingType: 1
|
||||
rootId: -1707533328
|
||||
|
||||
@ -13,32 +13,21 @@ public class Boid : MonoBehaviour {
|
||||
private Bounds innerBounds;
|
||||
|
||||
public NanoBrainComponent nanoBrain;
|
||||
|
||||
// public NanoBrain neuroidNet;
|
||||
// public Perception perception;
|
||||
|
||||
// public Nucleus behaviour;
|
||||
|
||||
// public Neuroid totalForce;
|
||||
public Receptor boundaryReceptor;
|
||||
public Receptor boidReceptor;
|
||||
|
||||
public int id;
|
||||
|
||||
void Awake() {
|
||||
nanoBrain = GetComponent<NanoBrainComponent>();
|
||||
this.id = this.GetInstanceID();
|
||||
|
||||
nanoBrain = GetComponent<NanoBrainComponent>();
|
||||
boundaryReceptor = Perceptoid.GetReceptor(nanoBrain.brain, BoundaryType);
|
||||
boidReceptor = Perceptoid.GetReceptor(nanoBrain.brain, BoidType);
|
||||
|
||||
sc = FindFirstObjectByType<SwarmControl>();
|
||||
|
||||
innerBounds = new(sc.transform.position, sc.spaceSize - 2 * sc.boundaryWidth);
|
||||
|
||||
// neuroidNet = GetComponent<NanoBrain>();
|
||||
// perception = new Perception(neuroidNet);
|
||||
|
||||
// //behaviour = new Roaming(neuroidNet, perception, sc);
|
||||
// behaviour = new Swarming(neuroidNet, perception, sc);
|
||||
|
||||
// totalForce = new(neuroidNet, "Total");
|
||||
// behaviour.AddReceiver(totalForce);
|
||||
}
|
||||
|
||||
void Update() {
|
||||
@ -52,8 +41,9 @@ public class Boid : MonoBehaviour {
|
||||
Vector3 localPosition = this.transform.InverseTransformPoint(neighbour.transform.position);
|
||||
//Debug.DrawRay(this.transform.position, this.transform.TransformDirection(localPosition), Color.magenta);
|
||||
|
||||
int thingId = neighbour.GetInstanceID();
|
||||
nanoBrain.perception.ProcessStimulus(thingId, BoidType, localPosition, neighbour.gameObject.name);
|
||||
//int thingId = neighbour.GetInstanceID();
|
||||
// nanoBrain.perception.ProcessStimulus(thingId, BoidType, localPosition, neighbour.gameObject.name);
|
||||
boidReceptor.position = localPosition;
|
||||
}
|
||||
}
|
||||
|
||||
@ -62,10 +52,9 @@ public class Boid : MonoBehaviour {
|
||||
Vector3 pointOnBounds = innerBounds.ClosestPoint(point);
|
||||
Vector3 desiredWorldSpace = (pointOnBounds - point).normalized * sc.speed;
|
||||
Vector3 desiredLocalSpace = -this.transform.InverseTransformPoint(desiredWorldSpace);
|
||||
nanoBrain.perception.ProcessStimulus(777, BoundaryType, desiredLocalSpace, "Boundary");
|
||||
boundaryReceptor.position = desiredLocalSpace;
|
||||
}
|
||||
|
||||
//Vector3 worldForce = this.transform.TransformDirection(behaviour.outputValue);
|
||||
Vector3 worldForce = this.transform.TransformDirection(nanoBrain.root.outputValue);
|
||||
|
||||
this.velocity = (1 - sc.inertia) * (worldForce * Time.deltaTime) + sc.inertia * velocity;
|
||||
@ -82,7 +71,6 @@ public class Boid : MonoBehaviour {
|
||||
transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, Time.deltaTime * 2f); // Adjust the speed of rotation
|
||||
}
|
||||
|
||||
//neuroidNet.UpdateNeurons();
|
||||
nanoBrain.brain.UpdateNuclei();
|
||||
}
|
||||
|
||||
|
||||
@ -3,7 +3,7 @@ public class Roaming : Nucleus {
|
||||
|
||||
public Neuroid output;
|
||||
|
||||
public Roaming(NanoBrainObj brain, Perception perception, SwarmControl sc) : base(null, "Roaming nucleus") {
|
||||
public Roaming(NanoBrainObj brain, Perception perception, SwarmControl sc) : base("Roaming nucleus") {
|
||||
avoidance = new(brain, "Avoidance") { inverse = true };
|
||||
perception.SendPositions(avoidance, Boid.BoundaryType);
|
||||
|
||||
|
||||
@ -10,7 +10,7 @@ public class Swarming : Nucleus {
|
||||
|
||||
public override Vector3 outputValue { get => output.outputValue; set => output.outputValue = value; }
|
||||
|
||||
public Swarming(NanoBrainObj brain, Perception perception, SwarmControl sc) : base(null, "Swarming Nucleus") {
|
||||
public Swarming(NanoBrainObj brain, Perception perception, SwarmControl sc) : base("Swarming Nucleus") {
|
||||
this.cohesion = new(brain, "Cohesion") { inverse = false };
|
||||
perception.SendPositions(this.cohesion, Boid.BoidType);
|
||||
|
||||
|
||||
88
Assets/Scenes/Boids/SwarmingBrain.asset
Normal file
88
Assets/Scenes/Boids/SwarmingBrain.asset
Normal file
@ -0,0 +1,88 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!114 &11400000
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 36081359186edfec998d891a1feeb17b, type: 3}
|
||||
m_Name: SwarmingBrain
|
||||
m_EditorClassIdentifier: Assembly-CSharp::NanoBrainObj
|
||||
title:
|
||||
count: 0
|
||||
color: {r: 1, g: 1, b: 1, a: 1}
|
||||
texture: {fileID: 0}
|
||||
nuclei:
|
||||
- id: -1707533328
|
||||
_name: Root
|
||||
synapses:
|
||||
- nucleusId: -112538112
|
||||
weight: 1
|
||||
- nucleusId: 1938577052
|
||||
weight: 1
|
||||
receivers: []
|
||||
nucleusType:
|
||||
average: 0
|
||||
inverse: 0
|
||||
exponent: 1
|
||||
- id: -112538112
|
||||
_name: Avoidance
|
||||
synapses:
|
||||
- nucleusId: 407735232
|
||||
weight: -1
|
||||
receivers:
|
||||
- nucleusId: -1707533328
|
||||
nucleusType:
|
||||
average: 0
|
||||
inverse: 0
|
||||
exponent: 1
|
||||
- id: 1938577052
|
||||
_name: Cohesion
|
||||
synapses:
|
||||
- nucleusId: -1408496896
|
||||
weight: 1
|
||||
- nucleusId: -133566816
|
||||
weight: 1
|
||||
receivers:
|
||||
- nucleusId: -1707533328
|
||||
nucleusType:
|
||||
average: 0
|
||||
inverse: 0
|
||||
exponent: 1
|
||||
perceptei:
|
||||
- id: 407735232
|
||||
_name: Boundary
|
||||
synapses: []
|
||||
receivers:
|
||||
- nucleusId: -112538112
|
||||
nucleusType: Perceptoid
|
||||
average: 0
|
||||
inverse: 0
|
||||
exponent: 1
|
||||
thingType: 1
|
||||
- id: -1408496896
|
||||
_name: Boid1
|
||||
synapses: []
|
||||
receivers:
|
||||
- nucleusId: 1938577052
|
||||
nucleusType: Perceptoid
|
||||
average: 0
|
||||
inverse: 0
|
||||
exponent: 1
|
||||
thingType: 2
|
||||
- id: -133566816
|
||||
_name: Boid2
|
||||
synapses: []
|
||||
receivers:
|
||||
- nucleusId: 27651644
|
||||
- nucleusId: 1938577052
|
||||
nucleusType: Perceptoid
|
||||
average: 0
|
||||
inverse: 0
|
||||
exponent: 1
|
||||
thingType: 2
|
||||
rootId: -1707533328
|
||||
@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 55099766f6f09071ab4e8c89b02fa302
|
||||
guid: fc1a4800a8c531eb4855b436bc9084ae
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 11400000
|
||||
Loading…
x
Reference in New Issue
Block a user