想要代码敲的好,高数算法不能少
html部分
<canvas id="c"></canvas>
css部分
* {
margin: 0;
overflow: hidden;
user-select: none;
}
body {
background: #333;
}
canvas {
background: #333;
width: 1000px;
height: 365px;
margin: 0 auto;
display: block;
}
js部分
var canvas;
var ctx;
var cloth;
var mouse = {
down: false,
button: 1,
x: 0,
y: 0,
px: 0,
py: 0
};
window.addEventListener("load", init);
requestAnimationFrame(update);
function init(e) {
canvas = document.getElementById('c');
ctx = canvas.getContext('2d');
canvas.width = canvas.clientWidth;
canvas.height = 365;
canvas.addEventListener("mousedown", mouseHandler);
canvas.addEventListener("mouseup", mouseHandler);
canvas.addEventListener("mousemove", mouseHandler);
canvas.addEventListener("oncontextmenu", mouseHandler);
ctx.strokeStyle = 'rgba(222,222,222,0.6)';
cloth = new Cloth(canvas.width);
}
function mouseHandler(e) {
if (e.type === "mousedown") {
mouse.button = e.which;
mouse.down = true;
} else if (e.type === "mouseup") {
mouse.down = false;
}
mouse.px = mouse.x;
mouse.py = mouse.y;
var rect = canvas.getBoundingClientRect();
mouse.x = e.clientX - rect.left;
mouse.y = e.clientY - rect.top;
e.preventDefault();
}
function Point(x, y) {
this.x = x;
this.y = y;
this.px = x;
this.py = y;
this.constraints = [];
}
Point.prototype = {
x: 0,
y: 0,
px: 0,
py: 0,
vx: 0,
vy: 0,
pin_x: null,
pin_y: null,
constraints: [],
update: function (delta, mouseObj) {
var mouse_influence = 20;
var mouse_cut = 5;
var gravity = 1000;
if (mouseObj.down) {
var diff_x = this.x - mouseObj.x;
var diff_y = this.y - mouseObj.y;
var dist = Math.sqrt(diff_x * diff_x + diff_y * diff_y);
if (mouseObj.button === 1) {
if (dist < mouse_influence) {
this.px = this.x - (mouseObj.x - mouseObj.px) * 1.8;
this.py = this.y - (mouseObj.y - mouseObj.py) * 1.8;
}
} else if (dist < mouse_cut) {
this.constraints = [];
}
}
this.add_force(0, gravity);
delta *= delta;
var nx = this.x + ((this.x - this.px) * .99) + ((this.vx / 2) * delta);
var ny = this.y + ((this.y - this.py) * .99) + ((this.vy / 2) * delta);
this.px = this.x;
this.py = this.y;
this.x = nx;
this.y = ny;
this.vy = this.vx = 0
},
draw: function () {
if (this.constraints.length <= 0) return;
for (var i = 0; i < this.constraints.length; i++) {
this.constraints[i].draw();
}
},
resolve_constraints: function (width, height) {
if (this.pin_x !== null && this.pin_y !== null) {
this.x = this.pin_x;
this.y = this.pin_y;
return;
}
for (var i = 0; i < this.constraints.length; i++) {
this.constraints[i].resolve();
}
if (this.x > width) {
this.x = 2 * width - this.x;
} else if (this.x < 1) {
this.x = 2 - this.x
}
if (this.y < 1) {
this.y = 2 - this.y
} else if (this.y > height) {
this.y = 2 * height - this.y
}
},
attach: function (point) {
var p = new Constraint(this, point);
this.constraints.push(p);
},
remove_constraint: function (lnk) {
for (var i = 0; i < this.constraints.length; i++) {
if (this.constraints[i] === lnk) {
this.constraints.splice(i, 1);
}
}
},
add_force: function (x, y) {
this.vx += x;
this.vy += y;
},
pin: function (x, y) {
this.pin_x = x;
this.pin_y = y;
}
};
function Constraint(p1, p2) {
this.p1 = p1;
this.p2 = p2;
this.length = Cloth.SPACING;
}
Constraint.prototype = {
p1: null,
p2: null,
length: 0,
resolve: function () {
var tear_distance = 60;
var diff_x = this.p1.x - this.p2.x;
var diff_y = this.p1.y - this.p2.y;
var dist = Math.sqrt(diff_x * diff_x + diff_y * diff_y);
var diff = (this.length - dist) / dist;
if (dist > tear_distance) {
this.p1.remove_constraint(this);
}
var px = diff_x * diff * 0.5;
var py = diff_y * diff * 0.5;
this.p1.x += px;
this.p1.y += py;
this.p2.x -= px;
this.p2.y -= py;
},
draw: function () {
ctx.moveTo(this.p1.x, this.p1.y);
ctx.lineTo(this.p2.x, this.p2.y);
}
};
function Cloth(canvasW) {
this.points = [];
var cloth_height = 30;
var cloth_width = 50;
var start_y = 20;
var start_x = canvasW/ 2 - cloth_width * Cloth.SPACING / 2;
for (var y = 0; y <= cloth_height; y++) {
for (var x = 0; x <= cloth_width; x++) {
var p = new Point(start_x + x * Cloth.SPACING, start_y + y * Cloth.SPACING);
if (x) {
p.attach(this.points[this.points.length - 1]);
}
if (!y) {
p.pin(p.x, p.y);
}
if (y) {
p.attach(this.points[x + (y - 1) * (cloth_width + 1)]);
}
this.points.push(p);
}
}
}
Cloth.SPACING = 7;
Cloth.prototype = {
update: function (mouseObj, width, height) {
var physics_accuracy = 5;
for (var i = 0; i < physics_accuracy; i++) {
for (var j = 0; j < this.points.length; j++) {
this.points[j].resolve_constraints(width, height);
}
}
for (var k = 0; k < this.points.length; k++) {
this.points[k].update(.016, mouseObj);
}
},
draw: function () {
ctx.beginPath();
for (var i = 0; i < cloth.points.length; i++) {
cloth.points[i].draw();
}
ctx.stroke();
}
};
function update() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
cloth.update(mouse, canvas.width - 1, canvas.height - 1);
cloth.draw();
requestAnimationFrame(update);
}