diff --git a/PlantWorld.cs b/PlantWorld.cs
index 522e720..659d0e7 100644
--- a/PlantWorld.cs
+++ b/PlantWorld.cs
@@ -60,7 +60,7 @@ public partial class PlantWorld : Node2D
if (eventMouseButton.ButtonIndex == MouseButton.Right && eventMouseButton.Pressed)
{
var pos = eventMouseButton.Position * GetViewportTransform();
- CreatePlant(pos, 128);
+ CreatePlant(pos, 12);
}
}
}
diff --git a/icon.svg b/icon.svg
new file mode 100644
index 0000000..b370ceb
--- /dev/null
+++ b/icon.svg
@@ -0,0 +1 @@
+
diff --git a/main.tscn b/main.tscn
index 97b8f8d..18b9708 100644
--- a/main.tscn
+++ b/main.tscn
@@ -1,10 +1,13 @@
-[gd_scene load_steps=3 format=3 uid="uid://d2rgfedikyr2w"]
+[gd_scene load_steps=4 format=3 uid="uid://d2rgfedikyr2w"]
-[ext_resource type="PackedScene" uid="uid://ixy2rotcnjk2" path="res://plant.tscn" id="1_mv10f"]
+[ext_resource type="Script" path="res://Main.cs" id="1_jrcl7"]
[ext_resource type="PackedScene" path="res://camera_2d.tscn" id="2_pvpm2"]
+[ext_resource type="PackedScene" uid="uid://cvjqldltcr7nl" path="res://plantWorld.tscn" id="2_t7d21"]
[node name="Main" type="Node2D"]
-
-[node name="Plant" parent="." instance=ExtResource("1_mv10f")]
+script = ExtResource("1_jrcl7")
[node name="Camera2D" parent="." instance=ExtResource("2_pvpm2")]
+
+[node name="PlantWorld" parent="." node_paths=PackedStringArray("Camera") instance=ExtResource("2_t7d21")]
+Camera = NodePath("../Camera2D")
diff --git a/src/BaseLifeComponent.cs b/src/BaseLifeComponent.cs
index fc13cc4..a812c1e 100644
--- a/src/BaseLifeComponent.cs
+++ b/src/BaseLifeComponent.cs
@@ -1,4 +1,4 @@
-namespace DrawingDemo;
+namespace LifeComponent;
using Godot;
@@ -6,7 +6,7 @@ public delegate void DiedEventHandler();
public class BaseLifeComponent
{
- public float Energy = 1000;
+ public float Energy = 100;
public float Age = 0;
public int MaxAge = 150;
public float Health = 100;
@@ -15,10 +15,10 @@ public class BaseLifeComponent
public event DiedEventHandler OnDied;
- public void Tick(float timeDelta)
+ public void Tick(float timeDelta, float size)
{
Age += timeDelta;
- ConsumeEnergy(0.1f); //Baseconsumption
+ ConsumeEnergy(0.1f * size); //Baseconsumption
if (Age > MaxAge || Health <= 0)
{
diff --git a/src/Genetics.cs b/src/Genetics.cs
index 3e81314..2aef5a1 100644
--- a/src/Genetics.cs
+++ b/src/Genetics.cs
@@ -1,9 +1,10 @@
+using System;
using Godot;
using Color = Godot.Color;
-namespace DrawingDemo;
+namespace LifeComponent;
-public static class ColorHelper
+public static class GeneHelper
{
public static Color ColorFrom6Bit(byte colorcode)
{
@@ -19,10 +20,22 @@ public static class ColorHelper
return new Color(value1 / colorperBit, value2 / colorperBit, value3 / colorperBit, value4 / colorperBit);
}
+
+
+ // public static int MapCodonToInt(byte codon, int min, int max)
+ // {
+ // int result = 0;
+ // if (codon > max)
+ // result = codon / max;
+ // if (codon < min)
+ // result = codon;
+ //
+ // return result;
+ // }
}
public class Genetics
{
- public GenStorage DNA = new GenStorage();
+ public GenStorage DNA;
public Color MainColor
{
@@ -30,10 +43,17 @@ public class Genetics
{
var codon = DNA.GetCodon(GenMapper.MainColor);
- return ColorHelper.ColorFrom6Bit(codon);
+ return GeneHelper.ColorFrom6Bit(codon);
}
}
+ public Genetics()
+ {
+ DNA = new GenStorage(12);
+ DNA.Randomize();
+
+ }
+
}
public enum GenMapper
@@ -52,9 +72,10 @@ public struct GenStorage
{
public byte[] Codons;
- public GenStorage()
+ public GenStorage(int codonCount)
{
- Codons = new byte[4] {42,0,0,0};
+ Codons = new byte[codonCount];// {42,0,0,0};
+
}
@@ -89,4 +110,38 @@ public struct GenStorage
return Codons[codon];
}
+ public byte[] GetBasePairs(int codonNr)
+ {
+ var codon = GetCodon(codonNr);
+ byte value1 = (byte)((codon & 0b11000000) >> 6);
+ byte value2 = (byte)((codon & 0b00110000) >> 4);
+ byte value3 = (byte)((codon & 0b00001100) >> 2);
+ byte value4 = (byte)(codon & 0b00000011);
+ return new[] { value1, value2, value3, value4 };
+ }
+ public float CodonAsFloat(int codonNr, float min = 0, float max = 1, int pairs = 4)
+ {
+ float result = 0;
+ var codon = GetCodon(codonNr);
+ if (pairs == 4)
+ {
+ result = Mathf.Lerp(min, max, (float) 255 / codon);
+ }
+ else
+ {
+ var values = GetBasePairs(codonNr);
+ // ...
+ }
+
+ return result;
+ }
+}
+
+
+
+public class PhenotypeAttribute : Attribute
+{
+ // Codon Marker index and base-pair lenght
+ // z.b. für angle between 0 - 6.2 = 1 Codon = 8 Byte -> lerp(0, 6.2, codon)
+
}
\ No newline at end of file
diff --git a/src/Plant.cs b/src/Plant.cs
index b1349d9..919b583 100644
--- a/src/Plant.cs
+++ b/src/Plant.cs
@@ -4,112 +4,302 @@ using System.Collections.Generic;
using System.Linq;
public partial class Plant : MeshInstance2D
{
+ private PlantLife _plantLife;
public Dictionary Segments;
- public Vector2 Origin;
private int _segmentIdCounter = 0;
public PlantSegmentNode RootNode;
- public Rect2 ClientRectangle = new Rect2(Vector2.Zero, new Vector2(-80, 80));
-
+ public Rect2 ClientRectangle = new Rect2(Vector2.Zero, new Vector2(-10, 10));
+ public bool CanGrow = true;
public override void _Ready()
{
- Start();
+ //Start();
-
-
}
- public void Start()
+ public void Init(int startNodes)
{
+ _plantLife = new PlantLife(this);
Segments = new Dictionary();
- PlantSegmentNode root = new PlantSegmentNode(null, maxChildren:1);
- root.Direction = Vector2.Up;
- root.NodeType = SegmentNodeTypes.Trunk;
+ _plantLife.Init();
+
+ PlantSegmentNode root = new PlantSegmentNode(null, maxChildren:_plantLife._plantParams.RootChildren);
+ root.Direction = _plantLife._plantParams.GrowDirection;
+ root.NodeType = PlantNodeTypes.Trunk;
+
RootNode = root;
Segments.Add(_segmentIdCounter, root);
_segmentIdCounter++;
- GrowDemo(4096);
+ GrowDemo(startNodes);
this.Mesh = CreateMesh();
+ CalulateClientRectangle();
+
}
- public Mesh CreateMesh()
+ public void CreateRootNode()
{
- ArrayMesh arrMesh = new ArrayMesh();
- var arrays = new Godot.Collections.Array();
- arrays.Resize((int)Mesh.ArrayType.Max);
-
- //Vector2[] vertices = CalculateVertices();
- Vector2[] vertices = CalculateLineVertices();
- Color[] colors = Helper.MakeColorArray(vertices.Length, 3);
-
- arrays[(int)Mesh.ArrayType.Vertex] = vertices;
- arrays[(int)Mesh.ArrayType.Color] = colors;
- //arrMesh.AddSurfaceFromArrays(Mesh.PrimitiveType.Triangles, arrays);
- arrMesh.AddSurfaceFromArrays(Mesh.PrimitiveType.Lines, arrays);
- return arrMesh;
}
-
- // Called every frame. 'delta' is the elapsed time since the previous frame.
+
public override void _Process(double delta)
{
+ if (_plantLife != null)
+ _plantLife.Tick((float)delta);
+ }
+
+ #region Segments
+
+ public void GrowDemo(int nodes)
+{
+ for (int i = 0; i < nodes -1; i++)
+ {
+ GrowNewNode( PlantParams.Default());
}
- public void GrowDemo(int nodes)
+}
+
+ public void AddNewSegment(PlantSegmentNode seg, PlantSegmentNode parent, int index)
{
- for (int i = 0; i < nodes -1; i++)
+ if (parent.AddChild(seg, index))
+ {
+ Segments.Add(_segmentIdCounter, seg);
+ _segmentIdCounter++;
+
+ this.UpdateAllGeometry();
+ }
+ else
{
- GrowNode();
+ GD.PrintErr("Error bei Add");
}
}
+ public void GrowNewNode(PlantParams pp)
+ {
+ int maxChildren = pp.MaxChildren;
+ PlantNodeTypes type = PlantNodeTypes.Trunk;
+
+ type = pp.GetRatioNodeType();
+ PlantNodeParams p = pp.NodeParams;
+
+ int maxDescentants = 4096;
+
+ var maxADiv = p.MaxToParentAngleRange / 2;
+ var a1 = p.MinToParentAngleRange;
+ var a2 = p.MaxToParentAngleRange;
+
+ var randAngleZeroDiv = (float)GD.RandRange(a1, a2);
+
+ float randF = (0.5f - GD.Randf());
+ int randI = GD.RandRange(0, 3);
- public void GrowNewNode(PlantNodeParams p)
+ var parent = GetFreeSlotSegment(false);
+ if (parent == null)
{
- //var randAngle = (float)GD.RandRange(-p.AllowedParentDiv/2, p.AllowedParentDiv/2);
- var randAngleZeroDiv = (float)GD.RandRange(20, 45);
-
- float randF = (0.5f - GD.Randf());
- int randI = GD.RandRange(0, 10);
-
- int maxChildren = p.MaxChildren;
- int maxDescentants = 4096;
- var parent = GetFreeSlotSegment(false);
- PlantSegmentNode seg;
- Vector2 dir = parent.Direction;
-
-
- var freeindex = parent.FreeNodeIndex();
- if (freeindex == -1)
- throw new System.Exception("Now free index, trotz free slot");
- switch (freeindex)
- {
- case 0: // Center
- dir = dir.Rotated(randF);
- maxChildren = 2;
- maxDescentants = 4096;
- break;
- case 1: // left
- dir = dir.Rotated(-randAngleZeroDiv);
- break;
- case 2:
- dir = dir.Rotated(+randAngleZeroDiv);
- break;
- // 3D...
+ GD.PrintErr("Outof Nodes");
+ CanGrow = false;
+ return;
+ }
+
+ PlantSegmentNode seg;
+ Vector2 dir = parent.Direction;
+ Vector2 size = parent.Size;
+
+ // get sibling dirs, if
+ // var sibRots = parent.GetChildrenToParentRotations();
+ // if (sibRots.Length == 0) // first child -> dir: center
+ // {
+ // dir = dir.Rotated(randF/8);
+ // }
+ // else
+ // {
+ // calc free spot:
+ // min distAngle = ~ maxparentdiv / max_children
+ // float optimalSpace = p.MaxToParentAngleRange / p.MaxChildren;
+ // if (p.MinAngleBetweenSibs > optimalSpace)
+ // {
+ // // to tight -> dont grow.
+ // }
+ //
+ // var r = FindSpot(p, sibRots);
+ //}
+
+ var freeindex = parent.FreeNodeIndex();
+ if (freeindex == -1)
+ throw new System.Exception("Now free index, trotz free slot");
+ switch (freeindex)
+ {
+ case 0: // Center
+ dir = dir.Rotated(randF/8);
+ maxChildren = 2;
+ size *= 0.95f;
+ maxDescentants = 4096;
+ break;
+ case 1: // left
+ dir = dir.Rotated(-randAngleZeroDiv);
+ size *= 0.85f;
+ maxDescentants = 128;
+ maxChildren = maxChildren;
+ break;
+ case 2:
+ dir = dir.Rotated(+randAngleZeroDiv);
+ size *= 0.85f;
+ maxDescentants = 128;
+ maxChildren = maxChildren;
+ break;
+ // 3D...
+
+ }
+ if (RootNode.Direction.Dot(dir) < 0) // ..<0 = 180 grad maxRootDeviationAngle)
+ maxChildren = 0; // wenn überhang -> branach ende
+
+ if (maxChildren == 0) // wird nix mehr -> kann ein blatt werden
+ {
+ //type = PlantNodeTypes.Leafes;
+ }
+
+
+ seg = new PlantSegmentNode(parent, maxChildren, maxDescentants);
+ seg.Direction = dir;
+ seg.Size = size;
+
+ seg.NodeType = type;
+
+ // if (CheckCollision(seg))
+ // {
+ // // Add stump dummy - so slot is ignored
+ // seg.NodeType = PlantNodeTypes.Stump;
+ // seg.MaxChildren = seg.ChildrenCount;
+ // seg.Size = Vector2.One;
+ // }
+
+ AddNewSegment(seg, parent, freeindex);
+ return;
+
+ if (parent.AddChild(seg, freeindex))
+ {
+ Segments.Add(_segmentIdCounter, seg);
+ _segmentIdCounter++;
+ }
+ else
+ {
+ GD.PrintErr("Error bei Add");
+ }
+ }
+
+ public float FindSpot(PlantNodeParams p, float[] usedAngles)
+ {
+ // calc free spot:
+ // min distAngle = ~ maxparentdiv / max_children
+
+ if (usedAngles.Length == 0)
+ return p.PreferedRotationToParent;
+
+ float optimalSpace = p.MaxToParentAngleRange / p.MaxChildren;
+ if (p.MinAngleBetweenSibs > optimalSpace)
+ {
+ // to tight -> dont grow.
+ GD.PrintErr("FindSpot: to tight! = params shit");
+ return 0;
+ }
+
+ List spots = new List();
+
+ for (int i = 0; i < usedAngles.Length; i++)
+ {
+ if (i + 1 >= usedAngles.Length)
+ break;
- }
- seg = new PlantSegmentNode(parent, p.MaxChildren);
- if (parent.AddChild(seg, freeindex))
+ if (usedAngles[i] - usedAngles[i + 1] >= p.MinAngleBetweenSibs)
{
- Segments.Add(_segmentIdCounter, seg);
- _segmentIdCounter++;
- }
- else
- {
- GD.PrintErr("Error bei Add");
+ spots.Add(usedAngles[i]);
}
}
- public void GrowNode()
+
+
+ if (spots.Count > 0)
+ {
+ return spots[GD.RandRange(0, spots.Count - 1)];
+ }
+ else
+ {
+ return 0;
+ }
+ }
+
+ public void GrowNewNode2(PlantNodeParams p)
+ {
+ int maxChildren = p.MaxChildren;
+ int maxDescentants = 4096;
+
+ //var randAngle = (float)GD.RandRange(-p.AllowedParentDiv/2, p.AllowedParentDiv/2);
+ var randAngleZeroDiv = (float)GD.RandRange(12, 23);
+ randAngleZeroDiv = Mathf.DegToRad(randAngleZeroDiv);
+
+ float randF = (0.5f - GD.Randf());
+ int randI = GD.RandRange(0, 3);
+
+
+ var parent = GetFreeSlotSegment(false);
+ PlantSegmentNode seg;
+ Vector2 dir = parent.Direction;
+ Vector2 size = parent.Size;
+
+ // get sibling dirs, if
+ var sibRots = parent.GetChildrenToParentRotations();
+
+
+ var freeindex = parent.FreeNodeIndex();
+ if (freeindex == -1)
+ throw new System.Exception("Now free index, trotz free slot");
+ switch (freeindex)
+ {
+ case 0: // Center
+ dir = dir.Rotated(randF/8);
+ maxChildren = 2;
+ size *= 0.95f;
+ maxDescentants = 4096;
+ break;
+ case 1: // left
+ dir = dir.Rotated(-randAngleZeroDiv);
+ size *= 0.85f;
+ maxDescentants = 128;
+ maxChildren = maxChildren - randI;
+ break;
+ case 2:
+ dir = dir.Rotated(+randAngleZeroDiv);
+ size *= 0.85f;
+ maxDescentants = 128;
+ maxChildren = maxChildren - randI;
+ break;
+ // 3D...
+
+ }
+ if (RootNode.Direction.Dot(dir) < 0) // ..<0 = 180 grad maxRootDeviationAngle)
+ maxChildren = 0; // wenn überhang -> branach ende
+
+ seg = new PlantSegmentNode(parent, maxChildren, maxDescentants);
+ seg.Direction = dir;
+ seg.Size = size;
+
+ // if (CheckCollision(seg))
+ // {
+ // // Add stump dummy - so slot is ignored
+ // seg.NodeType = PlantNodeTypes.Stump;
+ // seg.MaxChildren = seg.ChildrenCount;
+ // seg.Size = Vector2.One;
+ // }
+
+ if (parent.AddChild(seg, freeindex))
+ {
+ Segments.Add(_segmentIdCounter, seg);
+ _segmentIdCounter++;
+ }
+ else
+ {
+ GD.PrintErr("Error bei Add");
+ }
+ }
+ public void GrowNode_old()
{
// Config
float minAngleDiv =Mathf.DegToRad(23);
@@ -173,7 +363,7 @@ public partial class Plant : MeshInstance2D
// {
// //GD.Print("Collision ", seg);
// // Add stump dummy - so slot is ignored
- // seg.NodeType = SegmentNodeTypes.Stump;
+ // seg.NodeType = PlantNodeTypes.Stump;
// seg.MaxChildren = seg.ChildrenCount;
// seg.Size = Vector2.Zero;//seg.Size * 0.4f;
// }
@@ -189,6 +379,86 @@ public partial class Plant : MeshInstance2D
}
}
+
+
+ public bool CheckCollision(PlantSegmentNode node)
+ {
+
+ foreach (var kv in Segments)
+ {
+ var seg = kv.Value;
+
+ if (seg == node || seg.NodeType == PlantNodeTypes.Stump || seg == node.Parent)
+ continue;
+
+
+ Vector2 from1 = node.PositionRelativeParent;
+ Vector2 to1 = from1 + node.Line;
+
+ Vector2 from2 = seg.PositionRelativeParent;
+ Vector2 to2 = seg.PositionRelativeParent + seg.Line;
+ var intersection = Geometry2D.SegmentIntersectsSegment(from1, to1, from2, to2);
+ //Geometry2D.inter
+ if (intersection.VariantType != Variant.Type.Nil)
+ {
+ return true;
+ }
+
+ }
+ return false;
+
+ }
+ private PlantSegmentNode GetFreeSlotSegment(bool descending = false)
+ {
+
+ Dictionary elements = Segments;
+ //List list = elements.OrderBy(x => x.Key).ToList();
+
+ // if (descending)
+ // elements = elements.OrderByDescending(x => x.Key).ToDictionary(x => x.Key, x => x.Value);
+ // else
+ // {
+ // elements = elements.OrderBy(x => x.Key).ToDictionary(x => x.Key, x => x.Value);
+ //
+ // }
+
+ foreach (var item in elements)
+ {
+ if (item.Value.HasFreeChildSlot)
+ return item.Value;
+ }
+ return null;
+ }
+
+ #endregion
+
+ #region Geometry
+
+
+ public void UpdateAllGeometry()
+ {
+ this.Mesh = CreateMesh();
+ CalulateClientRectangle();
+ }
+
+ public Mesh CreateMesh()
+ {
+ ArrayMesh arrMesh = new ArrayMesh();
+ var arrays = new Godot.Collections.Array();
+ arrays.Resize((int)Mesh.ArrayType.Max);
+
+ //Vector2[] vertices = CalculateVertices();
+ Vector2[] vertices = CalculateLineVertices();
+ Color[] colors = Helper.MakeColorArray(vertices.Length, 3);
+
+ arrays[(int)Mesh.ArrayType.Vertex] = vertices;
+ arrays[(int)Mesh.ArrayType.Color] = colors;
+
+ //arrMesh.AddSurfaceFromArrays(Mesh.PrimitiveType.Triangles, arrays);
+ arrMesh.AddSurfaceFromArrays(Mesh.PrimitiveType.Lines, arrays);
+ return arrMesh;
+ }
+
public Vector2[] CalculateLineVertices()
{
int vertexCount = 2 * Segments.Count;
@@ -246,55 +516,29 @@ public partial class Plant : MeshInstance2D
}
return vertices;
}
-
- public bool CheckCollision(PlantSegmentNode node)
+
+ public void CalulateClientRectangle()
{
- return false;
-
- }
- private PlantSegmentNode GetFreeSlotSegment(bool descending = false)
- {
-
- Dictionary elements = Segments;
- //List list = elements.OrderBy(x => x.Key).ToList();
-
- if (descending)
- elements = elements.OrderByDescending(x => x.Key).ToDictionary(x => x.Key, x => x.Value);
- else
- {
- elements = elements.OrderBy(x => x.Key).ToDictionary(x => x.Key, x => x.Value);
+ float margin = 2;
+ float maxX = Segments.Max(x => (x.Value.VecToRoot + x.Value.Line).X);
+ float maxY = Segments.Max(x => (x.Value.VecToRoot + x.Value.Line).Y);
+ float minX = Segments.Min(x => x.Value.VecToRoot.X);
+ float minY = Segments.Min(x => x.Value.VecToRoot.Y);
+
+ Vector2 min = new Vector2(minX - margin, minY - margin);
+ Vector2 max = new Vector2(maxX + margin, maxY + margin);
+ Vector2 pos = min;
+ Vector2 size = max - min;
+ pos += Position;
+ ClientRectangle = new Rect2(pos, size);
+ // je nachdemn ob + oder - ....
+ //ClientRectangle = new Rect2(min, max);
- }
-
- foreach (var item in elements)
- {
- if (item.Value.HasFreeChildSlot)
- return item.Value;
- }
- return null;
}
-}
+ #endregion
-public struct PlantNodeParams
-{
- // Angle to grow - calculated from 0°(front) localspace
- public float AllowedParentDiv = Mathf.DegToRad(80);
- public float AllowedRootDiv = Mathf.DegToRad(180);
- //public float MinAngleParentDiv = 0;
- //public float MaxAngleParentDiv = 1f;
- //public float MaxRootDeviationAngle = 3.14f;
- public int MaxChildren = 3;
- public Vector2 Size = Vector2.One;
- public Vector2 Direction = Vector2.Up;
- public string ConfigName = "default";
- public SegmentNodeTypes NodeType = SegmentNodeTypes.Trunk;
-
- public PlantNodeParams()
- {
-
- }
}
diff --git a/src/PlantLife.cs b/src/PlantLife.cs
new file mode 100644
index 0000000..765c853
--- /dev/null
+++ b/src/PlantLife.cs
@@ -0,0 +1,87 @@
+
+using System;
+using System.Collections.Generic;
+using Godot;
+using LifeComponent;
+
+public class PlantLife
+{
+ private Genetics _genes;
+ private BaseLifeComponent _baseLife;
+ private Plant _plant_RefUp;
+ public PlantParams _plantParams;
+
+ public float _size = 1f;
+ //public PlantNodeParams RootParams;
+ public PlantLife(Plant plantRef)
+ {
+
+ _plant_RefUp = plantRef;
+ _genes = new Genetics();
+ _baseLife = new BaseLifeComponent();
+
+ }
+
+ public void Init()
+ {
+ _plantParams = new PlantParams();
+ _plantParams.NodeParams.maxToRootAngleRange = Mathf.DegToRad(270);
+
+ GenesToPhenes();
+ //_plantParams.GrowDirection = Vector2.Right;
+ _plantParams.NodeParams.MaxToParentAngleRange = Mathf.DegToRad(90);
+ _baseLife.Born();
+ }
+
+ public void GenesToPhenes()
+ {
+ // var c3 = _genes.DNA.Codons[3];
+ var bytes = _genes.DNA.GetBasePairs(3);
+
+ var a = bytes[0];
+ _plantParams.AverageChildren = a;
+ var b = bytes[1];
+
+ //var c = bytes[2];
+ //_plantParams.MaxChildren = c + 1;
+
+ var d = bytes[3];
+
+ if (b == 0)
+ _plantParams.GrowDirection = Vector2.Up;
+ if (b == 1)
+ _plantParams.GrowDirection = Vector2.Left;
+ if (b == 2)
+ _plantParams.GrowDirection = Vector2.Right;
+ if (b == 3)
+ _plantParams.GrowDirection = Vector2.Down;
+
+ //var v = Mathf.LerpAngle(0.5f, 5.8f, (float)d/4); // 0 - 6.2
+ var v = Mathf.Lerp(0.5f, 5.8f, (float)d/4);
+ _plantParams.NodeParams.MaxToParentAngleRange = v;
+
+ }
+
+ public void Tick(float deltaTime)
+ {
+ _baseLife.Tick(deltaTime, _size);
+
+ _baseLife.AddEnergy(1 * _size * 0.7f);
+ Grow();
+ }
+
+ public void Grow()
+ {
+ if (_baseLife.Energy > 50)
+ {
+ if (_plant_RefUp.CanGrow)
+ _plant_RefUp.GrowNewNode(_plantParams);
+
+ //GD.Print("Life grew! :) ");
+ _baseLife.Energy -= 30;
+ _size = _plant_RefUp.Segments.Count;
+
+ //_plant_RefUp.AddNewSegment()
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/PlantParmeters.cs b/src/PlantParmeters.cs
new file mode 100644
index 0000000..8a98ecd
--- /dev/null
+++ b/src/PlantParmeters.cs
@@ -0,0 +1,91 @@
+using System;
+using Godot;
+using LifeComponent;
+
+
+public struct PlantParams
+{
+ public PlantNodeParams NodeParams;
+
+ public float maxToRootAngleRange = Mathf.DegToRad(180);
+ public Vector2 GrowDirection = Vector2.Up;
+ public int RootChildren = 1;
+ public int AverageChildren = 2;
+ [Phenotype]
+ public int MaxChildren = 3; // Hardlimit - should overrule Nodes
+ public float SizeDecayOrderFactor = 0.99f;
+
+ public float LeaveRatio = 0.1f;
+ public float TrunkRatio = 0.5f;
+
+ public PlantParams()
+ {
+ //RootParams = rootParams;
+ NodeParams = PlantNodeParams.Default();
+ NodeParams.MaxChildren = MaxChildren;
+ }
+
+ public static PlantParams Default()
+ {
+ return new PlantParams();
+ }
+ public PlantNodeTypes GetRatioNodeType()
+ {
+ var r1 = (float)GD.RandRange(0, 10) / 10;
+
+ //if (r1 < LeaveRatio)
+ // return PlantNodeTypes.Leafes;
+ if (r1 > LeaveRatio && r1 < TrunkRatio)
+ return PlantNodeTypes.Trunk;
+
+ return PlantNodeTypes.Branch;
+ }
+
+
+
+}
+
+public struct PlantNodeParams
+{
+ // Angle to grow - calculated from 0°(front) localspace. +/- angle/2
+ [Phenotype]
+ public float MinToParentAngleRange = Mathf.DegToRad(12);
+ [Phenotype]
+ public float MaxToParentAngleRange = Mathf.DegToRad(80);
+
+ public float maxToRootAngleRange = Mathf.DegToRad(180);
+ public float MinAngleBetweenSibs = Mathf.DegToRad(12);
+ //public float MinAngleParentDiv = 0;
+ //public float MaxAngleParentDiv = 1f;
+ //public float MaxRootDeviationAngle = 3.14f;
+ public int MaxChildren = 3;
+ public Vector2 Size = Vector2.One;
+ public float PreferedRotationToParent = 0f;
+
+ public string ConfigName = "default";
+ public PlantNodeTypes NodeType = PlantNodeTypes.Trunk;
+
+ public PlantNodeParams()
+ {
+
+ }
+
+
+ public static PlantNodeParams Default()
+ {
+ return new PlantNodeParams();
+ }
+
+ public static PlantNodeParams Trunk()
+ {
+ var p = new PlantNodeParams();
+ p.MaxChildren = 2;
+ p.NodeType = PlantNodeTypes.Trunk;
+ p.maxToRootAngleRange = 0.1f;
+
+
+ return p;
+ }
+
+}
+
diff --git a/src/SegmentNodes.cs b/src/SegmentNodes.cs
index 119acd7..6dc6640 100644
--- a/src/SegmentNodes.cs
+++ b/src/SegmentNodes.cs
@@ -4,11 +4,11 @@ using System.Linq;
using Godot;
-public enum SegmentNodeTypes
+public enum PlantNodeTypes
{
Trunk,
Branch,
- Leave,
+ Leafes,
Fruit,
Stump, // basically blocks growth
}
@@ -21,33 +21,41 @@ public class PlantSegmentNode : LifeFormSegmentNode
public Vector2 VecToRoot;
public Vector2 Direction;
- private SegmentNodeTypes _nodeType = SegmentNodeTypes.Branch;
+ private PlantNodeTypes _nodeType = PlantNodeTypes.Branch;
- public SegmentNodeTypes NodeType
+ public PlantNodeTypes NodeType
{
get { return _nodeType; }
set {
- if (value == SegmentNodeTypes.Stump)
+ _nodeType = value;
+ if (value == PlantNodeTypes.Stump)
{
Size = Vector2.Zero;
MaxChildren = ChildrenCount;
Direction = ((PlantSegmentNode)Parent).Direction.Normalized();
- _nodeType = value;
+ base.RedimChildren();
+
}
-
+ else if (value == PlantNodeTypes.Branch)
+ {
+ //MaxChildren = base.MaxChildren + 2;
+ Size = Size * 0.95f;
+ }
+ else if (value == PlantNodeTypes.Leafes)
+ {
+ MaxChildren = ChildrenCount;
+ base.RedimChildren();
+ }
+
}
}
- public float Rotation
- {
- get { return Mathf.RadToDeg(Direction.Angle()); }
- }
public PlantSegmentNode(PlantSegmentNode parent, int maxChildren = 2, int maxRecursiveChildren = 4096) : base(parent, maxChildren, maxRecursiveChildren)
{
if (parent != null) // is child
{
Direction = parent.Direction.Normalized();
- Size = parent.Size / parent.MaxChildren;
+ Size = parent.Size; // parent.MaxChildren;
PositionRelativeParent = parent.PositionRelativeParent + parent.Line;
VecToRoot = parent.VecToRoot + parent.Line;
}
@@ -62,6 +70,20 @@ public class PlantSegmentNode : LifeFormSegmentNode
}
}
+ public float[] GetChildrenToParentRotations()
+ {
+ float[] r = new float[ChildrenCount];
+
+ for (int i = 0; i < ChildrenCount - 1; i++)
+ {
+ var child = Get_Child(i);// Children[i];
+ if (child != null)
+ r[i] = ((PlantSegmentNode)Children[i]).Direction.Angle();
+ }
+
+ return r;
+
+ }
public void UpdateSelfToParent()
{
if (IsRoot)
@@ -178,14 +200,14 @@ public abstract class LifeFormSegmentNode
}
else
{
- value = 0;
+ _maxChildren = 0;
}
}
}
public LifeFormSegmentNode(LifeFormSegmentNode parent, int maxChildren = 3, int maxRecursiveChildren = 4096)
{
- _maxChildren = maxChildren;
+ MaxChildren = maxChildren;
if (parent == null)
{
@@ -204,13 +226,13 @@ public abstract class LifeFormSegmentNode
if (_maxRecursiveChildren <= 0)
{
_maxRecursiveChildren = 0;
- _maxChildren = 0;
+ MaxChildren = 0;
}
else if (_maxRecursiveChildren < _maxChildren)
- _maxChildren = maxRecursiveChildren;
+ MaxChildren = maxRecursiveChildren;
}
- Children = new LifeFormSegmentNode[_maxChildren];
+ Children = new LifeFormSegmentNode[MaxChildren];
// Iterate ID
Id = LifeFormSegmentNode.NodeCounter;
@@ -263,15 +285,34 @@ public abstract class LifeFormSegmentNode
}
public int ChildrenCount
{
- //get { return Children.Count(x => x != null); }
+
get { return _childCount; }
}
public bool HasFreeChildSlot
{
- get { return ChildrenCount < _maxChildren; }
+ get { return ChildrenCount < MaxChildren; }
}
+ public void RedimChildren()
+ {
+
+ if (Children.Length > MaxChildren)
+ {
+ if (ChildrenCount <= MaxChildren)
+ Children = new LifeFormSegmentNode[MaxChildren];
+ else
+ {
+ // hmmm.... sollte eigentlich nicht sein. wenn ich nicht lösche, mal schauen.
+ GD.PrintErr("Hui RedimChildren: nodes löschen?");
+ }
+
+ //LifeFormSegmentNode[] cc = new LifeFormSegmentNode[MaxChildren];
+
+ //var copy = Children.Clone();
+
+ }
+ }
public int FreeNodeIndex()
{
// nur first ist immer rechtslastig -> rand?
@@ -282,18 +323,17 @@ public abstract class LifeFormSegmentNode
if (Children[0] == null) // center zuerst
return 0;
- if (_maxChildren > 1) // 1 rechts oder 2 links
+ if (MaxChildren > 1) // 1 rechts oder 2 links
{
- List nodes = new List();
- for (int j = 0; j < _maxChildren; j++)
+ List freeidx = new List();
+ for (int j = 0; j < MaxChildren; j++)
{
if (Children[j] == null)
- nodes.Add(j);
+ freeidx.Add(j);
}
-
- int li = 0;
- li = GD.RandRange(0, nodes.Count-1);
- return nodes[li];
+
+ int li = GD.RandRange(0, freeidx.Count-1);
+ return freeidx[li];
}
return -1;
}