diff --git a/sketch.js b/sketch.js index 6fefa8a..969e364 100644 --- a/sketch.js +++ b/sketch.js @@ -1,21 +1,99 @@ -var vec = p5.Vector; +const vec = p5.Vector; -class Segment { - constructor(x, y, size) { +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; } - get_rel(angleOffset, dist) { + getRel(angleOffset, dist) { let dir = vec.rotate(this.forward, angleOffset); dir.setMag(dist); - return vec.add(this.pos, dir) + 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(); @@ -26,7 +104,7 @@ class Segment { while (diff < -PI) diff += TWO_PI; while (diff > PI) diff -= TWO_PI; - let maxAngle = PI / 10; + let maxAngle = this.angleConstraint; diff = constrain(diff, -maxAngle, maxAngle); targetAngle = parentAngle + diff; @@ -34,70 +112,89 @@ class Segment { this.forward = p5.Vector.fromAngle(targetAngle); - let segmentLength = 20; - let dir = p5.Vector.mult(this.forward, -segmentLength); + let dir = p5.Vector.mult(this.forward, -this.size); this.pos = vec.add(target, dir); } } -var n = 0; -var sizes = [60, 55, 50, 40, 45, 47, 50, 45, 42, 39, 35, 30, 25, 22, 17, 13, ] -var segments = []; +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); - n = sizes.length; - for (let i = 0; i < n; i++) { - let seg = new Segment(400, 400, sizes[i]); - segments.push(seg); + 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); + background(150); // fisica - segments[0].follow(mouseX, mouseY); - for (let i = 1; i < n; i++) { - let prev_seg = segments[i - 1]; - segments[i].follow(prev_seg.pos.x, prev_seg.pos.y, prev_seg.forward); + 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); - beginShape(); - let head = segments[0]; - let tail = segments[n - 1]; + leg2.draw(); - for (let a = -HALF_PI; a <= HALF_PI; a += PI / 10) { - let p = head.get_rel(a, head.size); - vertex(p.x, p.y); - } + drawPoints(leg1.getPoints(), [20, 17, 15, 10, 5]); + drawPoints(bodyPoints, sizes); - for (let i = 1; i < n - 1; i++) { - let p = segments[i].get_rel(HALF_PI, segments[i].size); - vertex(p.x, p.y); - } - - for (let a = HALF_PI; a <= HALF_PI + PI; a += PI / 10) { - let p = tail.get_rel(a, tail.size); - vertex(p.x, p.y); - } - - for (let i = n - 2; i >= 1; i--) { - let p = segments[i].get_rel(-HALF_PI, segments[i].size); - vertex(p.x, p.y); - } - - - endShape(CLOSE); - - let eye1 = head.get_rel(HALF_PI / 2, 45); - let eye2 = head.get_rel(-HALF_PI / 2, 45); + 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);