Box2DFlash笔记(三)--鼠标移动事件实现

声明:欢迎任何人和组织转载本blog中文章,但必须标记文章原始链接和作者信息。

本文链接:http://blog.csdn.net/li_007/archive/2009/04/13/4071104.aspx

开拓进取的小乌龟------->CSDN点滴点点滴滴Blog

这段时间在研究Box2DFlash这个开源APE,现在分享一下Box2DFlash中鼠标实现的方法。在Box2DFlash自带的TestBed中就实现了鼠标事件和键盘事件,其实就是Actionscript 3键鼠事件,然后结合一下Box2DFlash。关于怎么实现鼠标移动,可以说是对研究APE必须弄清楚的,不然就不要玩APE了。

1、首先肯定就是Actionscript 3的鼠标监听事件了,这是基本,不然怎么交Box2D Flash版啊。在这里我们需要监听MOUDSE_DOWN这个事件的,在Box2DFlash中是这样实现的,当我我们按下鼠标的时候,以当前鼠标坐标点建立一个Shape(实际上只是一个框框,也就是一个域,范围),很小很小的shape(0.001有效位);然后遍历当前World中所有的Body,查找与刚建立的Shape有重叠的body,返回一个包含这个body的数组(其实只有一个,因为都是body,刚体,这是我的理解);再其次就是循环这些body,测试当前鼠标点是否在此body有效范围中(也即是确认那个body被点击了),然后返回符合条件的body,中止循环。关于这个功能的实现的GetBodyAtMouse函数实现如下:

private function getBodyAtMouse(includeStatic:Boolean = false):b2Body { // 利用当前鼠标点位置,创建当前鼠标向量 this._mousePreVector.Set(stage.mouseX / this._phyScale, stage.mouseY / this._phyScale); // 利用当前鼠标向量建立一个很小b2AABB类型的框(感觉叫Shape更好,但其实就是一个范围,一个域) var _aabb:b2AABB = new b2AABB(); _aabb.lowerBound.Set(this._mousePreVector.x - 0.001, this._mousePreVector.y - 0.001); _aabb.upperBound.Set(this._mousePreVector.x + 0.001, this._mousePreVector.y + 0.001); // 在World中查找与刚用鼠标向量定义的Shape相重叠的Shape,并返回符合条件的所有Shape数组 var k_maxCount:int = 10; var _shapes:Array = new Array(); var count:int = this._bWorld.Query(_aabb, _shapes, k_maxCount); var _body:b2Body = null; // 循环数组中的Shape,检测当前鼠标是否在当前的Shape所包含的范围内 for (var i:int = 0; i < count; ++i) { // 判断当前Shape的父Body是否是静态或者可移动的(这里要理解b2Body、b2BodyDef和b2Shape // 已经b2Shape子类的关系)。其实查阅源码会发现GetBody返回的是在b2Shape中保存的m_body // 这个变量,也就是当前的b2Body对象。 if (_shapes[i].GetBody().IsStatic() == false || includeStatic) { trace(_shapes[i]); // 将当前Shape转化为最初父类b2Shape. var _tShape:b2Shape = _shapes[i] as b2Shape; // 测试当前鼠标向量是否在符合条件的当前Shape范围内。注意在这里需要将当前body的坐标转化 // 世界坐标系,也即当前Sprite绘制场景。 var inside:Boolean = _tShape.TestPoint(_tShape.GetBody().GetXForm(), _mousePreVector); if (inside) { // 返回符号条件的body,并终止循环。 _body = _tShape.GetBody(); break; } _tShape = null; } } _aabb = null; _shapes = null; return _body; }

2、当我们得到了当前点击的body后,通过建立一个b2MouseJoint对象,在这里翻译成“鼠标关节”吧,让这个鼠标关节的一个物体为从b2World的GetGroundBody得到的没有碰撞检测形状的静态body,问另一个body则连接上被点击的body,然后不但更新这个鼠标关节的target位置为当前鼠标位置,这样就间接实现了物体被鼠标拖动了。代码如下:

var _tempBody:b2Body = getBodyAtMouse(); if (_tempBody) { // 建立鼠标节点定义 var _mouseJointDef:b2MouseJointDef = new b2MouseJointDef(); // 设置body1为无碰撞检测形状的静态刚体 _mouseJointDef.body1 = this._bWorld.GetGroundBody(); // 设置body2为当前被检测到被点击的刚体 _mouseJointDef.body2 = _tempBody; // 设置鼠标节点的最初世界位置 _mouseJointDef.target.Set(this._mousePreVector.x, this._mousePreVector.y); _mouseJointDef.maxForce = 5000 * _tempBody.GetMass(); _mouseJointDef.timeStep = this._timeStep; // 在世界中创建这个b2MouseJoint对象 this._mouseJoint = this._bWorld.CreateJoint(_mouseJointDef) as b2MouseJoint; // 如果当前body处于休眠状态,则唤醒。 _tempBody.WakeUp(); _mouseJointDef = null; _tempBody = null; }

3、好了,然后我们不但更新这个b2MouseJoint对象的坐标点就可以了,其实就是随着时间步中更新。

整个工程代码如下:(直接建立Actionscript 3的工程,用下面代码做文档类即可看到结果)

// // Box2DEvent.as // // the entry of application // // Written by Leezhm, 10st April, 2009 // Contact : leezhm@126.com // Last Modified by Leezhm@126.com on 11st April, 2009 // package Srcs { import Box2D.Collision.b2AABB; import Box2D.Collision.Shapes.b2CircleDef; import Box2D.Collision.Shapes.b2PolygonDef; import Box2D.Collision.Shapes.b2Shape; import Box2D.Collision.Shapes.b2ShapeDef; import Box2D.Common.Math.b2Vec2; import Box2D.Dynamics.b2Body; import Box2D.Dynamics.b2BodyDef; import Box2D.Dynamics.b2DebugDraw; import Box2D.Dynamics.b2World; import Box2D.Dynamics.Joints.b2MouseJoint; import Box2D.Dynamics.Joints.b2MouseJointDef; import flash.events.MouseEvent; import flash.display.Sprite; import flash.events.Event; public class Box2DEvent extends Sprite { private var _bWorld:b2World; private var _iterations:uint = 10; private var _timeStep:Number = 1.0 / 60.0; private var _phyScale:Number = 30.0; private var _dbgSprite:Sprite; private var _mouseJoint:b2MouseJoint; private var _mousePreVector:b2Vec2; private var _mouseDown:Boolean = false; public function Box2DEvent() { InitWorld(); addDynamicBodies(); this.addEventListener(Event.ENTER_FRAME, OnUpdateWorld, false, 0, true); this.addEventListener(MouseEvent.MOUSE_UP, OnMouseUpHandler, false, 0, true); this.addEventListener(MouseEvent.MOUSE_DOWN, OnMouseDownHandler, false, 0, true); } private function InitWorld():void { // define a AABB coordination var _bAABB:b2AABB = new b2AABB(); _bAABB.lowerBound.Set( -100.0, -100.0); _bAABB.upperBound.Set( 100.0, 100.0); // define the gravity vector var _gravity:b2Vec2 = new b2Vec2(0.0, 10.0); // allow the bodies to sleep var _bSleep:Boolean = true; // create the world object if (null == this._bWorld) { this._bWorld = new b2World(_bAABB, _gravity, _bSleep); } // define a b2DebugDraw class object to draw all bodies when you // debug this application var _b2Dbg:b2DebugDraw = new b2DebugDraw(); if (null == this._dbgSprite) { this._dbgSprite = new Sprite(); this.addChild(this._dbgSprite); } _b2Dbg.m_sprite = this._dbgSprite; _b2Dbg.m_fillAlpha = 0.6; _b2Dbg.m_lineThickness = 0.4; _b2Dbg.m_drawFlags = b2DebugDraw.e_shapeBit | b2DebugDraw.e_jointBit; _b2Dbg.m_drawScale = this._phyScale this._bWorld.SetDebugDraw(_b2Dbg); // define the ground body var _bodyDef:b2BodyDef = new b2BodyDef(); _bodyDef.position.Set(10, 19); var _rectangle:b2PolygonDef = new b2PolygonDef(); _rectangle.SetAsBox(800 / _phyScale, 50 / _phyScale); _rectangle.friction = 0.5; _rectangle.density = 0; _rectangle.restitution = 0.6; var _body:b2Body = this._bWorld.CreateBody(_bodyDef); _body.CreateShape(_rectangle); _body.SetMassFromShapes(); // left _bodyDef.position.Set( -2, 1); _rectangle.SetAsBox(80 / _phyScale, 800 / _phyScale); _rectangle.restitution = 0.6; _body = this._bWorld.CreateBody(_bodyDef); _body.CreateShape(_rectangle); _body.SetMassFromShapes(); // right _bodyDef.position.Set( 28, 1); _rectangle.SetAsBox(80 / _phyScale, 800 / _phyScale); _rectangle.restitution = 0.6; _body = this._bWorld.CreateBody(_bodyDef); _body.CreateShape(_rectangle); _body.SetMassFromShapes(); // top _bodyDef.position.Set( 1, -2); _rectangle.SetAsBox(800 / _phyScale, 80 / _phyScale); _rectangle.restitution = 0.6; _body = this._bWorld.CreateBody(_bodyDef); _body.CreateShape(_rectangle); _body.SetMassFromShapes(); _bAABB = null; _gravity = null; _dbgSprite = null; _b2Dbg = null; _rectangle = null; _bodyDef = null; _body = null; } private function addDynamicBodies():void { for (var i:uint = 0; i < 6; i ++) { var _bodyDef:b2BodyDef = new b2BodyDef(); _bodyDef.position.Set(Math.random() * _phyScale, Math.random()); var _circleDef:b2CircleDef = new b2CircleDef(); _circleDef.radius = Math.random() + 1.0; _circleDef.friction = 0.3; _circleDef.density = 3 * Math.random(); _circleDef.restitution = 0.8; var _body:b2Body = this._bWorld.CreateBody(_bodyDef); _body.CreateShape(_circleDef); _body.SetMassFromShapes(); _bodyDef = null; _circleDef = null; _body = null; } } private function OnUpdateWorld(evt:Event = null):void { this._bWorld.Step(this._timeStep, this._iterations); if (this._mouseJoint) { this._mousePreVector = new b2Vec2(stage.mouseX / this._phyScale, stage.mouseY / this._phyScale); this._mouseJoint.SetTarget(this._mousePreVector); } for (var bb:b2Body = this._bWorld.m_bodyList; bb; bb = bb.GetNext()) { if (bb.m_userData is Sprite) { bb.m_userData.x = bb.GetPosition().x * 30; bb.m_userData.y = bb.GetPosition().y * 30; bb.m_userData.rotation = bb.GetAngle() * (180/Math.PI); } } } private function OnMouseUpHandler(evt:MouseEvent = null):void { if (this._mouseJoint) { this._bWorld.DestroyJoint(this._mouseJoint); this._mouseJoint = null; } } private function OnMouseDownHandler(evt:MouseEvent = null):void { if (null == this._mousePreVector) { this._mousePreVector = new b2Vec2(); } var _tempBody:b2Body = getBodyAtMouse(); if (_tempBody) { // 建立鼠标节点定义 var _mouseJointDef:b2MouseJointDef = new b2MouseJointDef(); // 设置body1为无碰撞检测形状的静态刚体 _mouseJointDef.body1 = this._bWorld.GetGroundBody(); // 设置body2为当前被检测到被点击的刚体 _mouseJointDef.body2 = _tempBody; // 设置鼠标节点的最初世界位置 _mouseJointDef.target.Set(this._mousePreVector.x, this._mousePreVector.y); _mouseJointDef.maxForce = 5000 * _tempBody.GetMass(); _mouseJointDef.timeStep = this._timeStep; // 在世界中创建这个b2MouseJoint对象 this._mouseJoint = this._bWorld.CreateJoint(_mouseJointDef) as b2MouseJoint; // 如果当前body处于休眠状态,则唤醒。 _tempBody.WakeUp(); _mouseJointDef = null; _tempBody = null; } } private function getBodyAtMouse(includeStatic:Boolean = false):b2Body { // 利用当前鼠标点位置,创建当前鼠标向量 this._mousePreVector.Set(stage.mouseX / this._phyScale, stage.mouseY / this._phyScale); // 利用当前鼠标向量建立一个很小b2AABB类型的框(感觉叫Shape更好,但其实就是一个范围,一个域) var _aabb:b2AABB = new b2AABB(); _aabb.lowerBound.Set(this._mousePreVector.x - 0.001, this._mousePreVector.y - 0.001); _aabb.upperBound.Set(this._mousePreVector.x + 0.001, this._mousePreVector.y + 0.001); // 在World中查找与刚用鼠标向量定义的Shape相重叠的Shape,并返回符合条件的所有Shape数组 var k_maxCount:int = 10; var _shapes:Array = new Array(); var count:int = this._bWorld.Query(_aabb, _shapes, k_maxCount); var _body:b2Body = null; // 循环数组中的Shape,检测当前鼠标是否在当前的Shape所包含的范围内 for (var i:int = 0; i < count; ++i) { // 判断当前Shape的父Body是否是静态或者可移动的(这里要理解b2Body、b2BodyDef和b2Shape // 已经b2Shape子类的关系)。其实查阅源码会发现GetBody返回的是在b2Shape中保存的m_body // 这个变量,也就是当前的b2Body对象。 if (_shapes[i].GetBody().IsStatic() == false || includeStatic) { trace(_shapes[i]); // 将当前Shape转化为最初父类b2Shape. var _tShape:b2Shape = _shapes[i] as b2Shape; // 测试当前鼠标向量是否在符合条件的当前Shape范围内。注意在这里需要将当前body的坐标转化 // 世界坐标系,也即当前Sprite绘制场景。 var inside:Boolean = _tShape.TestPoint(_tShape.GetBody().GetXForm(), _mousePreVector); if (inside) { // 返回符号条件的body,并终止循环。 _body = _tShape.GetBody(); break; } _tShape = null; } } _aabb = null; _shapes = null; return _body; } } }

BTW:不知道么时候CSDN可以直接上传SWF到blog中。欢迎大家指正错误,以及讨论这些知识。

转载于:https://www.cnblogs.com/leezhm/archive/2009/04/13/2560318.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值