HavokActor

캐릭터 움직임을 하복 데모를 통해서 살펴 보자.

캐릭터의 움직임 타입은 아래 두가지가 있다.

hkpCharacterContext::HK_CHARACTER_PROXY
hkpCharacterContext::HK_CHARACTER_RIGIDBODY

이 타입은 hkpCharacterContext::setCharacterType( )으로 셋팅 한다.

HavokActor 클래스에서 메소드를 다음 순서로 알아 본다.
HavokActor::HavokActor( )
HavokActor::CreateCapsuleProxy( )
HavokActor::DeleteProxy( )
HavokActor::UpdateStep( )
HavokActor::SetPosition( )

HavokActor::HavokActor()

{

    //y-up 셋팅

    m_characterProxy = 0L;

    m_up.set( 0.0f, 1.0f, 0.0f );;

    m_forward.set( 0.0f, 0.0f, 1.0f );

 

    ....................

    {

        hkpCharacterState* state;

        hkpCharacterStateManager* manager = new  hkpCharacterStateManager();

 

        state = new  hkpCharacterStateOnGround();

        manager->registerState( state,    HK_CHARACTER_ON_GROUND);

        state->removeReference();

        ..................

        m_characterContext = new  hkpCharacterContext(manager, HK_CHARACTER_ON_GROUND);

        m_characterContext->setCharacterType( hkpCharacterContext::HK_CHARACTER_PROXY );

        //output의 최대 속도, 최대 가속도를 설정하는것으로 속도 제한을 없을려면 주석을 제거한다.

        //m_characterContext->setFilterParameters(0.9f, 30, 400.0f);

        manager->removeReference();

    }

}

hkpCharacterStateManager::registerState( )로 hkpCharacterStateOnGround, hkpCharacterStateInAir, hkpCharacterStateJumping, hkpCharacterStateClimbing 객세츨 등록한 다음 m_charactgerContext에 상태를 설정한다.

m_characterContext->setFilterParameters(0.9f, 30, 400.0f);

위 코드는 hkpCharacterContext의 input에서 output로 변환시 최대 속도와 최대 가속도를 재 설정하게 해준다. setFilterParameters( )를 사용하지 않으면 output은 기본적으로 설정되어 있는 최대 속도를 넘지 못한다.

void  HavokActor::CreateCapsuleProxy( const  hkVector4& position, float  strength, float  mass )

{

    hkReal height = CHARACTER_SCALE_RATIO * 0.4f;

    hkReal radius = CHARACTER_SCALE_RATIO * 0.490f;

 

    hkpCapsuleShape* characterShape;

    const  hkReal halfHeight = height*0.5f;

 

    hkVector4 vertexA(0, 0, halfHeight );

    hkVector4 vertexB(0, 0, -halfHeight );

 

    // Create a capsule to represent the character standing

    characterShape = new  hkpCapsuleShape(vertexA, vertexB, radius);

 

    // Construct a Shape Phantom

    hkpSimpleShapePhantom* phantom = new  hkpSimpleShapePhantom(

        characterShape,

        hkTransform::getIdentity(),

        hkpGroupFilter::calcFilterInfo(HavokManager::LAYER_ACTOR, 0 ));

    characterShape->removeReference();

 

    hkpWorld* pWorld = HavokManager::Instance()->GetWorld();

    pWorld->lock();

 

    // Add the phantom to the world

    pWorld->addPhantom(phantom);

    phantom->removeReference();

 

    // Construct a character proxy

    hkpCharacterProxyCinfo cpci;

    cpci.m_position.set(position(0), position(1), position(2));

    cpci.m_staticFriction = 0.0f;

    cpci.m_dynamicFriction = 1.0f;

    cpci.m_up.setNeg4( pWorld->getGravity() );

    cpci.m_up.normalize3();

    cpci.m_userPlanes = 4;

    cpci.m_maxCharacterSpeedForSolver = 1000.0f;

    cpci.m_maxSlope = 90.0f * HK_REAL_DEG_TO_RAD; //HK_REAL_PI / 3;

 

    cpci.m_shapePhantom = phantom;

    cpci.m_characterStrength = strength;

    cpci.m_characterMass = mass;

    this->m_characterProxy = new  hkpCharacterProxy(cpci);

 

    pWorld->unlock();

}

hkpCapsuleShape를 만들어 hkpSimpleShapePhantom의 오브젝트인 phantom으로 넘긴다.
phantom은 hkpWorld, hkpCharacterProxyCinfo에 추가한다.

hkpCharacterProxyCinfo 속성을 간단하게 살펴보자.

m_position : 위치
m_staticFriction : 정적인 마찰력
m_dynamicFriction : 동적인 마찰력
m_up : UP 좌표계
m_maxSlope : 캐릭터가 올라갈수 있는 최대 경사도
m_characterMass : 질량

 

void  HavokActor::DeleteProxy()

{

    hkpWorld* pWorld = HavokManager::Instance()->GetWorld();

    pWorld->lock();

    pWorld->removePhantom( this->m_characterProxy->getShapePhantom() );

    this->m_characterProxy->removeReference();

    this->m_characterProxy = HK_NULL;

    pWorld->unlock();

}

hkpCharacterProxy를 삭제한다.

void  HavokActor::UpdateStep( float  timestep )

{

    float  fDX = 0.0f;

    float  fDZ = 0.0f;

    float  fStepWidth = CHARACTER_SCALE_RATIO * 0.5f;;

 

    bool  jump = false;

    if( GetKey( VK_SPACE ) )

        jump = true;

 

    if( GetKey( VK_UP ) )

    {

        fDZ -= fStepWidth;

    }

 

    if( GetKey( VK_DOWN ) )

    {

        fDZ += fStepWidth;

    }

 

    if( GetKey( VK_LEFT ) )

    {

        fDX -= fStepWidth;

    }

 

    if( GetKey( VK_RIGHT ) )

    {

        fDX += fStepWidth;

    }

 

    hkpWorld* pWorld = HavokManager::Instance()->GetWorld();

    if( pWorld == 0L )

        return;

 

    pWorld->lock();

 

    hkpCharacterInput input;

    hkpCharacterOutput output;

    {

        input.m_inputLR = fDX;

        input.m_inputUD = fDZ;

 

        input.m_wantJump = jump;

        input.m_atLadder = false;

 

        input.m_up = m_up;

        input.m_forward = m_forward;

 

        hkQuaternion orient;

        orient.setAxisAngle( m_up, 0 );

        input.m_forward.setRotatedDir( orient, input.m_forward );

 

        hkVector4 characterGravity = m_up;

        float  gravity = -16 * CHARACTER_SCALE_RATIO;

        characterGravity.mul4( hkVector4(  gravity, gravity, gravity ) );  

        input.m_characterGravity = characterGravity;

 

        input.m_stepInfo.m_deltaTime = timestep;

        input.m_stepInfo.m_invDeltaTime = 1.0f / timestep;

        input.m_velocity = m_characterProxy->getLinearVelocity();

        input.m_position = m_characterProxy->getPosition();

 

        hkVector4 down;    down.setNeg4( m_up );

        hkpSurfaceInfo ground;

        m_characterProxy->checkSupport(down, ground);

 

        input.m_surfaceInfo = ground;

        // Apply the character state machine

        {

            HK_TIMER_BEGIN( "update character state", HK_NULL );

            m_characterContext->update(input, output);

            HK_TIMER_END();

        }

    }

 

    //Apply the player character controller   

    {

        m_characterProxy->setLinearVelocity( output.m_velocity );

        hkStepInfo si( hkTime(0.0f), hkTime(timestep) );

        m_characterProxy->integrate( si, pWorld->getGravity() );

    }

 

    pWorld->unlock();

}

 

UpdateStep( )에 물리 시뮬레이션을 업데이트 한다. 키보드를 눌러서 input에 값을 셋팅한다.
m_characterContext->update(input, output)으로 output으로 반환한다.

 

setLinearVelocity( )로 속도를 설정한다음 프록시에 통합한다.

m_characterProxy->setLinearVelocity( output.m_velocity );

 

void  HavokActor::SetPosition( float  x, float  y, float  z )

{

    hkpWorld* pWorld = HavokManager::Instance()->GetWorld();

    pWorld->lock();

    pWorld->markForWrite();

 

    hkVector4 pos( x, y, z );

    m_characterProxy->setPosition( pos );

 

    pWorld->unmarkForWrite();

    pWorld->unlock();

}

캐릭터 위치를 이동 시킨다.

프로젝트 : havok_actor.zip