canvas实现鼠标悬浮拖动铅球重力感应效果代码
代码语言:html
所属分类:动画
代码描述:canvas实现鼠标悬浮拖动铅球重力感应效果代码
代码标签: canvas 鼠标 悬浮 拖动 铅球 重力 感应 代码
下面为部分代码预览,完整代码请点击下载或在bfwstudio webide中打开
<!DOCTYPE html>
<html lang="en" >
<head>
<meta charset="UTF-8">
<style>
body, html {
position: absolute;
margin: 0;
padding: 0;
width: 100%;
height: 100%;
overflow: hidden;
}
canvas {
position: absolute;
width: 100%;
height: 100%;
cursor: none;
}
</style>
</head>
<body>
<script >
{
// Code never lies, comments sometimes do.
const Human = class {
constructor(size, gravity, x, y, struct) {
this.x = x;
this.y = y;
this.points = [];
this.constraints = [];
this.angles = [];
this.shapes = [];
// Points
for (const point of struct.points) {
this.points.push(
new Human.Point(canvas.width * x, canvas.height * y, point, size, gravity)
);
}
// constraints and shapes
for (const constraint of struct.constraints) {
const p0 = this.points[constraint.p0];
const p1 = this.points[constraint.p1];
this.constraints.push(new Human.Constraint(p0, p1, constraint));
if (constraint.svg) {
this.shapes.push(
new Human.Shape(p0, p1, constraint, struct.svg[constraint.svg], size)
);
}
}
// angle constraints
for (const angle of struct.angles) {
this.angles.push(
new Human.Angle(
this.points[angle.p0],
this.points[angle.p1],
this.points[angle.p2],
angle
)
);
}
}
anim() {
for (const point of this.points) point.integrate();
for (let i = 0; i < 5; ++i) {
for (const angle of this.angles) angle.update();
for (const constraint of this.constraints) constraint.update();
}
for (const point of this.points) point.collide(ball);
}
draw() {
for (const shape of this.shapes) shape.draw();
}
};
// Points
Human.Point = class {
constructor(x, y, p, s, g) {
this.x = x + p.x * s;
this.y = y + p.y * s;
this.px = this.x;
this.py = this.y;
this.vx = 0.0;
this.vy = 0.0;
this.m = p.m || 1.0;
this.g = g;
}
join(p1, distance, force) {
const dx = p1.x - this.x;
const dy = p1.y - this.y;
const dist = Math.sqrt(dx * dx + dy * dy);
const tw = this.m + p1.m;
const r1 = p1.m / tw;
const r0 = this.m / tw;
const dz = (distance - dist) * force;
const sx = dx / dist * dz;
const sy = dy / dist * dz;
p1.x += sx * r0;
p1.y += sy * r0;
this.x -= sx * r1;
this.y -= sy * r1;
}
dist(p1) {
const dx = this.x - p1.x;
const dy = this.y - p1.y;
return Math.sqrt(dx * dx + dy * dy);
}
integrate() {
// verlet integration
this.vx = this.x - this.px;
this.vy = this.y - this.py;
this.px = this.x;
this.py = this.y;
this.x += this.vx;
this.y += this.vy + this.g;
}
collide(ball) {
// collision with ball
const dx = this.x - ball.x;
const dy = this.y - ball.y;
const sd = dx * dx + dy * dy;
if (sd < ball.radius * ball.radius) {
const d = Math.sqrt(sd);
const dz = (ball.radius - d) * 0.5;
this.x += dx / d * dz;
this.y += dy / d * dz;
}
}
};
// Shapes
Human.Shape = class {
constructor(p0, p1, shape, src, size) {
this.p0 = p0;
this.p1 = p1;
this.width = shape.w * size;
this.height = shape.h * size;
this.shape = canvas.createImage(
shape.svg,
"data:image/svg+xml;base64," + window.btoa(src)
);
this.offset = shape.offset;
}
draw() {
canvas.drawImage(
this.shape,
this.p0.x,
this.p0.y,
this.height + this.width * this.offset,
this.width,
-this.height * this.offset,
-this.width * 0.5,
Math.atan2(this.p1.y - this.p0.y, this.p1.x - this.p0.x)
);
}
};
// Constraints
Human.Constraint = class {
constructor(p0, p1, constraint) {
this.p0 = p0;
this.p1 = p1;
this.distance = p0.dist(p1);
this.force = constraint.force || 1.0;
}
update() {
this.p0.join(this.p1, this.distance, this.force);
}
};
// Angles constraints
Human.Angle = class {
constructor(p0, p1, p2, constraint) {
this.p0 = p0;
this.p1 = p1;
this.p2 = p2;
this.len1 = p0.dist(p1);
this.len2 = p1.dist(p2);
this.angle = constraint.angle;
this.range = constraint.range;
this.force = constraint.force || 0.1;
let m = p0.m + p1.m;
this.m1 = p0.m / m;
this.m2 = p1.m / m;
m = p1.m + p2.m;
this.m3 = p1.m / m;
this.m4 = p2.m / m;
}
a12(p0, p1, p2) {
const a = Math.atan2(p1.y - p0.y, p1.x - p0.x);
const b = Math.atan2(p2.y - p1.y, p2.x - p1.x);
const c = this.angle - (b - a);
const d = c > Math.PI ? c - 2 * Math.PI : c < -Math.PI ? c + 2 * Math.PI : c;
const e = Math.abs(d) > this.range
? (-Math.sign(d) * this.range + d) * this.force
: 0;
const cos = Math.cos(a - e);
const sin = Math.sin(a - e);
const x1 = p0.x + (p1.x - p0.x) * this.m2;
const y1 = p0.y + (p1.y - p0.y) * this.m2;
p0.x = x1 - cos * this.len1 * this.m2;
p0.y = y1 - sin * this.len1 * this.m2;
p1.x = x1 + cos * this.len1 * this.m1;
p1.y = y1 + sin * this.len1 * this.m1;
return e;
}
a23(e, p1, p2) {
const a = Math.atan2(p1.y - p2.y, p1.x - p2.x) + e;
const cos = Math.cos(a);
const sin = Math.sin(a);
const x1 = p2.x + (p1.x - p2.x) * this.m3;
const y1 = p2.y + (p1.y - p2.y) * this.m3;
p2.x = x1 - cos * this.len2 * this.m3;
p2.y = y1 - sin * this.len2 * this.m3;
p1.x = x1 + cos * this.len2 * this.m4;
p1.y = y1 + sin * this.len2 * this.m4;
}
update() {
// resolve angular constraints
const e = this.a12(this.p0, this.p1, this.p2);
this.a23(e, this.p1, this.p2);
}
};
const canvas = {
// @greggman thanks for webglfundamentals!
// https://webglfundamentals.org/webgl/lessons/webgl-2d-drawimage.html
init() {
// create webGL canvas context
this.elem = document.createElement("canvas");
document.body.appendChild(this.elem);
const options = {
alpha: false,
stencil: false,
antialias: false,
depth: false
};
let gl = this.elem.getContext("webgl", options);
if (!gl) gl = this.elem.getContext("experimental-webgl", options);
if (!gl) return false;
this.gl = gl;
// set shaders
this.vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(
this.vertexShader,
`
precision highp float;
attribute vec2 aPosition;
uniform mat3 uMatrix;
varying vec2 vTexcoord;
void main() {
gl_Position = vec4(uMatrix * vec3(aPosition, 1), 1);
vTexcoord = aPosition;
}
`
);
gl.compileShader(this.vertexShader);
this.fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(
this.fragmentShader,
`
precision highp float;
varying vec2 vTexcoord;
uniform sampler2D texture;
void main() {
gl_FragColor = texture2D(texture, vTexcoord);
}
`
);
// compile shaders
gl.compileShader(this.fragmentShader);
this.program = gl.createProgram();
gl.attachShader(this.program, this.vertexShader);
gl.attachShader(this.program, this.fragmentShader);
gl.linkProgram(this.program);
// init attributes, uniforms and buffers
this.position = gl.getAttr.........完整代码请登录后点击上方下载按钮下载查看
网友评论0