鼠标关节

演示

源代码

window.onload = function () {
    var canvas, ctx, w, h, world, boxBody, planeBody, mouseConstraint, mouseBody;
    var scaleX = 50, scaleY = -50;
    
    init();
    requestAnimationFrame(animate);
    
    function init() {
        // 初始化画布
        canvas = document.getElementById("renderCanvas");
        w = canvas.width;
        h = canvas.height;
        ctx = canvas.getContext("2d");
        ctx.lineWidth = 0.05;

        // 初始化物理引擎
        world = new p2.World();

        // 添加一个盒子
        boxShape = new p2.Box({ width: 2, height: 1 });
        boxBody = new p2.Body({
            mass: 1,
            position: [0, 3],
            angularVelocity: 1
        });
        boxBody.addShape(boxShape);
        world.addBody(boxBody);
        
        // 添加一个平面
        planeShape = new p2.Plane();
        planeBody = new p2.Body();
        planeBody.addShape(planeShape);
        world.addBody(planeBody);

        // 添加一个用于光标的body
        mouseBody = new p2.Body();
        world.addBody(mouseBody);

        canvas.addEventListener('mousedown', function (event) {
            // 将光标在画布中的坐标转换为物理系统的坐标
            var position = getPhysicsCoord(event);
            // 检测光标是否位于盒子的内部
            var hitBodies = world.hitTest(position, [boxBody]);

            if (hitBodies.length) {
                // 将光标bodt移动到光标所在的位置
                mouseBody.position[0] = position[0];
                mouseBody.position[1] = position[1];
                // 添加一个关节约束(RevoluteConstraint)
                // 这个约束可以让body绕一个点旋转
                mouseConstraint = new p2.RevoluteConstraint(mouseBody, boxBody, {
                    worldPivot: position,
                    collideConnected: false
                });
                world.addConstraint(mouseConstraint);
            }
        });

        // 在光标移动时,使光标body与光标位置保持同步
        canvas.addEventListener('mousemove', function (event) {
            var position = getPhysicsCoord(event);
            mouseBody.position[0] = position[0];
            mouseBody.position[1] = position[1];
        });
        
        // 释放鼠标,则移除这个关节约束
        canvas.addEventListener('mouseup', function (event) {
            world.removeConstraint(mouseConstraint);
            mouseConstraint = null;
        });
    }
    
    // 将画布坐标转换为物理引擎的坐标
    function getPhysicsCoord(mouseEvent) {
        var rect = canvas.getBoundingClientRect();
        var x = mouseEvent.clientX - rect.left;
        var y = mouseEvent.clientY - rect.top;
        x = (x - w / 2) / scaleX;
        y = (y - h / 2) / scaleY;
        return [x, y];
    }
    
    function drawbox() {
        ctx.beginPath();
        var x = boxBody.interpolatedPosition[0],
            y = boxBody.interpolatedPosition[1];
        ctx.save();
        ctx.translate(x, y);        // 平移盒子
        ctx.rotate(boxBody.interpolatedAngle);  // 旋转盒子
        ctx.rect(-boxShape.width / 2, -boxShape.height / 2, boxShape.width, boxShape.height);
        ctx.stroke();
        ctx.restore();
    }
    
    function drawPlane() {
        var y = planeBody.interpolatedPosition[1];
        ctx.moveTo(-w, y);
        ctx.lineTo(w, y);
        ctx.stroke();
    }

    function render() {
        
        ctx.clearRect(0, 0, w, h);
        // 放大画布50倍,并将画布原点移动到画布中心,并使y轴向上
        ctx.save();
        ctx.translate(w / 2, h / 2);
        ctx.scale(scaleX, scaleY);
        // 绘制盒子和平面
        drawbox();
        drawPlane();
        ctx.restore();
    }

    var lastTime, timeStep = 1 / 60, maxSubSteps = 5;
    
    // 动画循环
    function animate(time) {
        requestAnimationFrame(animate);

        var dt = lastTime ? (time - lastTime) / 1000 : 0;
        dt = Math.min(1 / 10, dt);
        lastTime = time;

        // 进行物理模拟运算
        world.step(timeStep, dt, maxSubSteps);

        // 绘制场景
        render();
    }
 }

发布时间:2016/12/25 下午9:00:22  阅读次数:4346

2006 - 2024,推荐分辨率 1024*768 以上,推荐浏览器 Chrome、Edge 等现代浏览器,截止 2021 年 12 月 5 日的访问次数:1872 万 9823 站长邮箱

沪 ICP 备 18037240 号-1

沪公网安备 31011002002865 号