HavokCharacter

이번장에는 hkpCharacterContext::HK_CHARACTER_RIGIDBODY 타입으로 셋팅하여 캐릭터를 제어 한다.

다음의 메소드 순서로 알아 본다.

void HavokCharacter::Create( )
void HavokCharacter::Destroy()
void HavokCharacter::Update( )
void HavokCharacter::SetPosition( )

void HavokCharacter::Create( const hkVector4& position )

{

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

    hkVector4 scaledPosition = position;

    scaledPosition.mul4( fHAVOK_SCALE );

 

    // Define the shapes for the controller

    hkVector4 va( 0.0f, 0.0f, 0.1f );

    hkVector4 vb( 0.0f, 0.0f, -0.1f );

    m_pStandShape = new hkpCapsuleShape( va, vb, 1.1f );       

 

    va.setZero4();

    m_pCrouchShape = new hkpCapsuleShape( va, vb, 0.6f );

 

    // Construct a character rigid body

    hkpCharacterRigidBodyCinfo characterRigidBodyCInfo;

    characterRigidBodyCInfo.m_mass = 100.0f;

    characterRigidBodyCInfo.m_shape = m_pStandShape;

 

    characterRigidBodyCInfo.m_maxForce = 1000.0f;

    characterRigidBodyCInfo.m_up = m_up;

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

    //characterRigidBodyCInfo.m_maxSlope = 65.0f * HK_REAL_DEG_TO_RAD;

    characterRigidBodyCInfo.m_maxSlope = 90.0f * HK_REAL_DEG_TO_RAD;

    characterRigidBodyCInfo.m_friction = 0;

    characterRigidBodyCInfo.m_unweldingHeightOffsetFactor = 5;

    characterRigidBodyCInfo.m_maxLinearVelocity = 1000;

 

    m_pHavokRigidBody = new hkpCharacterRigidBody( characterRigidBodyCInfo );

 

    hkpCharacterRigidBodyListener* pListener = new hkpCharacterRigidBodyListener();

    m_pHavokRigidBody->setListener( pListener );

    pListener->removeReference();

 

    pWorld->lock();

    pWorld->markForWrite();

 

    pWorld->addEntity( m_pHavokRigidBody->getRigidBody() );

 

    hkpCharacterState* pState = NULL;

    hkpCharacterStateManager* pManager = new hkpCharacterStateManager();

 

    pState = new hkpCharacterStateOnGround();

    pManager->registerState( pState, HK_CHARACTER_ON_GROUND );

    pState->removeReference();

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

    m_characterContext = new hkpCharacterContext( pManager, HK_CHARACTER_ON_GROUND );

    pManager->removeReference();

 

    m_characterContext->setCharacterType( hkpCharacterContext::HK_CHARACTER_RIGIDBODY );

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

 

    pWorld->unmarkForWrite();

    pWorld->unlock();

}

캐릭터의 충돌체를 일반적인 형태 m_pStandShape와 쭈그린 m_pCrouchShape로 두 개를 만들어 사용한다.

HavokActor처럼 hkpCharacterStateManager에  다음의 캐릭터 상태를 등록한다.

hkpCharacterStateOnGround
hkpCharacterStateInAir
hkpCharacterStateJumping
hkpCharacterStateClimbing

hkpCharacterStateManager로 hkpCharacterContext를 설정한다.
캐릭터 타입은 hkpCharacterContext::HK_CHARACTER_RIGIDBODY로 설정한다.

output의 최대 속도를 설정하는 setFilterParameters( )는 주석 처리 한다.

void  HavokCharacter::Destroy()

{

    if( !m_bActive )

        return;

 

    m_bActive = false;

 

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

    if( pWorld == NULL )

        return;

 

    m_pHavokRigidBody->removeReference();

    m_pStandShape->removeReference();

    m_pCrouchShape->removeReference();

    delete  m_characterContext;

    m_pHavokRigidBody = NULL;

}

충돌 메쉬와 m_characterContext, m_pHavokRigidBody를 해제한다.

void  HavokCharacter::Update( const  float  fTimestep )

{

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

    if( pWorld == NULL )

        return;

 

    if( m_pHavokRigidBody == NULL )

        return;

 

    const  bool  bJump = m_bCameraControl && ( !m_bOldJump && GetKey( VK_SPACE ) );

    const  bool  bCrouch = m_bCameraControl && GetKey( 'C' );

    m_bOldJump = m_bCameraControl && GetKey( VK_SPACE );

 

    pWorld->lock();

    pWorld->markForWrite();

 

 

    hkVector4 p = m_pHavokRigidBody->getPosition();

 

    // TODO - the input code belongs in a player class or something

    hkpCharacterInput    xInput;

    hkpCharacterOutput    output;

 

    float  fDX = 0.0f;

    float  fDZ = 0.0f;

    float  fStepWidth = CHARACTER_SCALE_RATIO * 0.5f;

 

    if( m_bCameraControl )

    {

        if( GetKey( VK_UP ) )

        {

            fDZ -= fStepWidth;

        }

 

        if( GetKey( VK_DOWN ) )

        {

            fDZ += fStepWidth;

        }

 

        if( GetKey( VK_LEFT ) )

        {

            fDX -= fStepWidth;

        }

 

        if( GetKey( VK_RIGHT ) )

        {

            fDX += fStepWidth;

        }

    }

    else

    {

        fDX = m_xMovement.x;

        fDZ = m_xMovement.y;

    }

 

    xInput.m_inputLR = fDX;

    xInput.m_inputUD = fDZ;

 

    xInput.m_wantJump = bJump;

    xInput.m_atLadder = false;

 

    xInput.m_up = m_up;

 

    xInput.m_forward = m_forward;

    xInput.m_forward.normalize3();

 

    hkQuaternion orient;

    orient.setAxisAngle( m_up, 0 );

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

 

    hkStepInfo stepInfo;

    stepInfo.m_deltaTime = fTimestep;

    stepInfo.m_invDeltaTime = 1.0f / fTimestep;

    //stepInfo.m_endTime = HavokManager::Instance()->GetStopwatch()->getElapsedSeconds();

    xInput.m_stepInfo = stepInfo;

 

    hkVector4 characterGravity = m_up;

    float gravity = -16 * CHARACTER_SCALE_RATIO;

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

    xInput.m_characterGravity = characterGravity;

 

    hkpRigidBody* const  pRigidBody = m_pHavokRigidBody->getRigidBody();

 

    xInput.m_velocity = pRigidBody->getLinearVelocity();

    xInput.m_position = pRigidBody->getPosition();

 

    m_pHavokRigidBody->checkSupport( stepInfo, xInput.m_surfaceInfo );

 

    const  hkpCollidable* const  pCollidable = pRigidBody->getCollidable();

    if( pRigidBody == NULL )

    {

        assert( 0 && "A character's Havok collidable pointer has been nulled. We are going to assume they aren't crouching." );

    }

 

    const  bool  bIsCrouched = pCollidable ? ( pRigidBody->getCollidable()->getShape() == m_pCrouchShape ) : false;

 

    if ( bIsCrouched && !bCrouch )

        pRigidBody->setShape( m_pStandShape );

 

    if ( !bIsCrouched && bCrouch )

        pRigidBody->setShape( m_pCrouchShape );

 

    // Calculate and set current acceleration for mass factor modifier

    {

        // calculate and set acceleration for mass factor modifier

        hkVector4 currentVel;

        currentVel = pRigidBody->getLinearVelocity();

 

        hkVector4 currentAcc;

        currentAcc.setSub4(output.m_velocity, currentVel);

        currentAcc.mul4( 1/fTimestep );

 

        m_pHavokRigidBody->setLinearAccelerationToMassModifier(currentAcc);

    }

 

 

    // Apply the character state machine

    m_characterContext->update( xInput, output );

    m_pHavokRigidBody->setLinearVelocity( output.m_velocity, fTimestep );

 

    pWorld->unmarkForWrite();

    pWorld->unlock();

}

물리 시뮬레이션을 하는 곳이다.

키보드 입력값으로 input 값을 채워서 output으로 변환한다.
m_characterContext->update( xInput, output )

속도를 설정한다.

m_pHavokRigidBody->setLinearVelocity( output.m_velocity, fTimestep )

 

프록시 형인 hkpCharacterContext::HK_CHARACTER_PROXY과는 달리 intergrate( ) 명령이 필요 없다.

 

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

{

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

    pWorld->lock();

    pWorld->markForWrite();

 

    hkVector4 pos( x, y, z );

 

    hkpRigidBody* pRigidBody = m_pHavokRigidBody->getRigidBody();

    pRigidBody->setPosition( pos );

 

    pWorld->unmarkForWrite();

    pWorld->unlock();

}

캐릭터 위치를 설정한다.

 

프로젝트 : havok_character.zip