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