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