const vec = p5.Vector; class Leg { constructor() { this.base = new vec(0, 0); this.end = new vec(0, 0); this.ikJoint = new IKJoint(4, 30); } moveTo(startX, startY, endX, endY) { this.base = new vec(startX, startY); let target = new vec(endX, endY); if (vec.dist(target, this.end) > 80) { this.end = new vec(endX, endY); } this.ikJoint.moveTo(startX, startY, this.end.x, this.end.y); } getPoints() { return this.ikJoint.points; } draw() { let points = this.ikJoint.points; let numPts = points.length; let px = this.base.x; let py = this.base.y; for (let i = 0; i < numPts; i++) { let pt = points[i]; line(px, py, pt.pos.x, pt.pos.y); px = pt.pos.x; py = pt.pos.y; } } } class IKJoint { constructor(numPoints, pointDist) { this.origin = new vec(0, 0); this.points = []; for (let i = 0; i < numPoints + 1; i++) { this.points.push(new ConstraintPoint(0, 0, pointDist, 10)); } this.pointDist = pointDist; this.iterations = 15; } moveStart(targetX, targetY) { let numPts = this.points.length; this.points[0].pos.x = targetX; this.points[0].pos.y = targetY; 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, prevPoint.forward); } } 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 numPoints = 0; const sizes = [60, 55, 50, 40, 45, 47, 50, 47, 45, 42, 39, 35, 30, 25, 22, 17, 13]; const bodyPoints = []; const leg1 = new Leg(); const leg2 = new Leg(); const leg3 = new Leg(); const leg4 = new Leg(); function setup() { createCanvas(800, 800); numPoints = sizes.length; for (let i = 0; i < numPoints; i++) { let pt = new ConstraintPoint(400, 400, 20); bodyPoints.push(pt); } } function drawPoints(points, sizes) { 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) { let p = head.getRel(angle, sizes[0]); vertex(p.x, p.y); } for (let i = 1; i < numPoints - 1; i++) { let p = points[i].getRel(HALF_PI, sizes[i]); vertex(p.x, p.y); } for (let angle = HALF_PI; angle <= HALF_PI + PI; angle += PI / 10) { let p = tail.getRel(angle, sizes[numPoints - 1]); vertex(p.x, p.y); } for (let i = numPoints - 2; i >= 1; i--) { let p = points[i].getRel(-HALF_PI, sizes[i]); vertex(p.x, p.y); } endShape(CLOSE); } function draw() { background(150); // fisica bodyPoints[0].follow(mouseX, mouseY); for (let i = 1; i < numPoints; i++) { let prevPoint = bodyPoints[i - 1]; bodyPoints[i].follow(prevPoint.pos.x, prevPoint.pos.y, prevPoint.forward); } let baseJoint = bodyPoints[2]; let baseL1 = baseJoint.getRel(-HALF_PI, 20); let endL1 = baseJoint.getRel(-HALF_PI, 100); let baseR1 = baseJoint.getRel(HALF_PI, 20); let endR1 = baseJoint.getRel(HALF_PI, 100); leg1.moveTo(baseL1.x, baseL1.y, endL1.x, endL1.y); leg2.moveTo(baseR1.x, baseR1.y, endR1.x, endR1.y); // dibujar fill(249, 182, 249); stroke(0); strokeWeight(2); leg2.draw(); drawPoints(leg1.getPoints(), [20, 17, 15, 10, 5]); drawPoints(bodyPoints, sizes); 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); }