경첩이나 진자운동같은 형태를 만들기 위해 필요한 joint type입니다. 즉, 원운동에 필요한 joint. 이전에 했던 distance joint와는 다른점이.. 두 body 사이의 길이가 고정 이라는 점. 즉 무거운 물체가 두 물체 사이에 힘을 가한다고 해도 body 사이의 간격이 달라지지 않죠. 게다가 joint는 motor 역할을 시킬수도 있습니다. 그래서 자동차 바퀴가 돌아가는것이나 선풍기날같은 원운동을 하는 자동화된 모터가 되기도 합니다.

이번 예제해서는 revolute joint를 응용해서 진자 운동을 하는 '추' 와 조금 더 응용된 '밧줄'을 만들어보겠습니다. 만들면서 cut the rope가 생각나더군요.
마우스 액션은 없지만 이전의 예제들보다 한층 더 동적인 모습입니다. 밧줄처럼 보이는 것들은 사실 세로로 길죽한 네모를 여러개 붙인 모양이구요. 밧줄의 두께가 너무 얇으면 밧줄끼리 서로 뚫고 지나가서 엉키더군요. 아마 그런 것들을 방지하기 위해서 tracing을 할 수 있게 제공하긴 하지만, cpu사용량이 엄청나게 늘어나기 때문에 이 옵션을 켜는것은 무모한 생각이 듭니다.

소스를 들여다보기 전에.. DebugDraw나 b2Body를 생성하는 방법에 대한 내용은 다루지 않고 지나갈 예정입니다. 이 부분에 대한 자세한 코드나 활용법이 궁금하신분은 같은 programming 카테고리에 있는 User Manual예제코드를 보시면 됩니다.

function createRevoluteJoint(b1:b2Body, b2:b2Body, a:b2Vec2):b2Joint

{

var jointDef:b2RevoluteJointDef = new b2RevoluteJointDef();

jointDef.Initialize(b1, b2, a);

jointDef.collideConnected = false;

jointDef.enableLimit = false;

jointDef.enableMotor = false;

return world.CreateJoint(jointDef);

}


joint를 만들어 주는 함수입니다. joint 또한 definition 클래스를 먼저 만들고 world 클래스의 factory 함수를 통해서 만들죠. 따라서 개발자가 직접 Joint를 생성할 필요가 없습니다.

모든 joint의 설정값이 다 다를 수 있기 때문에 이같이 함수에 따로 묶어두는것이 바람직한 방법은 아닙니다. revolute joint는 기준점에서 body가 서로 이루는 각도를 제한할 수도 있으며 회전운동을 시킬 수 있는데 이같은 속성들을 하나씩 바꿔가면서 생성하려면 좀더 구체적인 방법이 필요할 것입니다. 이 예제는 revolute joint를 사용하는 모든 body가 같은 설정값을 가진다는 가정으로 제작되었습니다. 즉 회전 각도의 한계값은 적용되지 않고 (enableLimit) 또한 자동적으로 회전하는 motor joint도 없습니다(enableMotor). 그리고 각 body들은 서로 충돌하지 않도록 간섭을 피했습니다(collideConnected).

function createBox(px:Number, py:Number, w:Number, h:Number, angle:Number, isDynamic:Boolean):b2Body;


function createCircle(px:Number, py:Number, r:Number, isDynamic:Boolean):b2Body;


네모 상자와 원형 body를 만들어 주는 함수들입니다. 설명은 생략하겠습니다.

다음의 소스는 '진자'를 만들어주는 함수입니다. 진자는 자명종 시계의 추를 생각하시면 되죠. 마우스 액션이 따로 없는 대신 추의 시작 각도를 정할 수 있게 만들어봤습니다.

function createPendulum(px:Number, py:Number, r:Number, h:Number, angle:Number):void

{

var pivot:b2Body = createCircle(px, py, 1, false);

var _radian:Number = angle/180*Math.PI;

var _x:Number = Math.sin(_radian)*h;

var _y:Number = Math.cos(_radian)*h;

var circle:b2Body = createCircle(px+_x, py+_y, r, true);


createRevoluteJoint(pivot, circle, pivot.GetWorldCenter());

}


추가 고정될 위치를 먼저 잡습니다. joint는 반드시 두 body가 연결되어야하기 때문에 편의상 여기서는 반지름 1의 원을 하나 만들었습니다. 그리고 추는 고정되어야 하므로 static body 로 만들었구요.

그다음은 매개변수로 입력받은 초기 추의 각도를 기반으로 추가 생성될 좌표를 계산하는 코드입니다. 원운동의 좌표는 삼각함수로 미리 계산해 낼 수 있겠죠. cos 함수와 sin 함수 두개의 조합으로 원운동 좌표를 계산했습니다. 물론 radian 단위로 사용하기 때문에 degree->radian 변환도 했구요.

마지막으로 앞서 보여드린 소스중 revolute joint를 사용하는 코드입니다. 위에서 생성된 두 body와 기준 body의 중심점을 넘김으로써, 두 body가 revolute joint에 의해 엮입니다. 이렇게 하면 추는 중력의 영향을 받아서 위치변화량이 운동량으로 바뀌면서 진자 운동을 시작하겠네요.

function createRope(px:Number, py:Number, length:Number, thick:Number, seg:int = 10):void

{

var body1:b2Body = createBox(px, py, 1, 1, 0, false);

var body2:b2Body;

var pos:b2Vec2 = new b2Vec2(px, py);

var anchor:b2Vec2 = new b2Vec2(px/scale, py/scale);

var seg_w:Number = thick;

var seg_h:Number = length / seg;


for (var i:int = 0 ; i < seg ; i++) {

   body2 = createBox(pos.x,pos.y+seg_h/2,seg_w,seg_h,0,true);

   createRevoluteJoint(body1, body2, anchor);

   body1 = body2;

   pos.Set(pos.x, pos.y+seg_h);

   anchor.Set(pos.x/scale, pos.y/scale);

}

}


마지막 함수는 진자를 만드는 함수를 좀 더 응용해서 만들어본 밧줄 만드는 함수입니다. 시작위치와 밧줄의 길이, 두께, 촘촘함을 매개변수로 받아서 작은 box를 연결시켜줍니다.

위의 진자를 만드는 함수와 차이점이라면, 여러개의 body가 서로 꼬리를 물면서 revolute joint로 연결된다는 점입니다. 그리고 연결점은 기준 body의 중심점이 아닌 가장 꼬리부분으로 설정했습니다. 그렇게 해야 여로 엮여 있는 느낌이 나겠죠.

이런 joint를 만들면서 실수하기 쉬운부분은 바로 scale입니다. anchor point들은 화면 좌표계가 아닌 world 의 좌표계 이므로 픽셀 좌표로 보기 편하게 작업하던 방식과 혼돈하면 안됩니다. 그래서 포지션은 픽셀 단위로 사용하고 anchor point는 world 좌표계로 변환해서 사용했습니다. 이는 각 view와 world의 비율에 따라서 얼마든지 달라져야 하므로 개발시 상황에 맞게 튜닝 되야겠네요.

이렇게 만들어진 함수들을 초기화 함수에서 절절하게 호출해주면 이번 예제와 같은 모습이 나옵니다. 이 예제는 500 x 400 기분으로 ..

createPendulum(150, 0, 50, 350, -90);

for (var i:int = 1 ; i <= 4 ; i++) {

createRope(150+50*i, 0, 400, 10, 7);

}


이렇게 초기화 시켰습니다.

전체 소스를 첨부시키고 다음에..

'programming > box2d docs' 카테고리의 다른 글

b2PulleyJoint 예제  (0) 2011.02.01
b2PrismaticJoint 예제  (0) 2011.02.01
b2DistanceJoint 예제  (0) 2011.01.28
b2Body 예제 - Box2DFlash  (4) 2011.01.17
Box2DFlash v2.1a Update Notes 비공식 한글문서  (0) 2011.01.16

WRITTEN BY
buzzler

,