zoukankan      html  css  js  c++  java
  • 码农干货系列【2】由关节(Joint)说到割绳子(cut the rope)

    简介

    关节是相互连结且互相约束的物体,常见于各类物理引擎当中。关节的运用非常广泛,例如人体模拟、动物行走模拟、器材、绳子、机关、链桥等都可以灵活利用关节去模拟。

    image 普通的关节分两种,一种是有固定点,一种没有固定点。本文分别对两种关节进行计算并且输出图片进行模拟。

    关节

    关节通常用下面这种表达方式:

    (function (window) {
    var Joint = function (segLength, segCount, isFixed, startPoint) {
    this.segLength = segLength;
    this.segCount = segCount;
    this.isFixed = isFixed;
    this.startPoint = startPoint;
    this.points = [];
    for (var i = 0; i < this.segCount; i++) {
    this.points.push(new Vector2(this.startPoint.x, this.startPoint.y + i * this.segLength));
    }
    }
    window.Joint = Joint;
    } (window))

    其中:

    segLength表示关节每一段的长度(这里假定关节每一段是相等的)

    segCount表示关节个数(包括起点和终点)

    isFixed表示关节是否有固定点(如果isFixed为true,假设startPoint为固定点)

    startPoint表示关节的起点(这里假定关节的初始状态是笔直向下的)

    points表示关节上所有的支点(包括起点和终点)

    这里需要了解的是 ,在完整的关节表示当中,为了更好的模拟现实世界当中的物体,关节还会加上一个角度区间限制,即关节的最大张开角度和最小的角度。本文的关节不加此限制,任其360度无障碍旋转。

    图形化输出

    这里使用Easeljs输出关节的图像。先引用相关的脚本:

        <script src="script/Vector2.js" type="text/javascript"></script>
        <script src="script/joint.js" type="text/javascript"></script>
        <script src="script/easel.js" type="text/javascript"></script>
    

    定义一个拥有2个关节段,每段长度为60的关节。完整代码如下所示:

    var joint = new Joint(60,4,false,new Vector2(200,100));
    var canvas;
    var stage;
    var shape;
    (function (){
    canvas = document.getElementById("testCanvas");
    stage = new Stage(canvas);

    shape = new Shape();
    stage.addChild(shape);
    drawjoint(joint);
    }())

    function drawjoint(joint) {
    shape.graphics.clear();
    shape.graphics.ss(14, 'round', 'round');
    for (var i = 0; i < joint.points.length - 1; i++) {
    if (i % 2 === 0) {
    shape.graphics.beginStroke("green");
    }
    else {
    shape.graphics.beginStroke("red");
    }
    shape.graphics.mt(joint.points[i].x, joint.points[i].y).lt(joint.points[i + 1].x, joint.points[i + 1].y);
    }
    shape.graphics.endStroke();
    stage.update();
    }

    效果如图所示:
    image

    与鼠标交互

    要让关节绕着对应的支点动起来,这里让关节的终点跟随鼠标的位置移动。

    在方法中加入:

    canvas.onmousemove = canvasMouseMoveHandler; 

    所以,当鼠标移动的时候,需要实时的更新关节的位置。如下图所示:

    image

    这里需要注意的两点是:

    上图描述的是一次微小的拉动,真正要呈现如图所示的前后状态,其实已经经历的很多次位置更新

    上图反向延长线经过初始点是不准确的,准确的位置是初始点靠右一段距离(取决于两条线段的合力方向,但这不影响关节的模拟)

    image

    添加鼠标处理的方法:

    function canvasMouseMoveHandler(e) {
    var r = canvas.getBoundingClientRect();
    joint.points[joint.points.length - 1] = new Vector2(e.clientX - r.left, e.clientY - r.top);
    joint.updatePointsPosition(joint.points[joint.points.length - 1], joint.points.length - 1);
    drawjoint(joint);
    }

    在分析完具体的过程之后,利用递归的思路依次更新所有的点。更新方法接收两个参数:一个是更新的点、一个是该点的index,当index为1的时候退出递归。


    var p = Joint.prototype;
    p.updatePointsPosition = function (point, index) {
    var tempV = this.points[index - 1].sub(point).setLength(this.segLength);
    this.points[index - 1] = point.add(tempV);
    if (index > 1) {
    this.updatePointsPosition(this.points[index - 1], index - 1);
    }
    }

    其中var tempV = this.points[index - 1].sub(point).setLength(this.segLength);是计算支点的偏移量,Vector2.setLength是经过normalize(转换为该向量的单位向量) 再multiplyScalar(设置长度)。如下代码所示:

    setLength: function (l) {

    return this.normalize().multiplyScalar(l);

    },
    完整代码参见Vector2类。
    运行效果如下所示:
    请使用现代浏览器观看在线演示!

    固定起始点

    上面呈现的是没有固定点的关节,那么如果拥有固定点,该怎么更新关节上所有点的位置呢?需要做的仅仅是校正startPoint(启始点、固定点)的位置。

    var p = Joint.prototype;
    p.updatePointsPosition = function (point, index) {
    var tempV = this.points[index - 1].sub(point).setLength(this.segLength);
    this.points[index - 1] = point.add(tempV);
    if (index > 1) {
    this.updatePointsPosition(this.points[index - 1], index - 1);
    } else {
    if (this.isFixed) {
    var v = this.points[0].sub(this.startPoint);
    for (var i = 0; i < this.points.length; i++) {
    this.points[i].subSelf(v);
    }
    }
    }
    }

    当递归到最后,如果该关节是有固定点的,校正所有关节点的位置。效果如下所示:

    请使用现代浏览器观看在线演示!

    思考??

    这样子呢?

    var joint = new Joint(2,140,true,new Vector2(200,100));

    一共140个点,点与点之间距离为2,再加上点颜色区间变化。

    请使用现代浏览器观看在线演示!

    它是割绳子(cut the rope)中绳子的表达方式吗?这样表示绳子会有什么问题出现?

    那么请继续关注我后续的干货~~~~~

  • 相关阅读:
    .NET 客户端上传本地excel文件到服务器上,并在客户端显示
    C#实现数字字符串左补齐0的3种方法
    C# 输出pdf文件流在页面上显示
    ASP.NET 将数据生成PDF (二)
    asp.net生成PDF文件 (1)
    stl常用的查找算法
    stl中的transform()注意其与for_each的不同点(有无返回值)
    stl中的for_each() 函数的注意事项
    如何在VMware系统中的ubuntu16.04中建立与win7系统的共享文件夹
    关于linux中用vi新建立一个.c文件无法保存,显示E212错误的时候
  • 原文地址:https://www.cnblogs.com/iamzhanglei/p/2541195.html
Copyright © 2011-2022 走看看