/// <summary> /// Nudge the tree to create a zig-zag effect (so that the tree isn't dead straight) /// </summary> /// <param name="trunk">A trunk particle</param> private void TrunkNudgeBehaviour(Particle2D trunk) { // subtle x nudgings if (rnd.NextDouble() < zigzagTrunkPercentage) { // rotate the growing vector by a random zigzag strength factor trunk.Direction = trunk.Direction.Rotate(LineairScaleTo(rnd.NextDouble(), -zigzagTrunkStrength, zigzagTrunkStrength)); } if (trunk.Direction.Y < 1) { trunk.Direction.Y += 0.1f; } if (trunk.Direction.Y > 1) { trunk.Direction.Y = 1; } }
/// <summary> /// Describes the branching and general behaviour of a branch /// </summary> /// <param name="branchingPercent"></param> /// <param name="branch"></param> /// <param name="depth"></param> private void BranchingBehaviour(float branchingPercent, Particle2D t, int depth) { if (rnd.NextDouble() < branchingPercent)//* (Math.Pow(0.5f, depth))) { // 90 * 2 ^ depth-1 // [-90, 90] degrees => depth =1 // [-45, 45] degrees => depth = 2 // [-22.5, double narrower = (Math.Pow(branchNarrowing, depth)); // create a branch Vector2D initialDirection = t.Direction.Rotate(rnd.Next(-Math.PI * narrower, Math.PI * narrower)); Particle2D branch = new Particle2D() { Location = t.Location, Direction = initialDirection, // the life is based on the the life where it's splitting from (branch or trunk) but reduce the life of the new branch by a factor MaxLife = (int)(t.Life * branchSizeDecrease), Life = (int)(t.Life * branchSizeDecrease), Color = branchColor, }; // define the behaviour of the branch branch.Behaviour = b => { // branches should sprout leaves LeavesBehaviour(b); // branches can branch again BranchingBehaviour(branchingPercent, b, depth + 1); // weight behaviour if (applyWeightOnBranches) { b.Direction = new Vector2D(initialDirection.X, initialDirection.Y * LineairScaleTo((double)b.Life / (double)branch.MaxLife, -1f, 1f)); // +(2 * (((double)b.Life / (double)maxLife)) - 1); } }; particles.Add(branch); } }
/// <summary> /// Describes the behaviour of spawning leaves on branches /// </summary> /// <param name="b"></param> private void LeavesBehaviour(Particle2D b) { // if the branch doesn't have a lot of life left (based on the leaves percentage) if (b.Life < leavesPercentage * b.MaxLife) { // create leaf particles for (int i = 0; i < leavesNrSpawned; i++) { // leaves have no particular behaviour, they just grow until its life is done Particle2D l = new Particle2D() { Direction = new Vector2D(rnd.Next(-1f, 1f), rnd.Next(-1f, 1f)), Location = b.Location, Color = leavesColor, Life = leafLife, MaxLife = leafLife }; particles.Add(l); } } }
/// <summary> /// Describes how a trunk splits /// </summary> /// <param name="trunk">The trunk particle</param> private void TrunkSplittingBehaviour(Particle2D trunk) { // trunk split if (rnd.NextDouble() < trunkSplitPercentage) { // spawn a branch of the trunk in a direction random between [-pi, pi] Vector2D newDirection = trunk.Direction.Rotate(rnd.Next(-Math.PI, Math.PI)); Particle2D secondTrunk = new Particle2D() { Location = trunk.Location, Direction = newDirection, Color = trunk.Color, // reduce its max life with the specified decrease Life = (int)(trunk.Life * trunkSplitSpawnLifeDecrease), MaxLife = (int)(trunk.Life * trunkSplitSpawnLifeDecrease), Behaviour = trunk.Behaviour }; particles.Add(secondTrunk); // if the trhunk if going down, flip it (trunks don't grow down) if (secondTrunk.Direction.Y < 0) { secondTrunk.Direction.Y *= -1; } // reduce the original trunk's life (because splitting has a cost) trunk.Life = (int)(trunk.Life * trunkSplitOrigLifeDecrease); // mirror the new trunk direction to give to the original trunk trunk.Direction = new Vector2D(-newDirection.X, newDirection.Y); //trunk.Direction.Rotate(-Math.PI / 2 * rnd.NextDouble()); // again, check if it's going down and if so flip it if (trunk.Direction.Y < 0) { trunk.Direction.Y *= -1; } } }