add spider example
This commit is contained in:
parent
eb42ca3aa6
commit
e4c9793d9a
1 changed files with 225 additions and 0 deletions
225
spider.js
Normal file
225
spider.js
Normal file
|
|
@ -0,0 +1,225 @@
|
|||
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(4, 47);
|
||||
this.repositionDist = 90;
|
||||
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, 7));
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
let numPoints = 0;
|
||||
const bodySizes = [18, 22, 25, 22, 14, 30, 35, 40, 35, 30];
|
||||
const legSizes = [6, 5, 4, 3, 2, 2, 1, 1, 1];
|
||||
|
||||
const bodyPoints = [];
|
||||
const legs = [];
|
||||
let mouseInter = new vec(0, 0);
|
||||
|
||||
function setup() {
|
||||
createCanvas(displayWidth, displayHeight);
|
||||
numPoints = bodySizes.length;
|
||||
|
||||
for (let i = 0; i < numPoints; i++) {
|
||||
let pt = new ConstraintPoint(400, 400, 15);
|
||||
bodyPoints.push(pt);
|
||||
}
|
||||
|
||||
for (let i = 0; i < 8; i++) {
|
||||
legs.push(new Leg());
|
||||
}
|
||||
}
|
||||
|
||||
function draw() {
|
||||
background(180);
|
||||
|
||||
mouseInter.lerp(new vec(mouseX, mouseY), 0.05);
|
||||
let time = millis();
|
||||
|
||||
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 legAngles = [
|
||||
-PI / 3, PI / 3,
|
||||
-PI / 1.8, PI / 1.8,
|
||||
-PI * 0.7, PI * 0.7,
|
||||
-PI * 0.85, PI * 0.85
|
||||
];
|
||||
|
||||
let legAttachmentIndices = [1, 1, 2, 2, 3, 3, 4, 4];
|
||||
|
||||
for (let i = 0; i < 8; i++) {
|
||||
let baseJoint = bodyPoints[legAttachmentIndices[i]];
|
||||
let bodyRadius = bodySizes[legAttachmentIndices[i]];
|
||||
|
||||
let basePos = baseJoint.getRel(legAngles[i], bodyRadius * 0.6);
|
||||
|
||||
let reach = 120;
|
||||
let endPos = baseJoint.getRel(legAngles[i], reach);
|
||||
|
||||
legs[i].moveTo(basePos.x, basePos.y, endPos.x, endPos.y);
|
||||
}
|
||||
|
||||
fill(30);
|
||||
stroke(10);
|
||||
strokeWeight(1);
|
||||
|
||||
for (let i = 0; i < 8; i++) {
|
||||
drawPoints(legs[i].getPoints(), legSizes);
|
||||
}
|
||||
|
||||
let currentBodySizes = [...bodySizes];
|
||||
let breathSpeed = time * 0.005;
|
||||
|
||||
for (let i = 0; i < numPoints; i++) {
|
||||
if (i > 4) {
|
||||
let breathExpansion = sin(breathSpeed - i * 0.2) * 2.5;
|
||||
currentBodySizes[i] += breathExpansion;
|
||||
}
|
||||
}
|
||||
|
||||
drawPoints(bodyPoints, currentBodySizes);
|
||||
|
||||
let eye1 = bodyPoints[0].getRel(PI / 5, 12);
|
||||
let eye2 = bodyPoints[0].getRel(-PI / 5, 12);
|
||||
let eye3 = bodyPoints[0].getRel(PI / 2.5, 15);
|
||||
let eye4 = bodyPoints[0].getRel(-PI / 2.5, 15);
|
||||
|
||||
fill(220, 20, 20);
|
||||
noStroke();
|
||||
circle(eye1.x, eye1.y, 8);
|
||||
circle(eye2.x, eye2.y, 8);
|
||||
circle(eye3.x, eye3.y, 4);
|
||||
circle(eye4.x, eye4.y, 4);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue