P2中的形状(上)
为了精确的模拟物理碰撞,我们必须为刚体设定,与贴图相同的形状,例如下图是我们喜闻乐见的几个游戏人物,它们都必须转化为物理引擎中有棱有角的形状,才能完成游戏中的出色表现。
P2中设置了7中常用的形状,来满足游戏中常见的需求,这些形状包括:
- Capsule:胶囊形状。
- Circle:标准圆型。
- HeightFeild:地面形状。这种形状由一组y坐标组成,用来模拟高低不平的地面,如Tiny wing中的地面。
- Line:线段形状,用来创建高度为1个像素,长度为length的线段。
- Particle:粒子形状。粒子形状的尺寸均为零,没有质量和惯性….
- Plane:平面形状。
- Rectangle:矩形。
如果上面这些形状无法满足你的需求,可以通过convex类,根据实际的需要,通过已知的一组顶点,创建自定义的形状。
和其他的物理引擎相比,P2有一个独特的特性,在无其他类库或插件的帮助下,可以创建凹多边形,唯一的条件是,vertices中的顶点不存在交叉或中空。
形状的属性
p2中的形状种类很多,属性也不尽相同,但这些形状都继承自shape类,所以它们都拥有相同的一些属性,包括:collisionGroup、collisionMask、sensor和material。
- collisionGroup:碰撞分组,与接下来的collisionMask一起使用,限制形状只与规定条件的形状碰撞。
- collisionMask:碰撞筛选,与collisionGroup一起使用,限制形状至于规定条件的形状发生碰撞。
- sensor:设置形状是否为感应区域,默认为false,如果设置为true,则该形状不参与碰撞模拟,只作为感应区域,触发碰撞事件。
- material:形状材质,和Box2D物理引擎不同,p2中没有b2Fixture概念,刚体的材质信息,由形状中的material类,以及ContactMaterial类来定义。具体的内容,我们将在后续的教程中,陆续向你解释。
P2中的collisionGroup、collisionMask属性,和Box2D中的FilterData.categoryBits和FilterData.maskBits是一样的;而sensor属性,和Box2D中的sensor是相同的,具体请参考
http://www.ladeng6666.com/blog/2012/10/28/create-sensor-body-using-issensor/
http://www.ladeng6666.com/blog/2012/11/02/filterdata-to-separate-the-box2d-collision/
除此之外,每个形状子类,还包括了很多专属的属性,来定义形状的尺寸大小,具体请参考下表:
形状的这些属性,可以在形状类的构造函数中指定,以Rectangle为例,代码如下:
private createRectangle(x:number,y:number): void { var shape: p2.Rectangle = new p2.Rectangle(100, 50); var body: p2.Body = new p2.Body({ mass: 1, position: [x, y] }); body.addShape(shape); this.world.addBody(body); }
或者在创建了形状对象之后,再设定属性,代码如下:
shape.width = Math.random() * 50 + 30;
类似的,这一节,大家只是有一个大致的了解即可,针对这些特殊的形状,如Plane、HeightFeild等,我会在后面的教程中,陆续的讲解。
举个栗子
下载本节示例并运行后,点击舞台任意位置,可以创建形状随机的刚体。如下图所示:
示例中四周的围墙,使用了Plane形状搭建,底部高低不平的地面,通过HeightField形状实现,点击舞台任务一位置,创建矩形、圆形、胶囊或线段形状刚体。
大痔过程
- 为每个形状创建单独的函数,如CreateCircle()、CreateRectangle、CreateLine(),来分别创建对应形状的刚体。
- 在鼠标事件处理函数中,随机调用这些形状函数,创建对应的形状。
完整的源代码如下:
class Main extends AbstractP2Test { private debugDraw: p2DebugDraw; private world: p2.World; private trackingBody: p2.Body; public constructor() { super(); } public onAppReady(): void { this.createWorld(); this.createGround(); this.createDebug(); this.stage.addEventListener(egret.TouchEvent.TOUCH_BEGIN, this.addOneBox, this); } private createWorld(): void { var wrd:p2.World = new p2.World(); wrd.sleepMode = p2.World.BODY_SLEEPING; wrd.gravity = [0,10]; this.world = wrd;; } private createGround(): void { var groundShape: p2.Plane = new p2.Plane(); var groundBody: p2.Body = new p2.Body(); groundBody.addShape(groundShape); groundBody.type = p2.Body.STATIC; groundBody.position = [0,300]; groundBody.angle = Math.PI; this.world.addBody(groundBody); } private createDebug(): void { egret.Profiler.getInstance().run(); this.debugDraw = new p2DebugDraw(this.world); var sprite: egret.Sprite = new egret.Sprite(); this.addChild(sprite); this.debugDraw.setSprite(sprite); } public loop(): void { this.world.step(60 / 1000); this.debugDraw.drawDebug(); } private addOneBox(e: egret.TouchEvent): void { var positionX: number = Math.floor(e.stageX); var positionY: number = Math.floor(e.stageY); var ran: number = Math.random(); if (ran < 0.2) { this.createCircle(positionX, positionY); } else if (ran < 0.4) { this.createCapsule(positionX, positionY); } else if (ran < 0.6) { this.createLine(positionX, positionY); } else if (ran < 0.8) { this.createParticle(positionX, positionY); } else { this.createRectangle(positionX, positionY); } } private createRectangle(x:number,y:number): void { var shape: p2.Rectangle = new p2.Rectangle(100, 50); shape.width = Math.random() * 50 + 30; var body: p2.Body = new p2.Body({ mass: 1, position: [x, y] }); body.addShape(shape); this.world.addBody(body); } private createCapsule(x: number, y: number): void { var capsuleShape = new p2.Capsule(50, 10); var body: p2.Body = new p2.Body({ mass: 1, position: [x, y], angularVelocity: 1 }); body.addShape(capsuleShape); this.world.addBody(body); } private createCircle(x: number, y: number): void { var circleShape: p2.Circle = new p2.Circle(30); var body: p2.Body = new p2.Body({ mass: 1, position: [x, y], angularVelocity: 1 }); body.addShape(circleShape); this.world.addBody(body); } private createLine(x: number, y: number): void { var shape: p2.Line = new p2.Line(150); var body: p2.Body = new p2.Body({ mass: 1, position: [x, y], angularVelocity: 1 }); body.addShape(shape); this.world.addBody(body); } private createParticle(x: number, y: number): void { var shape: p2.Particle = new p2.Particle(); var body: p2.Body = new p2.Body({ mass: 1, position: [x, y], angularVelocity: 1 }); body.addShape(shape); this.world.addBody(body); } }
下载源代码
联系作者
又是一篇好文章,零基础刻苦学习中,希望多给予指导,急需了解碰撞
感谢支持,p2碰撞已经在我的计划中了,因为图文版耗时较长,我会调整计划,让大家尽快看到碰撞教程!
目前我看到你的bindAsset是单纯只支持矩形的.能否将常用的形状甚至于说自定义形状都添加进去呢.同时我看到constraint约束类似乎还没办法使用?我照其他地方使用没问题的p2的逻辑.然而在egret里面报错了.譬如这样Cannot use ‘in’ operator to search for ‘collideConnected’ in 4
自定义形状,我会在后后续的章节中进行介绍,关于p2中使用Constraint报错的问题,是因为官方的p2.d.ts中API不全导致的,我这两天优先更新一下p2.d.ts吧,最近好多同学在问。请持续关注我的网站!
弹性碰撞有没有参数设置?
p2中刚体的弹性,没有单独的属性,而是通过ContactMaterial对象指定。通过world的addMaterial()添加该对象后,在对象里设置碰撞对象的material属性,可以指定刚体之间的碰撞弹性,我会持续更新教程。
每次教程都写的那么好,as的时代就看,egret又开始了,哈哈
拉登兄,关注您很久了能交换个链接吗 http://www.41bj.com 已加
已添加,谢谢支持!
world.getBodyByID is not a function,这个太奇怪了,我看js也有,d.ts文件里也有,为什么就总提示我没有呢
提示没有,可能是编译后,项目文件夹下的libs->p2->p2.d.ts里,没有定义这个函数,如果我分析的原因不对,可以加我微信交流。
大神 p2的系列教程,咋不继续了呢?
不规则的用哪个
博主我遇到这样error TS2339: Property ‘hitTest’ does not exist on type ‘World’,用的是你的p2
请加入我的物理游戏QQ群:334059644,我们详细的沟通,谢谢。
拉登大叔,我还要~
P2 中的刚体怎么改变形状的大小 期待您的回答