P2中的形状(中)

今天翻看了一下以前的笔记。2011年~2013年,密密麻麻写了一个本子,写的很仔细。再看看博客里的文章,也大部分都是那个时间段写的。很佩服当年的自己。
现在的自己,自从结婚之后,每天上班检产品,下班看孩子,文章基本没有更新。老抱怨没有时间,工资又低。后来想想,不是时间少,挣钱少,而是自己太懒。
2012年开通个人博客的时候,励志要做中国版的emanueleferonato,人家依然成了业界大牛,而我还在原地踏步。都是自己太懒啦!
好啦,不说那么多没用了啦!来,今天我能来学习新的教程:p2中的形状(中)

上一节,我们简单了解了p2中的形状,以及这些形状的属性。这一节,我们来仔细了解每个形状的用法,以及相应的属性。

形状详解

首先,我们回忆一下创建和使用形状的过程,总共分三步,一,把冰箱门打开~,啊不是:

  1. 创建Shape形状,或其子类形状。
  2. 创建刚体
  3. 使用body类的addShape()函数,将形状添加到刚体中
    大致代码如下:
    var shape: p2.Shape = new p2.Shape();
    var body: p2.Body = new p2.Body();
    body.addShape(shape);
    

    我们可以把上面代码中的Shape类,换成Box、Circle等Shape的子类,然后就可以创建对应形状的刚体了。

    需要注意的是:截止到当前2015-12-2,p2的最新版本为v7.0,在最新版的p2中,所有形状的预置属性,如Circle的radius属性,均不作为构造函数的指定参数,而是成为参数options中的一个可选参数。代码说明如下:

变更前:

    function Circle(
            radius: number
    )

变更后:

    function Circle(
        options?: {
            radius: number
        }
    )

接下来,我们就来仔细学习一下这些形状。

Box

Alt text

Box矩形(p2 v7.0之前的版本里,矩形是Rectangle类)是p2中的基本形状通过它的width和height属性,可以创建任意长宽尺寸的矩形。Box的构造函数如下:

function Box(
    options: {
        width?: number;
        height?: number
    }
)

参数说明:

  • width:矩形的宽度,默认为1。
  • height:矩形的高度,默认为1。

Circle

Alt text

Circle圆形,同样是p2中的基本形状,这里的圆形是一个半径为radius的标准圆,它的构造函数如下

    function Circle(
        options?: {
            radius: number
        }
    )

参数说明:

  • radius:圆形的半径,默认为1。

Capsule

Alt text

胶囊形状,啊哈,又学了一个新的单词,顾名思义,就是外形类似胶囊的形状,或者你也可以把它想象成egret中的drawRoundRect()函数绘制的圆角矩形,其长度为length,高度为2*radius,两端是和两个半径为radius的半圆形,具体如上图所示,

Capsule的构造函数如下

function Capsule(
    optoins?: {
        length?: number;
        radius?: number
    }
)

参数说明:

  • length:胶囊形状的长度,默认为1。
  • radius:胶囊形状的半径,或者叫半度,默认为1。

Line

Alt text

线段形状,顾名思义就是一个长度为length的线段,看上去与高度为1的rectangle形状无异,但算法上省去了对高度的检测,效率上会有所提升
Line形状的构造函数如下

    function Line(
        option?: {
            length?: number
        }
    )

参数说明:

  • length:线段形状的长度,默认为1。

Plane

Alt text

这是一个特殊的形状,普通的形状都有一个有限的边界,平面形状的特殊之处在于,它沿y轴负方向是无限扩展的,这个描述让人很容易联想到地平面,无论我们走多久都走不到尽头。
plane形状的构造函数如下,

     function Plane()

很简单,没有任何的参数,然而,初始情况下的plane并不是我们所设想的地平面,而是一个倒置的地平面,如下图所示
Alt text

实际应用中,我们可以通过调整刚体的angle角度,使plane平面朝向不同的方向,来模拟墙体的物体。

Particle

Alt text

粒子形状,粒子大家都知道,就是微小的颗粒,小到像一粒沙子,p2物理引擎中的粒子尺寸为零,这个意思是说,当粒子形状与其他形状堆叠到一起时,不会对其他形状或角度产生影响。
呃…那这个粒子能用来做什么?
粒子形状可以用来模拟钉子,做为关节的一个刚体,将另一个刚体固定在某个位置,这一点,类似于Box2d中的b2World.GetGroundBody()返回的空刚体相似。

不过空刚体正确的做法,实际上直接创建一个刚体,不为其添加形状,即可。

为了调试可见,在p2DebugDraw中,我用上图所示的形状表示粒子形状。

Particle的构造函数如下

function Particle()

HeightField

Alt text

海拔形状,这是一个类似于plane的形状,不过它不像地平面那样一马平川,而是有一组y坐标组成的高低不平的丘陵。这些“丘陵”之间的间隔都是elementWidth,如下图所示:
Alt text

和Plane形状一样,HeightField形状也是朝向y轴负方向,无限扩展的,水平方向的宽度是elementWidth与y坐标数量的乘积。

HeightField形状的构造函数如下:

function Heightfield(
    options?: {
        heights: number[];
        minValue?: number;
        maxValue?: number;
        elementWidth?: number;
    }
)

参数说明如下:

  • heights:每个丘陵的高度组成的一个数组
  • minValue:heights中最小的高度值。当heights中的高度是由一定的算法计算得出时,为了防止高度小于某个指定,可以设置minValue为高度的最小值。
  • maxValue:与minValue参数类似,表示heights中的最大高度。
  • elementWidth:每个高度之间的间隔,如上图所示。

其实,创建HeightField形状的过程,就是定义data属性中y坐标数组的过程,正如我在第一节里讲的,因为x坐标是以elementWidth逐渐增加的,这个过程恰恰和二元一次线性方程是相似的,所以根据上学时学习过的线性方式,可以很容易的创建出有规律的heightField形状。
例如,我们非常熟悉的三角函数,y=sin(i),取i从0到100时,y坐标计算结果,并保存x=i*elementWidth,到data属性中,这样就可以创建出圆滑的sin曲线。
Alt text

对应的Egret代码大致如下:


    private createHeightfeild(): void {
        var radius:number = 50/ this.factor;
        var heights: number[]=[];
        var elementWidth:number = 1/ this.factor;

        for(var i:number = 0; i<600;i++){
            var y:number = Math.sin(i*0.02) *radius +4;
            heights.push(y);
        }

        var heightfeildShape: p2.Heightfield = new p2.Heightfield({heights:heights,elementWidth:elementWidth});
        var body: p2.Body = new p2.Body({ mass: 1 });
        body.type = p2.Body.STATIC;
        body.addShape(heightfeildShape);
        this.world.addBody(body);

    }

点击下载源文件

前方有坑

相信很多同学,都和我一样,学习了这么多稀奇古怪的形状,都想赶紧编写代码试一试,但p2并不像Box2D那么成熟,作者还有很多todo项目没有完成,以下几点说明,是拉登一脚一脚才过来的坑,请大家注意绕行。

  • 形状键碰不完整
    前面介绍的7中形状,他们之间并不是都可以完美的实现碰撞检测,例如,particle和圆形之间不进行碰撞 ,作者也在Github文档中有专门提出,后续会慢慢实现这些形状之间的碰撞模拟。
    类似的情况,还有很多,具体请参考下图中的,形状碰撞关系表

Alt text

  • HeightField不能旋转
    前面说过,Plane和HeightField形状,都是沿y轴负方向无限扩展的,其中plane形状可以通过旋转刚体,实现其他角度的地平面,遗憾的是,HeightField形状目前还不支持这一点,不随刚体的旋转发生变化。始终保持朝向y轴负方向。

举个例子

本节的内容主要是讲解各种行的实现过程,以及相关的属性。属性部分,和上一节类似,这里就不在单独举例了,具体可以参考上一节内容

下一节预告

  • 使用Convex创建三角形等多边形
  • 使用fromPolygon()函数,随手绘制刚体

联系作者

公众号:拉小登 | 微博:拉登Dony | B站:拉小登Excel

One Reply to “P2中的形状(中)”

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注