鼠标获取并删除Nape刚体的方法

删除刚体并不是什么复杂的技巧,但是仅仅只是这个简单的功能也可以做出像Totem destroyer这样优秀的Flash游戏(游戏截图如下)。你有没有像我一样,试图在Nape API文档里找到Space.destroy类似的函数?那是Box2D里的做法,今天我们就来学习一下,如何在Nape空间里删除一个刚体。

Nape与Box2D不同,Space里面没有像b2World.destroy()这样的方法来删除刚体。Nape类库里有nape.phys.BodyList类,Space中的所有刚体都保存在BodyList列表中,Body刚体和BodyList的关系就像是Flash里显示对象和显示列表一样。所以要在Nape中删除某个刚体,用BodyList.remove()方法把它从列表中移除即可。

具体的讲,Space中有一个BodyList类型的bodies属性,调用space.bodies.remove()方法,即可删除指定的刚体,具体如下:

			//napeWorld是Space对象,bb是要删除的刚体
			napeWorld.bodies.remove(bb);

知道了怎么删除Nape刚体之后,我们还要了解一件事情。Totem destroyer游戏中删除的是鼠标点击的刚体,那怎么获取鼠标点击的刚体呢?很简单,至少比Box2D的方法简单。

Space类中有一个bodiesUnderPoint()方法,看名字应该能猜出它的作用,获取某个点下面的刚体。是的,我们只要把鼠标的坐标点传入到bodiesUnderPoint()方法中,它就可以返回一个包含鼠标坐标下面所有刚体的一个BodyList对象,然后我们在用BodyList.foreach()方法遍历这些刚体,然后逐个删掉。foreach()的参数是一个函数,这个函数必须有一个Body类型的参数。下面是具体的代码:

				//获取鼠标下方的body刚体
				var bodiesList:BodyList = napeWorld.bodiesUnderPoint(mp);
				//遍历每个刚体
				bodiesList.foreach(
					function( bb:Body):void{
						if(bb.isDynamic()){
							//如果刚体是非静止的,则删除刚体
							napeWorld.bodies.remove(bb);
						}
					}
				);

好了,基本都讲完了,下面我们来看看用Nape实现的Totem destroyer游戏模型吧!

[swfobject]728[/swfobject]

是不是一模一样?源代码和注释如下:

package 
{
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import nape.phys.BodyList;

	import nape.constraint.PivotJoint;
	import nape.geom.Vec2;
	import nape.phys.Body;
	import nape.phys.BodyType;

	[SWF(frameRate="60",width=550,height=400,backgroundColor="0xCCCCCC")]

	public class T8_GetAndRemoveBody extends AbstractNapeTest
	{
		private var hand:PivotJoint;

		public function T8_GetAndRemoveBody()
		{
			super();
			createWall();
			createBodies();

			//添加上方的按钮
			var ui:UISetting = new UISetting(this, function (e:Event):void {
				//按钮点击事件处理函数
				napeWorld.bodies.clear();
				createWall();
				createBodies();
			});
		}

		private function createBodies():void
		{
			//创建多个刚体,按照游戏中的样式摆放
			createBox(275,335,30,30,BodyType.DYNAMIC);
			createBox(365,335,30,30,BodyType.DYNAMIC);
			createBox(320,305,120,30,BodyType.DYNAMIC);
			createBox(320,275,60,30,BodyType.DYNAMIC);
			createBox(305,245,90,30,BodyType.DYNAMIC);
			createBox(320,200,120,60,BodyType.DYNAMIC);
		}
		override protected function mouseEventHanlder(event:MouseEvent):void
		{
			if (event.type == MouseEvent.MOUSE_DOWN) {
				//获取鼠标位置向量
				var mp:Vec2=new Vec2(mouseX,mouseY);
				//获取鼠标下方的body刚体
				var bodiesList:BodyList = napeWorld.bodiesUnderPoint(mp);
				//遍历每个刚体
				bodiesList.foreach(
					function( bb:Body):void{
						if(bb.isDynamic()){
							//如果刚体是非静止的,则删除刚体
							napeWorld.bodies.remove(bb);
						}
					}
				);
			}
		}
	}
}
import com.bit101.components.PushButton;

import flash.display.DisplayObjectContainer;

class UISetting{
	public function UISetting(container:DisplayObjectContainer,handler:Function):void{
		var btn:PushButton=new PushButton(container,300,10,"ReStart",handler);
	}
}

对了,后面的教程中,我们还会重复的创建Nape世界、刚体、设置刚体的属性等等,为了避免重复复制粘贴代码,我把这些动作封装到了AbstractNapeTest.as类中,本例以及后面的教程,只要继承这个类,就可以轻松的创建Nape应用了。

完整的AbstractNapeTest.as类代码如下:

package 
{
	import flash.display.Graphics;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.KeyboardEvent;
	import flash.events.MouseEvent;
	import flash.geom.Point;

	import nape.constraint.PivotJoint;
	import nape.geom.Vec2;
	import nape.phys.Body;
	import nape.phys.BodyType;
	import nape.phys.Material;
	import nape.shape.Circle;
	import nape.shape.Polygon;
	import nape.space.Space;
	import nape.util.BitmapDebug;

	[SWF( width="550", height="400", frameRate="60")]
	public class AbstractNapeTest extends Sprite
	{		

		protected var napeWorld:Space;
		protected var debug:BitmapDebug;

		protected var isCtrlDown:Boolean;
		protected var isShiftDown:Boolean;

		protected var mouseJoint:PivotJoint;

		public function AbstractNapeTest()
		{
			//1.创建Nape空间,重力,调试视图
			createNapeWorld();
			//2.添加事件
			setUpEvents();
			//添加FPS监视器
			addChild(new Stats());
		}
		//创房Nape世界
		protected function createNapeWorld():void
		{
			//定义Nape世界的重力
			var gravity:Vec2 = new Vec2( 0, 600 );
			napeWorld =new Space( gravity );

			//添加Nape调试试图
			debug= new BitmapDebug(550, 400, 0xD6D6D6);
			addChild(debug.display);
		}
		//添加事件侦听
		protected function setUpEvents():void
		{
			//侦听帧更新事件
			stage.addEventListener(Event.ENTER_FRAME, loop);
			//add listener to MouseEvent,like mouseDown or MouseUp
			stage.addEventListener(MouseEvent.MOUSE_DOWN, mouseEventHanlder);
			stage.addEventListener(MouseEvent.MOUSE_UP, mouseEventHanlder);
			//侦听键盘事件
			stage.addEventListener(KeyboardEvent.KEY_DOWN, keyBoardEventHanlder);
			stage.addEventListener(KeyboardEvent.KEY_UP, keyBoardEventHanlder);
		}

		protected function keyBoardEventHanlder(event:KeyboardEvent):void
		{
			//键盘事件处理函数
			//在键盘按下时,记录Ctrl和Shift键的状态
			isCtrlDown=event.ctrlKey;
			isShiftDown=event.shiftKey;
		}
		protected function mouseEventHanlder(event:MouseEvent):void
		{
			//鼠标事件处理函数
		}
		protected function loop(event:Event):void
		{
			//更新Nape世界
			napeWorld.step(1/60);
			debug.clear();
			debug.draw(napeWorld);
			debug.flush();
		}
		//创建矩形刚体,之前我们都已经讲过
		protected function createBox(posX:Number, posY:Number, w:Number, h:Number, type:BodyType):void{
			var box:Body = new Body(type, new Vec2(posX, posY));
			var boxShape:Polygon=new Polygon(Polygon.box(w,h), Material.glass());
			box.shapes.push(boxShape);
			box.space= napeWorld;
		}
		//创建指定边数的规则多边形刚体
		protected function createRegular(posX:Number, posY:Number, r:Number, rotation:Number, edgeCount:int, type:BodyType):void{
			var regular:Body = new Body(type, new Vec2(posX, posY));
			//通过Polygon预定义的regular方法绘制规则的边数位edgeCount的多边形刚体
			var regularShape:Polygon=new Polygon(Polygon.regular(r*2,r*2,edgeCount), Material.glass());
			regularShape.rotate(rotation);
			regular.shapes.push(regularShape);
			regular.space= napeWorld;
		}
		//创建圆形刚体
		protected function createCircle(posX:Number, posY:Number, radius:int, type:BodyType):void
		{
			var circle:Body=new Body(type, new Vec2(posX, posY));
			var shape:Circle=new Circle(radius,null,Material.glass());
			circle.shapes.push(shape);
			circle.space=napeWorld;
		}
		//绘制包围的静态刚体
		protected function createWall():void{
			createBox(stage.stageWidth/2, 0, stage.stageWidth, 10, BodyType.STATIC);
			createBox(stage.stageWidth/2, stage.stageHeight, stage.stageWidth, 10, BodyType.STATIC);
			createBox(0, stage.stageHeight/2, 10, stage.stageHeight, BodyType.STATIC);
			createBox(stage.stageWidth, stage.stageHeight/2, 10,stage.stageWidth, BodyType.STATIC);
		}

	}
}

好了,23:14了,不早了,我睡觉了。

对了,源文件下载地址在这里!

联系作者

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

10 Replies to “鼠标获取并删除Nape刚体的方法”

  1. 从早上看到现在,吧拉登大叔的BOX2D全看完,虽然没有全部自己写一遍,不过也体会不浅,
    有了这些做个简单的物理游戏足够了,
    希望拉登继续教程。
    另外贴图能否平滑? 矢量效果倒是还可以,位图就抖 锯齿的厉害!

  2. 谢谢,我会继续努力的!!关于锯齿的问题,应该是Flash Player渲染本身的问题,跟Box2D没有太大关系,你可以试着设置stage.quality = StageQuality.HIGH;看看效果如何。

  3. 请问下我的body贴图了,好像 napeWorld.bodies.remove(bb);移除不了,是不是还有什么没有删掉呢,谢谢

发表回复

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