Nape中的DistanceJoint——距离关节

前面我们学习了PivotJoint关节和WeldJoint关节,今天要学习的是DistanceJoint关节,即”距离关节”。但是Nape中的距离关机与Box2D稍有不同,我们可以通过jointMin和jointMax参数,设置关节的最短距离和最长距离。

实际上,这个关节效果在游戏中应用的并不是很多,至少我是没怎么见到过。但这并不代表它没用,充分发挥我们的想象力,说不定下一个游戏中就会用得到。

首先我来看一下DistanceJoint关节的构造函数:

public function DistanceJoint(
	body1:Body,
	body2:Body,
	anchor1:Vec2,
	anchor2:Vec2,
	jointMin:Number,
	jointMax:Number):void

PivotJoint关节类似,DistanceJoint同样连接了两个刚体,有两个节点anchor1和anchor2。不过连接刚体的控制节点同样也有两个,这一点与PivotJoint关节不同。正如Nape Mannual里所示:

同样anchor1和anchor2也是相对于刚体本地坐标的。我们可以先定义好全局的控制节点坐标(即我们看到的在舞台上的坐标位置),然后再通过body.worldPointToLocal转换成刚体本地坐标。

另外就是参数jointMin和jointMax,DistanceJoint关节中限制刚体移动的范围。下图红红色线条表示jointMin,蓝色线条表示jointMax,这样两个刚体只能在图中红色区域内移动。而Box2D中的距离关节只是jointMin=jointMax时的情况。

jointMin_jointMax

另外在初始化jointMin和jointMax的时候要注意,jointMin要小于jointMax, jointMax要大于两个刚体初始的距离。好了,接下来我们来看一下示例把。

在下面的SWF中,有两个圆形刚体,小圆是动态刚体,大圆是sensor刚体。在大圆内点击鼠标创建矩形刚体,如果刚体处在上面的sensor刚体中,则会自动创建一个jointMin=0, jointMax=150的距离关节。如果是在下面的sensor刚体中,则会创建一个jointMin=50, jointMax=150的距离关节。试试看吧!

[swfobject]845[/swfobject]

完整的代码和注释如下:

package learnNape {
	import ldEasyNape.LDEasyUserData;
	import nape.callbacks.InteractionCallback;
	import nape.callbacks.CbType;
	import nape.callbacks.InteractionType;
	import nape.callbacks.CbEvent;
	import nape.callbacks.InteractionListener;
	import nape.shape.Circle;
	import flash.events.MouseEvent;
	import flash.events.Event;

	import nape.geom.Vec2;
	import nape.constraint.DistanceJoint;
	import ldEasyNape.LDEasyNape;
	import nape.phys.Body;
	import learnNape.AbstractNapeTest;

	/**
	 * @author yangfei
	 */
	 [SWF( width="400", height="500", frameRate="60")]
	public class T16_DistanceJoint extends AbstractNapeTest {

		//定义关节所需的变量
		private var anchorBody1 : Body;
		private var anchorBody2 : Body;
		private var joint1 : DistanceJoint;
		private var joint2 : DistanceJoint;

		//定义sensor刚体所需的内容
		private var sensorListener : InteractionListener;
		private var sensorShape : Circle;		
		private var sensorType : CbType;
		private var bodyType : CbType;
		//定义贴图
		private var graphic : LDEasyUserData;

		public function T16_DistanceJoint() {
			super(600);
		}

		override protected function onNapeWorldReady() : void {
			graphic = new LDEasyUserData();
			graphic.setGraphicAuotmatically(0);

			//定义sensor图形,侦听鼠标点击产生的刚体,是否在感应区域内
			sensorShape = new Circle(110);
			sensorShape.sensorEnabled = true;
			//senor刚体的类型,在碰撞处理函数中使用
			sensorType = new CbType();
			//鼠标点击时创建的刚体类型
			bodyType = new CbType();

			//创建上下两个圆形刚体,并添加一个大的sensor图形
			anchorBody1 = LDEasyNape.createCircle(200, 100, 10, false, true, graphic);
			anchorBody1.shapes.add(sensorShape);
			anchorBody1.cbTypes.add(sensorType);
			anchorBody2 = LDEasyNape.createCircle(200, 350, 10, false, true, graphic);
			anchorBody2.shapes.add(sensorShape.copy());
			anchorBody2.cbTypes.add(sensorType);

			//先创建好两个关节,这和PivotJoint差不多,设置active为FALSE,不进行物理模拟
			joint1 = new DistanceJoint(anchorBody1, null, Vec2.weak(),Vec2.weak(),0, 110);
			joint1.active=false;
			joint1.space = napeWorld;
			joint2 = new DistanceJoint(anchorBody2, null, Vec2.weak(),Vec2.weak(),50, 110);
			joint2.active=false;
			joint2.space = napeWorld;
			//添加碰撞事件侦听,具体碰撞教程请参考我的文章
			//http://www.ladeng6666.com/blog/2013/02/20/handling-nape-collision/
			sensorListener = new InteractionListener(CbEvent.BEGIN, InteractionType.SENSOR, sensorType, bodyType, sensorHanlder);
			napeWorld.listeners.add(sensorListener);
		}

		private function sensorHanlder(cb:InteractionCallback):void{
			var body1 : Body = cb.int1.castBody;
			var body2 : Body = cb.int2.castBody;
			//如果刚体已与anchor刚体连接,则返回
			if(body2.constraints.length>0) return;
			//上面的anchor刚体
			if(body1.position.y < 200){
				//更新第2个刚体引用,变更后,原刚体会自动解除与anchor刚体的关节,自由下落
				joint1.body2 = body2;
				//激活关节
				joint1.active = true;
			//下面的anchor刚体
			}else{
				joint2.body2 = body2;
				joint2.active = true;
			}
		}
		override protected function loop(event : Event) : void {
			super.loop(event);
			napeWorld.liveBodies.foreach(function (b:Body):void{
				//刚体超出舞台时,删除该刚体
				if(b.position.y> stage.stageHeight+50){
					napeWorld.liveBodies.remove(b);
				}
			});
		}

		override protected function mouseEventHanlder(event : MouseEvent) : void {
			super.mouseEventHanlder(event);
			//在鼠标点击位置创建矩形刚体
			if(event.type == MouseEvent.MOUSE_DOWN){
				if(LDEasyNape.getBodyAtMouse()==null || !LDEasyNape.getBodyAtMouse().cbTypes.has(bodyType)){
					graphic.setGraphicAuotmatically(0xff0000);
					var body : Body = LDEasyNape.createBox(mouseX,mouseY, 30, 30, false, false, graphic);
					body.cbTypes.add(bodyType);
				}

			}
		}

	}
}

点击下载源文件

联系作者

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

2 Replies to “Nape中的DistanceJoint——距离关节”

发表回复

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