From eb42ca3aa646a4f33d8430e1eb523c75fe79386a Mon Sep 17 00:00:00 2001 From: Daniel Kauss Serna Date: Thu, 12 Mar 2026 13:57:04 +0100 Subject: [PATCH] final steps, change color --- body1.js | 196 +++++++++++++++++++++++++++++++++++++++++ body2.js | 253 +++++++++++++++++++++++++++++++++++++++++++++++++++++ chain3.js | 7 ++ ikjoint.js | 98 +++++++++++++++++++++ sketch.js | 16 ++-- 5 files changed, 563 insertions(+), 7 deletions(-) create mode 100644 body1.js create mode 100644 body2.js create mode 100644 ikjoint.js diff --git a/body1.js b/body1.js new file mode 100644 index 0000000..c64aedc --- /dev/null +++ b/body1.js @@ -0,0 +1,196 @@ +let vec = p5.Vector + +class Leg { + constructor() { + this.base = new vec(0, 0); + this.end = new vec(0, 0); + this.interPos = new vec(0, 0); + this.ikJoint = new IKJoint(8, 8); + this.repositionDist = 50; + this.moveSpeed = 0.4; + } + + moveTo(startX, startY, endX, endY) { + this.base = new vec(startX, startY); + let target = new vec(endX, endY); + + if (vec.dist(target, this.end) > this.repositionDist) { + this.end = new vec(endX, endY); + } + this.interPos.lerp(this.end, this.moveSpeed); + this.ikJoint.moveTo(startX, startY, this.interPos.x, this.interPos.y); + } + + getPoints() { + return this.ikJoint.points; + } +} + +class IKJoint { + constructor(numSegments, pointDist) { + this.origin = new vec(0, 0); + this.points = []; + for (let i = 0; i < numSegments + 1; i++) { + this.points.push(new ConstraintPoint(0, 0, pointDist, 1.3)); + } + this.pointDist = pointDist; + this.iterations = 20; + } + + moveStart(targetX, targetY) { + let numPts = this.points.length; + this.points[0].size = 1; + this.points[0].follow(targetX, targetY); + + for (let i = 1; i < numPts; i++) { + let prevPoint = this.points[i - 1]; + this.points[i].follow(prevPoint.pos.x, prevPoint.pos.y, prevPoint.forward); + } + } + + moveEnd(targetX, targetY) { + let numPts = this.points.length; + this.points[numPts - 1].pos.x = targetX; + this.points[numPts - 1].pos.y = targetY; + + for (let i = numPts - 2; i >= 0; i--) { + let prevPoint = this.points[i + 1]; + this.points[i].follow(prevPoint.pos.x, prevPoint.pos.y, null); + } + } + + moveTo(origX, origY, targetX, targetY) { + for (let i = 0; i < this.iterations; i++) { + this.moveEnd(targetX, targetY); + this.moveStart(origX, origY); + } + } +} + +class ConstraintPoint { + constructor(x, y, size, angleConstraint = 0.2) { + this.size = size; + this.pos = new vec(x, y); + this.forward = new vec(0, 0); + this.angleConstraint = angleConstraint; + } + + getRel(angleOffset, dist) { + let dir = vec.rotate(this.forward, angleOffset); + dir.setMag(dist); + return vec.add(this.pos, dir); + } + + follow(targetX, targetY, parentForward = null) { + let target = new vec(targetX, targetY); + let targetForward = vec.sub(target, this.pos); + let targetAngle = targetForward.heading(); + + if (parentForward) { + let parentAngle = parentForward.heading(); + let diff = targetAngle - parentAngle; + + while (diff < -PI) diff += TWO_PI; + while (diff > PI) diff -= TWO_PI; + + let maxAngle = this.angleConstraint; + diff = constrain(diff, -maxAngle, maxAngle); + + targetAngle = parentAngle + diff; + } + + this.forward = p5.Vector.fromAngle(targetAngle); + + let dir = p5.Vector.mult(this.forward, -this.size); + this.pos = vec.add(target, dir); + } +} +let baseColor; +let gillColor; + +let points = [] +let sizes = [60, 55, 50, 40, 45, 47, 50, 47, 45, 42, 39, 35, 30, 25, 22, 17, 13] +function setup() { + createCanvas(400, 400); + + for (let i = 0;i < sizes.length;i++) { + points.push(new ConstraintPoint(0, 0, 20)); + } + baseColor = color(249, 182, 249) + gillColor = color(243, 158, 189) + +} + +function drawPoints(points, sizes) { + beginShape(); + for (let a = -HALF_PI;a < HALF_PI;a+=0.1) { + let p = points[0].getRel(a, sizes[0]) + vertex(p.x, p.y); + } + for (let i = 0;i < points.length;i++) { + let p = points[i].getRel(HALF_PI, sizes[i]) + vertex(p.x, p.y); + } + + for (let a = HALF_PI;a < HALF_PI + PI;a+=0.1) { + let p = points[points.length -1].getRel(a, sizes[points.length -1]) + vertex(p.x, p.y); + } + + for (let i = points.length-1;i >= 0;i--) { + let p = points[i].getRel(-HALF_PI, sizes[i]) + vertex(p.x, p.y); + } + + endShape(); +} + +let leg1 = new Leg() +let leg2 = new Leg() +let leg3 = new Leg() +let leg4 = new Leg() +let legSizes = [15,15,15,15,15,15,15,15,15,15] +function draw() { + background(220); + + points[0].follow(mouseX, mouseY) + for (let i = 1;i < sizes.length;i++) { + let prev = points[i - 1]; + points[i].follow(prev.pos.x, prev.pos.y, prev.forward); + } + + let legEndDist = 70; + let baseJointL1 = points[2]; + let baseL1 = baseJointL1.getRel(-HALF_PI, 30); + let endL1 = baseJointL1.getRel(-HALF_PI, legEndDist); + let baseR1 = baseJointL1.getRel(HALF_PI, 30); + let endR1 = baseJointL1.getRel(HALF_PI, legEndDist); + + let baseJointL2 = points[6]; + let baseL2 = baseJointL2.getRel(-HALF_PI, 30); + let endL2 = baseJointL2.getRel(-HALF_PI, legEndDist); + let baseR2 = baseJointL2.getRel(HALF_PI, 30); + let endR2 = baseJointL2.getRel(HALF_PI, legEndDist); + + leg1.moveTo(baseL1.x, baseL1.y, endL1.x, endL1.y); + leg2.moveTo(baseR1.x, baseR1.y, endR1.x, endR1.y); + leg3.moveTo(baseL2.x, baseL2.y, endL2.x, endL2.y); + leg4.moveTo(baseR2.x, baseR2.y, endR2.x, endR2.y); + + fill(baseColor); + + drawPoints(leg1.getPoints(), legSizes); + drawPoints(leg2.getPoints(), legSizes); + drawPoints(leg3.getPoints(), legSizes); + drawPoints(leg4.getPoints(), legSizes); + + drawPoints(points, sizes); + + let eye1 = points[0].getRel(HALF_PI / 2, 45) + let eye2 = points[0].getRel(-HALF_PI / 2, 45) + fill(0); + circle(eye1.x, eye1.y, 15); + circle(eye2.x, eye2.y, 15); +} + + diff --git a/body2.js b/body2.js new file mode 100644 index 0000000..44fc2c2 --- /dev/null +++ b/body2.js @@ -0,0 +1,253 @@ +const vec = p5.Vector; + +class Leg { + constructor() { + this.base = new vec(0, 0); + this.end = new vec(0, 0); + this.interPos = new vec(0, 0); + this.ikJoint = new IKJoint(8, 8); + this.repositionDist = 50; + this.moveSpeed = 0.4; + } + + moveTo(startX, startY, endX, endY) { + this.base = new vec(startX, startY); + let target = new vec(endX, endY); + + if (vec.dist(target, this.end) > this.repositionDist) { + this.end = new vec(endX, endY); + } + this.interPos.lerp(this.end, this.moveSpeed); + this.ikJoint.moveTo(startX, startY, this.interPos.x, this.interPos.y); + } + + getPoints() { + return this.ikJoint.points; + } +} + +class IKJoint { + constructor(numSegments, pointDist) { + this.origin = new vec(0, 0); + this.points = []; + for (let i = 0; i < numSegments + 1; i++) { + this.points.push(new ConstraintPoint(0, 0, pointDist, 0.5)); + } + this.pointDist = pointDist; + this.iterations = 20; + } + + moveStart(targetX, targetY) { + let numPts = this.points.length; + this.points[0].size = 1; + this.points[0].follow(targetX, targetY); + + for (let i = 1; i < numPts; i++) { + let prevPoint = this.points[i - 1]; + this.points[i].follow(prevPoint.pos.x, prevPoint.pos.y, prevPoint.forward); + } + } + + moveEnd(targetX, targetY) { + let numPts = this.points.length; + this.points[numPts - 1].pos.x = targetX; + this.points[numPts - 1].pos.y = targetY; + + for (let i = numPts - 2; i >= 0; i--) { + let prevPoint = this.points[i + 1]; + this.points[i].follow(prevPoint.pos.x, prevPoint.pos.y, null); + } + } + + moveTo(origX, origY, targetX, targetY) { + for (let i = 0; i < this.iterations; i++) { + this.moveEnd(targetX, targetY); + this.moveStart(origX, origY); + } + } +} + +class ConstraintPoint { + constructor(x, y, size, angleConstraint = 0.2) { + this.size = size; + this.pos = new vec(x, y); + this.forward = new vec(0, 0); + this.angleConstraint = angleConstraint; + } + + getRel(angleOffset, dist) { + let dir = vec.rotate(this.forward, angleOffset); + dir.setMag(dist); + return vec.add(this.pos, dir); + } + + follow(targetX, targetY, parentForward = null) { + let target = new vec(targetX, targetY); + let targetForward = vec.sub(target, this.pos); + let targetAngle = targetForward.heading(); + + if (parentForward) { + let parentAngle = parentForward.heading(); + let diff = targetAngle - parentAngle; + + while (diff < -PI) diff += TWO_PI; + while (diff > PI) diff -= TWO_PI; + + let maxAngle = this.angleConstraint; + diff = constrain(diff, -maxAngle, maxAngle); + + targetAngle = parentAngle + diff; + } + + this.forward = p5.Vector.fromAngle(targetAngle); + + let dir = p5.Vector.mult(this.forward, -this.size); + this.pos = vec.add(target, dir); + } +} + +function drawPoints(points, sizes, turnSegments = 10) { + beginShape(); + + let numPoints = points.length; + let head = points[0]; + let tail = points[numPoints - 1]; + + for (let angle = -HALF_PI; angle <= HALF_PI; angle += PI / turnSegments) { + let p = head.getRel(angle, sizes[0]); + curveVertex(p.x, p.y); + } + + for (let i = 1; i < numPoints - 1; i++) { + let p = points[i].getRel(HALF_PI, sizes[i]); + curveVertex(p.x, p.y); + } + + for (let angle = HALF_PI; angle <= HALF_PI + PI; angle += PI / turnSegments) { + let p = tail.getRel(angle, sizes[numPoints - 1]); + curveVertex(p.x, p.y); + } + + for (let i = numPoints - 2; i >= 1; i--) { + let p = points[i].getRel(-HALF_PI, sizes[i]); + curveVertex(p.x, p.y); + } + endShape(CLOSE); + +} + +function drawGills(basePoint, sign) { + push(); + + let p = basePoint.getRel(sign * 1.5 * PI, 35); + translate(p.x, p.y); + rotate(basePoint.forward.heading() + 0.7 * sign); + + strokeWeight(4); + stroke(0); + fill(243, 158, 189); + + for (let i = -1; i <= 1; i++) { + push(); + rotate(i * QUARTER_PI); + ellipse(-10, 0, 80, 30); + pop(); + } + noStroke(); + + for (let i = -1; i <= 1; i++) { + push(); + rotate(i * QUARTER_PI); + ellipse(-10, 0, 80, 30); + pop(); + } + fill(249, 182, 249); + ellipse(16, 0, 40, 55); + + pop(); +} + +let numPoints = 0; +const bodySizes = [60, 55, 50, 40, 45, 47, 50, 47, 45, 42, 39, 35, 30, 25, 22, 17, 13]; +const legSizes = Array.from({ length: 20 }, () => 15); +const bodyPoints = []; +const leg1 = new Leg(); +const leg2 = new Leg(); +const leg3 = new Leg(); +const leg4 = new Leg(); +let mouseInter = new vec(0, 0); +let baseColor; +let gillColor; + +function setup() { + createCanvas(displayWidth, displayHeight); + numPoints = bodySizes.length; + for (let i = 0; i < numPoints; i++) { + let pt = new ConstraintPoint(400, 400, 20); + bodyPoints.push(pt); + } + baseColor = color(249, 182, 249) + gillColor = color(243, 158, 189) +} + +function draw() { + background(150); + + mouseInter.lerp(new vec(mouseX, mouseY), 0.01); + + // fisica + bodyPoints[0].follow(mouseInter.x, mouseInter.y); + + for (let i = 1; i < numPoints; i++) { + let prevPoint = bodyPoints[i - 1]; + bodyPoints[i].follow(prevPoint.pos.x, prevPoint.pos.y, prevPoint.forward); + } + let legEndDist = 70; + let baseJointL1 = bodyPoints[2]; + let baseL1 = baseJointL1.getRel(-HALF_PI, 30); + let endL1 = baseJointL1.getRel(-HALF_PI, legEndDist); + let baseR1 = baseJointL1.getRel(HALF_PI, 30); + let endR1 = baseJointL1.getRel(HALF_PI, legEndDist); + + let baseJointL2 = bodyPoints[6]; + let baseL2 = baseJointL2.getRel(-HALF_PI, 30); + let endL2 = baseJointL2.getRel(-HALF_PI, legEndDist); + let baseR2 = baseJointL2.getRel(HALF_PI, 30); + let endR2 = baseJointL2.getRel(HALF_PI, legEndDist); + + leg1.moveTo(baseL1.x, baseL1.y, endL1.x, endL1.y); + leg2.moveTo(baseR1.x, baseR1.y, endR1.x, endR1.y); + leg3.moveTo(baseL2.x, baseL2.y, endL2.x, endL2.y); + leg4.moveTo(baseR2.x, baseR2.y, endR2.x, endR2.y); + + // dibujar + fill(baseColor); + stroke(0); + strokeWeight(2); + + drawPoints(leg1.getPoints(), legSizes); + drawPoints(leg2.getPoints(), legSizes); + drawPoints(leg3.getPoints(), legSizes); + drawPoints(leg4.getPoints(), legSizes); + + drawPoints(bodyPoints, bodySizes); + + let p1 = bodyPoints[4].pos; + let p2 = bodyPoints[6].pos; + let p3 = bodyPoints[8].pos; + let p4 = bodyPoints[10].pos; + push(); + noStroke(); + fill(gillColor); + bezier(p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, p4.x, p4.y); + pop(); + + drawGills(bodyPoints[2], 1); + drawGills(bodyPoints[2], -1); + + let eye1 = bodyPoints[0].getRel(HALF_PI / 2, 45); + let eye2 = bodyPoints[0].getRel(-HALF_PI / 2, 45); + fill(0); + circle(eye1.x, eye1.y, 12); + circle(eye2.x, eye2.y, 12); +} diff --git a/chain3.js b/chain3.js index 28b0fe6..d5cd251 100644 --- a/chain3.js +++ b/chain3.js @@ -81,4 +81,11 @@ function draw() { fill(255) drawPoints(points, sizes); + + let eye1 = points[0].getRel(HALF_PI / 2, 45) + let eye2 = points[0].getRel(-HALF_PI / 2, 45) + fill(0); + circle(eye1.x, eye1.y, 15); + circle(eye2.x, eye2.y, 15); } + diff --git a/ikjoint.js b/ikjoint.js new file mode 100644 index 0000000..2f02aa4 --- /dev/null +++ b/ikjoint.js @@ -0,0 +1,98 @@ +let vec = p5.Vector +class IKJoint { + constructor(numSegments, pointDist) { + this.origin = new vec(0, 0); + this.points = []; + for (let i = 0; i < numSegments + 1; i++) { + this.points.push(new ConstraintPoint(0, 0, pointDist, 1.3)); + } + this.pointDist = pointDist; + this.iterations = 20; + } + + moveStart(targetX, targetY) { + let numPts = this.points.length; + this.points[0].size = 1; + this.points[0].follow(targetX, targetY); + + for (let i = 1; i < numPts; i++) { + let prevPoint = this.points[i - 1]; + this.points[i].follow(prevPoint.pos.x, prevPoint.pos.y, prevPoint.forward); + } + } + + moveEnd(targetX, targetY) { + let numPts = this.points.length; + this.points[numPts - 1].pos.x = targetX; + this.points[numPts - 1].pos.y = targetY; + + for (let i = numPts - 2; i >= 0; i--) { + let prevPoint = this.points[i + 1]; + this.points[i].follow(prevPoint.pos.x, prevPoint.pos.y, null); + } + } + + moveTo(origX, origY, targetX, targetY) { + for (let i = 0; i < this.iterations; i++) { + this.moveEnd(targetX, targetY); + this.moveStart(origX, origY); + } + } +} + +class ConstraintPoint { + constructor(x, y, size, angleConstraint = 0.2) { + this.size = size; + this.pos = new vec(x, y); + this.forward = new vec(0, 0); + this.angleConstraint = angleConstraint; + } + + getRel(angleOffset, dist) { + let dir = vec.rotate(this.forward, angleOffset); + dir.setMag(dist); + return vec.add(this.pos, dir); + } + + follow(targetX, targetY, parentForward = null) { + let target = new vec(targetX, targetY); + let targetForward = vec.sub(target, this.pos); + let targetAngle = targetForward.heading(); + + if (parentForward) { + let parentAngle = parentForward.heading(); + let diff = targetAngle - parentAngle; + + while (diff < -PI) diff += TWO_PI; + while (diff > PI) diff -= TWO_PI; + + let maxAngle = this.angleConstraint; + diff = constrain(diff, -maxAngle, maxAngle); + + targetAngle = parentAngle + diff; + } + + this.forward = p5.Vector.fromAngle(targetAngle); + + let dir = p5.Vector.mult(this.forward, -this.size); + this.pos = vec.add(target, dir); + } +} + +let ik = new IKJoint(8, 20); +function setup() { + createCanvas(400, 400); +} + +function draw() { + background(220); + ik.moveTo(200, 200, mouseX, mouseY); + + for (let i = 0;i < 8;i++) { + let p = ik.points[i].pos + noFill(); + circle(p.x, p.y, 20); + } + +} + diff --git a/sketch.js b/sketch.js index a9791c5..a01626e 100644 --- a/sketch.js +++ b/sketch.js @@ -52,8 +52,6 @@ class IKJoint { let numPts = this.points.length; this.points[numPts - 1].pos.x = targetX; this.points[numPts - 1].pos.y = targetY; - // this.points[numPts - 1].size = 1; - // this.points[numPts - 1].follow(targetX, targetY); for (let i = numPts - 2; i >= 0; i--) { let prevPoint = this.points[i + 1]; @@ -108,14 +106,14 @@ class ConstraintPoint { } } -function drawPoints(points, sizes) { +function drawPoints(points, sizes, turnSegments = 10) { beginShape(); let numPoints = points.length; let head = points[0]; let tail = points[numPoints - 1]; - for (let angle = -HALF_PI; angle <= HALF_PI; angle += PI / 10) { + for (let angle = -HALF_PI; angle <= HALF_PI; angle += PI / turnSegments) { let p = head.getRel(angle, sizes[0]); curveVertex(p.x, p.y); } @@ -125,7 +123,7 @@ function drawPoints(points, sizes) { curveVertex(p.x, p.y); } - for (let angle = HALF_PI; angle <= HALF_PI + PI; angle += PI / 10) { + for (let angle = HALF_PI; angle <= HALF_PI + PI; angle += PI / turnSegments) { let p = tail.getRel(angle, sizes[numPoints - 1]); curveVertex(p.x, p.y); } @@ -178,6 +176,8 @@ const leg2 = new Leg(); const leg3 = new Leg(); const leg4 = new Leg(); let mouseInter = new vec(0, 0); +let baseColor; +let gillColor; function setup() { createCanvas(displayWidth, displayHeight); @@ -186,6 +186,8 @@ function setup() { let pt = new ConstraintPoint(400, 400, 20); bodyPoints.push(pt); } + baseColor = color(249, 182, 249) + gillColor = color(243, 158, 189) } function draw() { @@ -230,7 +232,7 @@ function draw() { leg4.moveTo(baseR2.x, baseR2.y, endR2.x, endR2.y); // dibujar - fill(249, 182, 249); + fill(baseColor); stroke(0); strokeWeight(2); @@ -257,7 +259,7 @@ function draw() { let p4 = bodyPoints[10].pos; push(); noStroke(); - fill(243, 158, 189); + fill(gillColor); bezier(p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, p4.x, p4.y); pop();