Box2D刚体缩放

刚刚提缩放,无非就是设置一下width、height或scaleX、scaleY属性嘛,这么简单的东西也要写个教程?很遗憾的告诉你,Box2D刚体不像Flash里的显示对象,没有width、height或scaleX、scaleY这样的属性,那么怎么办呢?继续看教程!

好吧,即使不一样,这么简单的东西能做出什么样的效果?能做游戏?没错,不怕做不到,就怕想不到。Shrink it就是用刚体缩放制作的一个游戏(如下图),点击刚体进行缩放,让上面的多边形碰撞星星,这也是今天我们要模仿的效果。

shrinkit

 

不是显示对象,就无法使用width、height或scaleX、scaleY来调整刚体的大小了。不过我们还是有办法的!

b2Body类没有直接影响刚体尺寸的属性或方法,而是要通过b2Shape类的一些方法来实现,所以首先要用b2Body.GetFixtureList().GetShape()获取刚体的图形,然后根据图形的类型进行不同的设置。

			//获取鼠标点击刚体的图形数据
			var pressedShape = pressedBody.GetFixtureList().GetShape();

我们知道b2Shape的子类有两种,一个是b2CircleShape类,这个图形的尺寸调整起来比较简单,直接调用b2CircleShape.setRadius()就可以重新设置新的半径。参数可以设置为b2CircleShape.getRadius()*scale来进行比例缩放,代码如下:

				//通过SetRadius()方法,将圆形的半径缩小为0.9倍
				pressedShape.SetRadius(pressedShape.GetRadius()*.9);

另一个是b2PolygonShape类,因为多边形的顶点数量和位置不同,形成的图形也不同,所以没有类似于SetRadius()的SetWidth()或SetHeight()方法。实际上,我们可以把多边形分解成多个顶点,多边形等比例缩放时,顶点到中心点的距离也是等比例缩放的(如下图所示),所以我们只需要用顶点向量的Multiply()方法乘以指定的缩放比例即可。

				//遍历图形的所有顶点,将顶点到中心点的距离缩小为0.9倍
				for each( var vec:b2Vec2 in pressedShape.GetVertices()) {
					vec.Multiply(0.9);
				}

b2shapeSample

下面的示例中,我模拟了Shrink it游戏的第一关,点击动态刚体进行缩放,点击Restart按钮重置刚体。

[swfobject]753[/swfobject]

完整的源代码和注释如下:

package  
{
	import Box2D.Collision.Shapes.b2CircleShape;
	import Box2D.Collision.Shapes.b2PolygonShape;
	import Box2D.Collision.Shapes.b2Shape;
	import Box2D.Common.Math.b2Vec2;
	import Box2D.Dynamics.b2Body;
	import Box2D.Dynamics.b2World;
	import com.bit101.components.PushButton;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;

	/**
	 * ...
	 * @author ladeng6666
	 */
	public class Main extends Sprite 
	{
		private var world:b2World;

		public function Main() 
		{
			//创建世界
			createWorld();
			//侦听事件
			setupEvent();
			//创建刚体
			createBody();
			//添加按钮
			setUI();
		}

		private function createWorld():void 
		{
			//添加世界
			world = LDEasyBox2D.createWorld();
			//添加调试试图
			addChild(LDEasyBox2D.createDebug(world));
			LDEasyBox2D.stage = this;
		}
		private function createBody():void 
		{
			//添加包围的墙体
			LDEasyBox2D.createWrapWall(world, this);

			//创建圆形刚体
			LDEasyBox2D.createCircle(world, 300, 50, 30);
			//创建8边形
			LDEasyBox2D.createRegular(world, 255, 50, 30, 8);
			//创建动态刚体
			LDEasyBox2D.createBox(world, 270, 170, 288, 30);
			//创建3个静态的刚体
			LDEasyBox2D.createBox(world, 140, 200, 100, 30, true);
			LDEasyBox2D.createBox(world, 400, 200, 100, 30, true);
			LDEasyBox2D.createBox(world, 265, 300, 100, 30, true);
		}

		private function clearBodies():void {
			//清除所有的刚体
			var body:b2Body;
			for (body = world.GetBodyList(); body; body = body.GetNext()) {
				world.DestroyBody(body);
			}
		}
		private function setupEvent():void 
		{
			stage.addEventListener(Event.ENTER_FRAME, loop);
			stage.addEventListener(MouseEvent.MOUSE_DOWN, mouseHandler);
		}

		private function mouseHandler(e:MouseEvent):void 
		{
			var pressedBody:b2Body = LDEasyBox2D.getBodyAtMouse(world);

			if (pressedBody == null || pressedBody.GetType() == b2Body.b2_staticBody) return;
			//获取鼠标点击刚体的图形数据
			var pressedShape = pressedBody.GetFixtureList().GetShape();
			if (pressedBody.GetFixtureList().GetShape() is b2CircleShape) {
				//通过SetRadius()方法,将圆形的半径缩小为0.9倍
				pressedShape.SetRadius(pressedShape.GetRadius()*.9);
			}else {
				//遍历图形的所有顶点,将顶点到中心点的距离缩小为0.9倍
				for each( var vec:b2Vec2 in pressedShape.GetVertices()) {
					vec.Multiply(0.9);
				}

			}
			//缩放完之后,唤醒刚体
			pressedBody.SetAwake(true);

		}

		private function loop(e:Event):void 
		{

			LDEasyBox2D.updateWorld(world);
		}

		private function setUI():void 
		{
			var btn:PushButton = new PushButton(this, 270, 15, "ReStart", function():void {
				clearBodies();
				createBody();
			});
		}
	}

}

下载源文件

联系作者

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

24 Replies to “Box2D刚体缩放”

  1. 拉登,受你影响,我也装了个wordpress,你的博客里面代码看着很舒服,是装的主题,还是插件?
    我也想弄个代码看着舒服点儿的。

  2. 拉登,我也用了Crayon Syntax Highlighter,很好用,谢谢推荐。
    建议你将Crayon的工具栏设置为始终显示,鼠标滑过去显示,移出要等一会儿
    才消失,感觉不好,当然,这只是我的感觉。

  3. 拉登你好最近看你的教程发现,你的LDeasyBOX2D中的userData只是用来贴图的,如果我想给每个刚体在创建的时候赋一个名字怎么弄呢?

  4. 拉登大叔,看了部分你的box 2d相关教程,确实收获不少,不过一直有个问题弄不明白,如果我想重新设置某个 b2body 实例的坐标怎么实现,期待您的解答,谢谢!

  5. 可以通过body.SetPosition()方法手动调整刚体的坐标!但是用的时候要小心,Box2D引擎在模拟物理运动时,会自动更新刚体的坐标,不要发生冲突!

  6. I used to be recommended this website by
    way of my cousin. I’m now not positive whether this publish is written by him as nobody else recognize such specific about my trouble. You are incredible! Thanks!

  7. 不知用box2d+starling开发游戏,怎么 才能自适应屏幕呢
    starling里的元件大小变了,但是box2d的位置和大小就对不上了,怎么处理呢
    我用的CitrusEngine

  8. 关于Starling自适应的问题,可以通过设置stage.algin=StageAlign.TOP_LEFT,然后在设置1秒延迟后调用你的init函数,我是这么结局的,你可以试一下!

  9. 我最近正在学习Cocos2D,JS版本的box2d不包含debugdraw,我会尝试编写适合cocos2d-js的debugdraw,请留下你的邮箱,我尽量在一周内回复你!感谢

  10. 拉登老师您好,如果我想把一个矩形刚体,在y方向一直拉伸,x方向比例不变,请问可以实现吗,类似图片宽度值不变,高度值变大。

发表回复

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