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