box2D와 관련된 자료가 한국 사이트에는 많이 없어서 이것저것 배울 수 있는 자료에 제약이 많다.
이럴때마다 느끼는게 영어가 절대적으로 배움이 필요하다는걸 느낀다.
box2D는 다양한 언어로 개발이 되어있고 공식 포럼란에 가면 flash포럼란이 따로있다.
그곳에는 많은 사람들이 정보를 공유하고 있지만 정작 내가 얻을 수 있는게 많지 않다는게 아쉬울뿐이다.
위에 작업은 아주 기본적인 예제 자료에서 Loader클래스로 이미지를 불러온다음 무비클립에 이미지를
담은 후 객체를 생성에 물리공간안에 뿌려주게된다.
공부를 하면서 참고를 많이 할 수 있었던 곳은 네이버에 ooaso님이 운영중이신 http://cafe.naver.com/uiaa 카페에
가면 box2d와 관련된 좋은 강좌들을 만나볼 수 있다.
box2D 공식 홈페이지 http://www.box2d.org/
Flash Box2DFlashAS3.0 다운로드 http://box2dflash.sourceforge.net/
ooaso님이 운영중이신 uiaa카페 box2d 강좌란 http://cafe.naver.com/uiaa.cafe
이곳에 가면 관련자료들이 많다.
그리고 아래 사용된 소스들은 http://cafe.naver.com/uiaa.cafe에 운영자이신
ooaso님이 작성하신 소스를 가지고 편집했음을 알려드립니다.
출처 : http://cafe.naver.com/uiaa.cafe
package { /** * ... * sanoi(ooaso@naver.com/sanoi@iamg.kr)@ IAMG * http://cafe.naver.com/uiaa.cafe */ import adobe.utils.CustomActions; import flash.display.*; import flash.events.*; import Box2D.Collision.*; // 경계박스를 사용하기 위해 필요합니다. import Box2D.Common.Math.*; // 벡터를 사용하기 위해 필요합니다. import flash.net.URLRequest; // 벡터는 중력을 정의할 때 사용합니다. import Box2D.Dynamics.*; // 물체와 world 를 정의할 때 필요합니다. import Box2D.Collision.Shapes.*; // shape 을 정의할 때 필요합니다. public class Box2DRectTest extends Sprite { private var myWorld:b2World; // world private var m_timeStep:Number; // time step private var m_iterations:int; // iterations private var mouseHandel:Box2DMouseHandle; private var mouseDown:Boolean; private var McImg:MovieClip; function Box2DRectTest(){ m_timeStep = 1.0 / 36.0; m_iterations = 10; //world 경계박스 var worldBox:b2AABB = new b2AABB(); worldBox.lowerBound.Set(-100,-100) // 1 미터 = 30 픽셀 worldBox.upperBound.Set(100,100); // 중력 var gravity:b2Vec2 = new b2Vec2(0, 50 ); var bSleep:Boolean = true; // world 만들기 myWorld = new b2World(worldBox, gravity, bSleep); mouseHandel = new Box2DMouseHandle(myWorld, 30, m_timeStep, m_iterations); mouseDown = false; // 디버그 모드 /* var dbgDraw:b2DebugDraw = new b2DebugDraw(); dbgDraw.m_sprite = new Sprite(); addChild(dbgDraw.m_sprite); dbgDraw.m_drawScale = 30.0; dbgDraw.m_fillAlpha = 0.3; dbgDraw.m_lineThickness = 1.0; dbgDraw.m_drawFlags = b2DebugDraw.e_shapeBit|b2DebugDraw.e_jointBit; myWorld.SetDebugDraw(dbgDraw); */ setGround(); startCalc(); // McImg = new Sprite(); for (var i:int = 1; i < 17;i++){ makeDynamicBody(i); } stage.addEventListener(MouseEvent.MOUSE_DOWN, mousePress); stage.addEventListener(MouseEvent.CLICK, mouseRelease); stage.addEventListener(MouseEvent.MOUSE_MOVE, mouseMove); stage.addEventListener(Event.MOUSE_LEAVE, mouseLeave); } private function mouseLeave(e:Event):void { mouseDown = false; } private function mouseMove(e:MouseEvent):void { mouseDown = e.buttonDown; } private function mouseRelease(e:MouseEvent):void { mouseDown = false; } private function mousePress(e:MouseEvent):void { mouseDown = true; } private function setGround():void { // 정적 물체 만들기 // shape 정의 var boxDef:b2PolygonDef = new b2PolygonDef(); boxDef.SetAsBox(11,.1); // 1 meter = 30 pixels, width 90, height 30 boxDef.friction = 0.8 // between 0 and 1 var posX:Array = [ 400, 0, 800]; var posY:Array = [ 605, 200, 200]; var angle:Array = [ 0, 90*Math.PI/180, 90*Math.PI/180]; for(var i:int = 0;i<3;i++){ // 바디정의 만들기 var bodyDef:b2BodyDef = new b2BodyDef(); bodyDef.userData = new Sprite(); bodyDef.userData.width = 510; bodyDef.userData.height = 3; bodyDef.angle = angle[i]; bodyDef.position.Set(posX[i]/30, posY[i]/30); addChild(bodyDef.userData); // 실제 바디를 만든다 var body:b2Body = myWorld.CreateBody(bodyDef); body.CreateShape(boxDef); } } private function makeDynamicBody(i:int):void { // 크기는 랜덤하게 var loader:Loader = new Loader(); loader.load(new URLRequest('http://nicekon.cafe24.com/test/box2d_gallery/images/'+i+'_s.jpg')); loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoadExternalImg); } // 동적 물체 만들기 // 호출 될 때 마다 하나의 물체를 만든다. private function onLoadExternalImg(e:Event):void { // 크기는 랜덤하게 buttonMode = true; var w:int = int((Math.random()*50) + 90); var h:int = w; var boxDef:b2PolygonDef = new b2PolygonDef(); boxDef.SetAsBox(w/60,h/60); // 1 meter = 30 pixels, width 90, height 30 boxDef.friction = 0.6 // between 0 and 1 boxDef.density = 20; // 질량이 있는 물체이므로 밀도를 지정해 준다 var bodyDef:b2BodyDef = new b2BodyDef(); //bodyDef.userData = new Sprite(); var bitmapContainer:MovieClip = new MovieClip(); var bmp:Bitmap = e.target.content; bmp.x -= bmp.width / 2; bmp.y -= bmp.height / 2; bitmapContainer.addChild(e.target.content); bodyDef.userData = bitmapContainer; bodyDef.userData.width = w; bodyDef.userData.height = h; bodyDef.angle = (Math.random() * 90) * Math.PI / 180; bodyDef.position.Set(int(Math.random() * 800)/30, int(Math.random() * -1000/30)); addChild(bodyDef.userData); // 실제 바디를 만든다 var body:b2Body = myWorld.CreateBody(bodyDef); body.CreateShape(boxDef); body.SetMassFromShapes(); // Shape 정보로 부터 질량을 자동으로 계산한다 addEventListener( MouseEvent.MOUSE_DOWN, onDownBody ); } private function makeWater():void { // 크기는 랜덤하게 buttonMode = true; var w:int = 8; var h:int = 8; var circleBodyDef:b2CircleDef = new b2CircleDef(); circleBodyDef.radius = 0.13; circleBodyDef.friction = 0.2; circleBodyDef.restitution = 0.5; circleBodyDef.density = 10; var bodyDef:b2BodyDef = new b2BodyDef(); //bodyDef.userData = new Sprite(); //var bitmapContainer:MovieClip = new MovieClip(); //var bmp:Bitmap = e.target.content; //bmp.x -= bmp.width / 2; //bmp.y -= bmp.height / 2; //bitmapContainer.addChild(e.target.content); bodyDef.userData = new McWater(); bodyDef.userData.width = w; bodyDef.userData.height = h; bodyDef.angle = (Math.random() * 90) * Math.PI / 180; bodyDef.position.Set(int(Math.random() * 800)/30, int(Math.random() * -300/30)); addChild(bodyDef.userData); // 실제 바디를 만든다 var body:b2Body = myWorld.CreateBody(bodyDef); body.CreateShape(circleBodyDef); body.SetMassFromShapes(); // Shape 정보로 부터 질량을 자동으로 계산한다 addEventListener( MouseEvent.MOUSE_DOWN, onDownBody ); } private function onDownBody(e:MouseEvent):void { } // 물리 세계 시뮬레이션 시작 private function startCalc():void { addEventListener(Event.ENTER_FRAME, Update); } private function Update(e:Event):void { // 마우스 조인트 연동 mouseHandel.MouseDrag(stage.mouseX, stage.mouseY, mouseDown); // 물리 세계 시뮬레이션 myWorld.Step(m_timeStep, m_iterations); if(int(Math.random() * 10)==0){ makeWater(); } // Go through body list and update sprite positions/rotations for (var bb:b2Body = myWorld.m_bodyList; bb; bb = bb.m_next){ if (bb.m_userData is MovieClip){ 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); } } } } }