From 67beb5e48657b4876817e8b3707a0a8008bf96d3 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Wed, 6 May 2026 09:48:21 +0200 Subject: [PATCH] Add neuron property drawer --- Editor/Scripts/Ant_Editor.cs | 11 +++- NanoBrain/Editor/Neuron_Drawer.cs | 79 +++++++++++++++++++++++ NanoBrain/Editor/Neuron_Drawer.cs.meta | 11 ++++ NanoBrain/Runtime/Scripts/Core/Cluster.cs | 15 +++-- NanoBrain/Runtime/Scripts/Core/Neuron.cs | 2 +- Runtime/Scripts/Ant.cs | 2 +- 6 files changed, 108 insertions(+), 12 deletions(-) create mode 100644 NanoBrain/Editor/Neuron_Drawer.cs create mode 100644 NanoBrain/Editor/Neuron_Drawer.cs.meta diff --git a/Editor/Scripts/Ant_Editor.cs b/Editor/Scripts/Ant_Editor.cs index 72b5f76..a72fb2e 100644 --- a/Editor/Scripts/Ant_Editor.cs +++ b/Editor/Scripts/Ant_Editor.cs @@ -19,16 +19,21 @@ namespace CreatureControl { HomePheromonePrefabInspector(); FoodPheromonePrefabInspector(); + + EditorGUILayout.PropertyField(serializedObject.FindProperty(nameof(Ant.targetDirection))); + EditorGUILayout.PropertyField(serializedObject.FindProperty(nameof(Ant.foodReceptor))); + EditorGUILayout.PropertyField(serializedObject.FindProperty(nameof(Ant.homeReceptor))); + EditorGUILayout.PropertyField(serializedObject.FindProperty(nameof(Ant.hasFood))); } private void HomePheromonePrefabInspector() { SerializedProperty homePheromonePrefabProp = serializedObject.FindProperty(nameof(Ant.homePheromonePrefab)); - homePheromonePrefabProp.objectReferenceValue = (GameObject) EditorGUILayout.ObjectField("Home Pheromone Prefab", homePheromonePrefabProp.objectReferenceValue, typeof(GameObject), true); + homePheromonePrefabProp.objectReferenceValue = (GameObject)EditorGUILayout.ObjectField("Home Pheromone Prefab", homePheromonePrefabProp.objectReferenceValue, typeof(GameObject), true); } - + private void FoodPheromonePrefabInspector() { SerializedProperty foodPheromonePrefabProp = serializedObject.FindProperty(nameof(Ant.foodPheromonePrefab)); - foodPheromonePrefabProp.objectReferenceValue = (GameObject) EditorGUILayout.ObjectField("Food Pheromone Prefab", foodPheromonePrefabProp.objectReferenceValue, typeof(GameObject), true); + foodPheromonePrefabProp.objectReferenceValue = (GameObject)EditorGUILayout.ObjectField("Food Pheromone Prefab", foodPheromonePrefabProp.objectReferenceValue, typeof(GameObject), true); } } diff --git a/NanoBrain/Editor/Neuron_Drawer.cs b/NanoBrain/Editor/Neuron_Drawer.cs new file mode 100644 index 0000000..dac91b2 --- /dev/null +++ b/NanoBrain/Editor/Neuron_Drawer.cs @@ -0,0 +1,79 @@ +using UnityEngine; +using UnityEditor; +using Unity.Mathematics; +using System; +using System.Reflection; +using System.Collections; + +namespace NanoBrain { + [CustomPropertyDrawer(typeof(Neuron))] + class NeuronDrawer : PropertyDrawer { + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { + // Draw foldout + properties + label = EditorGUI.BeginProperty(position, label, property); + + // Begin indent block + int indent = EditorGUI.indentLevel; + EditorGUI.indentLevel = 0; + + object instance = GetTargetObjectOfProperty(property); + + float lineHeight = EditorGUIUtility.singleLineHeight; + Rect r = new(position.x, position.y, position.width, lineHeight); + if (instance != null) { + FieldInfo field = typeof(Neuron).GetField("_outputValue", BindingFlags.NonPublic | BindingFlags.Instance); + if (field != null) { + float3 val = (float3)field.GetValue(instance); + EditorGUI.Vector3Field(r, $"Neuron: {label}", val); + } + } + + EditorGUI.indentLevel = indent; + EditorGUI.EndProperty(); + } + + public override float GetPropertyHeight(SerializedProperty property, GUIContent label) { + // height for 1 line + return (EditorGUIUtility.singleLineHeight * 1) + (EditorGUIUtility.standardVerticalSpacing * 0); + } + + public static object GetTargetObjectOfProperty(SerializedProperty prop) { + var path = prop.propertyPath.Replace(".Array.data[", "["); + object obj = prop.serializedObject.targetObject; + var elements = path.Split('.'); + foreach (var element in elements) { + if (element.Contains("[")) { + var elementName = element.Substring(0, element.IndexOf("[")); + var index = Convert.ToInt32(element.Substring(element.IndexOf("[")).Replace("[", "").Replace("]", "")); + obj = GetValue_Imp(obj, elementName, index); + } + else { + obj = GetValue_Imp(obj, element); + } + } + return obj; + } + + static object GetValue_Imp(object source, string name) { + if (source == null) + return null; + + Type t = source.GetType(); + FieldInfo f = t.GetField(name, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance); + if (f != null) + return f.GetValue(source); + PropertyInfo p = t.GetProperty(name, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance); + return p?.GetValue(source, null); + } + static object GetValue_Imp(object source, string name, int index) { + if (GetValue_Imp(source, name) is not IEnumerable enumerable) + return null; + IEnumerator en = enumerable.GetEnumerator(); + for (int i = 0; i <= index; i++) { + if (!en.MoveNext()) + return null; + } + return en.Current; + } + } +} \ No newline at end of file diff --git a/NanoBrain/Editor/Neuron_Drawer.cs.meta b/NanoBrain/Editor/Neuron_Drawer.cs.meta new file mode 100644 index 0000000..b3a4b00 --- /dev/null +++ b/NanoBrain/Editor/Neuron_Drawer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: aa0e340763ca6299e93d514b271ae38d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/NanoBrain/Runtime/Scripts/Core/Cluster.cs b/NanoBrain/Runtime/Scripts/Core/Cluster.cs index 8077e04..973c692 100644 --- a/NanoBrain/Runtime/Scripts/Core/Cluster.cs +++ b/NanoBrain/Runtime/Scripts/Core/Cluster.cs @@ -556,14 +556,15 @@ namespace NanoBrain { return this; // Find a sleeping cluster - foreach (Cluster cluster in this.siblingClusters) { - if (cluster.defaultOutput.isSleeping) { - RemoveThingCluster(cluster); - return cluster; - } - } + // foreach (Cluster cluster in this.siblingClusters) { + // if (cluster.defaultOutput.isSleeping) { + // RemoveThingCluster(cluster); + // return cluster; + // } + // } - // Otherwise find longest unused cluster + // Find longest unused cluster + // Note this uses the default output... Cluster unusedCluster = this.siblingClusters[0]; for (int ix = 1; ix < this.siblingClusters.Length; ix++) { if (this.siblingClusters[ix].defaultOutput.lastUpdate < unusedCluster.defaultOutput.lastUpdate) diff --git a/NanoBrain/Runtime/Scripts/Core/Neuron.cs b/NanoBrain/Runtime/Scripts/Core/Neuron.cs index b5dcc66..d434b04 100644 --- a/NanoBrain/Runtime/Scripts/Core/Neuron.cs +++ b/NanoBrain/Runtime/Scripts/Core/Neuron.cs @@ -285,7 +285,7 @@ namespace NanoBrain { public Action WhenFiring; - public virtual bool isSleeping => Time.time - this.lastUpdate > this.timeToSleep; //this.outputMagnitude == 0; + public virtual bool isSleeping => false;// Time.time - this.lastUpdate > this.timeToSleep; //this.outputMagnitude == 0; public void SleepCheck() { if (this.isSleeping) { #if UNITY_MATHEMATICS diff --git a/Runtime/Scripts/Ant.cs b/Runtime/Scripts/Ant.cs index 99f272b..b9f5971 100644 --- a/Runtime/Scripts/Ant.cs +++ b/Runtime/Scripts/Ant.cs @@ -225,7 +225,7 @@ namespace CreatureControl { Vector3 smellDirection = this.transform.InverseTransformPoint(nest.transform.position); float distance = smellDirection.magnitude; - float angle = Vector3.Angle(Vector3.forward, smellDirection); + float angle = Vector3.Angle(Vector3.back, smellDirection); if (angle < smellAngle && distance > 0.01) { float intensity = nest.StrengthAt(distance); Vector3 value = smellDirection.normalized * intensity;