Boids seem to work, but don't flock together
This commit is contained in:
parent
2e803179e3
commit
1771ab7d23
@ -37,6 +37,11 @@ public class GraphEditorWindow : EditorWindow {
|
||||
int neuroidIx = 0;
|
||||
|
||||
foreach (Neuroid neuroid in neuroids) {
|
||||
if (neuroid.IsStale()) {
|
||||
neuronVisited.Add(neuroid);
|
||||
continue;
|
||||
}
|
||||
|
||||
// If this neuroid is not visited while its output neuroid is visited
|
||||
if (!neuronVisited.Contains(neuroid) && (neuroid.outputNeuroid == null ||
|
||||
(neuronVisited.Contains(neuroid.outputNeuroid) && neuroid.outputNeuroid.layerIx == layerIx - 1))) {
|
||||
@ -109,17 +114,23 @@ public class GraphEditorWindow : EditorWindow {
|
||||
float inputMargin = 100 + inputSpacing / 2;
|
||||
foreach (Synapse synapse in layerNeuroid.synapses.Values) {
|
||||
if (synapse.neuroid != null) {
|
||||
Vector2Int inputNeuroidPos = this.neuroidPositions[synapse.neuroid];
|
||||
Vector3 pos = new(100 + inputNeuroidPos.x * 100, inputMargin + inputNeuroidPos.y * inputSpacing, 0.0f);
|
||||
if (this.neuroidPositions.ContainsKey(synapse.neuroid)) {
|
||||
|
||||
float brightness = synapse.weight / 10.0f;
|
||||
Handles.color = new Color(brightness, brightness, brightness);
|
||||
Handles.DrawLine(parentPos, pos);
|
||||
Vector2Int inputNeuroidPos = this.neuroidPositions[synapse.neuroid];
|
||||
Vector3 pos = new(100 + inputNeuroidPos.x * 100, inputMargin + inputNeuroidPos.y * inputSpacing, 0.0f);
|
||||
|
||||
float brightness = synapse.weight / 10.0f;
|
||||
Handles.color = new Color(brightness, brightness, brightness);
|
||||
Handles.DrawLine(parentPos, pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float size = layerNeuroid.outputValue.magnitude / maxValue * 20;
|
||||
Handles.color = Color.white;
|
||||
if (layerNeuroid.IsStale())
|
||||
Handles.color = Color.yellow;
|
||||
else
|
||||
Handles.color = Color.white;
|
||||
Handles.DrawSolidDisc(parentPos, Vector3.forward, size);
|
||||
Rect neuronRect = new(parentPos.x - size, parentPos.y - size, size * 2, size * 2);
|
||||
if (neuronRect.Contains(Event.current.mousePosition))
|
||||
@ -131,7 +142,12 @@ public class GraphEditorWindow : EditorWindow {
|
||||
|
||||
private void HandleMouseHover(Neuroid neuroid, Rect rect) {
|
||||
// Draw the tooltip
|
||||
GUIContent tooltip = new($"{neuroid.name}\n synapse count {neuroid.synapses.Count} \n Value: {neuroid.outputValue}");
|
||||
GUIContent 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
|
||||
|
||||
@ -20,6 +20,12 @@ public class NeuroidNetwork {
|
||||
Neuroid neuroid = new(this);
|
||||
return neuroid;
|
||||
}
|
||||
|
||||
public void Update() {
|
||||
foreach (Neuroid neuroid in neuroids) {
|
||||
neuroid.stale++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class Neuroid {
|
||||
@ -27,6 +33,7 @@ public class Neuroid {
|
||||
public string name;
|
||||
|
||||
public int layerIx;
|
||||
public int stale = 0;
|
||||
|
||||
public readonly Dictionary<int, Synapse> synapses = new();
|
||||
|
||||
@ -97,6 +104,7 @@ public class Neuroid {
|
||||
|
||||
this.outputValue = Activation(sum);
|
||||
this.outputNeuroid?.SetInput(this.outputNeurix, this.outputValue);
|
||||
this.stale = 0;
|
||||
}
|
||||
|
||||
Vector3 Activation(Vector3 sum) {
|
||||
@ -111,5 +119,9 @@ public class Neuroid {
|
||||
};
|
||||
//return sum; //(sum.magnitude > 0.5f) ? sum : Vector3.zero;
|
||||
}
|
||||
|
||||
public bool IsStale() {
|
||||
return this.stale > 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -7,15 +7,23 @@ public class Receptor {
|
||||
neuroid.SetInput(neuroid.id, value);
|
||||
}
|
||||
}
|
||||
public Vector3 GetValue() {
|
||||
if (neuroid != null)
|
||||
return neuroid.synapses[neuroid.id].value;
|
||||
else
|
||||
return Vector3.zero;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class SensoryNeuroid : Neuroid {
|
||||
public Receptor receptor;
|
||||
public int thingId;
|
||||
|
||||
public SensoryNeuroid(NeuroidNetwork net, int id) : base(net) {
|
||||
this.name = "sensory neuroid";
|
||||
this.id = id;
|
||||
// this.id = id;
|
||||
this.thingId = id;
|
||||
this.receptor = new Receptor {
|
||||
neuroid = this
|
||||
};
|
||||
|
||||
@ -371,14 +371,15 @@ MonoBehaviour:
|
||||
m_Script: {fileID: 11500000, guid: 0464906885ae3494f8fd0314719fb2db, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: Assembly-CSharp::SwarmControl
|
||||
speed: 0.5
|
||||
speed: 1
|
||||
inertia: 0.1
|
||||
alignmentForce: 1
|
||||
cohesionForce: 10
|
||||
alignmentForce: 5
|
||||
cohesionForce: 5
|
||||
separationForce: 5
|
||||
separationDistance: 0.5
|
||||
separationDistance: 0.3
|
||||
bodyForce: 20
|
||||
boundaryForce: 2
|
||||
perceptionDistance: 2
|
||||
boundaryForce: 5
|
||||
spaceSize: {x: 10, y: 10, z: 10}
|
||||
boundaryWidth: {x: 1, y: 1, z: 1}
|
||||
--- !u!114 &301943979
|
||||
@ -393,11 +394,11 @@ MonoBehaviour:
|
||||
m_Script: {fileID: 11500000, guid: ec888ca5333d45a438f9f417fa5ce135, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: Assembly-CSharp::SwarmSpawn
|
||||
count: 100
|
||||
count: 1000
|
||||
boidPrefab: {fileID: 8702527964058765413, guid: f9c706268554ce449a8773675b2864b8, type: 3}
|
||||
spawnAreaSize: {x: 0.5, y: 0.5, z: 0.5}
|
||||
minDelay: 0.1
|
||||
maxDelay: 1
|
||||
minDelay: 0.05
|
||||
maxDelay: 0.2
|
||||
--- !u!4 &301943980
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
|
||||
@ -21,17 +21,17 @@ Material:
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: White
|
||||
m_Shader: {fileID: 4800000, guid: 933532a4fcc9baf4fa0491de14d08ed7, type: 3}
|
||||
m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0}
|
||||
m_Parent: {fileID: 0}
|
||||
m_ModifiedSerializedProperties: 0
|
||||
m_ValidKeywords: []
|
||||
m_ValidKeywords:
|
||||
- _GLOSSYREFLECTIONS_OFF
|
||||
m_InvalidKeywords: []
|
||||
m_LightmapFlags: 4
|
||||
m_EnableInstancingVariants: 0
|
||||
m_DoubleSidedGI: 0
|
||||
m_CustomRenderQueue: -1
|
||||
stringTagMap:
|
||||
RenderType: Opaque
|
||||
stringTagMap: {}
|
||||
disabledShaderPasses:
|
||||
- MOTIONVECTORS
|
||||
m_LockedProperties:
|
||||
@ -115,6 +115,7 @@ Material:
|
||||
- _Glossiness: 0
|
||||
- _GlossyReflections: 0
|
||||
- _Metallic: 0
|
||||
- _Mode: 0
|
||||
- _OcclusionStrength: 1
|
||||
- _Parallax: 0.005
|
||||
- _QueueOffset: 0
|
||||
@ -125,12 +126,13 @@ Material:
|
||||
- _SrcBlend: 1
|
||||
- _SrcBlendAlpha: 1
|
||||
- _Surface: 0
|
||||
- _UVSec: 0
|
||||
- _WorkflowMode: 1
|
||||
- _XRMotionVectorsPass: 1
|
||||
- _ZWrite: 1
|
||||
m_Colors:
|
||||
- _BaseColor: {r: 1, g: 1, b: 1, a: 1}
|
||||
- _Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
- _BaseColor: {r: 1, g: 0.9858491, b: 0.9858491, a: 1}
|
||||
- _Color: {r: 0.41509432, g: 0.41509432, b: 0.41509432, a: 1}
|
||||
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
|
||||
- _SpecColor: {r: 0.19999996, g: 0.19999996, b: 0.19999996, a: 1}
|
||||
m_BuildTextureStacks: []
|
||||
|
||||
@ -59,12 +59,12 @@ public class Boid : MonoBehaviour {
|
||||
}
|
||||
|
||||
void Update() {
|
||||
Physics.OverlapSphereNonAlloc(this.transform.position, 10, results);
|
||||
Physics.OverlapSphereNonAlloc(this.transform.position, sc.perceptionDistance, results);
|
||||
neighbourCount = 0;
|
||||
|
||||
cohesion.ResetWeights();
|
||||
alignment.ResetWeights();
|
||||
separation.ResetWeights();
|
||||
//separation.ResetWeights();
|
||||
|
||||
foreach (Collider c in results) {
|
||||
if (c == null)
|
||||
@ -79,18 +79,16 @@ public class Boid : MonoBehaviour {
|
||||
Vector3 relativeVelocity = neighbour.velocity - this.velocity;
|
||||
|
||||
int id = neighbour.GetInstanceID();
|
||||
Receptor receptor = GetReceptor(id);
|
||||
if (receptor != null) {
|
||||
receptor.SetValue(localPosition);
|
||||
}
|
||||
ProcessStimulus(id, localPosition);
|
||||
|
||||
Vector3 separationForce = -localPosition / localPosition.sqrMagnitude;
|
||||
// which is equivalent to -(localPosition.normalized / localPosition.magnitude)
|
||||
|
||||
separation.SetInput(id, separationForce, sc.separationDistance);
|
||||
//cohesion.SetInput(id, localPosition, sc.cohesionForce);
|
||||
alignment.SetInput(id, relativeVelocity, sc.alignmentForce);
|
||||
|
||||
neighbourCount++;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -126,24 +124,81 @@ public class Boid : MonoBehaviour {
|
||||
Quaternion targetRotation = Quaternion.LookRotation(this.velocity);
|
||||
transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, Time.deltaTime * 2f); // Adjust the speed of rotation
|
||||
}
|
||||
|
||||
//Debug.Log($"neighbours: {neighbourCount} synapses: {cohesion.synapses.Count}");
|
||||
neuroidNet.Update();
|
||||
}
|
||||
|
||||
Receptor GetReceptor(int id) {
|
||||
Receptor GetReceptor(Neuroid perceptionNeuroid, int id) {
|
||||
int availableIx = -1;
|
||||
for (int i = 0; i < neighbourSensor.Length; i++) {
|
||||
if (neighbourSensor[i] == null)
|
||||
if (neighbourSensor[i] == null || neighbourSensor[i].IsStale())
|
||||
availableIx = i;
|
||||
else if (neighbourSensor[i].id == id)
|
||||
else if (neighbourSensor[i].thingId == id)
|
||||
return neighbourSensor[i].receptor;
|
||||
}
|
||||
if (availableIx != -1) {
|
||||
Debug.Log($"new receptor for {id}");
|
||||
SensoryNeuroid neuroid = new(neuroidNet, id);
|
||||
cohesion.GetInputFrom(neuroid);
|
||||
neighbourSensor[availableIx] = neuroid;
|
||||
return neuroid.receptor;
|
||||
if (neighbourSensor[availableIx] != null) {
|
||||
Debug.Log($"revived receptor {availableIx} for {id}");
|
||||
neighbourSensor[availableIx].thingId = id;
|
||||
return neighbourSensor[availableIx].receptor;
|
||||
}
|
||||
else {
|
||||
Debug.Log($"new receptor for {id}");
|
||||
SensoryNeuroid neuroid = new(neuroidNet, id);
|
||||
perceptionNeuroid.GetInputFrom(neuroid);
|
||||
neighbourSensor[availableIx] = neuroid;
|
||||
return neuroid.receptor;
|
||||
}
|
||||
}
|
||||
|
||||
//Debug.LogWarning($"No available receptor for {id}");
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ProcessStimulus(int thingId, Vector3 value) {
|
||||
int availableIx = -1;
|
||||
SensoryNeuroid leastInterestingNeuroid = null;
|
||||
for (int i = 0; i < neighbourSensor.Length; i++) {
|
||||
if (neighbourSensor[i] == null || neighbourSensor[i].IsStale())
|
||||
availableIx = i;
|
||||
else if (neighbourSensor[i].thingId == thingId) {
|
||||
neighbourSensor[i].receptor.SetValue(value);
|
||||
return;
|
||||
}
|
||||
// if (leastInterestingIx == -1 || neighbourSensor[leastInterestingIx].receptor.GetValue().magnitude > neighbourSensor[i].receptor.GetValue().magnitude)
|
||||
// leastInterestingIx = i;
|
||||
if (neighbourSensor[i] != null) {
|
||||
if (leastInterestingNeuroid == null || leastInterestingNeuroid.receptor.GetValue().magnitude > neighbourSensor[i].receptor.GetValue().magnitude)
|
||||
leastInterestingNeuroid = neighbourSensor[i];
|
||||
}
|
||||
}
|
||||
if (availableIx != -1) {
|
||||
if (neighbourSensor[availableIx] != null) {
|
||||
// Debug.Log($"revived receptor {availableIx} for {thingId}");
|
||||
neighbourSensor[availableIx].thingId = thingId;
|
||||
neighbourSensor[availableIx].receptor.SetValue(value);
|
||||
}
|
||||
else {
|
||||
// Debug.Log($"new receptor for {thingId}");
|
||||
SensoryNeuroid neuroid = new(neuroidNet, thingId);
|
||||
cohesion.GetInputFrom(neuroid);
|
||||
neighbourSensor[availableIx] = neuroid;
|
||||
neuroid.receptor.SetValue(value);
|
||||
}
|
||||
}
|
||||
else if (leastInterestingNeuroid != null) {
|
||||
//Debug.Log($"replaced receptor {leastInterestingNeuroid.thingId} for {thingId}");
|
||||
leastInterestingNeuroid.thingId = thingId;
|
||||
leastInterestingNeuroid.receptor.SetValue(value);
|
||||
}
|
||||
|
||||
//Debug.LogWarning($"No available receptor for {id}");
|
||||
}
|
||||
|
||||
void OnDrawGizmosSelected() {
|
||||
Gizmos.DrawWireSphere(transform.position, sc.perceptionDistance);
|
||||
}
|
||||
}
|
||||
|
||||
@ -11,6 +11,7 @@ public class SwarmControl : MonoBehaviour
|
||||
public float separationForce = 5.0f;
|
||||
public float separationDistance = 0.5f;
|
||||
public float bodyForce = 20;
|
||||
public float perceptionDistance = 1.0f;
|
||||
|
||||
public float boundaryForce = 2.0f;
|
||||
public Vector3 spaceSize = new (10, 10, 10);
|
||||
|
||||
8
Assets/_Recovery.meta
Normal file
8
Assets/_Recovery.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 895037c7e323e03ada7f43d011f1390b
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
1123
Assets/_Recovery/0.unity
Normal file
1123
Assets/_Recovery/0.unity
Normal file
File diff suppressed because it is too large
Load Diff
7
Assets/_Recovery/0.unity.meta
Normal file
7
Assets/_Recovery/0.unity.meta
Normal file
@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e5398245724c5668992c64c27db35040
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
19
NanoBrain-Unity.code-workspace
Normal file
19
NanoBrain-Unity.code-workspace
Normal file
@ -0,0 +1,19 @@
|
||||
{
|
||||
"folders": [
|
||||
{
|
||||
"path": "."
|
||||
}
|
||||
],
|
||||
"settings": {
|
||||
"files.associations": {
|
||||
"*.asset": "yaml",
|
||||
"*.meta": "yaml",
|
||||
"*.prefab": "yaml",
|
||||
"*.unity": "yaml"
|
||||
},
|
||||
"dotnet.defaultSolution": "NanoBrain-Unity.sln",
|
||||
"dotnet.server.useOmnisharp": true,
|
||||
"omnisharp.useModernNet": false,
|
||||
"dotnet.automaticallyCreateSolutionInWorkspace": false
|
||||
}
|
||||
}
|
||||
BIN
mono_crash.mem.19211.1.blob
Normal file
BIN
mono_crash.mem.19211.1.blob
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user