11RIA 闪客社区 - 最赞 Animate Flash 论坛

搜索
查看: 2312|回复: 0
上一主题 下一主题

[2D 物理引擎] 【9RIA—ladeng6666】—【Box2D系列教程 17】让刚体听我的——鼠标拖动Box2D刚体

[复制链接] TA的其它主题
发表于 2018-2-6 14:19:48 | 显示全部楼层 |阅读模式

【游客模式】——注册会员,加入11RIA 闪客社区吧!一起见证Flash的再次辉煌……

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
转载:9RIA游戏开发者社区(天地会)
作者:ladeng6666(拉登大叔)
作者博客:http://www.ladeng6666.com/blog/


【Box2D系列教程-导航帖】—拉登大叔出品(总贴)



在前面我们学习了键盘+ ApplyForce、ApplyImpulse和SetLinearVelocity(Box2D系列教程 8)来控制刚体运动。今天我们学习一下用MouseJointDef实现鼠标拖动刚体运动。

鼠标拖动刚体运动,这在Flash中实现起来是非常简单的:鼠标按下之后,调用startDrag()方法,这样对象就会跟随鼠标移动;鼠标弹起后,调用stopDrag()方法,停止拖动。效果如下:



听起来确实很简单,那么这个方法是否适用于Box2D刚体呢?如果你看过掉落的苹果教程,可以知道,Box2D的所有刚体都绘制在一个debugSprite中,也就是说,通过鼠标事件,我们只能获取debugSprite,并且只能执行对debugSprite的拖动,因此所有的刚体全部同时动起来,无法多每个刚体单独拖动,所以这条路行不通了。

有人可能会说了,每个刚体不是都有userData对象吗?它们都是DisplayObject,调用它们的鼠标事件,执行拖动,再更新刚体的坐标就好了。但是我想说的是,Box2D是用刚体来驱动userData的,而不是用userData来更新刚体的坐标,否则会跟Box2D内部的计算引起冲突,所以这条路也行不通了。

说了这么多,还是回到正确的方法上来。Box2D中有一个b2MouseJointDef对象,可以帮我们实现这个功能。

b2MouseJointDef是一个关节(关于关节,我会专门写一篇教程来介绍,大家稍安勿躁),用于链接鼠标和被拖动的刚体,它主要包含下面几个属性:
    bodyA:关节连接的一个节点
    bodyB:关节连接的另外一个节点
    maxForce:限制鼠标关节上可以施加的最大的力,这里通常需要乘以刚体的质量multiplier * mass * gravity
了解了鼠标关节(这里我只简单的介绍这么多,在后面的教程我会专门介绍Box2D里的关节),接下来,我们开始编写拖动过程。


鼠标是否滑过刚体
首先,要确定是否在刚体上,并找出这个刚体。在Flash中,我们调用DisplayObject的MOUSE_OVER方法,可以判断鼠标是否滑过该对象。

与Flash不同,Box2D用b2World世界的QueryPoint方法来实现这个功能,QueryPoint方法如下:

[Actionscript3] 纯文本查看 复制代码
public function QueryPoint(
	callback:Function,
	p:b2Vec2
):void


QueryPoint方法会遍历world中所有的刚体,判断p点是否在刚体上,如果是,则将刚体对应的b2Fixture传入到callBack函数中。然后我可以利用b2Fixture.GetBody()方法获取刚体,具体代码如下:
[Actionscript3] 纯文本查看 复制代码
		private function getBodyAtMouse():b2Body
		{
			//转换鼠标坐标单位,除以30从m该为px
			var mouseVector:b2Vec2 = new b2Vec2(mouseX / 30, mouseY / 30);
			//鼠标下的刚体
			var bodyAtMouse:b2Body = null;
			//queryPoint函数中要用到的回调函数,注意,它必须有一个b2Fixture参数
			function callBack(fixture:b2Fixture):void {
				if ( fixture == null) return;
				//如果fixture不为null,设置为鼠标下的刚体
				bodyAtMouse = fixture.GetBody();
			}
			//利用QueryPoint方法查找鼠标滑过的刚体
			world.QueryPoint(callBack, mouseVector);
			//返回找到的刚体
			return bodyAtMouse;
		}



拖动刚体
找到鼠标点击的刚体后,下面是拖动刚体。前面说过,我们是用鼠标关节MouseJointDef来实现拖动刚体,所以针对拖动过程,我创建鼠标关节,然后把点击的刚体设置为关节的一个节点,然后鼠标关节的目标点位鼠标点,并实时更新就好了,代码如下:

[Actionscript3] 纯文本查看 复制代码
		private function startDragBody(body:b2Body):void {
			if (body == null) return;//如果鼠标下的刚体不为空
			_isDragBodyWithMouse = true;//设置拖动标识为true
			//创建鼠标关节需求
			var mouseJointDef:b2MouseJointDef = new b2MouseJointDef();
			mouseJointDef.bodyA = world.GetGroundBody();//设置鼠标关节的一个节点为空刚体,GetGroundBody()可以理解为空刚体
			mouseJointDef.bodyB = body//设置鼠标关节的另一个刚体为鼠标点击的刚体
			mouseJointDef.target.Set(mouseX / 30, mouseY / 30);//更新鼠标关节拖动的点
			mouseJointDef.maxForce = 1000;//设置鼠标可以施加的最大的力
 
			//创建鼠标关节
			_mouseJoint = world.CreateJoint(mouseJointDef) as b2MouseJoint;
 
		}
		private function loop(e:Event):void
		{
			LDEasyBox2D.updateWorld(world);
			//如果有鼠标关节存在,更新鼠标关节的拖动点
			if (_mouseJoint != null) {
				var mouseVector:b2Vec2 = new b2Vec2(mouseX / 30, mouseY / 30);
				_mouseJoint.SetTarget(mouseVector);
			}
		}


完成后的效果如下:


完整的代码和注释如下:
[Actionscript3] 纯文本查看 复制代码
package
{
	import Box2D.Collision.b2AABB;
	import Box2D.Collision.Shapes.b2Shape;
	import Box2D.Common.Math.b2Vec2;
	import Box2D.Dynamics.b2Body;
	import Box2D.Dynamics.b2Fixture;
	import Box2D.Dynamics.b2World;
	import Box2D.Dynamics.Joints.b2MouseJoint;
	import Box2D.Dynamics.Joints.b2MouseJointDef;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.KeyboardEvent;
	import flash.events.MouseEvent;
	import flash.ui.Keyboard;
 
	/**
	 * [url]http://www.ladeng6666.com[/url]
	 * @author ladeng6666
	 */
	public class Main extends Sprite
	{
		//创建世界的基本元素
		private var world:b2World;
		private var debugSprite:Sprite;
		private var body:b2Body;
 
		private var vector:b2Vec2 = new b2Vec2();
 
		private var _isDragBodyWithMouse:Boolean;
		private var _mouseJoint:b2MouseJoint;
 
		public function Main()
		{
			world=LDEasyBox2D.createWorld();
			addChild(LDEasyBox2D.createDebug(world));
 
			LDEasyBox2D.createWrapWall(world, stage);
 
			createBodies();
 
			//侦听事件
			addEventListener(Event.ENTER_FRAME, loop);
			stage.addEventListener(MouseEvent.MOUSE_DOWN, onStageMouseDown);
			stage.addEventListener(MouseEvent.MOUSE_UP, onStageMouseUp);
		}
 
		private function getBodyAtMouse():b2Body
		{
			//转换鼠标坐标单位,除以30从m该为px
			var mouseVector:b2Vec2 = new b2Vec2(mouseX / 30, mouseY / 30);
			//鼠标下的刚体
			var bodyAtMouse:b2Body = null;
			//queryPoint函数中要用到的回调函数,注意,它必须有一个b2Fixture参数
			function callBack(fixture:b2Fixture):void {
				if ( fixture == null) return;
				//如果fixture不为null,设置为鼠标下的刚体
				bodyAtMouse = fixture.GetBody();
			}
			//利用QueryPoint方法查找鼠标滑过的刚体
			world.QueryPoint(callBack, mouseVector);
			//返回找到的刚体
			return bodyAtMouse;
		}
 
		private function onStageMouseUp(e:MouseEvent):void
		{
			//鼠标弹起后,设置鼠标拖动标识为false
			if (_isDragBodyWithMouse ) {
				_isDragBodyWithMouse = false;
				//同时删除鼠标关节
				if (_mouseJoint != null) {
					world.DestroyJoint(_mouseJoint);
					_mouseJoint = null;
				}
 
			}
		}
 
		private function onStageMouseDown(e:MouseEvent):void
		{
			_isDragBodyWithMouse = true;
			startDragBody(getBodyAtMouse());
		}
		private function startDragBody(body:b2Body):void {
			if (body == null) return;//如果鼠标下的刚体不为空
			_isDragBodyWithMouse = true;//设置拖动标识为true
			//创建鼠标关节需求
			var mouseJointDef:b2MouseJointDef = new b2MouseJointDef();
			mouseJointDef.bodyA = world.GetGroundBody();//设置鼠标关节的一个节点为空刚体,GetGroundBody()可以理解为空刚体
			mouseJointDef.bodyB = body//设置鼠标关节的另一个刚体为鼠标点击的刚体
			mouseJointDef.target.Set(mouseX / 30, mouseY / 30);//更新鼠标关节拖动的点
			mouseJointDef.maxForce = 1000;//设置鼠标可以施加的最大的力
 
			//创建鼠标关节
			_mouseJoint = world.CreateJoint(mouseJointDef) as b2MouseJoint;
 
		}
 
		private function createBodies():void
		{
			var bodiesNum:Number = 4;
			for (var i:int = 0; i < bodiesNum; i++) {
				//创建矩形刚体
				LDEasyBox2D.createBox(world, Math.random()*stage.stageWidth, 50, 50, 50);
			}
 
		}
		private function loop(e:Event):void
		{
			LDEasyBox2D.updateWorld(world);
			//如果有鼠标关节存在,更新鼠标关节的拖动点
			if (_mouseJoint != null) {
				var mouseVector:b2Vec2 = new b2Vec2(mouseX / 30, mouseY / 30);
				_mouseJoint.SetTarget(mouseVector);
			}
		}
	}
 
}


另外,代码中我用到了LDEasyBox2D。

2.swf

86.14 KB, 下载次数: 1, 下载积分: 银子 -10 , 活跃 1

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关闭

站长推荐 上一条 /1 下一条

感谢所有支持论坛的朋友:下面展示最新的5位赞助和充值的朋友……更多赞助和充值朋友的信息,请查看:永远的感谢名单

SGlW(66139)、 anghuo(841)、 whdsyes(255)、 longxia(60904)、 囫囵吞澡(58054)

下面展示总排行榜的前3名(T1-T3)和今年排行榜的前3名的朋友(C1-C3)……更多信息,请查看:总排行榜今年排行榜

T1. fhqu1462(969)、 T2. lwlpluto(14232)、 T3. 1367926921(962)  |  C1. anghuo(147)、 C2. fdisker(27945)、 C3. 囫囵吞澡(58054)



快速回复 返回顶部 返回列表