2. Box2DFlash에 대하여
Box2DFlash는 게임을 위한 2차원 rigid body simulation (강체 시뮬레이션) 라이브러리이다. 프로그레머는 게임내의 물체들이 자연스럽게 움직이거나 게임을 더 인터렉티브하도록 보이게 하기 위해서 이 라이브러리를 사용할 수 있다. 게임 플레이어의 시각으로, 물리엔진은 단지 절차적인 애니메이션을 위한 시스템으로 밖에 보이지 않는다. Box2DFlash는 액션스크립트 3.0으로 작성되었고, Box2D의 네임스페이스를 그대로 유지하고 있다. C++버전과의 매칭을 위해서 엔진에 정의된 대부분의 type들은 b2 라는 접두사를 가진다.

2.1. 필수조건
매뉴얼에서는 이 글을 읽는 사람이 mass(질랑), force(힘), torque(회전력),  impulse(충격)등의 기본 물리지식에 익숙하다고 가정하고 있다. 만약 그렇지 않다면 Chris Hecker 와 David Baraff가 제공하는 수많은 교본을 먼저 읽어보길 권장한다(이름을 구글링하면 된다). 그들의 교본을 상세하게 파악하고 있을 필요는 없다. 단지 그들은 Box2D를 쓸 수 있도록 기본 컨셉만 나열하는 수준이다.

Wikipedia 또한 물리와 수학 지식의 좋은 참조자료이다. 어떤면에서는 더 신중하게 작성된 내용이라서 구글링보다 더 유용하기도 하다.

이건 필수조건은 아니지만,  만약 당신이 Box2D의 내부 동작에 대해서 호감을 가지고 있다면 이런 기사들을 읽어볼 수도 있다.

Box2Flash는 액션스크립트 3.0 으로 써진덕에 당신은 액션스크립트 3.0 으로만 사용할 수 있다. 만약 당신이 액션스크립트 2.0 지식을 바탕으로 Box2D를 사용하기 전에 간단한 프로젝트를 더 쉽게 시작해볼 수 있는 방법을 찾았다면, 그것은 불가능하다.

2.2. 핵심 컨셉
Box2D는 몇가지 기본적인 핵심 오브젝트들로 동작한다.  우리는 간략하게 이러한 오브젝트를 정의하고 자세한 내용은 이 문서의 뒷부분에 서술할 것이다.

rigid body
강체. 즉 크고 단단한 물질. 
shape
충돌가능한, body에 단단하게 할당된 2D 오브젝트. Shape은 마찰계수나, 반발계수같은 속성을 가지고 있다. 
constraint
constraint는 물체들의 자유로운 각도를 제한하는 물리적 결합이다. 2D 에서 물체는 3가지의 각도를 가지고 있다. 만약 우리가 물체를 벽에 핀으로 고정시킨다면(진자운동을 하는 추처럼) 그 물체는 벽에 contrained 된다. 여기서 물체는 고정된 핀을 기준으로밖에 회전할 수 없게 되므로 나머지 2가지의 각도가 제한 받는것이다.
contact constraint
강체가 서로 관통하거나, 마찰 또는 반발을 시뮬레이션하기 위해서 고안된 특수한 contraint이다. 이것은 Box2D에 의해서 자동적으로 생성되므로 당신이 직접 만들일은 없다.
joint
이것은 둘 이상의 물체를 서로 고정시키는 용도의 constraint이다. Box2D는 revolute, prismatic, distance 그외 여러종류의 joint를 지원한다. joint는 또한 limit, motor 같은 기능을 제공한다.
joint limit
joint limit은 joint의 모션 범위를 제한한다. 예를들면 인간의 팔꿈치가 움직일 수 있는 각도를 제한하는 것.
joint motor
joint motor는 여러 joint의 자유로운 각도를 제어할 수 있도록 한다. 예를들면 당신은 motor를 사용해서 팔꿈치의 모션을 제어할 수 있다.
world
world는 body, shape, constraint 들이 서로 상호작용할 수 있는 집합체이다. Box2D는 여러개의 world를 지원하지만 필수도 아닐뿐더러 바람직하지 않다.

3. Hello Box2D
이것는 커다란 바닥 물체와 작은 움직이는 박스를 생성하는 단순한 예제이다. 이 코드에는 어떠한 그래픽 요소도 담고 있지 않기 때문에 큰 감흥은 없을것이다. : )

3.1. World 생성하기
모든 Box2D 프로그램은 world를 생성하는것으로 시작한다. 이것은 물체와 시뮬레이션을 관리하는 물리 허브(physics hub)역할을 한다.

world를 생성하기 위해서는, 첫째로 world의 바운딩 박스를 선언할 필요가 있다. Box2D는 충돌검사를 더욱 신속하게 하기 위해서 바운딩 박스를 사용한다.  그 크기는 치명적이지 않지만 그보다는 딱맞는 핏감이 성능 향상에 도움이 된다. 매우 작은것보단 매우 큰것이 더 낫다.

1 var worldAABB:b2AABB = new b2AABB();
2 worldAABB.lowerBound.Set(-100.0, -100.0);
3 worldAABB.upperBound.Set(100.0100.0);

주의

worldAABB는 body들이 놓일 공간들보다 항상 더 커야한다. worldAABB를 너무 작게 설정하는것보단 크게 설정하는것이 더 낫다. 만약 body가 바운딩박스에 닿는다면(또는 넘어간다면) worldAABB는 시뮬레이션이 멈추게 될 것이다.

다음은 중력 벡터를 선언한다. 그렇다 당신은 중력을 마음대로 설정할 수가 있다. 또한 우리는 world가 더이상 시뮬레이션 할 필요가 없다면 sleep상태로 되도록 설정한다. 잠자는 body는 어떠한 시뮬레이션도 요구하지 않는다.
1 var gravity:b2Vec2 = new b2Vec2 (0.0, -10.0);
2 var doSleep:Boolean true;
자 그럼 world를 만들어보자.
1 var world:b2World = new b2World(worldAABB, gravity, doSleep);
이렇게 해서 우린 physics world를 갖게 되었다. 이제 이곳에 몇가지를 더 추가해 보자.

3.2. Ground Box 생성하기
body는 다음과같은 절차를 통해서 생성된다.
  1. position, damping 과 함께 body를 정의한다.
  2. body를 생성하기 위해서 world 오브젝트를 사용한다.
  3. geometry(기하), friction(마찰), density(밀도) 로 shape를 정의한다.
  4. body위에 shape들을 생성한다.
  5. body에 붙여진 shape에 따라서 부가적으로 mass(질량)를 할당하기도 한다.
첫번째로 ground body를 생성한다. 그렇게 하기 위해서 body의 정의가 필요하다. 이 정의와 함께 초기 위치를 ground body에 할당한다.
1 var groundBodyDef:b2BodyDef = new b2BodyDef();
2 groundBodyDef.position.Set(0.0, -10.0);
두번째,  ground body를 생성하기 위해서 b2BodyDef (body 정의) 를 world 객체에 넘긴다. world 객체는 해당 b2BodyDef의 참조를 유지시키지 않는다. ground body는 static body로 생성되어진다. static body는 다른 static body들과 충돌하지도 않으며 움직일 수도 없다. Box2D는 body의 질량이 0인 경우 이 body를 static body라고 가정한다.  body의 질량 기본값이 0 이므로 static body가 기본값인셈이다.
1 var groundBody:b2Body = world.CreateBody(groundBodyDef);
세번째,  ground polygon 정의를 생성한다. 우리는 SetAsBox 함수를 통해서 ground polygon을 박스로 만드는데, 박스는 부모 body의 원점을 중심으로 박스형태를 가지게 된다. 
1 var groundShapeDef:b2PolygonDef = new b2PolygonDef();
2 agroundShapeDef.SetAsBox(50.010.0);
SetAsBox 함수의 매개변수들은 각각 half-width, half-height 이다.  그래서 이 경우 가로는 100, 세로는 20을 가지게 된다. Box2D는 기본적으로 meter (미터), kilograms (킬로그램), second (초) 단위를 사용한다. 그러나, 나중에 이 문서에서 거론하겠지만, 이러한 단위 시스템은 변경할 수 있다.

마지막으로, ground body에 ground polygon shape을 생성한다.
1 groundBody.CreateShape(groundShapeDef);
반복하지만, Box2D는 shape 이나 body 정의를 내부에 사본으로 따로 담고, 직접 참조를 유지시키진 않는다.

모든 shape는 부모 body를 가지고 있다. static shape이더라도. 그러나 당신은 모든 static shape를 하나의 body에 생성할 수 있다. 이렇게 하여 잠재적 오류 발생을 억제하고 코드가 내부적으로 다형성을 가질 수 있게 한다.

당신은 여기서 한가지 패턴을 알아차렸을것이다. 모든 Box2D의 type들은 b2 라고 하는 접두사를 가진다. 이것은 당신의 코드와 네이밍 충돌을 피하기 위함이다.

3.3. Dynamic Body 생성하기
자 이렇게 해서 우린 ground body를 생성하였다. 위와 동일한 방법으로 우리는 dynamic body 또한 생성할 수 있다. 주요한 차이점이라면 mass(질량)을 설정해야 한다는 것이다.

처음으로, CreateBody 함수로 body를 생성한다.
1 var bodyDef:b2BodyDef = new b2BodyDef();
2 bodyDef.position.Set(0.04.0);
3  
4 var body:b2Body = world.CreateBody(bodyDef);
다음으로, polygon shape을 하나 만들고 body에 붙인다. density (밀도) 를 1로 설정함을 주목하라. 기본 질량값은 0이다. 또한 shape의 마찰계수는 0.3 으로 세팅되었다. shape을 body에 붙인후 우리는 body의 새로운 mass값을 계산하도록 SetMassFromShapes 함수를 통해 시킬 것이다. 이것으로 당신은 아마 한개의 body에 여러 shape을 붙일 수 있다는 것을 알았을 것이다. 만약 위의 함수를 통해서 계산된 결과 mass가 0이라면 해당 body는 static body가 된다. ground body를 SetMassFromShapes함수를 호출 할 필요가 없도록 하기 위해서 기본적으로 body들은 기본 질량값 0을 가진다.
1 var shapeDef:b2PolygonDef = new b2PolygonDef();
2 shapeDef.SetAsBox(1.01.0);
3 shapeDef.density = 1.0;
4 shapeDef.friction = 0.3;
5 body.CreateShape(shapeDef);
6 body.SetMassFromShapes();
초기화가 모두 끝났다. 이제 실제 시뮬레이션을 해보자.

3.4. World 시뮬레이션하기
이제 ground box와 dynamic box 모두 초기화 하였다. 이제 뉴튼을 엿먹일 차례다. 우리가 고려할 것들이 몇가지 남아있지 않다.

Box2D는 intergrator라고 불리는 산술 코드를 조금 사용하고 있다. intergrator는 매 시간 물리공식을 시뮬레이션한다. 그래서 우리는 Box2D의 time step을 고를 필요가 있다. 일반적으로 게임에 쓰이는 물리엔진은 1/60 초 단위의 물리 연산을 한다. 이런 time step은 큰 숫자로 그냥 둬도 상관없지만 , 너무 자주 바뀌거나 플래시의 frame rate와는 동일하지 않게 하기를 권장하므로 신중히 선택해야한다. time step은 다음과 같다.
1 var timeStep:Number 1.0 60.0;
intergrator 이 외에 Box2D에는 contraint solver라고 불리는 좀더 큰 코드를 사용한다. 말그대로 매시간 시뮬레이션 하는 동안 contraint들을 풀어낸다. 단일 constraint들은 완벽하게 풀어진다. 하지만,  한 constraint가 풀리는 동안 다른 constraint까지 신경쓰는것이 쉽지 않다. 그래서 모든 시간에 걸쳐 사용할 constraint들을 통합시킬 필요가 있다. 우리는 그 반복 횟수를 10으로 사용할 것을 권장한다. 당신은 이 횟수를 속도와 정확도를 맞바꿔가며 조절할 수 있다.  반복획수가 적으면 성능은 향상되지만 그만큼 정확도가 떨어지고, 반복횟수를 늘이면 성능은 저하되지만 시뮬레이션 퀄러티는 향상된다. 이것이 우리가 선택한 반복횟수이다.
1 var iterations:Number 10;
time step 과 iteration(반복 횟수)은 완전히 무관한 점을 명심하라. 한번의 반복은 sub-step이 아니다. 하나의 iteration은 한 time step에서의 모든 constraint들을 통틀어 싱글패스다. 이를 당신은 멀티패스로 처리하게 할 수도 있다.

우리는 지금 시뮬레이션 루프를 시작할 준비가 되었다. 당신의 게임 시뮬레이션 루프는 게임의 메인 루프에 통합될 수도 있다. 매 게임 루프마다 b2World.Step을 호출하여 각 패스를 통과한다.  게임의 frame rate와 설정한 물리적 time step에 의존하여 보통 한번의 호출로 충분하다.

Hello Wolrd 프로그램은 매우 단순하게 종료되도록 고안되었다. 그래서  그래픽적인 출력이 존재하지 않는다. 출력 아웃풋이 없이 만들어져 있어서 많이 지루하지만 이 코드는 body의 위치와 회전량을 출력 하여 준다. 자! 여기에 시뮬레이셔닝 되는 1초 동안 총 60번의 step으로 시뮬레이팅 되는 시뮬레이션 루프가 있다.
1 for (var i:Number 0; i < 60; ++i)
2  
3 {
4     world.Step(timeStep, iterations);
5     var position:b2Vec2 = body.GetPosition();
6     var angle:Number = body.GetAngle();
7     trace(position.x +','+ position.y +','+ angle);
8  
9 }

3.5. Testbed
당신이 Hello World 예제를 정복했다면,  Box2DFlash의 테스트베드를 보기 보기 시작해야 한다. testbed는 단위 테스트 프레임워크이고 데모 환경이다. 아래와 같은 기능을 가지고 있다.
  • dynamic body에 첨부된 shape들의 마우스 선택
  • 테스트의 확장 세트
testbed는 테스트케이스와 프레임워크 스스로 Box2D의 많은 예제를 가지고 있다.나는 당신이 Box2D를 배우듯 testbed를 탐색하고 만지작거리길 장려한다.


4. API 디자인
4.1. 메모리 관리
Box2DFlash는 C++ 라이브러리인 Box2D의 직 포팅 버전이다. 그렇게 때문에 메모리 관리를 gabage collector에 의존한것보다 철저하게 관리된다. 이는 버벅임을 줄일 수 있다. 그리하여 수많은 생성, 삭제 메소드에서 객체들은 재활용되어진다.

4.2. Factory 와 정의
위에서 말한대로 메모리관리는 Box2D API 설계상의 중심적 역할이 된다. 그래서 당신이 b2Body나 b2Joint를 생성할때 당신은 b3World의 factory 함수들을 호출할 필요가 있는 것이다.

생성함수들은 이런한 것들이 있다.
1 b2World.CreateBody(def:b2BodyDef):b2Body
2 b2World.CreateJoint(def:b2JointDef):b2Joint
그리고 그에 대응되는 삭재함수들이 있다.
1 b2World.DestroyBody(body:b2Body):void
2  
3 b2World.DestroyJoint(joint:b2Joint):void
당신이 body나 joint를 생성할때 당신은 definition또는 짧게 def 를 재공할 필요가 있다. 이러한 정의들은 body나 joint를 만들기 위한 모든 정보들은 포함하고 있다. 이러한 어프로치를 사용함으로써 우리는 생성자 오류들을 예방할 수 있고, 수많은 함수의 매개변수들을 작게 유지시킬 수 있고, 기본값들을 제공할 수 있으며 접근수를 줄일 수 있다.

body처럼 shape도 b2Body라는 factory method를 사용하여 생성하고 삭제된다.
1 b2Body.CreateShape(def:b2ShapeDef):b2Shape
2 b2Body.DestroyShape(shape:b2Shape):void
factory들은 definition의 참조를 가지고 있지 않는다. 그래서 당신은 한번 생성된 definition들을 스택에 임시로 유지시켜놓고  다시 사용할 수 있는것이다.

4.3. 단위값
Box2D는 소수점 연산과 함께 동작 한다 그래서 조금의 오차가 있을 수 있다. 이러한 오차는 meters-kilogram-second 단위값들과 잘 동작하게 하기 위해서 개선되어지고 있다. 

2D 물리 엔진이 pixels을 단위값으로 사용하는것을 시도하는 사람도 있으나 이는 불행히도 엉터리 시뮬레이션으로 망칠뿐만 아니라 괴상한 기능을 보여줄 수도 있다. 200픽셀 길이의 한 객체는 Box2D에서는 45층 건물로 보일 수 있다.

주의
Box2D는 MKS 단위계에 맞춰져있다. 움직이는 물체의 크기를 대략 0.1~10 미터 사이로 유지하라. 당신은 게임 배경과 캐릭터들을 렌더링할때 스케일링 시스템이 필요할 것이다. DebugDraw 안에는 스케일링 시스템이 이미 내장되어있다.

4.4. 사용자 데이터
b2Shape, b2Body, b2Joint 클래스들은 당신이 어떠한 유져 데이타라도 담을 수 있도록 하고 있다. 당신이 Box2D 데이타 구조체들 탐색하거나 당신의 게임 엔진에서의 데이타 구조체들과의 관계를 결정할 때 이것은 간편한 방법이 되어준다.

캐릭터를 rigid body에 붙이는 전형적인 예를 들어보겠다. 이것은 순환 참조(circular reference)가 구성된다. 만약 당신이 캐릭터를 가지고 있다면 body를 참조할 수 있고, body를 가지고 있다면 캐릭터를 참조할 수 있게된다.
1 actor:GameActor = new GameCreateActor();
2 bodyDef:b2BodyDef = new b2BodyDef();
3 bodyDef.userData = actor;
4 actor.body = box2Dworld.CreateBody(bodyDef);
여기 몇가지 당신이 유져 데이타들을 필요로 하는 경우의 예들이 있다.
  • 캐릭터가 충돌 검사 결과, 충돌된 데미지를 캐릭터에 적용하는것
  • 플레이어가 AABB 안으로 들어가서 스크립팅된 이벤트를 수행해야 하는것
  • Box2D가 joint의 파괴를 당신에게 알려서 게임 구조체에 접근하는것
잊지 말아야할 것은, 유져 데이타는 옵션이고, 당신은 그곳에 어떠한 것이라도 담을 수 있다. 그러나 당신은 일관성을 지켜야 한다. 예를들면 당신이 만약 하나의 body에 하나의 캐릭터 데이타를 저장해놓고자 한다면, 당신은 아마 모든 body들에도 그렇게 해야할것이다.

4.5. Strawman
만약 당신이 이런 API 디자인이 맘에 들지 않는다고해도 걱정하지 마라. 당신은 소스 코드를 가지고 있다. 당신이Box2D에 관련된 어떠한것이라도 피드백 남길것이 있다면 포럼에 코멘트를 달아주길 진심으로 바란다.

5. The World
5.1. world 란?
b2World 클래스는 body와 joint를 포함하고 있다. b2World는 시뮬레이션의 모든 측면을 관리하고 비동기 질의(AABB 질의와 같은)들을 허용한다. Box2D와 관련된 대부분의 상호작용은 b2World 객체에서 이루어진다고 할 수 있다.

5.2. world를 생성하고 삭재하기
world를 생성하는것은 상당히 간편하다. 당신은 바운딩 박스와 중력 벡터만 제공하면 된다.

AABB는 world를 감싸야한다. 당신은 바운딩 박스를 world보다 살짝 더 크게 만듬으로써(안전하게 두배로 설정해도된다) 성능향상시킬 수 있다. 만약 구렁에 빠지는 수많은 body들을 구현해야 한다면 당신의 어플리케이션은 이것들을 모두 감지하여 body들을 삭제해야한다. 이렇게 함으로써 floating point overflow를 예방하고 성능향상을 시킬 수 있을 것이다.

1 var myWorld:b2World = new b2World(aabb, gravity, doSleep)

myWorld가 쓸모없어지면 garbage collector에 의해서 자동적으로 삭제될 것이다.

주의
world의 AABB는 항상 body들이 차지할 영역보다 크게 설정되어있어야함을 기억하라. 만약 body들이 world의 AABB 밖으로 나간다면 그것들은 모두 멈춰버릴것이다. 이것은 버그가 아니다.

5.3. world 사용하기
world 클래스는 body와 joint의 생성에 필요한 factory들을 포함하고 있다. 이러한 factory는 body와 joint 섹션을 다룰때 더 자세히 거론할 것이다. b2World에는 지금부터 설명할 만한 또다른 인터렉션들이 있다.

5.4. 시뮬레이션
world 클래스는 시뮬레이션을 진행시키기 위해서 사용되어진다. 당신은 time step과 iteration count를 설정해야한다. 예를들자면
1 var timeStep:Number 1.0 60.;
2 var iterationCount:Number 10;
3 myWorld.Step(timeStep, iterationCount);
time step 이후 정보를 얻기위해서 body들과 joint들을 측정할 수 있다. 아마도 필수적으로 당신은 body들을 부동작하도록 잡아둘 것이다. 그렇게 함으로써 게임 캐릭터들을 업데이트하고 렌더링할 수 있다. game loop의 어디에서든 time step을 실행시킬 수 있지만 그것들의 순서를 알아두어야 할 것이다. 예를들자면, 새로운 body들이 현제 프레임에서 충돌된 결과를 얻기 원하는 경우, 그 body들을 time step의 전에 body들을 생성해야만 한다.

위의 HelloWorld 튜토리얼 에서도 언급했듯이, 당신은 고정된 time step을 사용해야 한다.  큰 time step을 사용하는것은 당신의 작은 fram rate에서 좋은 성능을 가져올 수 있다. 그러나 일반적으로 당신은 1/30 보다 큰 time step을 써서는 안된다. 1/60 의 time step이 일반적으로 질좋은 시뮬레이션 결과를 가져온다.

iteration count는 world에 있는 모든 contact과 joint들의 constraint를 얼마나 많이 계산할 것인지를 제어한다. 더 많은 iteration는 항상 더 좋은 시뮬레이션 결과를 낸다. 그러나 큰 iteration count를 위해서 작은 time step과 타협하지 마라. 60Hz 그리고 10 iteration 은 30Hz 와 20 iteration보다 훨씬 좋다. 

5.5. world 탐험하기
이전에 말했듯, world는 body들과 joint들을 포함하고 있다. 당신은 world에 리스팅되어있는 body와 joint의 리스트를 지속적으로 건드려야 할 것이다. 예를들면, 이 코드는 world에 있는 모든 body를 깨워준다(역자주: 시뮬레이션 되지 않는 body들은 잠든다).
1 for (var b:b2Body = myWorld.GetBodyList(); b; b = b.GetNext())
2  
3 {
4     b.WakeUp();
5 }
불행하게도 삶은 더 복잡해질 수도 있다. 예를들면, 아래의 코드는 오류가 난다

01 for (var b:b2Body = myWorld.GetBodyList(); b; b = b.GetNext())
02  
03 {
04     var myActor:GameActor = b->GetUserData() as GameActor;
05     if (myActor.IsDead())
06     {
07         myWorld.DestroyBody(b); // ERROR: now GetNext returns garbage.
08  
09     }
10 }

body가 삭제되기 전까지 모든것이 문제 없었다. body가 삭제되는순간 그 다음 포인터가 엉뚱한곳을 가리키게 된다. 그래서 b2Body.getNext() 를 호출하면 쓰레기를 되돌려줄 것이다. 해결책은 body를 삭제하기 전에 미리 다음 body의 참조를 챙겨두는 것이다.

01 var node:b2Body = myWorld.GetBodyList();
02 while (node)
03  
04 {
05     var b:b2Body = node;
06     node = node.GetNext();
07   
08     var myActor:GameActor = b->GetUserData() as GameActor;
09     if (myActor.IsDead())
10  
11     {
12         myWorld.DestroyBody(b);
13     }
14

이 코드는 안전하게 현제 body를 삭제한다. 그러나 당신은 여러 body들을 한꺼번에 삭제하는 기능을 호출 하고 싶을지도 모른다. 이런 경우는 매우 조심할 필요가 있다. 해결책은 어플리케이션마다 다를것이다. 하지만 편의를 위해서 이 문제를 해결하는 한가지 방법을 보여줄 것이다.
01 var node:b2Body = myWorld.GetBodyList();
02 while (node)
03  
04 {
05     var b:b2Body = node;
06     node = node.GetNext();
07   
08     var myActor:GameActor = b.GetUserData() as GameActor;
09     if (myActor.IsDead())
10  
11     {
12         var otherBodiesDestroyed:Boolean = GameCrazyBodyDestroyer(b);
13         if (otherBodiesDestroyed)
14         {
15  
16             node = myWorld.GetBodyList();
17         }
18     }
19 }
당연하게도 이것을 동작시키기 위해서는 GameCrazyBodyDestroyer가 정확해야 한다.

5.6. AABB(Axis-aligned Bounding Box) 질의
가끔은 당신은 지역내의 모든 shape들을 알아보고 싶을 것이다. b2World 클래스는 broad-phase data structure(광역 데이타 구조)에 사용하기위한 빠른 log(N) 함수를 가지고 있다. 당신이 world 좌표계에 에 AABB를 제공하면 b2World는 그 AABB와 잠제적으로 교차되는 모든 shape 배열을 돌려준다. 이것은 제공한 AABB와 교차되는 모든 shape들의 AABB와 교차를 찾는것이기 때문에 정확하진 않다.  예를들면, 아래의 코드는 특정 AABB와 잠재적으로 교차되는 모든 shape들을 찾고 관련된 모든 body들을 깨운다.
01 var aabb:b2AABB = new b2AABB();
02 aabb.lowerBound.Set(-1.0, -1.0);
03 aabb.upperBound.Set(1.01.0);
04  
05 var k_bufferSize:Number 10;
06 var buffer:Array = [];
07 var count:Number = myWorld.Query(aabb, buffer, k_bufferSize);
08  
09 for (var i:Number 0; i < count; ++i)
10 {
11     buffer[i].GetBody().WakeUp();
12  
13 }
Note: 전형적인 AS3의 사용보단 좀 모호한 문법을 사용한다. 이것은 Box2DAS3가 C++ 용 라이브러리에서 유례되었기 때문인데 애초에 C++에서는 사이즈 변경이 가능한 배열을 손쉽게 만들 수 없다.

6. Bodies
6.1. About
body들은 포지션과 속도 정보를 가지고 있다. 당신은 body에 force나 torque, impulse를 적용할 수 있다. body들은 static일수도 dynamic일 수도 있다. static body는 움직이지 않도록 고정되어 있으며 다른 static body들과 충돌하지 않는다.

body들은 shape을 위한 근간(backbone)이다. body들은 world에서 shape을 실어 나르고 이동시킨다. Box2D에서 body들은 항상 강체(rigid body)이다. 즉, 하나의 강체에 첨부된 두 shape은 서로서로 간섭을 일으키지 않는다.

당신은 보통 당신이 만든 모든 body들의 포인터를 유지시킬 것이다. 이런 방법으로 당신의 그래픽적인 엔티티들의 업데이트를 위해서 body 포지션들을 질의할 수 있다. 당신은 또한 body 포인터를 유지시켜야 한다. 그래야 당신은 필요없어졌을 때에 body를 삭제할 수 있다.

6.2. Body Definition
body가 생성되기 전에 당신은 body definition (b2BodyDef)를 생성해야만 한다. 당신은 스택이나 당신의 게임의 데이타 구조체들 안에 내장시켜서 body definition을 생성할 수 있다. 선택은 당신에게 달려있다.

Box2D 는 body definition을 가리키는 포인터를 따로 유지시키지 않고 body definition의 밖에 데이타 따로 사본을 만든다.  이 말은 당신은 여러 body들을 생성하기 위해서 하나의 body definition을 재활용 할 수 있다는 의미이기도 하다.

자 그럼 body definition의 중요 요소들을 들여다 보자.

6.3. Mass Properties
하나의 body에 mass(질량) 속성을 수립하는 방법은 다음과 같이 몇가지가 있다.
  1. body definition안에 질량 속성을 명시한다.
  2. 이미 만들어진 body에 질량 속성을 새롭게 명시한다.
  3. body에 첨부된 shape들의 밀도에 기반하여 질량 속성을 설정한다.
shape들의 밀도에 기반한 질량을 계산하는 것은 많은 게임 시나리오상으로 이해하기 쉽다. 이것은 body들이 합리적이고 일관된 질량값을 갖도록 하는것에 도움이 된다.

그러나, 다른 게임 시나리오들은 더 명시적인 질량값을 요구할지도 모른다. 예를들면 당신가진 메카니즘이 명확한 질량값들 필요로 하는 scale 같은것을 사용할때 이다.

당신은 다음과같이 body definition 에 질량 속성을 명시할 수 있다.
1 bodyDef.massData.mass = 2.0;             // the body's mass in kg
2  
3 bodyDef.massData.center.SetZero();       // the center of mass in local coordinates
4 bodyDef.massData.I = 3.0;                // the rotational inertia in kg*m^2.
질량 속성을 설정하기위한 다른 방법들은 이 문서의 다른 곳에서 또 여러차례 다뤄질 것이다.

6.4. Position and Angle
body definition은 당신에게 body 생성시의 포지션을 초기활 할 기회를 제공한다. 이는 생성한 이후 포지션을 변경하는것보다 좋은 성능을 낸다.

하나의 body는 두 개의 흥미로운 요점을 가지고 있다. 첫번째는 body의 원형이다. shape과 joint들은 그 body 원형을 참조하여 첨부된다. 두번째 흥미로운 점은 '질량의 중심'이다. 질량의 중심은 첨부된 shape들의 질량 분포로 부터 측정되어지거나 b2MassData에 명쾌하게 설정된다. 수많은 Box2D의 내부 연산들은 질량의 중심점을 사용한다. 그 예로 b2Body 는 질량 중심의 선속도(linear velocity)를 저장하고 있다.

당신이 body definition을 만들때 당신은 질량의 중심이 어디에 위치해 있는지 아마도 모를것이다. 그런이유로 당신은 body 원형의 포지션을 형시한다. 당신은 또한 질량의 중심에 영향받지 않는 body의 라디안 각도를 명시할지도 모른다. body의 질량 속성들을 바꿀 기회가 오면 질량 중심은 body로 옮겨질지도 모른다. 하지만 그 원래 포지션은 바뀌지 않고 첨부된 shape과 joint들은 움직이지 않는다.
1 bodyDef.position.Set(0.02.0);     // the body's origin position.
2 bodyDef.angle = 0.25 * b2Settings.b2_pi;       // the body's angle in radians.
6.5. Damping
damping(제동)은 body들의 속도(world velocity)를 감소시키는 때에 사용된다. damping은 두 면들이 접해서만 발생되는 friction(마찰)과는 다르다. 또한 damping은 마찰보다 시뮬레이션 하는 것에 있어서 더 가볍다. 그렇지만 요점은 damping은 마찰을 대체하기 위한 방법이 아니고 함께 사용되어지는 효과라는 점이다.

damping 매개변수는 '0' 부터 '무한대'까지 될 수 있다. 0은 damping이 없다는 의미이고 무한대는 최대 제동력을 의미한다. 일반적으로 당신은 damping값을 0부터 1 사이에서 사용할 것이다. 나는 일반적으로 linear damping는 body를 가볍게 보이도록 하기 때문에 사용하지 않는다. 
1 bodyDef.linearDamping = 0.0;
2 bodyDef.angularDamping = 0.1;
damping은 안정성과 성능을 위해 근사치를 사용한다. 작은 damping 값에서 damping 효과는 대게 time step에서 독립적이다. 큰 damping값에서 damping 효과는 time step에 의존적으로 달라질 것이다. 당신이 time step을 내가 제안했던것처럼 '고정값'으로 사용한다면 이런 것들은 이슈가 되지 않는다.

6.6. Sleep Parameters
sleep은 어떤 의미일까? body들을 시뮬레이팅 하는 것은 비싼(성능을 낭비하는) 작업이다 그래서 더 나은 시뮬레이팅을 해야 한다. body가 쉬어야 할 때 우리는 시뮬레이션을 중단해야 한다.

Box2D는 body(또는 body들 그룹)가 쉬어야 하는지는 결정했을때, body는 CPU로드를 매우 조금만 사용하는 sleep 상태로 들어간다. 만약 sleep상태의 body가 다른 body와 충돌하면 그 body는 sleep상태에서 깨어난다. 만약 그 body에 첨부된 joint 또는 contact 가 body에서 삭제될 때에도 body들은 또한 깨어날 것이다. 또한 당신이 직접 깨어나도록 할 수도 있다.

body definition은 생성된 body가 sleep할수있는지와 sleep상태로 생성될지를 당신에게 명시하도록 한다.
1 bodyDef.allowSleep = true;
2 bodyDef.isSleeping = false;

6.7. Bullets
게임 시뮬레이션은 보통 몇 프레임 레이트의 제생될 이미지 시퀀스를 만들어낸다. 이런 환경에서 rigid body(강체)는 한 time step동안 큰 양의 이동을 할 수 있다. 만약 물리엔진이 큰 모션을 위한 관리를 하지 않는 경우, 당신은 일부 잘못된 제각각의 물체들을 볼 수 있을지도 모른다. 이런 현상을 tunneling이라고 부른다.

기본적으로, Box2D는 static body들로 인한 터널링으로부터 dynamic body를 막기위해 Continuous Collision Detection(CCD)를 사용한다. 이는 shape을 이전 포지션에서 새로운 그 포지션으로 쓸어냄으로써 이루어 진다. 엔진은 sweep시의 새로운 충돌들과 이러한 충돌들을 위한 Time of Impact (TOI)를 계산을 구한다. body들은 그들의 첫 TOI로 움직여지고 그런 다음에는 원래 time step의 끝까지 시뮬레이트된다. 이러한 프로세스는 필요한만큼 계속 반복된다.

일반적으로 CCD는 dynamic body에서는 사용되지 않는다. 이것은 성능을 아끼기 위한 조치이다. 어떤 게임 시나이오상에서는 당신은 dynamic body가 CCD를 사용하길 필요로 할것이다. 예를들면, 당신이 빠른 속도의 총알이 얇은 벽을 향해 쏘는것일지도 모른다. CCD가 없이는 그 총알은 벽을 통과해버린다.

Box2Ddp서는 빠르게 움직이는 물체를 bullets라고 부른다. 당신은 어떠한 body들이 당신의 게임 디자인에 기반하여 bullet이 되는지를 결정해야 한다. 만약 당신이 한 body를 bullet이라고 조치해야한다고 결정했다면 아래와 같은 설정을 사용해라.
1 bodyDef.isBullet = true;
그 bullet 플래그는 dynamic body에서만 효력이 있다.

CCD는 값비싼 연산이라서 당신은 아마 모든 움직이는 body가 bullet이 되는것을 원치 않을 것이다. 그래서 기본적으로 Box2D는 CCD를 움직이는 body와 static body들에게만 사용한다. 이것은 당신의 world에서 body들이 탈출해버리는것을 예방할 매우 효율적인 접근법이다. 그러나 언젠가 당신은 어떤 빠른 body에서 CCD를 필요로 할지도 모른다.

6.8. Body Factory
body들은 world 클래스에서 주어진 body factory를 사용하여 생성되고 삭제된다. 이는 body가 world 구조에 추가하고 효율적인 할당량으로 생성되도록 한다.

body들은 질량 속성에 의존하여 dynamic과 static이 될수 있다. 두 body 타잎은 동일한 생성, 삭제함수를 사용한다.
1 var dynamicBody:b2Body = myWorld.CreateBody(bodyDef);
2  
3 //... do stuff ...
4 myWorld.DestroyBody(dynamicBody);
5 dynamicBody = null;
static body는 다른 body들의 영향에 의해 절대 움직이지 않는다. 당신은 수동적으로 static body를 움직일지도 모른다 하지만 당신은 두개 이상의 static body 사이에 dynamic body를 밀어넣지 않도록 주의해야 할 것이다. 당신이 static body를 임의대로 움직여도 friction(마찰)은 정상적으로 작용하지 않을것이다. static body는 절대 스스로 시뮬레이셔닝 되지 않고 다른 static body들과 충돌도 일어나지 않는다. 하나의 static body에 몇개의 shape들을 첨부하는것이 각각 따로 static body들에 첨부하는것보다 (시뮬레이션 속도가)빠르다. 내부적으로, Box2D 는 static body에 대해서 질량이나 역-질량(inverse mass)을 0으로 설정한다. 이것은 static body를 특별한 케이스로 간주하여 대부분의 알고리즘의 수학연산을 피하기 위한 조치이다.

Box2D는 body definition이나 다른 어떤 데이타들의 참조를 유지하지 않는다(유저 데이타 포인터는 제외). 그래서 당신은 임시 body definition 을 만들어서 제사용할 수 있다.

Box2D는 작업 데이타를 말끔히 청소하기 위한 방법으로 b2World 인스턴스를 제거하기만 하면 포함된 모든 body들을 삭제하는 수고를 덜 수 있도록 해준다. 그러나 당신은 게임 엔진에서 body포인터들을 무력화 하기위해 따로 참조를 유지하는것을 염두해 두어야 한다.

body를 삭제할때엔, 첨부된 shape들과 joint들이 자동적으로 함께 삭제된다. 이는 어떻게 당신이 shape과 joint의 포인터들을 관리할 것인가에 대해 중요한 의미가 담겨있다.

당신이 한 dynamic body를 땅위의 joint에 연결하길 원한다고 가정하자. 당신은 그 joint를 static body에 연결 할 필요가 있을것이다. 당신이 static body를 가지지 않았다면 당신은 world 객체로부터 ground body를 공유받을 수 있다. 또한 static shape들을 ground body에 첨부할수도 있다.
1 var ground:b2Body = myWorld.GetGroundBody();
2 //... build a joint using the ground body ...

6.9. Using a Body
body를 생성한 이후엔, 당신이 body에 행할 수 있는 많은 운용들이 있다. 질량 속성을 할당하는것이나, 포지션이나 속도에 접근하는것, 힘을 적용하는것, 포인터와 벡터들의 변형들이 이것에 포함된다.

6.10. Mass Data
당신은 런타임시 body의 질량을 적용할 수 있다. 질량값은 보통 생성할때나 body의 shape들을 삭제할때 결정된다. 당신은 현제 첨부된 shape들을 기준으로 body의 질량을 적용하길 원할 수도 있다.
1 b2Body.SetMassFromShapes():void;
당신은 질량 속성을 직접적으로 설정하길 원할 수도 있다. 예를들면 당신이 shape을 변경해도 당신의 질량 공식을 사용하기 원할지도 모른다.
1 b2Body.SetMass(massData:b2MassData):void;
body의 질량 데이타는 다음과 같은 함수들을 통해서 이용할 수있다.
1 b2Body.GetMass():Number;
2 b2Body.GetInertia():Number;
3 b2Body.GetLocalCenter():b2Vec;

6.11. State Infomation
Box2D는 body의 상태변화를 로깅한다. 당신은 다음과 같은 함수들을 통해서 이런 상태값에 효율적으로 접근할 수 있다.
01 b2Body.IsBullet():Boolean;
02 b2Body.SetBullet(flag:Boolean):void;
03  
04   
05 b2Body.IsStatic():Boolean
06 b2Body.IsDynamic():Boolean;
07   
08 b2Body.IsFrozen():Boolean;
09  
10   
11 b2Body.IsSleeping():Boolean;
12 b2Body.AllowSleeping(flag:Boolean):void;
13 b2Body.WakeUp():void;
bullet 상태는 Bullets에 서술되어 있다. frozen 상태는 World Boundary에 서술되어있다.

6.12. Position and Velocity
당신은 body의 포지션과 로테이션에 접근한다. 게임에 나오는 주인공을 그릴때 이는 공통적인 부분이다. 비록 '이동'을 시뮬레이션 하기위해 Box2D를 사용할 때까지 이는 덜 공통적이겠지만,  포지션을 셋팅할 수도 있다.
1 SetXForm(position:b2Vec2, angle:Number):Boolean;
2 GetXForm():b2XForm;
3 GetPosition():b2Vec2;
4 GetAngle():Number;
world 좌료계에서 당신은 질량의 중심 위치에 접근할 수도 있다. Box2D의 내부적인 시뮬레이션 대부분은 질량 중심을 사용한다. 그러나 당신은 일반적으로 그것에 접근할 필요는 없을 것이다. 그 대신에 당신은 보통 body transform 으로 작업하게 될것이다.
1 GetWorldCenter():b2Vec2;
당신은 linear veocity(선속도) 와 angular velocity(각속도) 에 접근할 수 있다. linear velocity는 질량 중심에 작용한다.
?
1 function SetLinearVelocity(v:b2Vec2):void;
2  
3 function GetLinearVelocity():b2Vec2;
4 function SetAngularVelocity(omega:Number):void;
5 function GetAngularVelocity():Number;

6.13. Forces and Impulses
body에 force나 torque, impulse를 적용할 수 있다. force나 impulse를 적용할때, 적용될 지점을 지정해줘야 한다. torque는 보통 질량 중심에 작용된다.
1 ApplyForce(force:b2Vec2, point:b2Vec2):void;
2 ApplyTorque(float32 torque):void;
3 ApplyImpulse(impulse:b2Vec2, point:b2Vec2):void;
force와 torque, impulse를 지정하면 body는 깨어난다. 때때로 이는 달갑지 않을것이다. 예를들면 지속적인 force를 적용하고 성능을 유지시키기 위해서 body를 sleep상태로 만들길 원할때이다. 이런 경우에 아래와 같이 사용할 수 있다.
1 if (myBody.IsSleeping() == false)
2 {
3     myBody.ApplyForce(myForce, myPoint);
4 }

6.14. Coordinates Transformations
body 클래스는 점이나 벡터들을 local과 world 좌표계 사이에서 변환하도록 도와주는 함수들을 제공한다. 만약 이런 컨셉을 이해 못한다면 Jim Van Verth 와 Lars Bishop이 저술한 "Essential Mathematics for Games and Interactive Applications"를 읽어보길 권장한다. 이러한 함수들은 효율적이며 큰 도움이 될것이다.
1 GetWorldPoint(localPoint:b2Vec2):b2Vec2;
2 GetWorldVector(localVector:b2Vec2):b2Vec2;
3 GetLocalPoint(worldPoint:b2Vec2):b2Vec2;
4 GetLocalVector(worldVector:b2Vec2):b2Vec2;

6.15. Lists
body의 shape들에 반복적인 접근이 있을때 활용할 수 있다. 이는 shape에 포함된 유저 데이타에 접근을 필요로할때 유용하다.
1 for (var s:b2Shape = body.GetShapeList(); s; s = s.GetNext())
2 {
3     var data:MyShapeData = s.GetUserData() as MyShapeData;
4     ... do something with data ...
5  
6 }
비슷한 방법으로 body의 joint list도 사용할 수 있다.

7. Shapes
7.1. About
shape은 body에 첨부된 충돌검사용 기하체이다. body의 질량을 정의하는데에 사용되기도 한다. 질량은 직접 지정할 수도 있고 Box2D가 질량 속성들을 계산할 수도 있다.

shape에는 friction(마찰력)과 restitution(반발계수) 이라는 속성을 가지고 있다. 게임내의 물체들과 충돌들을 방지하기 위한 '충돌 필터 정보'도 가지고 있다.

shape은 항상 body가 가지고 있다. 한 개의 body에 여러 shape들을 첨부할 수 있다. shape은 추상클래스들이라서 Box2D에는 많은 종류의 shape들이 구현될 수 있다. 용기가 있다면 직접 shape 타잎(그리고 충돌 알고리즘)을 구현할 수도 있다.

7.2. The Shape Definition
shape definition은 shape을 생성하기 위해 사용된다. b2ShapeDef 에 의해 유지되는 common shape data 와 파생 클래스들에 의해서 유지되는 specific shape data가 있다.

7.3. Friction and Restitution
마찰은 물체가 각각 현실적인 미끄러짐을 하도록 만들때 사용된다. Box2D는 static friction과 dynamic friction을 제공하지만 매개변수는 동일하게 사용한다. Box2D에서 마찰은 정교하게 시뮬레이딩 되고 그 강도는 일반적인 force에 정비례한다(이를 Coulomb friction이라고 부른다). 마찰계수는 보통 0에서 1 사이값이다. 0은 마찰이 없는것을 의미하며 그 반대는 마찰의 강도를 나타낸다. 두 shape 사이에서 마찰을 계산할때, Box2D는 두 shape의 마찰계수를 합해야 한다. 아래의 공식으로 처리한다.
1 var friction : Number = Math.sqrt(shape1.friction * shape2.friction);
반발력은 물체가 튕길때 사용한다. 반발값은 보통 0에서 1 사이의 값으로 셋팅한다. 공을 테이블 위에 떨어트린다고 가정해보자. 반발값이 0이면 그 공은 튀어 오르지 않는다는 의미이다. 이를 inelastic collision(비탄성 충돌)이라고 부른다.  그 값이 1이면 공의 속도는 정확히 반사된 값이된다. 이를 perfectly elastic collision이라고 부른다. 반발은 아래와 같은 공식을 사용하여 합산되어진다.
1 var restitution: Number = Math.Max(shape1.restitution, shape2.restitution);
shape이 여러 접점을 가질때 반발력은 근사치로 시뮬레이팅 된다. 왜냐하면 Box2D는 인터렉티브 해결사를 사용하기 위해서다. 또한 충돌 속도가 작을 때 Box2D는 비탄성 충돌을 사용한다. 이는 jitter(덜덜 떨리는것)를 예방하기 위한 작업이다.

7.4. Density
Box2D는 부가적으로 body의 질량과 회전 관성량을 첨부된 shape들에 의해 함축된 질량 분포를 사용하여 계산한다. 질량을 직접적으로 명시하는것은 종종 형편없는 시뮬레이션 결과를 가져올 수 있다. 그러므로 body 질량을 명시하는것의 권장 방법은 shape들의 밀도들을 셋팅함으로써 지정하는것과, b2Body.SetMassFromShape 를 body에 첨가될 모든 shape이 첨부된 이후 한번 호출하는것이다.

7.5. Filtering
충돌 필터링은 shape들 사이에서의 충돌을 방지하기위한 시스템이다. 예를들면 자전거를 타는 캐릭터를 만들때이다. 자전거가 지형의 충돌하도록 원할것이고 캐릭터가 지형과 충돌하도록 만들고 싶겠지만 캐릭터가 자전거와 충돌되길 원하진 않을 것이다(왜냐하면 그 둘은 서로 오버랩되어야 하니까). Box2D는 category와 group들을 이용하여 충돌 필터링과 같은 것을 지원한다.

Box2D는 16개의 충돌 범주를 제공한다. shape 각각 속한 카테고리를 지정한다.  그리고 이 shape가 어떤 카테고리의 것들과 충돌하는지도 지정할 수 있다. 예를들면 멀티플레이 게임에서 모든 플레이어가 서로 충돌하지 않고 몬스터들이 서로 충돌하지 않지만 플레이어와 몬스터들은 서로 충돌하도록 지정하는것이다. 이것은 마스킹 비트(masking bit)로 이루어진 것이다. 예를들어보자.
1 playerShapeDef.filter.categoryBits   = 0x0002;
2 monsterShapeDef.filter.categoryBits  = 0x0004;
3 playerShapeDef.filter.maskBits       = 0x0004;
4 monsterShapeDef.filter.maskBits      = 0x0002;
충돌 그룹은 그룹 인덱스를 설정할 수 있도록 한다. 같은 그룹의 모든 shaoe들을 항상 충돌하도록(양수 인덱스) 또록 항상 그렇지 않도록(음수 인텍스) 할 수 있다. 그룹 인덱스들은 자전거의 부품처럼 보통 어떻게든 연관된 것들을 위해서 사용되어진다. 아래의 예제에서는 shape1와 shape2가 항상 충돌하지만 shape3와 shape4는 절대 충돌하지 않는다.
1 shape1Def.filter.groupIndex = 2;
2 shape2Def.filter.groupIndex = 2;
3 shape3Def.filter.groupIndex = -8;
4 shape4Def.filter.groupIndex = -8;
서로 다른 그룹 인덱스를 가진 shape끼리의 충돌은 카테고리와 마스크 비트에 따라서 필터링된다. 다시 말하면, 그룹 필터링은 카테고리 필터링보다 더 연산 우선순위(precendence)가 높다.

Box2D에서 발생하는 추가적인 충돌 필터링을 메모해두자.
  • static body에 첨부된 shape은 다른 static body에 첨부된 shape와 절대 충돌하지 않는다.
  • 같은 body에 첨부된 shape은 절대 서로 충돌하지 않는다.
  • 하나의 joint에 의해서 연결된 body들에 첨부된 shape사이의 충돌은 추가적으로 켤수도, 끌수도 있다.
가끔 당신은 shape가 생성된 이후에 충돌 필터링을 변경하는것을 필요로 할지도 모른다. 이미 생성된 shape에서 b2Shape.GetFilterData 그리고 b2Shape.SetFilterData 함수를 이용해서 b2FilterData 구조체를 설정할 수도, 받아올 수도 있다. Box2D는 결과값은 캐싱하므로 당신은 수동으로 다시 shape를 b2World.Refilter를 사용해서 필터링 해야한다.

7.6. Sensors
때때로 게임 로직은 두 shape가 충돌하기 전에 겹치는지 알아보길 필요로 한다. 이는 센서(sensor)를 사용한다. 센서는 충돌을 감지하는 하나의 shape이지만 충돌에 대한 응답을 만들지는 않는다.

어떤 shape라도 센서가 되도록 깃발을 꼽아둘 수 있다. 센서들은 static 이나 dynamic이 될것이다. 당신은 body에 여러개의 shape를 담을 수 있고 센서인 shape와 그렇지 않은 shape들을 섷어둘 수 있다는 것을 기억해라.
1 myShapeDef.isSensor = true;

7.7. Circle Definitions
b2CircleDef 는 b2ShapeDef 를 상속받았고 반지름과 로컬 포지션을 추가한 것이다.
1 var def:b2CircleDef;
2 def.radius = 1.5;
3 def.localPosition.Set(1.00.0);

7.8. Polygon Definitions
b2PolyDef는 convex polygon(역자주: 모든 내각이 180도 미만인 다각형)을 구현하기 위해서 사용된다. 정확하게 사용하기 위해 비트 꼼수가 있으므로 침착하게 읽어보라. 최대 vertex(꼭지점) 숫자는 초기값이 8인 b2_maxPolyVertices에 의해서 정의된다. 만약 더 많은 vertex가 필요하다면 b2Settings 파일 안에있는 b2_maxPolyVertices 를 수정해야 한다.

polygon definition을 생성할때 당신은 사용할 vertex의 숫자를 명시해야 한다. vertex들은 오른손 좌표계의 z축에 대해서 반시계방향으로 정의되어야 한다. 게임에서 사용하는 좌표계 변환에 의존해서 이는 화면에 시계방향으로 바뀔지도 모른다.

다각형은 convex여야 한다. 즉, 각 꼭지점은 내각이 180 미만이어야 한다. 마지막으로 vertex는 겹치지 않도록 해야한다. Box2D는 자동적으로 반복을 종료한다. (역자주: OpenGL에서의 다각형 지정 방식과 동일하다)

여기에 삼각형의 polygon definition의 예제가 있다.
1 var triangleDef:b2PolygonDef = b2PolygonDef()
2 triangleDef.vertexCount = 3
3  
4 triangleDef.vertices[0].Set(-1.00.0)
5 triangleDef.vertices[1].Set(1.00.0)
6  
7 triangleDef.vertices[2].Set(0.02.0)
vertex들은 부모 body의 좌표계 안에서 정의되어진다. 부모 body에서 한 다각형에 offset을 필요로 한다면 그 다각형의 모든 vertex에 offset을 주면 된다.

편의를 위해서 box같은 다각형은 다각형 초기화를 위한 함수들이 있다. body의 원점 가운데 축정렬된 box나 body의 원점으로 부터 offset을 가진 oriented box를 생성하기 위한 함수들도 있다.
01 var alignedBoxDef:b2PolygonDef = new b2PolygonDef();
02  
03 var hx:Number 1.0// half-width
04 var hy:Number 2.0// half-height
05  
06 alignedBoxDef.SetAsBox(hx, hy);
07   
08 var orientedBoxDef:b2PolygonDef = new b2PolygonDef();
09 var center:b2Vec2 = new b2Vec2(-1.50.0);
10  
11 var angle:Number 0.5 * b2Settings.b2_pi;
12 orientedBoxDef.SetAsOrientedBox(hx, hy, center, angle);

7.9. Shape Factory
shape들은 shape definition을 초기화하는것으로 생성되어지고 그런다음엔 그 definition이 그 부모 body로 전달된다.
1 var circleDef:b2CircleDef = new b2CircleDef();
2 circleDef.radius = 3.0;
3 circleDef.density = 2.5;
4  
5 var myShape:b2Shape = myBody.CreateShape(circleDef);
6 //[optionally store shape object somewhere]
이는 shape를 생성하고 body에 첨부한다.  body가 삭제되면서 shape가 자동적으로 삭제될때까지 shape의 포인터를 저장해둘 필요가 없다.

body에 shape들을 추가가 모두 끝난 이후에는 첨부된 shape에 기반한 질량값을 다시 계산하는것을 원할지도 모른다.
1 myBody.SetMassFromShapes()
이 함수는 비싼 연산이므로 꼭 필요할 때만 사용하라.

당신은 부모 body에서 shape를 쉬게 삭제할 수 있다. 깨질수있는 모델로 설정하면 된다. 반면에 당신은 shape를 내버려두고 body가 첨부된 모든 shape들의 삭제를 돌보도록 할 수있다.
1 myBody.DestroyShape(myShape)
body에서 shape들이 삭제된 이후 당신은 SetMassFromShapes를 다시 호출하길 원할지도 모르겠다.

7.10. Using a Shape
여기에 할말은 그닥 많지 않다. shape들의 형식과 그들의 부모 body를 받을 수 있다. 또한 한 지점이 shape에 포함되는지를 확인하기위해 테스트할 수도 있다. 자세한것은 b2Shape.as 를 들여다 보라.

WRITTEN BY
buzzler

,