class Plant {
constructor(x, y, seedShape, germinationFrame) {
this.x = x;
this.y = y;
this.seedShape = seedShape;
this.germinationFrame = germinationFrame;
this.age = 0;
this.maxSize = random(40, 80);
this.maxBranches = floor(random(25, 60));
this.growthChance = random(0.1, 0.3);
this.nutrientConsumptionRate = random(0.1, 0.5);
this.hue;
this.saturation = 80;
this.brightness = 70;
this.branches = [];
switch (seedShape) {
case 'triangle':
this.hue = map(random(), 0, 1, 30, 50);
break;
case 'square':
this.hue = map(random(), 0, 1, 45, 65);
break;
case 'pentagon':
case 'hexagon':
this.hue = map(random(), 0, 1, 180, 220);
break;
}
let trunkLength = random(10, 20);
let trunkThickness = random(2, 4);
this.branches.push(new Branch(createVector(0, 0), createVector(0, -1), trunkLength, trunkThickness, 0));
}
update() {
this.age++;
let plantBaseX = floor(this.x / cellSize);
let plantBaseY = floor((this.y - (height - soilHeight)) / cellSize);
for (let rOffset = 0; rOffset < 3; rOffset++) {
let cellR = plantBaseY - rOffset;
let cellC = plantBaseX;
if (cellR >= 0 && cellR < rows && cellC >= 0 && cellC < cols) {
soilGrid[cellR][cellC] = constrain(soilGrid[cellR][cellC] - (this.nutrientConsumptionRate / 3), 0, 100);
}
}
if (random() < this.growthChance && this.branches.length < this.maxBranches) {
let activeBranches = this.branches.filter(b => b.active);
if (activeBranches.length === 0) return;
let parentBranch = random(activeBranches);
let lightDirection = createVector(0, -1);
let avoidanceDirection = createVector(0, 0);
for (let otherPlant of plants) {
if (otherPlant !== this) {
let distToOther = dist(this.x, this.y, otherPlant.x, otherPlant.y);
if (distToOther < this.maxSize * 0.75 + otherPlant.maxSize * 0.75) {
let dirToOther = createVector(otherPlant.x - this.x, otherPlant.y - this.y).normalize();
avoidanceDirection.sub(dirToOther);
}
}
}
avoidanceDirection.normalize();
let baseDirection = parentBranch.direction.copy();
baseDirection.add(p5.Vector.mult(lightDirection, 0.5));
baseDirection.add(p5.Vector.mult(avoidanceDirection, 0.3));
baseDirection.normalize();
switch (this.seedShape) {
case 'triangle':
if (parentBranch.depth < 3) {
let newLength = parentBranch.length * random(0.6, 0.8);
let newThickness = parentBranch.thickness * random(0.6, 0.8);
let angle1 = random(-PI / 4, PI / 4);
let newDir1 = rotateVector(baseDirection, angle1);
this.branches.push(new Branch(parentBranch.end, newDir1, newLength, newThickness, parentBranch.depth + 1));
if (random() < 0.5) {
let angle2 = random(-PI / 4, PI / 4);
let newDir2 = rotateVector(baseDirection, angle2);
this.branches.push(new Branch(parentBranch.end, newDir2, newLength, newThickness, parentBranch.depth + 1));
}
}
break;
case 'square':
let newLengthSquare = parentBranch.length * random(0.8, 1.1);
let newThicknessSquare = parentBranch.thickness * random(0.9, 1.1);
let angleSquare = random([-PI / 2, PI / 2]);
angleSquare += random(-PI / 12, PI / 12);
let newDirSquare = rotateVector(baseDirection, angleSquare);
this.branches.push(new Branch(parentBranch.end, newDirSquare, newLengthSquare, newThicknessSquare, parentBranch.depth + 1));
break;
case 'pentagon':
case 'hexagon':
let newLengthCurve = parentBranch.length * random(0.7, 0.9);
let newThicknessCurve = parentBranch.thickness * random(0.7, 0.9);
let spiralBias = (this.seedShape === 'pentagon' ? PI / 12 : -PI / 12);
spiralBias += random(-PI / 24, PI / 24);
let newDirCurve = rotateVector(baseDirection, spiralBias);
this.branches.push(new Branch(parentBranch.end, newDirCurve, newLengthCurve, newThicknessCurve, parentBranch.depth + 1));
if (random() < 0.3) {
let newDirCurve2 = rotateVector(baseDirection, -spiralBias);
this.branches.push(new Branch(parentBranch.end, newDirCurve2, newLengthCurve, newThicknessCurve, parentBranch.depth + 1));
}
break;
}
if (parentBranch.length < 5) parentBranch.active = false;
}
}
draw() {
push();
translate(this.x, this.y);
rotate(sin(frameCount * 0.02) * 0.1);
for (let branch of this.branches) {
branch.draw(this.hue, this.saturation, this.brightness);
}
pop();
}
}