미완성. 영어실력이 일천하므로 의역이 대부분입니다. 지적 감사히 받습니다.
개인적인 학습을 위해 작성된 게시물이며 원 저작권은 Box2D 포럼에 있습니다.

매뉴얼의 각 챕터의 번역은 역자의 판단에 따른 중요도 순서대로 진행될 예정입니다.
원문보기
2012년 12월 현재 원문 매뉴얼은 위키에서 제거되고 PDF화된 매뉴얼이 배포중입니다. 근시일내 PDF에 대한 번역작업을 새로이 진행할 것이며 이하 번역내용은 2009년의 것으로 현재 버전과 다른 점이 있을 수 있음을 유의하시기 바랍니다.




개요


조인트는 강체들을 세계에, 또는 서로에게 속박시키는데 사용된다. 래그돌, 시소, 풀리 등이 게임에서 사용되는 전형적인 예이다. 조인트는 흥미로운 동작들을 만들기 위한 여러가지 방법을 내포하고 있을 수 있다. 어떤 조인트는 동작의 범위를 조절하기 위한 한계를 제공한다. 어떤 조인트는 지정된 토크, 속도로 동작하는 모터를 제공한다. 모터는 여러가지 방법으로 사용될 수 있다. 당신은 조인트의 속도를 지정함으로서 강체의 현재 위치로부터 원하는 위치 사이의 비율을 조절하는 데 모터를 사용할 수 있다 또한 당신은 모터의 속도를 0에 가깝게 낮도록, 그러나 출력은 최대로 지정함으로서 조인트의 마찰을 흉내내는 데에도 모터를 사용할 수 있다. 그럴 경우 충분한 하중이 가해지지 않으면 움직이지 않고 제자리를 지키려고 할 것이다.


조인트의 정의
각 조인트의 정의는 b2JointDef로부터 유도된다. 모든 조인트는 두개의 서로 다른 강체 사이에 연결된다. 한 개의 강체는 정적일 것이다(?). 당신이 메모리를 낭비하고 싶다면 두 개의 정적 강체 사이에 조인트를 만들면 된다 :)

당신은 모든 형태의 조인트에 연동 데이터(user data:사용자 지정)를 지정할 수 있으며, 연결된 강체가 서로 충돌하지 않도록 클래그를 제공할 수 있다. 이것은 사실 기본적인 행동이며 당신은 두 강체 사이의 충돌을 허용할 것인지, collidDConnected 부울 값을 지정해야만 한다.

대부분의 조인트의 정의는 당신이 약간의 기하 데이터를 제공할 것을 요구한다. 대개 조인트는 anchor point로서 정의된다. 연결된 강체를 고정해두는 점들이 있다. Box2D는 그런 점들이 로컬 좌표에 지정될 것을 요구한다. 그러함으로서, 게임이 저장되었다가 다시 불러졌을 때 일반적으로 발생하는 현재 강체의 변환이 조인트의 구속과 충돌할 경우에도 조인트가 지정될 수 있다. 또한, 일부 조인트의 정의는 두 강체 사이의 기본적인 상대적 각도를 알아야 한다고 요구한다.


거리 조인트
가장 단순한 조인트 중의 하나는 두 개의 강체를 잇는 점들의 거리가 일정함을 의미하는 거리 조인트이다. 당신이 거리 조인트를 지정할 때 두 개의 강체는 이미 존재하고 있어야 한다. 그럴 경우 당신은 월드좌표 안에 두 개의 앵커(anchor)를 정의하게 된다. 한 앵커 포인트는 body1에 연결되며, 두번째 앵커 포인트는 body2에 연결된다. 이 포인트들은 구속된 거리의 길이를 의미한다.
distanceJoint.gif
여기 거리 조인트 정의의 한 예가 있다. 이 케이스에서 우리는 강체의 충돌을 허용할 것을 결정하였다.

var jointDef:b2DistanceJointDef = new b2DistanceJointDef();
jointDef.Initialize(myBody1, myBody2, worldAnchorOnBody1, worldAnchorOnBody2);
jointDef.collideConnected = true;


경첩(revolute) 조인트
경첩 조인트는 두 강체가 일반적인 흔히 경첩(hinge point)이라 불리는 앵커 포인트 하나를 공유하도록 강제한다. 경첩은 두 강체의 상대적 회전에 대해 자유로운 각도를 가지고 있다. 이것은 사잇각(joint angle)이라고 불린다.
revoluteJoint.gif
꺾임을 정의하기 위해 당신은 세계 공간 안에 두 개의 강체와 하나의 앵커 포인트 제공해야 한다. 초기화 함수는 이미 두 강체가 정확한 위치에 있다고 가정한다.
이 예제에서, 두 강체는 첫번째 강체의 질량중심에 경첩 조인트로 연결된다.
var jointDef:b2RevoluteJointDef = new b2RevoluteJointDef();
jointDef.Initialize(myBody1, myBody2, myBody1->GetWorldCenter());


경첩 조인트의 각도는 body2가 이음매에 대해서 시계반대 회전을 할 때 양의 값이다. Box2D의 모든 각도와 같이 경첩의 각도 역시 라디안으로서 측정된다. 관례적으로 경첩 각도는 Initialize()에 의해 생성되었을 때, 현재 두 강체의 회전값에 관계없이 0 이다.

몇 가지 경우에 당신은 사잇각을 조절하고 싶을 것이다. 이를 위해, 경첩 조인트는 조인트 한계와 모터를 선택적으로 시뮬레이션할 수 있다.(?)

조인트 한계는 사잇각이 최저값과 최대값 사이를 유지하도록 강제한다. 한계는 충분히 토크가 강할 때 적용된다. 한계범위는 0을 포함해야 한다. 그렇지 않으면 시뮬레이션이 시작되었을 때 조인트가 비틀거릴 수 있다.

조인트 모터는 당신이 조인트의 속도(시간에 대한 각도 변화)를 지정할 수 있도록 허용한다. 속도는 양수이거나 음수일 수 있다. 모터는 무한한 힘을 가질 수 있다. 그러나 이것은 당신이 들어본 표현식 중엔 일반적으로 바람직하지 않다. (???)

경고

"움직일 수 없는 물체에 불가항력이 가해졌을 때 무슨 일이 일어나는가?"

나는 당신에게 적절하지 않다고 말해줄 수 있다.(?) 그러므로 당신은 조인트 모터에 최대 토크를 제공할 수 있다. 조인트 모터는 요구되는 토크가 한계치를 넘지 않는 한 지정된 속도를 유지할 것이다. 최대 토크가 초과되었을 때, 조인트는 느려지거나 그 반대가 될 수 있다.

당신은 조인트 모터를 조인트의 저항력을 흉내내는데 사용할 수 있다. 단지 조인트의 속도를 0으로 지정하고, 최대 토크를 조금 작지만 의미있는 값으로 지정하는 것 만으로. 모터는 조인트가 회전하는것을 방해하려고 시도할 것이다. 그러나 적절한 부하에는 굴복할 것이다.

여기에 이전의 경첩 조인트 정의의 수정본이 있다. 이번에는 조인트가 한계점을 가지며 모터가 동작한다. 모터는 저항력을 흉내내기 위해 설정되었다.
var jointDef:b2RevoluteJointDef = new b2RevoluteJointDef();
jointDef.Initialize(body1, body2, myBody1.GetWorldCenter());
jointDef.lowerAngle = -0.5 * b2Settings.b2_pi; // -90 degrees
jointDef.upperAngle = 0.25 * b2Settings.b2_pi; // 45 degrees
jointDef.enableLimit = true;
jointDef.maxMotorTorque = 10.0;
jointDef.motorSpeed = 0.0;
jointDef.enableMotor = true;





기둥(Prismatic) 조인트

기둥 조인트는 특정 축에 대한 두 강체 사이의 상대적인 변환을 허용한다. 기둥 조인트는 상대적인 회전을 방해한다. 그러므로, 기둥 조인트는 특정 각도에 대해서만 자유롭다.(?)

prismaticJoint.gif
기둥 조인트의 정의는 경첩 조인트의 정의와 유사하다. 단지 substitute translation for angle and force for torque(불명). 이 유사성을 통해  조인트 한계와 저항력을 갖는 기둥 조인트의 정의의 예제가 제공된다.
var worldAxis:b2Vec2 = new b2Vec2(1.0, 0.0);
var jointDef:b2PrismaticJointDef = new b2PrismaticJointDef();
jointDef.Initialize(myBody1, myBody2, myBody1.GetWorldCenter(), worldAxis);
jointDef.lowerTranslation= -5.0;
jointDef.upperTranslation= 2.5;
jointDef.enableLimit = true;
jointDef.maxMotorForce = 1.0;
jointDef.motorSpeed = 0.0;
jointDef.enableMotor = true;



경첩 조인트는 스크린 밖으로 나오는 가상의 축을 가지고 있다. 기둥 조인트는 스크린에 평행한, 명백한 축을 필요로 한다. 이 축은 두 강체와 그들의 움직임을 고정한다.
경첩 조인트와 같이, Initialize()를 사용하여 초기화 되었을 때 기둥 조인트의 변환은 0이다. 그러므로 당신이 정한 최저,최대 변환값 한계 사이에 0이 있음은 명백하다.


활차 조인트

활차는 가상의 도르래를 만들기 위해 사용된다. 활차는 두 강체를 ground를 통해 서로 연결한다. 한 강체가 올라가면 다른 강체는 내려간다. 활차 끈의 총 길이는 초기 구성대로 유지된다.
length1 + length2 == constant

pulleyJoint.gif
당신은 "벽돌과 도르래"를 흉내내기 위한 비율을 제공할 수 있다.(?) 이것은 한 쪽의 활차가 다른 쪽보자 빨리 늘어날 수 있는 원인이 된다. 동시에 한쪽에 작용하는 구속력이 다른 쪽보다 작을 수 있다. 당신은 이것을 기계적인 지레 작용에 사용할 수 있다.
length1 + ratio * length2 == constant

예를 들면, 비율이 2라고 할 때 length1은 length2의 두배로 변화한다. 마찬가지로 body1에 달린 로프에 가해지는 힘은 body2에 달린 로프에 가해지는 힘의 절반이 된다.
활차 조인트는 한쪽이 최대로 늘어났을때 골치아파질 수 있다. 반대쪽의 끈이 0의 길이를 갖게 될 것이다. 이 점에서 구속력의 방정식이 단일 해를 갖게 된다. 그런 까닭에 풀리 조인트는 어느 쪽이든 가능한 다다를 수 있는 최대 길이를 구속한다. 또한, 당신은 게임 플레이상의 이유로 최대 길이를 조절하길 원할지도 모른다. 그래서 최대 길이는 안정적이고 당신에게 제어권을 제공하도록 개선되었다.

여기 도르래의 정의에 대한 한 가지 예가 있다.
var anchor1:b2Vec2 = myBody1.GetWorldCenter();
var anchor2:b2Vec2 = myBody2.GetWorldCenter();
var groundAnchor1:b2Vec2 = new b2Vec2(p1.x, p1.y + 10.0);
var groundAnchor2:b2Vec2 = new b2Vec2(p2.x, p2.y + 12.0);
var ratio:Number = 1.0;
var jointDef:b2PulleyJointDef = new b2PulleyJointDef();
jointDef.Initialize(myBody1, myBody2, groundAnchor1, groundAnchor2, anchor1, anchor2, ratio);
jointDef.maxLength1 = 18.0;
jointDef.maxLength2 = 20.0;



기어 조인트
만약 당신이 정교한 기계장치를 만들고 싶다면, 당신은 기어를 사용하려고 할 것이다. 기본적으로, 당신은 Box2D에서 톱니바퀴 이빨을 가진 복합 형체를 사용함으로서 기어를 생성할 수 있다. 이것은 매우 효율적이지 못하며 제작자를 짜증나게 한다. 또한 당신은 톱니 메시가 부드럽게 정렬되도록 주의해야 한다. Box2D는 기어 조인트라는, 기어를 만들기 위한 간단한 방법을 가지고 있다.
gearJoint.gif
당신은 역시 두 강체를 경첩 또는 기둥 조인트로서 ground에 연결해야 한다. 당신은 어떤 조인트들의 조합이라도 사용할 수 있다. 또한, Box2D는 ground에 이어진 경첩,기둥 조인트가 body1에 생성될 것을 요구한다.

활차의 비율과 마찬가지로, 당신은 기어의 비율을 지정할 수 있다. 그러나, 이번 케이스에는 기어의 비율이 음수일 수 있다. 역시 한 조인트가 경첩(각도)이고 다른 조인트가 기둥(변환)일 때를 주의하라. 그러므로 기어의 비율은 길이 이상의 일정한 단위를 가진다(?)
(therefore the gear ratio will have units of length or one over length. 부정)
coordinate1 + ratio * coordinate2 == constant

여기 기어 조인트의 한가지 예가 있다.
var jointDef:b2GearJointDef = new b2GearJointDef();
jointDef.body1 = myBody1;
jointDef.body2 = myBody2;
jointDef.joint1 = myRevoluteJoint;
jointDef.joint2 = myPrismaticJoint;
jointDef.ratio = 2.0 * b2Settings.b2_pi / myLength;

주목할 점은 기어 조인트가 두개의 다른 조인트에 의존하고 있다는 것이다. 이것은 나쁜 상황을 만든다. 만약 그 조인트들 중 하나가 지워지면 어떻게 될까?

경고
항상 기어 조인트를 경첩,기둥 조인트보다 먼저 제거해야 한다. 그렇지 않으면 기어 조인트의 고아가 된 포인터들로 인해 당신의 코드는 잘못된 방향으로 치달을 것이다.(역주:이것은 C++코드에 해당하는 표현으로 as의 릴리스 빌드에서는 단지 아무일도 일어나지 않게 될 것이다.) 또한 당신은 강체에 연관된 무언가(그것이 무엇이든)를 지우기 전에 먼저 기어 조인트를 제거해야 한다.

----------------------------------------

Joint Factory

조인트는 월드의 팩토리 메소드에 의해 생성/파괴되어야 한다. 이것은 오래된 이슈를 상기시킨다.

경고
강체나 조인트를 스택 또는 힙에 new 또는 malloc을 사용해 생성하려고 하지 말라. 당신은 반드시 b2World클래스의 생성/파괴 메소드를 사용해 강체와 조인트를 다루어야 한다.

다음에 경첩조인트의 일생이 담긴 예제가 있다.

var jointDef:b2RevoluteJointDef = new b2RevoluteJointDef();
jointDef.body1 = myBody1;
jointDef.body2 = myBody2;
jointDef.anchorPoint = myBody1.GetCenterPosition();
var joint:b2RevoluteJoint = myWorld.CreateJoint(jointDef);
... do stuff ...
myWorld.DestroyJoint(joint);
joint = null;

포인터가 파괴된 후에는 항상 초기화시켜 두는 것이 좋다. 당신이 포인터를 재사용하려고 했을 때 프로그램의 크래시를 통제된 방법으로 처리할 수 있게 해준다.

조인트의 일생은 단순하지 않다. 이 경고에 주의하라.

경고
조인트는 연결된 강체가 파괴될 때 같이 파괴된다.
이 예방책은 항상 필요하진 않다. 당신은 당신의 게임 엔진에 대해, 조인트들이 항상 연결된 강체들에 앞서 파괴되도록 구성할 수 있다. 이 경우, 당신은 리스너를 구현할 필요가 없다. 자세한 것은 묵시적 파괴를 참조하라.
Using Joints

많은 시뮬레이션들은 조인트를 만들고 그것들이 파괴될 때까지 다시 거들떠보지도 않는다. 그러나 더 풍부한 시뮬레이션을 만들기 위해서, 당신은 조인트 안에 든 유용한 데이터들을 사용할 수 있다.

먼저, 당신은 조인트로부터 강체를 얻거나, 연결점을 얻거나, 사용자 데이터를 얻을 수 있다.

GetBody1():b2Body;
GetBody2():b2Body;
GetAnchor1():b2Vec2;
GetAnchor2():b2Vec2;
GetUserData():*;

모 든 조인트는 반응 힘과 반응 토크 양쪽을 가지고 있다. 그것들은 body2의 연결점에 적용된다. 당신은 반응 힘을 조인트의 파괴나 기타 게임 이벤트를 트리거하는데 사용할 수 있다. 이런 메소드들은 약간의 계산을 필요로 하므로 당신에게 필요없을 때는 호출하지 말라.

function GetReactionForce():b2Vec2;
function GetReactionTorque():Number;