Box2DWeb_03之Shape
之前都是球!一个充满了球的世界!悲催········
在box2d中为我们提供的shape就只有球和多边形!
shape是为我们的body提供形状的,虽然不能决定其外表如何!但已经奠定了其内在基础!再整容业真实的触碰范围也就那么大!至于外观!后面会说到!
box2d把body叫刚体,就是永不变形的身体!假设他可以承受所有外力而不变形!我们可以认为他是硬邦邦的石头!只有两个基础shape一个圆一个多边形!所以我们创建复杂的刚体的时候大多要基于多变形!他为我们提供了SetAsArray方法我们就可以有人一多顶点只需要按顺时针方向依次顺序排列好的数组传给进去!就可以了!
官方要求是这么传的!为什么必须这么传你懂得!他要不顺序乱交叉出来的不一定是什么形状!你自己可以再canvas上每画一根线fill依次!画个方别按顺序来!
所以在box2d的世界只能够支持凸形状不支持凹形状!为什么?和上面一样!他总得closePath才能fill,所以总是凸的!
通常我们需要画复杂的形状或者凹形状的办法是用多个凸的形状是有joint连接起来!组成一个(看似一个)shape
代码如下:
createContainer();
function createContainer()
{
var shapeCoords = [
[[61,55],[77,67],[39,135],[23,124]],
[[23,124],[39,135],[25,220],[6,218]],
[[6,218],[25,220],[44,305],[28,312]],
[[28,312],[44,305],[94,372],[82,384]],
[[82,384],[94,372],[167,413],[161,425]],
[[161,425],[167,413],[250,424],[250,437]],
[[250,438],[250,424],[339,416],[341,429]],
[[341,430],[339,416],[411,383],[418,393]],
[[418,393],[411,383],[464,327],[478,334]],
[[478,334],[464,327],[489,254],[504,252]],
[[504,252],[489,254],[488,183],[504,177]],
[[504,177],[488,183],[470,112],[488,103]],
[[488,103],[470,112],[443,66],[465,63]],
[[77,67],[72,46],[436,43],[443,66]]
];
//创建一个刚体定义
var bodyDef = new b2BodyDef();
bodyDef.type = b2Body.b2_staticBody;
bodyDef.position.Set(-8 / drawScale, -50/drawScale);
//创建刚体
_container = world.CreateBody(bodyDef);
//为刚体创建修饰物
//传递顶点数组作为参数
createFixtrues(shapeCoords);
};
//创建Fixtures
//根据顶点数组的第一维度,创建多个Fixture
function createFixtrues(coords)
{
for(var i = 0; i<coords.length; i++)
{
var shape = new b2PolygonShape();
//调用创建顶点方法,将数组的第二维度作为参数
//返回一个顶点数组,用于创建shape
var shapeVertices = createVerticesArray(coords[i]);
shape.SetAsArray(shapeVertices);
var shapeFixtureDef = new b2FixtureDef();
shapeFixtureDef.shape = shape;
shapeFixtureDef.density = 1;
shapeFixtureDef.restitution = 1.0;
_container.CreateFixture(shapeFixtureDef);
}
};
//创建顶点数组
function createVerticesArray(coords)
{
//不能少于三个顶点
if(coords.length < 3)
{
throw new Error("Shape create wrong");
}
var vertices = new Array();
//遍历顶点数组的第二维度,生成b2Vec2数组
for (var i = 0; i<coords.length ; i++)
{
var vertice = new b2Vec2(coords[i][0]/drawScale, coords[i][1]/drawScale);
vertices.push(vertice);
}
return vertices;
};
看着那一堆数组有没有很恶心!我看着他也很恶心!
其实主要是获取这些点的问题!
如果这些点我们直接用鼠标画是不是爽多了!至少我认为之这样!So..........
我们用点击一次确定一个点,第二次确定另外一个点,并且把前一个点和这个点连接形成一个shape !
您老自己只要把口封好了,closePath,拿着vec里面这些point!那不是想画什么,是什么吗!
但是记得吧坐标系转换成物理坐标系
vec.push(new Point(e.offsetX,e.offsetY));
if(vec.length>1){
context.strokeStyle = "#ffffff";
context.beginPath();
context.moveTo(vec[0].x,vec[0].y);
for(var i=1;i<vec.length;i++)
context.lineTo(vec[i].x,vec[i].y);
context.stroke();
}
}
function Point(_x,_y){this.x = _x;this.y = _y};
看了这么就debugdraw,也该添加以下外观了!放哪儿呢!其实爱放哪儿放哪!因为这个外观其实和box2d没多大关系!
你放哪自己指导就行!通常放body的userdata或者fixture的userdata!或者把body对象持有给你自己的对象!
为什么说外观和box2d没有关系!因为外观是什么样他不关心!他也不会管理!需要我们自己同步外观得坐标以及角度!另外即使fixturedef的shape是圆形你给一个方形也没人管!
他也就依旧这个走着!
其实这也是显示和逻辑分离的一个应用吧!
上面那个只有小球是动的,那个容器不动都是静态也可以给他一个对象就装着图片,但是意义不大所以就直接给摆张img吧!我们主要同步小球的皮肤!
给小球创建外观!并且同步所以先建一个小球类吧!
this.x;this.y;this.r=r;this.body;
this.draw = function(context){
this.x = this.body.GetPosition().x * drawScale;
this.y = this.body.GetPosition().y * drawScale;
var my_gradient= context.createRadialGradient(this.x,this.y,this.r/4, this.x,this.y,this.r*2);
my_gradient.addColorStop(0, "#FAACBD");
my_gradient.addColorStop(1, "#772777");
context.save();
context.fillStyle = "#ABDFCD";
context.beginPath();
context.arc(this.x,this.y,this.r,0,Math.PI/180*360,true);
context.closePath();
context.stroke();
context.fill();
context.restore();
};
};
定义好之后再创建小球body的时候把小球的body传给ball.body就ok了!在update方法里ball.draw()就ok了!
这样小球就会跟据body的position更新自己的位置,当然还是坐标转换注意下!
var timeStep = 1/60;
world.Step(timeStep,10,10);
world.ClearForces();
world.DrawDebugData();
ball.draw(context);
};
现在呢是一个小球要是多个小球呢!也是一样的!放进数组里!写一方法一起同步了
或者写一个统一的父类必须包含body属性和draw方法,然后其他显示对象继承他!body.GetNext()遍历所有body判断是这个类型的,统一调用draw方法!
或者更好的!这个就个人发挥吧!
不想看见debugDraw的!你懂得!world.DrawDebugData();注掉