使用Canvas实现手撕渔网袜特效(*^▽^*)

想要代码敲的好,高数算法不能少

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);
    }
  • 8
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值