[Box2D]五.和刚体交互

5 篇文章 0 订阅



点这看效果



此demo包含以下内容:

1.通过鼠标选择刚体

2.销毁刚体

3.对刚体设置自定义属性(包括皮肤)

4.循环遍历世界中的所有刚体

5.获取刚体信息


详细的解释请看代码

皮肤下载skin1.swc

package 
{	
	import Box2D.Collision.Shapes.b2PolygonShape;
	import Box2D.Common.Math.b2Vec2;
	import Box2D.Dynamics.b2Body;
	import Box2D.Dynamics.b2BodyDef;
	import Box2D.Dynamics.b2Fixture;
	import Box2D.Dynamics.b2FixtureDef;
	import Box2D.Dynamics.b2World;
	
	import flash.display.DisplayObject;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.text.TextField;
	import flash.text.TextFieldAutoSize;
	import flash.text.TextFormat;
	
	[SWF(width="410", height="480")]
	public class Interact extends Sprite {
		
		private var stageWidth:Number = 410;			//舞台宽度
		private var stageHeight:Number = 480;			//舞台高度
		private var backgroundColor:uint = 0x333333;	//背景色
		
		private var world:b2World;                //Box2D世界
		private var worldScale:Number = 30;        //一米等于30像素
		private var timeStep:Number = 1 / 30;    //时间步, 世界将在每一个时间步被更新
		
		//只是定义了时间步还不够。在每一步,每一个物理实体(physic entity)根据作用
		//于自身的作用力来更新(不包括睡眠状态)。处理这项任务的算法叫约束解算器
		//(constraint solver)。它是基于循环每一个约束然后解算来进行的,一次一个。
		private var velIterations:int = 10;        //速率约束解算器
		private var posIterations:int = 10;        //位置约束解算器
		
		private var info:TextField;	//info实时显示头像的坐标,速度,角度
		
		public function Interact() {
			drawBackground();
			createTip();
			createInfo();
			createWorld();
			//创建地面
			var floorAsset:DisplayObject = new FloorAsset();
			createRectBody( {x:floorAsset.width/2, y:stageHeight - floorAsset.height/2, 
							 width:floorAsset.width, height:floorAsset.height, 
							 asset:floorAsset, id:"floor"} );
			
			//创建左边界
			createRectBody({x:1, y:stageHeight/2, width:2, height:stageHeight, id:"leftBound"});
			//创建右边界
			createRectBody({x:stageWidth - 1, y:stageHeight/2, width:2, height:stageHeight, id:"rightBound"});
			
			//创建砖块
			var brickAsset:Sprite = new BrickAsset1();
			createRectBody({x:175, y:435, width:brickAsset.width, height:brickAsset.height, 
				            asset:brickAsset, type:b2Body.b2_dynamicBody, canDestroy:true, id:"brick1"});

			brickAsset = new BrickAsset2();
			createRectBody({x:265, y:435, width:brickAsset.width, height:brickAsset.height, 
				            asset:brickAsset, type:b2Body.b2_dynamicBody, canDestroy:true, id:"brick2"});
			
			brickAsset = new BrickAsset3();
			createRectBody({x:220, y:405, width:brickAsset.width, height:brickAsset.height, 
				            asset:brickAsset, type:b2Body.b2_dynamicBody, canDestroy:true, id:"brick3"});
			
			brickAsset = new BrickAsset4();
			createRectBody({x:220, y:375, width:brickAsset.width, height:brickAsset.height, 
				            asset:brickAsset, type:b2Body.b2_dynamicBody, canDestroy:true, id:"brick4"});
			
			brickAsset = new BrickAsset5();
			createRectBody({x:205, y:345, width:brickAsset.width, height:brickAsset.height, 
				            asset:brickAsset, type:b2Body.b2_dynamicBody, canDestroy:true, id:"brick5"});
			
			brickAsset = new BrickAsset6();
			createRectBody({x:220, y:300, width:brickAsset.width, height:brickAsset.height, 
				           asset:brickAsset, type:b2Body.b2_dynamicBody, canDestroy:true, id:"brick6"});
			
			//创建头像
			var iconAsset:IconAsset = new IconAsset();
			createRectBody({x:220, y:80, width:iconAsset.width, height:iconAsset.height, 
				          asset:iconAsset, type:b2Body.b2_dynamicBody, id:"userIcon"});
			
			addEventListener(Event.ENTER_FRAME,onUpdate);
			stage.addEventListener(MouseEvent.CLICK, onStageClick);
		}
		
		private function drawBackground():void {
			graphics.beginFill(backgroundColor);
			graphics.drawRect(0, 0, stageWidth, stageHeight);
			graphics.endFill();
		}
		
		private function createTip():void {
			var tip:TextField = new TextField();
			var format:TextFormat = new TextFormat();
			format.size = 14;
			format.color = 0xFFFFFF;
			tip.autoSize = TextFieldAutoSize.LEFT;
			tip.defaultTextFormat = format;
			tip.text = "砖块可销毁(点击它)";
			addChild(tip);
			tip.x = (stageWidth - tip.width) / 2;
		}
		
		private function createInfo():void {
			info = new TextField();	
			var format:TextFormat = new TextFormat();
			format.size = 14;
			format.color = 0xFFFFFF;
			info.autoSize = TextFieldAutoSize.LEFT;
			info.defaultTextFormat = format;
			addChild(info);
		}
		
		private function createWorld():void {
			var gravity:b2Vec2 = new b2Vec2(0, 9.81);    //重力
			//世界中的刚体静止时,可以允许他们进入睡眠状态,睡眠的刚体无需模拟
			var sleep:Boolean = true;
			world = new b2World(gravity, sleep);
		}
		
		private function onStageClick(event:MouseEvent):void {
			var x:Number = mouseX / worldScale;
			var y:Number = mouseY / worldScale;
			//世界的QueryPoint方法查询世界中所有的夹具,找出在点上的夹具,
			//然后如果有夹具在鼠标点击的点上,我们可以说我们点击了一个夹具。
			world.QueryPoint(queryCallback, new b2Vec2(x, y));
		}
		
		//在鼠标点击的点上的夹具。因为一个点上可以有不止一个的夹具(试
		//想一下重叠的staitc类型的刚体),如果你希望检查下一个夹具,那么你需要
		//让函数返回true,或者返回false将停止检查。
		private function queryCallback(fixture:b2Fixture):Boolean {
			var touchedBody:b2Body = fixture.GetBody();
			var userData:Object = touchedBody.GetUserData(); //获取自定义的刚体信息
			if(userData.canDestroy == true) {
				world.DestroyBody(touchedBody);	//销毁刚体
				removeChild(userData.asset);
			}
			//我们假设只可以有一个夹具在鼠标点击的点上
			//所以return false
			return false;
		}
		
		private function createRectBody(data:Object):void {
			var bodyDef:b2BodyDef = new b2BodyDef(); //刚体定义
			if(data.type != undefined) {
				bodyDef.type = data.type;  //刚体类型默认为静态	
			}
			bodyDef.position.Set(data.x/worldScale, data.y/worldScale);//设置刚体坐标, Box2D坐标用米表示	
			bodyDef.userData = new Object();
			if(data.id != undefined) {
				bodyDef.userData.id = data.id;	
			}
			if(data.asset != undefined) {
				bodyDef.userData.asset = data.asset;//为刚体设置皮肤
			}
			if(data.canDestroy != undefined) {
				bodyDef.userData.canDestroy = data.canDestroy;//点击时,是否能销毁
			}else {
				bodyDef.userData.canDestroy	= false;
			}
			var polygonShape:b2PolygonShape = new b2PolygonShape(); //创建多边形
			polygonShape.SetAsBox(data.width/2/worldScale, data.height/2/worldScale);//轴对称的矩形, 半宽长和半高长          
			
			var fixtureDef:b2FixtureDef = new b2FixtureDef(); //夹具(fixture)用于将形状绑定到刚体上
			if(data.density != undefined) { //密度	
				fixtureDef.density = data.density;
			}else {
				fixtureDef.density = 1;
			}
			if(data.restitution != undefined) { //弹性系数
				fixtureDef.restitution = data.restitution;
			}else {
				fixtureDef.restitution = 0.1;
			}
			if(data.friction != undefined) { //摩擦系数
				fixtureDef.friction = data.friction;
			}else {
				fixtureDef.friction = 0.1;
			}
			fixtureDef.shape = polygonShape;
			
			var body:b2Body = world.CreateBody(bodyDef); //创建刚体
			body.CreateFixture(fixtureDef);
			
			if(data.asset != undefined) {
				addChild(data.asset);
				data.asset.x = body.GetPosition().x * worldScale;
				data.asset.y = body.GetPosition().y * worldScale;
			}
		}

		private function onUpdate(e:Event):void {
			world.Step(timeStep, velIterations, posIterations);
			world.ClearForces();
			//GetBodyList()方法获得世界刚体列表并返回列表的第一个刚体.
			//使用GetNext()方法获得列表的下一个刚体,但是如果你的刚
			//体已经到达了刚体列表的末端,这时GetNext()方法将返回null
			for (var body:b2Body = world.GetBodyList(); body; body = body.GetNext()) {
				if(body.GetUserData()) {
					var x:Number = body.GetPosition().x * worldScale;
					var y:Number = body.GetPosition().y * worldScale;
					var angle:Number = body.GetAngle() * 180 / Math.PI; //弧度转为度
					if(body.GetUserData().id == "userIcon") {
						info.text = "头像刚体的属性\n坐标: ";
						info.appendText(x.toFixed(1));
						info.appendText(", ");
						info.appendText(y.toFixed(1));
						info.appendText("\n角度: ");
						info.appendText(angle.toFixed(1));
						info.appendText("\n速度: ");
						//GetLinearVelocity()方法获得刚体中心的线速度,然后返回
						//一个b2Vec2对象,它代表水平和垂直速度,单位是米每秒
						var v:b2Vec2 = body.GetLinearVelocity();
						var vx:Number = v.x * worldScale;
						info.appendText(vx.toFixed(1));
						info.appendText(", ");
						var vy:Number = v.y * worldScale;
						info.appendText(vy.toFixed(1));
						
					}
					if(body.GetUserData().asset) {
						body.GetUserData().asset.x = x;
						body.GetUserData().asset.y = y;
						body.GetUserData().asset.rotation = angle;	
					}
				}
			}
		}
	}
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值