hkpTriggerVolume

hkpTriggerVolume을 이용하면 hkpRigidBody를 트리거로 사용 할 수 있다.
기본 도형인 박스만 원모양의 도형은 물론, 3DSMAX에서 익스포트한 hkpRigidBody를 트리거로 등록 할 수 있다.

Collider인 RigidBody가 Collidee hkpTriggerVolume에 충돌 되면 트리거가 발동된다. 포함관계는 지원 되는지 찾을수 없다.

트리거 생성, 트리거 콜백, hkpRigidBody를 트리거에 등록, 트리거 이벤트  4가지로 나눠서 알아 본다.

< 트리거 생성 >

class  HavokTriggerVolume : public  hkpTriggerVolume

{

public:

    HavokTriggerVolume( hkpRigidBody* triggerBody, HavokTrigger* pTrigger );

 

    // Bring in the other callback we are not overriding

    using  hkpTriggerVolume::triggerEventCallback;

    virtual  void  triggerEventCallback( hkpRigidBody* body, EventType type );

 

private:

    HavokTrigger* m_pOwner;   

};

hkpTriggerVolume을 상속하여 트리거를 만든다.
HavokTrigger 클래스는 hkpTriggerVolume에 등록하는 RigidBody를 관리한다.
메인 루프에서 실제로 접근하는 클래스는 HavokTrigger 클래스이다.
 

< 트리거 콜백 >

void  HavokTriggerVolume::triggerEventCallback( hkpRigidBody* body, EventType type )

{

    if ( type & ENTERED_EVENT )

    {

        if( body->hasProperty( HAVOK_UID_PROPERTY ) )

        {

            int  uid = 0;

            uid = body->getProperty( HAVOK_UID_PROPERTY ).getInt();

            std::vector<int>& idArr = m_pOwner->GetIDArray();

            idArr.push_back( uid );

            OutputDebugPrintf( "박스 트리거 발동 시작: %d\n", uid );

        }

    }

    else  if ( type & LEFT_EVENT )

    {

        if( body->hasProperty( HAVOK_UID_PROPERTY ) )

        {

            int  uid = 0;

            uid = body->getProperty( HAVOK_UID_PROPERTY ).getInt();

            std::vector<int>& idArr = m_pOwner->GetIDArray();

            std::vector<int>::iterator iter = std::find( idArr.begin(), idArr.end(), uid );

            if( iter != idArr.end() )

            {

                idArr.erase( iter );

            }

            OutputDebugPrintf( "박스 트리거 발동 종료: %d\n", uid );

        }

    }

}

EventType이 ENTERED_EVENT이면 충돌이 발생했을 때, LEFT_EVENT 이면 충돌이 끝났을 때 콜백이 불리운다.
충돌시 HAVOK_UID_PROPERTY의 속성을 별도로 저장하여 hkpRigidBody의 ID를 저장한다.
HAVOK_UID_PROPERTY 속성의 ID로 어떤 RigidBody가 충돌했는지 알수 있다.

< hkpRigidBody를 트리거에 등록 >

bool  HavokTrigger::Create( hkpWorld* pWorld, int  id, const  TriggerBox& trBox )

{

    const  PhysicsDefine::Vector3&    pos = trBox.pos;

    const  PhysicsDefine::Vector3&    halfExtent = trBox.halfExtent;

 

    pWorld->lock();

 

    hkpShape* boxShape = hkpShapeGenerator::createConvexVerticesBox( hkVector4( halfExtent.x, halfExtent.y, halfExtent.z ) );

 

    hkpRigidBodyCinfo boxInfo;

    boxInfo.m_motionType = hkpMotion::MOTION_FIXED;

    boxInfo.m_shape = boxShape;

 

    boxInfo.m_position.set( pos.x, pos.y, pos.z );

 

    hkpRigidBody* box = new  hkpRigidBody( boxInfo );

    box->addProperty( HAVOK_UID_PROPERTY, id );

 

    pWorld->addEntity( box );

    boxShape->removeReference();

 

    ( new  HavokTriggerVolume( box, this ) )->removeReference();

 

    pWorld->unlock();

    m_world = pWorld;

    m_pRigidBody = box;

 

    if( HavokDebug::Instance() )

        HavokDebug::Instance()->MakeMesh( boxShape, m_pRigidBody, true );

 

    return  true;

}

hkpTriggerVolume을 상속한 클래스에 hkpRigidBody를 등록해야 충돌시 트리거 콜백이 실행된다.
 ( new  HavokTriggerVolume( box, this ) )->removeReference( )에서 RigidBody를 등록해주고 있다.

HavokDebug::Instance()->MakeMesh( boxShape, m_pRigidBody, true )는 트리거를 눈으로 보여주고 디버깅 하기 위해 렌더링 하는 명령이다.

< 트리거 이벤트 >

std::vector<int>& uidArr = g_boxTrigger->m_charIDArr;

std::vector<int>::iterator intIter = std::find( uidArr.begin(), uidArr.end(), SPHERE_ID );

 

char strDisplay[128];

if( intIter != uidArr.end() )   

    sprintf_s( strDisplay, 128, "'2'키:스태틱박스 공통과, '3'키: 스택틱박스 충돌    Sphere %d는 트리거와 충돌", SPHERE_ID );

else

    sprintf_s( strDisplay, 128, "'2'키:스태틱박스 공통과, '3'키: 스택틱박스 충돌    Sphere %d는 트리거와 미충돌", SPHERE_ID );

HavokTrigger의 g_boxTrigger를 통하여 트리거가 발동 되었는지 체크 한다.
m_charIDArr에 트리거와 충돌한 RigidBody의 ID를 저장된다.
HavokTrigger는 트리거의 매니저가 아니다. 한 개의 RigidBody, 한 개의 hkpTriggerVolume만 처리한다.
아니면 RigidBody가 여러개이더라도 하나의 RigidBody처럼 처리하는 것은 문제가 없다.

프로젝트 : havok_triggerVolume.zip