You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

300 lines
6.9 KiB

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()
{
}
}