Files
UltimateFishing/Assets/Scripts/Assembly-CSharp/Mtree/Node.cs
2026-02-21 16:45:37 +08:00

326 lines
8.7 KiB
C#

using System.Collections.Generic;
using UnityEngine;
namespace Mtree
{
public class Node
{
public List<Node> children;
public Vector3 position;
public Vector3 direction;
public float radius;
public int creator;
public float distanceFromOrigin;
public NodeType type;
public GrowthInformation growth;
public float positionInBranch;
public float branchVariation;
public Node(Vector3 pos, float rad, Vector3 dir, int crea, NodeType type = NodeType.Branch, float distancToOrigin = 0f)
{
position = pos;
radius = rad;
direction = dir;
children = new List<Node>();
creator = crea;
growth = new GrowthInformation(0f, 0f, 1f);
this.type = type;
distanceFromOrigin = distancToOrigin;
}
public Queue<Node> Grow(float length, float splitProba, int maxNumber, float rad, float secondaryBranchRadius, float angle, int creator, float randomness, float upAttraction, Transform treeTransform, float gravityStrength, float flatten)
{
int num = (int)(splitProba / Random.value) + 1;
if (num > maxNumber)
{
num = maxNumber;
}
if (!growth.canBeSplit)
{
num = 1;
}
Queue<Node> queue = new Queue<Node>();
bool flag = length > growth.remainingGrowth;
if (flag)
{
length = growth.remainingGrowth;
}
Vector3 vector = Vector3.zero;
for (int i = 0; i < num; i++)
{
Vector3 vector2 = Random.onUnitSphere;
if (flatten >= 0f && num > 1)
{
vector2 = Vector3.Lerp(vector2, Vector3.up * (Random.Range(0, 1) * 2 - 1), flatten);
}
Vector3 vector3 = Vector3.Cross(vector2, direction);
if (num == 2)
{
if (i == 0)
{
vector = vector3;
}
if (i == 1)
{
vector3 = -vector;
}
randomness = secondaryBranchRadius * angle;
}
if (vector3.y < 0f)
{
vector3.y -= vector3.y * upAttraction;
}
Vector3 vector4 = Vector3.down * gravityStrength * 0.1f * length;
if (i == 0)
{
Vector3 dir = Vector3.Lerp(direction, vector3, randomness).normalized;
if (!ObstacleAvoidance(ref dir, position, treeTransform, 10f))
{
dir += vector4;
if (gravityStrength != 0f)
{
dir.Normalize();
}
Vector3 vector5 = position + dir * length;
Vector3 pos = vector5;
float rad2 = rad;
Vector3 dir2 = dir;
int crea = creator;
float distancToOrigin = distanceFromOrigin + length / (0.1f + radius);
Node node = new Node(pos, rad2, dir2, crea, NodeType.Branch, distancToOrigin);
node.growth = new GrowthInformation(growth.growthGoal, growth.remainingGrowth - length, growth.initialRadius);
if (!flag)
{
queue.Enqueue(node);
}
children.Add(node);
}
continue;
}
Vector3 dir3 = (direction * (1f - angle) + vector3 * angle).normalized;
if (!ObstacleAvoidance(ref dir3, position, treeTransform, 10f))
{
dir3 += vector4;
if (gravityStrength != 0f)
{
dir3.Normalize();
}
Vector3 vector6 = position + dir3 * length;
Vector3 pos = position;
float distancToOrigin = rad * 0.9f;
Vector3 dir4 = dir3;
int crea = creator;
float rad2 = distanceFromOrigin;
Node node2 = new Node(pos, distancToOrigin, dir4, crea, NodeType.Branch, rad2);
node2.growth.canBeSplit = false;
dir4 = vector6;
rad2 = rad * secondaryBranchRadius;
pos = dir3;
crea = creator;
distancToOrigin = distanceFromOrigin + length;
Node node3 = new Node(dir4, rad2, pos, crea, NodeType.Branch, distancToOrigin);
node2.children.Add(node3);
children.Add(node2);
node3.growth = new GrowthInformation(growth.growthGoal, growth.remainingGrowth - length, growth.initialRadius * secondaryBranchRadius);
if (!flag)
{
queue.Enqueue(node3);
}
}
}
return queue;
}
public Stack<Queue<TreePoint>> ToSplines()
{
Stack<Queue<TreePoint>> stack = new Stack<Queue<TreePoint>>();
stack.Push(new Queue<TreePoint>());
ToSplinesRec(stack, Vector3.up);
return stack;
}
private void ToSplinesRec(Stack<Queue<TreePoint>> points, Vector3 parentDirection, float parentRadius = 0f)
{
int count = children.Count;
float parentRadius2 = radius;
if (type == NodeType.Trunk && count > 0)
{
parentRadius2 = children[0].radius;
direction = (children[0].position - position).normalized;
}
points.Peek().Enqueue(new TreePoint(position, direction, radius, type, parentDirection, distanceFromOrigin, parentRadius));
if (count > 0)
{
children[0].ToSplinesRec(points, direction);
}
for (int i = 1; i < count; i++)
{
points.Push(new Queue<TreePoint>());
children[i].ToSplinesRec(points, direction, parentRadius2);
}
}
public void GetSelection(Queue<Node> selected, int selection, bool extremitiesOnly, ref float maxHeight)
{
if (selection == creator && (!extremitiesOnly || children.Count <= 0))
{
selected.Enqueue(this);
if (position.y > maxHeight)
{
maxHeight = position.y;
}
}
foreach (Node child in children)
{
child.GetSelection(selected, selection, extremitiesOnly, ref maxHeight);
}
}
public void GetSplitCandidates(Queue<Node> selected, int selection, float start, float remainingLength)
{
if (start <= positionInBranch && selection == creator && children.Count == 1)
{
positionInBranch = (positionInBranch - start) * (1f - start);
selected.Enqueue(this);
}
for (int i = 0; i < children.Count; i++)
{
if (i == 0)
{
float magnitude = (children[i].position - position).magnitude;
children[i].GetSplitCandidates(selected, selection, start, remainingLength - magnitude);
}
else
{
children[i].GetSplitCandidates(selected, selection, start, start);
}
}
}
public void DebugPosRec(List<Vector3> positions)
{
positions.Add(position);
foreach (Node child in children)
{
child.DebugPosRec(positions);
}
}
public void AddGrowth(float growthLength)
{
growth.remainingGrowth = growthLength;
growth.growthGoal = growthLength;
growth.initialRadius = radius;
}
private bool ObstacleAvoidance(ref Vector3 dir, Vector3 position, Transform transform, float distance)
{
RaycastHit hitInfo;
if (Physics.Raycast(transform.TransformPoint(position), transform.TransformDirection(dir), out hitInfo, distance))
{
Vector3 vector = transform.InverseTransformDirection(hitInfo.normal) * Mathf.Exp((0f - hitInfo.distance) * 0.3f) * 1f;
dir += vector;
dir.Normalize();
return vector.magnitude > 0.5f;
}
return false;
}
public void GetLeafCandidates(Queue<LeafCandidate> candidates, float maxBranchRadius, ref float totalLength, int selection)
{
if (radius < maxBranchRadius && creator == selection)
{
float num = 0f;
if (children.Count > 0)
{
num = (children[0].position - position).magnitude;
}
totalLength += num;
candidates.Enqueue(new LeafCandidate(position, direction, Mathf.Pow(radius, 0.2f), num, distanceFromOrigin, children.Count > 0));
}
foreach (Node child in children)
{
child.GetLeafCandidates(candidates, maxBranchRadius, ref totalLength, selection);
}
}
public void Simplify(Node parent, float angleThreshold, float radiusThreshold)
{
if (radius < radiusThreshold)
{
children = new List<Node>();
return;
}
Node parent2 = this;
int count;
if (children.Count > 0 && parent != null && parent.radius / children[0].radius < 2f)
{
Vector3 vector = position - parent.position;
Vector3 to = children[0].position - position;
if (Vector3.Angle(vector, to) < angleThreshold && type != NodeType.Flare)
{
List<Node> list = new List<Node>();
list.Add(children[0]);
List<Node> list2 = list;
count = parent.children.Count;
for (int i = 1; i < count; i++)
{
list2.Add(parent.children[i]);
}
count = children.Count;
for (int j = 1; j < count; j++)
{
list2.Add(children[j]);
}
parent.children = list2;
parent2 = parent;
}
}
count = 0;
foreach (Node child in children)
{
if (count == 0)
{
child.Simplify(parent2, angleThreshold, radiusThreshold);
}
else
{
child.Simplify(null, angleThreshold, radiusThreshold);
}
count++;
}
}
public float UpdatePositionInBranch(float distanceFromBranchOrigin = 0f, Node parent = null)
{
float num = ((parent != null) ? Vector3.Distance(parent.position, position) : 0f);
num += distanceFromBranchOrigin;
float num2;
if (children.Count == 0)
{
positionInBranch = 1f;
num2 = num;
}
else
{
num2 = children[0].UpdatePositionInBranch(num, this);
positionInBranch = num / num2;
for (int i = 1; i < children.Count; i++)
{
children[i].UpdatePositionInBranch();
}
}
return num2;
}
}
}