commit
808aee880a
10 changed files with 1020 additions and 0 deletions
@ -0,0 +1,50 @@
@@ -0,0 +1,50 @@
|
||||
extends Camera2D |
||||
|
||||
var velocity = Vector2(0, 0) |
||||
var mouse_down_pos = Vector2.ZERO |
||||
|
||||
# Called when the node enters the scene tree for the first time. |
||||
func _ready(): |
||||
pass # Replace with function body. |
||||
|
||||
|
||||
# Called every frame. 'delta' is the elapsed time since the previous frame. |
||||
func _process(delta): |
||||
var dir = Vector2(0,0) |
||||
|
||||
if Input.is_key_pressed(KEY_W): |
||||
dir.y -= 1 |
||||
if Input.is_key_pressed(KEY_S): |
||||
dir.y += 1 |
||||
if Input.is_key_pressed(KEY_A): |
||||
dir.x -= 1 |
||||
if Input.is_key_pressed(KEY_D): |
||||
dir.x += 1 |
||||
|
||||
position += dir * delta * 100 |
||||
|
||||
|
||||
func _input(event): |
||||
if event is InputEventMouseButton: |
||||
if event.button_index == 1: |
||||
if event.pressed: |
||||
mouse_down_pos = event.position |
||||
else: |
||||
var move = mouse_down_pos - event.position |
||||
position += move |
||||
|
||||
var zoomf = 0 |
||||
var nzoom = 0 |
||||
if event.button_index == 4: |
||||
zoomf += 0.1 |
||||
|
||||
if event.button_index == 5: |
||||
zoomf -= 0.1 |
||||
|
||||
nzoom = zoom + Vector2(zoomf, zoomf) |
||||
if nzoom.length() != 0 and zoomf != 0: |
||||
zoom = nzoom |
||||
|
||||
|
||||
|
||||
# print( event.button_index) |
||||
@ -0,0 +1,7 @@
@@ -0,0 +1,7 @@
|
||||
[gd_scene load_steps=2 format=3 uid="uid://bnsf7lnm8elui"] |
||||
|
||||
[ext_resource type="Script" path="res://camera2D.gd" id="1_exvdf"] |
||||
|
||||
[node name="Camera2D" type="Camera2D"] |
||||
position_smoothing_enabled = true |
||||
script = ExtResource("1_exvdf") |
||||
@ -0,0 +1,10 @@
@@ -0,0 +1,10 @@
|
||||
[gd_scene load_steps=3 format=3 uid="uid://d2rgfedikyr2w"] |
||||
|
||||
[ext_resource type="PackedScene" uid="uid://ixy2rotcnjk2" path="res://plant.tscn" id="1_mv10f"] |
||||
[ext_resource type="PackedScene" path="res://camera_2d.tscn" id="2_pvpm2"] |
||||
|
||||
[node name="Main" type="Node2D"] |
||||
|
||||
[node name="Plant" parent="." instance=ExtResource("1_mv10f")] |
||||
|
||||
[node name="Camera2D" parent="." instance=ExtResource("2_pvpm2")] |
||||
@ -0,0 +1,6 @@
@@ -0,0 +1,6 @@
|
||||
[gd_scene load_steps=2 format=3 uid="uid://ixy2rotcnjk2"] |
||||
|
||||
[ext_resource type="Script" path="res://src/Plant.cs" id="1_3shty"] |
||||
|
||||
[node name="Plant" type="MeshInstance2D"] |
||||
script = ExtResource("1_3shty") |
||||
@ -0,0 +1,20 @@
@@ -0,0 +1,20 @@
|
||||
; Engine configuration file. |
||||
; It's best edited using the editor UI and not directly, |
||||
; since the parameters that go here are not all obvious. |
||||
; |
||||
; Format: |
||||
; [section] ; section goes between [] |
||||
; param=value ; assign values to parameters |
||||
|
||||
config_version=5 |
||||
|
||||
[application] |
||||
|
||||
config/name="PlantLife2D" |
||||
run/main_scene="res://main.tscn" |
||||
config/features=PackedStringArray("4.2", "C#", "Forward Plus") |
||||
config/icon="res://icon.svg" |
||||
|
||||
[dotnet] |
||||
|
||||
project/assembly_name="PlantLife2D" |
||||
@ -0,0 +1,93 @@
@@ -0,0 +1,93 @@
|
||||
namespace DrawingDemo; |
||||
|
||||
using Godot; |
||||
|
||||
public delegate void DiedEventHandler(); |
||||
|
||||
public class BaseLifeComponent |
||||
{ |
||||
public float Energy = 1000; |
||||
public float Age = 0; |
||||
public int MaxAge = 150; |
||||
public float Health = 100; |
||||
private float MaxHealth = 100; |
||||
public bool Alive = true; |
||||
public event DiedEventHandler OnDied; |
||||
|
||||
|
||||
public void Tick(float timeDelta) |
||||
{ |
||||
Age += timeDelta; |
||||
ConsumeEnergy(0.1f); //Baseconsumption |
||||
|
||||
if (Age > MaxAge || Health <= 0) |
||||
{ |
||||
Die(); |
||||
return; |
||||
} |
||||
|
||||
|
||||
} |
||||
|
||||
public void Born() |
||||
{ |
||||
Alive = true; |
||||
} |
||||
public void AddEnergy(float amount) |
||||
{ |
||||
if (Alive) |
||||
Energy += amount; |
||||
} |
||||
public void Heal(float amount) |
||||
{ |
||||
if (Health + amount >= MaxHealth) |
||||
Health = MaxHealth; |
||||
else |
||||
Health += amount; |
||||
} |
||||
|
||||
|
||||
|
||||
public float ConsumeEnergy(float amount, float costFactor = 1) |
||||
{ |
||||
if (!Alive) |
||||
return 0; |
||||
float cost = amount * costFactor; |
||||
float consume = amount; |
||||
|
||||
if (Energy > 5) |
||||
{ |
||||
consume = Mathf.Clamp(consume, 0, Energy - 5); |
||||
Energy -= consume; |
||||
float energy = consume; |
||||
return energy; |
||||
} |
||||
else |
||||
return 0; |
||||
} |
||||
private void Die() |
||||
{ |
||||
Alive = false; |
||||
Health = 0; |
||||
Energy = 0; |
||||
if (OnDied != null) OnDied(); |
||||
} |
||||
|
||||
public string Stats() |
||||
{ |
||||
string stats = $"Health: {Health}\nEnergy:{Energy}\nAge: {Age}"; |
||||
return stats; |
||||
} |
||||
|
||||
public bool CanReproduce => (Age > 5 && Energy > 100 && Health > 50); |
||||
|
||||
public void Reproduce() |
||||
{ |
||||
if (CanReproduce) |
||||
{ |
||||
Energy -= 50; |
||||
|
||||
} |
||||
|
||||
} |
||||
} |
||||
@ -0,0 +1,92 @@
@@ -0,0 +1,92 @@
|
||||
using Godot; |
||||
using Color = Godot.Color; |
||||
|
||||
namespace DrawingDemo; |
||||
|
||||
public static class ColorHelper |
||||
{ |
||||
public static Color ColorFrom6Bit(byte colorcode) |
||||
{ |
||||
// 64 Colors - 2 bit for farbe A... mal schaun |
||||
// oder 256 farben / 4 = 64 Values |
||||
float bitsPerColor = 2; |
||||
float colorperBit = 4; |
||||
|
||||
byte value1 = (byte)((colorcode & 0b11000000) >> 6); |
||||
byte value2 = (byte)((colorcode & 0b00110000) >> 4); |
||||
byte value3 = (byte)((colorcode & 0b00001100) >> 2); |
||||
byte value4 = (byte)(colorcode & 0b00000011); |
||||
|
||||
return new Color(value1 / colorperBit, value2 / colorperBit, value3 / colorperBit, value4 / colorperBit); |
||||
} |
||||
} |
||||
public class Genetics |
||||
{ |
||||
public GenStorage DNA = new GenStorage(); |
||||
|
||||
public Color MainColor |
||||
{ |
||||
get |
||||
{ |
||||
var codon = DNA.GetCodon(GenMapper.MainColor); |
||||
|
||||
return ColorHelper.ColorFrom6Bit(codon); |
||||
} |
||||
} |
||||
|
||||
} |
||||
|
||||
public enum GenMapper |
||||
{ |
||||
// 1. byte - 1 codon - 1. phenotyp |
||||
|
||||
MainColor, |
||||
Color2, |
||||
Color3, |
||||
GrowSpeed, |
||||
|
||||
|
||||
} |
||||
|
||||
public struct GenStorage |
||||
{ |
||||
public byte[] Codons; |
||||
|
||||
public GenStorage() |
||||
{ |
||||
Codons = new byte[4] {42,0,0,0}; |
||||
} |
||||
|
||||
|
||||
public void Randomize() |
||||
{ |
||||
for (int i = 0; i <= Codons.Length-1; i++) |
||||
{ |
||||
Codons[i] = (byte)(GD.Randi() % 255); |
||||
} |
||||
|
||||
} |
||||
|
||||
public byte[] GetMutatedGenome(float mutationRate) |
||||
{ |
||||
var ri = GD.Randi() % 32; |
||||
byte[] mut = Codons; |
||||
|
||||
for (int i = 0; i < Codons.Length-1; i++) |
||||
{ |
||||
//mut[i] += (byte)ri; |
||||
} |
||||
|
||||
return mut; |
||||
} |
||||
|
||||
public byte GetCodon(GenMapper codon) |
||||
{ |
||||
return Codons[(int)codon]; |
||||
} |
||||
public byte GetCodon(int codon) |
||||
{ |
||||
return Codons[codon]; |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,28 @@
@@ -0,0 +1,28 @@
|
||||
|
||||
using Godot; |
||||
|
||||
public static class Helper |
||||
{ |
||||
public static Color[] myColors = new[] |
||||
{ |
||||
Colors.Red, Colors.Blue, Colors.Green, Colors.Yellow, Colors.Purple, Colors.Orange, Colors.Indigo, Colors.White |
||||
}; |
||||
|
||||
public static Color[] MakeColorArray(int vertexCount, int verticePerColor) |
||||
{ |
||||
Color[] vertices = new Color[vertexCount]; |
||||
int ci = -1; |
||||
for (int i = 0; i < vertexCount; i++) |
||||
{ |
||||
if (i % verticePerColor == 0) |
||||
{ |
||||
ci++; |
||||
} |
||||
|
||||
vertices[i] = myColors[ci % myColors.Length]; |
||||
} |
||||
return vertices; |
||||
} |
||||
|
||||
|
||||
} |
||||
@ -0,0 +1,300 @@
@@ -0,0 +1,300 @@
|
||||
using System; |
||||
using Godot; |
||||
using System.Collections.Generic; |
||||
using System.Linq; |
||||
public partial class Plant : MeshInstance2D |
||||
{ |
||||
public Dictionary<int, PlantSegmentNode> Segments; |
||||
public Vector2 Origin; |
||||
private int _segmentIdCounter = 0; |
||||
public PlantSegmentNode RootNode; |
||||
public Rect2 ClientRectangle = new Rect2(Vector2.Zero, new Vector2(-80, 80)); |
||||
|
||||
public override void _Ready() |
||||
{ |
||||
Start(); |
||||
|
||||
|
||||
|
||||
} |
||||
|
||||
public void Start() |
||||
{ |
||||
Segments = new Dictionary<int, PlantSegmentNode>(); |
||||
PlantSegmentNode root = new PlantSegmentNode(null, maxChildren:1); |
||||
root.Direction = Vector2.Up; |
||||
root.NodeType = SegmentNodeTypes.Trunk; |
||||
RootNode = root; |
||||
Segments.Add(_segmentIdCounter, root); |
||||
_segmentIdCounter++; |
||||
GrowDemo(4096); |
||||
|
||||
this.Mesh = CreateMesh(); |
||||
|
||||
} |
||||
|
||||
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; |
||||
} |
||||
|
||||
// Called every frame. 'delta' is the elapsed time since the previous frame. |
||||
public override void _Process(double delta) |
||||
{ |
||||
} |
||||
public void GrowDemo(int nodes) |
||||
{ |
||||
for (int i = 0; i < nodes -1; i++) |
||||
{ |
||||
GrowNode(); |
||||
} |
||||
} |
||||
|
||||
|
||||
public void GrowNewNode(PlantNodeParams p) |
||||
{ |
||||
//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... |
||||
|
||||
} |
||||
seg = new PlantSegmentNode(parent, p.MaxChildren); |
||||
if (parent.AddChild(seg, freeindex)) |
||||
{ |
||||
Segments.Add(_segmentIdCounter, seg); |
||||
_segmentIdCounter++; |
||||
} |
||||
else |
||||
{ |
||||
GD.PrintErr("Error bei Add"); |
||||
} |
||||
} |
||||
public void GrowNode() |
||||
{ |
||||
// Config |
||||
float minAngleDiv =Mathf.DegToRad(23); |
||||
float maxAngleDiv = Mathf.DegToRad(48); |
||||
int maxChildren = 2; |
||||
int maxDescentants = 128; |
||||
float maxRootDeviationAngle = Mathf.DegToRad(180); |
||||
|
||||
// Params |
||||
var randAngle = (float)GD.RandRange(minAngleDiv, maxAngleDiv); |
||||
float randF = (0.5f - GD.Randf()); |
||||
int randI = GD.RandRange(0, 10); |
||||
// Get lowest free node |
||||
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(-randAngle); |
||||
break; |
||||
case 2: |
||||
dir = dir.Rotated(+randAngle); |
||||
break; |
||||
// 3D... |
||||
|
||||
} |
||||
if (randI < 6) |
||||
maxChildren = 1; |
||||
|
||||
if (RootNode.Direction.Dot(dir) < 0) // ..<0 = 180 grad maxRootDeviationAngle) |
||||
maxChildren = 0; // wenn überhang -> branach ende |
||||
|
||||
seg = new PlantSegmentNode(parent, maxChildren); |
||||
seg.Direction = dir; |
||||
|
||||
|
||||
if (freeindex == 0) // center node |
||||
{ |
||||
seg.Size = parent.Size * 0.95f; |
||||
} |
||||
else |
||||
{ |
||||
seg.Size = parent.Size * (0.88f + randF/10); |
||||
if (randI < 6) |
||||
maxChildren = 2; |
||||
|
||||
} |
||||
|
||||
// if (CheckShootCollided(seg)) |
||||
// { |
||||
// //GD.Print("Collision ", seg); |
||||
// // Add stump dummy - so slot is ignored |
||||
// seg.NodeType = SegmentNodeTypes.Stump; |
||||
// seg.MaxChildren = seg.ChildrenCount; |
||||
// seg.Size = Vector2.Zero;//seg.Size * 0.4f; |
||||
// } |
||||
|
||||
if (parent.AddChild(seg, freeindex)) |
||||
{ |
||||
Segments.Add(_segmentIdCounter, seg); |
||||
_segmentIdCounter++; |
||||
} |
||||
else |
||||
{ |
||||
GD.PrintErr("Error bei Add"); |
||||
} |
||||
} |
||||
|
||||
public Vector2[] CalculateLineVertices() |
||||
{ |
||||
int vertexCount = 2 * Segments.Count; |
||||
Vector2[] vertices = new Vector2[vertexCount]; |
||||
|
||||
for (int i = 0; i < _segmentIdCounter; i++) |
||||
{ |
||||
PlantSegmentNode segment = Segments[i]; |
||||
|
||||
Vector2 pos = segment.VecToRoot; |
||||
Vector2 par = segment.PositionRelativeParent; |
||||
Vector2 dir = segment.Direction; |
||||
Vector2 line = segment.Line; |
||||
Vector2 size = segment.Size; |
||||
|
||||
Vector2 start = pos; |
||||
Vector2 end = pos + line; |
||||
int j = i * 2; |
||||
vertices[j] = start; |
||||
vertices[j+1] = end; |
||||
|
||||
} |
||||
return vertices; |
||||
} |
||||
|
||||
public Vector2[] CalculateVertices() |
||||
{ |
||||
Vector2[] vertices = new Vector2[6 * _segmentIdCounter]; |
||||
|
||||
for (int i = 0; i < Segments.Count; i++) |
||||
{ |
||||
PlantSegmentNode segment = Segments[i]; |
||||
|
||||
Vector2 pos = segment.VecToRoot; |
||||
Vector2 par = segment.PositionRelativeParent; |
||||
Vector2 dir = segment.Direction; |
||||
Vector2 line = segment.Line; |
||||
Vector2 size = segment.Size; |
||||
float width = size.X; |
||||
|
||||
Vector2 a = pos; |
||||
//Vector2 b = new Vector2(a.X, a.Y + size.Y); |
||||
//Vector2 c = new Vector2(b.X + width, b.Y); |
||||
Vector2 b = a + line; |
||||
Vector2 c = new Vector2(b.X + width, b.Y); |
||||
Vector2 d = new Vector2(a.X + width, a.Y); |
||||
|
||||
int j = i * 6; |
||||
vertices[j] = a; |
||||
vertices[j+1] = b; |
||||
vertices[j+2] = c; |
||||
vertices[j+3] = a; |
||||
vertices[j+4] = c; |
||||
vertices[j+5] = d; |
||||
} |
||||
return vertices; |
||||
} |
||||
|
||||
public bool CheckCollision(PlantSegmentNode node) |
||||
{ |
||||
|
||||
|
||||
return false; |
||||
|
||||
} |
||||
private PlantSegmentNode GetFreeSlotSegment(bool descending = false) |
||||
{ |
||||
|
||||
Dictionary<int, PlantSegmentNode> elements = Segments; |
||||
//List<PlantSegmentNode> list = elements.OrderBy(x => x.Key).ToList<PlantSegmentNode>(); |
||||
|
||||
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; |
||||
} |
||||
|
||||
} |
||||
|
||||
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() |
||||
{ |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,414 @@
@@ -0,0 +1,414 @@
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Linq; |
||||
using Godot; |
||||
|
||||
|
||||
public enum SegmentNodeTypes |
||||
{ |
||||
Trunk, |
||||
Branch, |
||||
Leave, |
||||
Fruit, |
||||
Stump, // basically blocks growth |
||||
} |
||||
|
||||
public class PlantSegmentNode : LifeFormSegmentNode |
||||
{ |
||||
//public LifeformNodeConfiguration Settings; |
||||
public Vector2 Size; |
||||
public Vector2 PositionRelativeParent; |
||||
public Vector2 VecToRoot; |
||||
public Vector2 Direction; |
||||
|
||||
private SegmentNodeTypes _nodeType = SegmentNodeTypes.Branch; |
||||
|
||||
public SegmentNodeTypes NodeType |
||||
{ |
||||
get { return _nodeType; } |
||||
set { |
||||
if (value == SegmentNodeTypes.Stump) |
||||
{ |
||||
Size = Vector2.Zero; |
||||
MaxChildren = ChildrenCount; |
||||
Direction = ((PlantSegmentNode)Parent).Direction.Normalized(); |
||||
_nodeType = value; |
||||
} |
||||
|
||||
} |
||||
} |
||||
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; |
||||
PositionRelativeParent = parent.PositionRelativeParent + parent.Line; |
||||
VecToRoot = parent.VecToRoot + parent.Line; |
||||
} |
||||
else // is root |
||||
{ |
||||
// must be root |
||||
Direction = Vector2.Up; |
||||
VecToRoot = Vector2.Zero; |
||||
Size = new Vector2(5, 20); |
||||
PositionRelativeParent = Vector2.Zero; //new Vector2() + Line; |
||||
|
||||
} |
||||
} |
||||
|
||||
public void UpdateSelfToParent() |
||||
{ |
||||
if (IsRoot) |
||||
return; |
||||
|
||||
var parent = (PlantSegmentNode)Parent; |
||||
PositionRelativeParent = parent.PositionRelativeParent + parent.Line; |
||||
} |
||||
|
||||
public Vector2 Line |
||||
{ |
||||
get { return Direction.Normalized() * Size.Length(); } |
||||
} |
||||
|
||||
// public Vector2[] GetPoints() |
||||
// { |
||||
// //Polygon2D polygon = new Polygon2D(); |
||||
// float width = Size.X; |
||||
// float height = Size.Y; |
||||
// |
||||
// Vector2 leftbottom = new Vector2(0 - width/2, 0); |
||||
// Vector2 rightbottom = new Vector2(width / 2, 0); |
||||
// |
||||
// Vector2 lefttop = leftbottom + new Vector2(0, height); |
||||
// Vector2 righttop = rightbottom + new Vector2(0, height); |
||||
// |
||||
// var points = new Vector2[] |
||||
// { |
||||
// leftbottom, lefttop, righttop, rightbottom, leftbottom |
||||
// }; |
||||
// return points; |
||||
// //return polygon; |
||||
// } |
||||
public PlantSegmentNode Get_Child(int index) |
||||
{ |
||||
if (Children[index] is PlantSegmentNode) |
||||
{ |
||||
return (PlantSegmentNode)Children[index]; |
||||
} |
||||
|
||||
return null; |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Calls recursive through all Children |
||||
/// </summary> |
||||
public override void UpdateChildren() |
||||
{ |
||||
UpdateSelfToParent(); |
||||
if (HasChildren) |
||||
{ |
||||
foreach (var child in Children) |
||||
{ |
||||
child?.UpdateChildren(); |
||||
} |
||||
} |
||||
} |
||||
public List<PlantSegmentNode> GetChildren() |
||||
{ |
||||
List<PlantSegmentNode> result = new List<PlantSegmentNode>(); |
||||
|
||||
for (int i = 0; i < Children.Length; i++) |
||||
{ |
||||
if (Children[i] != null) |
||||
result.Add((PlantSegmentNode)Children[i]); |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
public bool AddChild(PlantSegmentNode child, SegmentDirections dir = SegmentDirections.center) |
||||
{ |
||||
return base.AddChild(child, dir); |
||||
} |
||||
} |
||||
|
||||
|
||||
public enum SegmentDirections |
||||
{ |
||||
center, |
||||
left, |
||||
right, |
||||
forward, |
||||
back, |
||||
} |
||||
|
||||
// Neu: Fixe vorgabe der Childnodes - wildwuchs bringt nix. |
||||
// Für 2D node maximal 3 childnodes. mitte(rauf), links, rechts |
||||
// 3D max 5 - mitte(rauf), links, rechts, vorn, hinten, vll. mehr |
||||
// index 0 = immer: mitte(rauf) |
||||
// array wird max. init bei max_child kein adden mehr |
||||
|
||||
|
||||
public abstract class LifeFormSegmentNode |
||||
{ |
||||
public static int NodeCounter = 0; |
||||
public LifeFormSegmentNode Parent; |
||||
protected LifeFormSegmentNode[] Children; |
||||
public int Order = 1; // 1 = root, 2 - child of root, 3.... |
||||
public readonly bool IsRoot = false; |
||||
private int _maxChildren; |
||||
private int _maxRecursiveChildren; |
||||
private int _childCount = 0; |
||||
|
||||
public int Id; |
||||
// reduce macht im moment noch nix. Nodes bleiben.... |
||||
public int MaxChildren |
||||
{ |
||||
get { return _maxChildren; } |
||||
set |
||||
{ |
||||
if (value > 0) |
||||
{ |
||||
_maxChildren = value; |
||||
} |
||||
else |
||||
{ |
||||
value = 0; |
||||
} |
||||
} |
||||
} |
||||
|
||||
public LifeFormSegmentNode(LifeFormSegmentNode parent, int maxChildren = 3, int maxRecursiveChildren = 4096) |
||||
{ |
||||
_maxChildren = maxChildren; |
||||
|
||||
if (parent == null) |
||||
{ |
||||
IsRoot = true; |
||||
Order = 1; |
||||
_maxRecursiveChildren = maxRecursiveChildren; |
||||
GD.Print("Root Node erstellt"); |
||||
} |
||||
else |
||||
{ |
||||
Parent = parent; |
||||
Order = parent.Order + 1; |
||||
// Count down the values through the child nodes |
||||
_maxRecursiveChildren = parent._maxRecursiveChildren - _maxChildren; |
||||
|
||||
if (_maxRecursiveChildren <= 0) |
||||
{ |
||||
_maxRecursiveChildren = 0; |
||||
_maxChildren = 0; |
||||
} |
||||
else if (_maxRecursiveChildren < _maxChildren) |
||||
_maxChildren = maxRecursiveChildren; |
||||
} |
||||
|
||||
Children = new LifeFormSegmentNode[_maxChildren]; |
||||
|
||||
// Iterate ID |
||||
Id = LifeFormSegmentNode.NodeCounter; |
||||
LifeFormSegmentNode.NodeCounter++; |
||||
} |
||||
|
||||
public bool AddChild(LifeFormSegmentNode childNode, int index) |
||||
{ |
||||
if (!HasFreeChildSlot || Children[index] != null || index > _maxChildren -1) |
||||
return false; |
||||
|
||||
if (childNode.Parent != this) |
||||
throw new Exception("Kukuk Error: Child is not of this node."); |
||||
|
||||
//childNode.Parent = this; |
||||
childNode.Order = this.Order + 1; |
||||
Children[index] = childNode; |
||||
_childCount++; |
||||
return true; |
||||
} |
||||
|
||||
public bool AddChild(LifeFormSegmentNode childNode, SegmentDirections dir) |
||||
{ |
||||
return AddChild(childNode, (int)dir); |
||||
} |
||||
|
||||
|
||||
public LifeFormSegmentNode GetChild(SegmentDirections dir) |
||||
{ |
||||
return GetChild((int)dir); |
||||
} |
||||
|
||||
public LifeFormSegmentNode GetChild(int index) |
||||
{ |
||||
if (ChildrenCount < index || index > ChildrenCount) |
||||
return null; |
||||
|
||||
return Children[index]; |
||||
|
||||
if (index < _maxChildren - 1 && Children[index] != null) |
||||
return Children[index]; |
||||
else |
||||
{ |
||||
return null; |
||||
} |
||||
} |
||||
public bool HasChildren |
||||
{ |
||||
get { return ChildrenCount > 0; } |
||||
} |
||||
public int ChildrenCount |
||||
{ |
||||
//get { return Children.Count(x => x != null); } |
||||
get { return _childCount; } |
||||
} |
||||
|
||||
public bool HasFreeChildSlot |
||||
{ |
||||
get { return ChildrenCount < _maxChildren; } |
||||
} |
||||
|
||||
public int FreeNodeIndex() |
||||
{ |
||||
// nur first ist immer rechtslastig -> rand? |
||||
|
||||
int i = 0; |
||||
if (!HasFreeChildSlot) |
||||
return -1; |
||||
|
||||
if (Children[0] == null) // center zuerst |
||||
return 0; |
||||
if (_maxChildren > 1) // 1 rechts oder 2 links |
||||
{ |
||||
List<int> nodes = new List<int>(); |
||||
for (int j = 0; j < _maxChildren; j++) |
||||
{ |
||||
if (Children[j] == null) |
||||
nodes.Add(j); |
||||
} |
||||
|
||||
int li = 0; |
||||
li = GD.RandRange(0, nodes.Count-1); |
||||
return nodes[li]; |
||||
} |
||||
return -1; |
||||
} |
||||
|
||||
public abstract void UpdateChildren(); |
||||
} |
||||
|
||||
// public abstract class LifeFormSegmentNode |
||||
// { |
||||
// |
||||
// public LifeFormSegmentNode Parent; |
||||
// protected LifeFormSegmentNode[] Children; |
||||
// public readonly int Order = 1; // 1 = root, 2 - child of root, 3.... |
||||
// public readonly bool IsRoot = false; |
||||
// private int _maxChildren; |
||||
// private int _maxRecursiveChildren; |
||||
// private int _lastChildIndex = 0; |
||||
// |
||||
// public bool HasChildren |
||||
// { |
||||
// get { return (_lastChildIndex > 0); } |
||||
// } |
||||
// |
||||
// public LifeFormSegmentNode(LifeFormSegmentNode parent, int maxChildren = 3, int maxRecursiveChildren = 4096) |
||||
// { |
||||
// _maxChildren = maxChildren; |
||||
// |
||||
// if (parent == null) |
||||
// { |
||||
// IsRoot = true; |
||||
// Order = 1; |
||||
// _maxRecursiveChildren = maxRecursiveChildren; |
||||
// GD.Print("Root Node erstellt"); |
||||
// } |
||||
// else |
||||
// { |
||||
// Parent = parent; |
||||
// Order = parent.Order + 1; |
||||
// // Count down the values through the child nodes |
||||
// _maxRecursiveChildren = parent._maxRecursiveChildren - _maxChildren; |
||||
// |
||||
// if (_maxRecursiveChildren <= 0) |
||||
// { |
||||
// _maxRecursiveChildren = 0; |
||||
// _maxChildren = 0; |
||||
// } |
||||
// else if (_maxRecursiveChildren < _maxChildren) |
||||
// _maxChildren = maxRecursiveChildren; |
||||
// } |
||||
// Children = new LifeFormSegmentNode[_maxChildren]; |
||||
// |
||||
// } |
||||
// |
||||
// public bool HasFreeChildSlot |
||||
// { |
||||
// get { return (_lastChildIndex <= _maxChildren - 1); } |
||||
// } |
||||
// public int ChildrenCount |
||||
// { |
||||
// get { return _lastChildIndex + 1; } |
||||
// } |
||||
// |
||||
// protected bool AddChild(LifeFormSegmentNode child) |
||||
// { |
||||
// if (HasFreeChildSlot) |
||||
// { |
||||
// if (child.Parent != this) |
||||
// throw new Exception("Kukuk Error: Child is not of this node."); |
||||
// if (Children[_lastChildIndex] == null) |
||||
// { |
||||
// Children[_lastChildIndex] = child; |
||||
// _lastChildIndex++; |
||||
// return true; |
||||
// } |
||||
// } |
||||
// return false; |
||||
// } |
||||
// |
||||
// public abstract void UpdateChildren(); |
||||
// |
||||
// |
||||
// } |
||||
|
||||
// public struct LifeformNodeConfiguration |
||||
// { |
||||
// public float MaxSegmentAngle; |
||||
// public int MaxChildren; |
||||
// public Vector2 Size; |
||||
// public Vector2 Direction; |
||||
// public string ConfigName = "empty"; |
||||
// |
||||
// public LifeformNodeConfiguration(string name, Vector2 direction, Vector2 size, int maxChildren = 3) |
||||
// { |
||||
// ConfigName = name; |
||||
// Direction = direction; |
||||
// Size = size; |
||||
// MaxChildren = maxChildren; |
||||
// MaxSegmentAngle = Mathf.DegToRad(45f); |
||||
// } |
||||
|
||||
|
||||
|
||||
// public static LifeformNodeConfiguration GetTree() |
||||
// { |
||||
// Vector2 size = new Vector2(10, 50); |
||||
// return new LifeformNodeConfiguration("tree", Vector2.Up, size); |
||||
// } |
||||
// public static LifeformNodeConfiguration GetDefault() |
||||
// { |
||||
// LifeformNodeConfiguration conf = new LifeformNodeConfiguration(); |
||||
// conf.MaxSegmentAngle = Mathf.DegToRad(45f); |
||||
// conf.MaxChildren = 3; |
||||
// conf.ConfigName = "default"; |
||||
// conf.Size = Vector2.One; |
||||
// conf.Direction = Vector2.Up; |
||||
// return conf; |
||||
// } |
||||
//} |
||||
Loading…
Reference in new issue