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);
}
}
}
}
}
box2D.zip