pv3d和box2d

以前研究魔术笔的游戏,今日心血来潮仿制了一个pv3d和box2d的小程序,按下鼠标左键右拖动绘制盒子,按下左拖动绘制球,还比较有意思。完整源码下载  

box2d: http://box2dflash.sourceforge.net/

papervision3d: http://www.papervision3d.org

 文件较大,耐心等待... 

代码如下:

package
{
	import Box2D.Collision.Shapes.b2CircleDef;
	import Box2D.Collision.Shapes.b2PolygonDef;
	import Box2D.Collision.Shapes.b2Shape;
	import Box2D.Collision.b2AABB;
	import Box2D.Common.Math.b2Vec2;
	import Box2D.Dynamics.Joints.b2MouseJoint;
	import Box2D.Dynamics.Joints.b2MouseJointDef;
	import Box2D.Dynamics.b2Body;
	import Box2D.Dynamics.b2BodyDef;
	import Box2D.Dynamics.b2DebugDraw;
	import Box2D.Dynamics.b2World;
	
	import General.FpsCounter;
	import General.Input;
	
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.geom.Point;
	import flash.utils.getTimer;
	
	import org.papervision3d.core.effects.view.ReflectionView;
	import org.papervision3d.lights.PointLight3D;
	import org.papervision3d.materials.shadematerials.GouraudMaterial;
	import org.papervision3d.materials.utils.MaterialsList;
	import org.papervision3d.objects.DisplayObject3D;
	import org.papervision3d.objects.primitives.Cube;
	import org.papervision3d.objects.primitives.Sphere;
	
	[SWF(width="600", height="600", backgroundColor="#000000", frameRate="40")] 
	public class DrawBox extends ReflectionView
	{
		public var w:int = 600,h:int = 600;//视野的宽和高
		public const scale:Number = 30;//缩放比率,box2d中1px = 30m
		protected var iterations:int = 10,timeStep:Number = 1/30;
		protected var world:b2World;
		protected var mouseXWorldPhys:Number,mouseYWorldPhys:Number;
		protected var isDrawing:Boolean = false,isMouseDown:Boolean = false;
        protected var clickX:Number,clickY:Number;//点击开始点
        protected var drawSprite:Sprite = new Sprite();
		
		
		protected var materialsList:MaterialsList;
        protected var light:PointLight3D = new PointLight3D(true);//灯光
        protected var gmaterials:GouraudMaterial ;
        
        static public var m_fpsCounter:FpsCounter = new FpsCounter();
		
		public function DrawBox()
		{  
			//Fps
			m_fpsCounter.x = 7;
			m_fpsCounter.y = 5;
			addChildAt(m_fpsCounter, 0);
			//绘制容器
			addChild(drawSprite);
			
			super(this.w,this.h,true,false,"CAMERA3D");
			  //以舞台正中间的为起点 
			surfaceHeight = -this.h + 110;
			light.x = 1000;light.y = 1000;light.z = -1000;
			this.camera.focus = 10;this.camera.zoom = 100;
			this.gmaterials = new GouraudMaterial(light,0xcc0000,0x111111,10);
			this.materialsList = new MaterialsList({all : gmaterials});
			
			
			//初始包围盒
			var b2aabb:b2AABB = new b2AABB();
            b2aabb.lowerBound.Set(0, 0);
            b2aabb.upperBound.Set(this.w / this.scale, this.h / this.scale);
            //重力
            var g:b2Vec2 = new b2Vec2(0, 10);
            //2d物理世界
            this.world = new b2World(b2aabb, g, true);
            //debug绘制
            //this.setupDebugDraw();
            //地面
            this.createFloor();
            
            for(var i:int = 0; i < 2;i++){
           		this.addCube(Math.random()*20,Math.random()*20,Math.random()*60,Math.random()*60);
            	this.addSphere(Math.random()*60,Math.random()*20,Math.random()*30);
            }
          
            //开始3d的渲染
            this.startRendering();
			//事件初始
			stage.addEventListener(Event.ENTER_FRAME, this.enterFrame);
            stage.addEventListener(MouseEvent.MOUSE_DOWN, this.onMouseDown);
            stage.addEventListener(MouseEvent.MOUSE_MOVE, this.onMouseMove);
            stage.addEventListener(MouseEvent.MOUSE_UP, this.onMouseUp);
		}
		
		//创建所有墙体
		private function createFloor() : void{
			//下
          	createBox(this.w / this.scale / 2, (this.h + 5) / this.scale ,this.w / this.scale / 2, 10 / this.scale);
            //左
            createBox(-5 / this.scale, this.h / this.scale / 2,10 / this.scale, this.h / this.scale / 2);
            //右
            createBox(this.w / this.scale, this.h / this.scale / 2,10 / this.scale, this.h / this.scale / 2);
        }
        //添加3d盒子 
        public function addCube(x:Number,y:Number,bw:Number,bh:Number):void{
        	var body:b2Body = createBox((x + bw / 2) / this.scale, (y + bh / 2) / this.scale ,bw / 2 / this.scale, bh / 2 / this.scale,false);
        	var cube:Cube = new Cube(this.materialsList, bw, (bw + bh) / 2, bh);
            scene.addChild(cube);
            body.m_userData = cube;
        }
        //添加3d球体 
        public function addSphere(x:Number,y:Number,radius:Number):void{
        	var body:b2Body = createCircle(x  / this.scale, y / this.scale , radius ,false);
        	var sphere:Sphere = new Sphere(this.gmaterials, radius);
            scene.addChild(sphere);
            body.m_userData = sphere;
        }
        
        //矩形
        private function createBox(x:Number,y:Number,hx:Number,hy:Number,isSleep:Boolean = true):b2Body{
        	var def:b2PolygonDef  = new b2PolygonDef();
        	if(isSleep == false){
        		def.density = 1;
            	def.friction = 0.7;
            	def.restitution = 0.7;
         	}
            var bodyDef:b2BodyDef  = new b2BodyDef();
            bodyDef.position.Set(x,y);
            def.SetAsBox(hx,hy);
            var body:b2Body = this.world.CreateBody(bodyDef);
            body.CreateShape(def);
            body.SetMassFromShapes();
            return body;
        }
        
        //球
        private function createCircle(x:Number,y:Number,radius:Number,isSleep:Boolean = true):b2Body{
        	var def:b2CircleDef  = new b2CircleDef();
        	if(isSleep == false){
        		def.density = 1;
            	def.friction = 0.7;
            	def.restitution = 0.7;
         	}
         	def.radius = radius / this.scale
            var bodyDef:b2BodyDef  = new b2BodyDef();
            bodyDef.position.Set(x,y);
            var body:b2Body = this.world.CreateBody(bodyDef);
            body.CreateShape(def);
            body.SetMassFromShapes();
            return body;
        }
        
      
        
		//debug绘制刚体等外观轮廓
		public function setupDebugDraw() : void {
            var dbg:Sprite = new Sprite();
            addChild(dbg);
            var dd:b2DebugDraw = new b2DebugDraw();
            dd.m_sprite = dbg;
            dd.m_drawScale = this.scale;
            dd.m_fillAlpha = 0.5;
            dd.m_lineThickness = 1;
            dd.m_drawFlags = b2DebugDraw.e_shapeBit | b2DebugDraw.e_jointBit | b2DebugDraw.e_centerOfMassBit;
            this.world.SetDebugDraw(dd);
        }
		
		//2d物理世界主循环
		public function enterFrame(evt:Event) : void{
			var physStart:uint = getTimer();
			this.updateMouseWorld();
			this.mouseDrag();
		 	this.world.Step(this.timeStep, this.iterations);
		 	 var d3d:DisplayObject3D;
		 	 for (var bb:b2Body = world.m_bodyList; bb; bb = bb.m_next){
                if (bb.m_userData is DisplayObject3D){   
                 	d3d = bb.m_userData as DisplayObject3D;
                 	d3d.x = bb.GetPosition().x * this.scale - this.w * 0.5;
                    d3d.y = (-bb.GetPosition().y) * this.scale + this.h * 0.5 + 50;
                    d3d.rotationZ = (-bb.GetAngle()) * (180 / Math.PI);
                }
    		}
    		this.singleRender();
    		m_fpsCounter.update();
    		m_fpsCounter.updatePhys(physStart);
		}
		
		public function updateMouseWorld() : void{
        	this.mouseXWorldPhys = mouseX / this.scale;
            this.mouseYWorldPhys = mouseY / this.scale;
        }
		
		//开始拖动
		public function onMouseDown(evt:MouseEvent) : void{
		 	this.clickX = mouseX;
            this.clickY = mouseY;
            this.isDrawing = true;
            this.isMouseDown = true;
		}
		//拖动绘制
		public function onMouseMove(evt:MouseEvent) : void{
		 	if (this.isDrawing){
                with(drawSprite){
	                graphics.clear();
	                graphics.beginFill(0xFF0000, 0.5);
	                if (this.clickX > mouseX){
	                    graphics.drawCircle(mouseX, mouseY, Math.min(40, Point.distance(new Point(this.clickX, this.clickY), new Point(mouseX, mouseY)) / 2));
	                }else{
	                    graphics.drawRect(clickX,clickY, Math.min(200, mouseX - this.clickX), Math.min(100, mouseY - this.clickY));
	                }
                }
                this.isMouseDown = false;
            }
		}
		//拖动结束
		public function onMouseUp(evt:MouseEvent) : void{
            if (this.isDrawing){
                if (this.clickX > mouseX){//向左画圆
                    this.addSphere(mouseX, mouseY,drawSprite.width/2);
                }else{//向右画方
                    this.addCube(clickX,clickY,drawSprite.width,drawSprite.height);
                }
                drawSprite.graphics.clear();
                this.isDrawing = false;
            }
            this.isMouseDown = false;
		}
		
		
		
		//拖动选中的3d对象
		public var m_mouseJoint:b2MouseJoint;
		public function mouseDrag():void{
			// mouse press
			if (isMouseDown && !m_mouseJoint){
				var body:b2Body = GetBodyAtMouse();
				if (body){
					this.isDrawing = false;
                    drawSprite.graphics.clear();
					var md:b2MouseJointDef = new b2MouseJointDef();
					md.body1 = world.GetGroundBody();
					md.body2 = body;
					md.target.Set(mouseXWorldPhys, mouseYWorldPhys);
					md.maxForce = 300.0 * body.GetMass();
					md.timeStep = timeStep;
					m_mouseJoint = world.CreateJoint(md) as b2MouseJoint;
					body.WakeUp();
				}
			}
			// mouse release
			if (!isMouseDown){
				if (m_mouseJoint){
					world.DestroyJoint(m_mouseJoint);
					m_mouseJoint = null;
				}
			}
			// mouse move
			if (m_mouseJoint){
				m_mouseJoint.SetTarget(new b2Vec2(mouseXWorldPhys, mouseYWorldPhys));
			}
		}
		
		
		
		//按d键删除选中的3d对象
		public function MouseDestroy():void{
			// mouse press
			if (!this.isMouseDown && Input.isKeyPressed(68/*D*/)){
				var body:b2Body = GetBodyAtMouse(true);
				if (body){
					world.DestroyBody(body);
					return;
				}
			}
		}
		
		//取当前鼠标下刚体
		private var mousePVec:b2Vec2 = new b2Vec2();
		public function GetBodyAtMouse(includeStatic:Boolean=false):b2Body{
			// Make a small box.
			mousePVec.Set(mouseXWorldPhys, mouseYWorldPhys);
			var aabb:b2AABB = new b2AABB();
			aabb.lowerBound.Set(mouseXWorldPhys - 0.001, mouseYWorldPhys - 0.001);
			aabb.upperBound.Set(mouseXWorldPhys + 0.001, mouseYWorldPhys + 0.001);
			
			// Query the world for overlapping shapes.
			var k_maxCount:int = 10;
			var shapes:Array = new Array();
			var count:int = world.Query(aabb, shapes, k_maxCount);
			var body:b2Body = null;
			for (var i:int = 0; i < count; ++i)
			{
				//if (shapes[i].GetBody().IsStatic() == false || includeStatic)
				{
					var tShape:b2Shape = shapes[i] as b2Shape;
					var inside:Boolean = tShape.TestPoint(tShape.GetBody().GetXForm(), mousePVec);
					if (inside){
						body = tShape.GetBody();
						break;
					}
				}
			}
			return body;
		}
		
		
	}
}



[本日志由 c 于 2009-07-16 04:55 PM 编辑]
文章来自: 本站原创
引用通告: 查看所有引用 | 我要引用此文章
Tags:
评论: 0 | 引用: 0 | 查看次数: -
发表评论
昵 称:
密 码: 游客发言不需要密码.
内 容:
验证码: 验证码
选 项:
虽然发表评论不用注册,但是为了保护您的发言权,建议您注册帐号.