您的位置:首页 > 其它

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

2009-04-13 22:56 525 查看
声明:欢迎任何人和组织转载本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中。欢迎大家指正错误,以及讨论这些知识。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: