不同的动作衔接的时候进行动画平滑过渡。通过m_bIdle和bCanMove控制动作的平滑过渡,SetMoveKey()是移动动画平滑过渡,SetIdleKey()是闲置动画平滑过渡
void CTiny::SetMoveKey()
{
DWORD dwNewTrack = ( m_dwCurrentTrack == 0 ? 1 : 0 );
LPD3DXANIMATIONCONTROLLER pAC;
LPD3DXANIMATIONSET pAS;
m_pAI->GetAnimController( &pAC );
if( m_fSpeed == m_fSpeedWalk )
pAC->GetAnimationSet( m_dwAnimIdxWalk, &pAS );
else
pAC->GetAnimationSet( m_dwAnimIdxJog, &pAS );
pAC->SetTrackAnimationSet( dwNewTrack, pAS );
pAS->Release();
pAC->UnkeyAllTrackEvents( m_dwCurrentTrack );
pAC->UnkeyAllTrackEvents( dwNewTrack );
pAC->KeyTrackEnable( m_dwCurrentTrack, FALSE, m_dTimeCurrent + MOVE_TRANSITION_TIME );
pAC->KeyTrackSpeed( m_dwCurrentTrack, 0.0f, m_dTimeCurrent, MOVE_TRANSITION_TIME, D3DXTRANSITION_LINEAR );
pAC->KeyTrackWeight( m_dwCurrentTrack, 0.0f, m_dTimeCurrent, MOVE_TRANSITION_TIME, D3DXTRANSITION_LINEAR );
pAC->SetTrackEnable( dwNewTrack, TRUE );
pAC->KeyTrackSpeed( dwNewTrack, 1.0f, m_dTimeCurrent, MOVE_TRANSITION_TIME, D3DXTRANSITION_LINEAR );
pAC->KeyTrackWeight( dwNewTrack, 1.0f, m_dTimeCurrent, MOVE_TRANSITION_TIME, D3DXTRANSITION_LINEAR );
m_dwCurrentTrack = dwNewTrack;
pAC->Release();
}
void CTiny::SetIdleKey( bool bResetPosition )
{
DWORD dwNewTrack = ( m_dwCurrentTrack == 0 ? 1 : 0 );
LPD3DXANIMATIONCONTROLLER pAC;
LPD3DXANIMATIONSET pAS;
m_pAI->GetAnimController( &pAC );
pAC->GetAnimationSet( m_dwAnimIdxLoiter, &pAS );
pAC->SetTrackAnimationSet( dwNewTrack, pAS );
pAS->Release();
pAC->UnkeyAllTrackEvents( m_dwCurrentTrack );
pAC->UnkeyAllTrackEvents( dwNewTrack );
pAC->KeyTrackEnable( m_dwCurrentTrack, FALSE, m_dTimeCurrent + IDLE_TRANSITION_TIME );
pAC->KeyTrackSpeed( m_dwCurrentTrack, 0.0f, m_dTimeCurrent, IDLE_TRANSITION_TIME, D3DXTRANSITION_LINEAR );
pAC->KeyTrackWeight( m_dwCurrentTrack, 0.0f, m_dTimeCurrent, IDLE_TRANSITION_TIME, D3DXTRANSITION_LINEAR );
pAC->SetTrackEnable( dwNewTrack, TRUE );
pAC->KeyTrackSpeed( dwNewTrack, 1.0f, m_dTimeCurrent, IDLE_TRANSITION_TIME, D3DXTRANSITION_LINEAR );
pAC->KeyTrackWeight( dwNewTrack, 1.0f, m_dTimeCurrent, IDLE_TRANSITION_TIME, D3DXTRANSITION_LINEAR );
if( bResetPosition )
pAC->SetTrackPosition( dwNewTrack, 0.0 );
m_dwCurrentTrack = dwNewTrack;
pAC->Release();
}
SmoothLotier()是闲置时候进行的闲置动画的平滑过渡
void CTiny::SmoothLoiter()
{
LPD3DXANIMATIONCONTROLLER pAC;
LPD3DXANIMATIONSET pASTrack, pASLoiter;
m_pAI->GetAnimController( &pAC );
// check if we're loitering
pAC->GetTrackAnimationSet( m_dwCurrentTrack, &pASTrack );
pAC->GetAnimationSet( m_dwAnimIdxLoiter, &pASLoiter );
if( pASTrack && pASTrack == pASLoiter )
{
D3DXTRACK_DESC td;
pAC->GetTrackDesc( m_dwCurrentTrack, &td );
if( td.Position > pASTrack->GetPeriod() - IDLE_TRANSITION_TIME ) // come within the change delta of the end
SetIdleKey( true );
}
SAFE_RELEASE( pASTrack );
SAFE_RELEASE( pASLoiter );
SAFE_RELEASE( pAC );
}
应用代码为
void CTiny::Animate( double dTimeDelta )
{
// adjust position and facing based on movement mode
if( m_bUserControl )
AnimateUserControl( dTimeDelta ); // user-controlled
else if( m_bIdle )
AnimateIdle( dTimeDelta ); // idling - not turning toward
else
AnimateMoving( dTimeDelta ); // moving or waiting - turning toward
// loop the loiter animation back on itself to avoid the end-to-end jerk
SmoothLoiter();
D3DXMATRIX mxWorld, mx;
// compute world matrix based on pos/face
D3DXMatrixRotationY( &mxWorld, -m_fFacing );
D3DXMatrixTranslation( &mx, m_vPos.x, m_vPos.y, m_vPos.z );
D3DXMatrixMultiply( &mxWorld, &mxWorld, &mx );
D3DXMatrixMultiply( &mxWorld, &m_mxOrientation, &mxWorld );
m_pAI->SetWorldTransform( &mxWorld );
}
void CTiny::AnimateUserControl( double dTimeDelta )
{
// use keyboard controls to make Tiny move
bool bCanMove;
if( GetKeyState( 'V' ) < 0 )
{
m_bUserControl = false;
SetSeekingState();
return;
}
if( GetKeyState( 'W' ) < 0 )
{
bCanMove = true;
if( GetAsyncKeyState( VK_SHIFT ) < 0 )
{
if( m_fSpeed == m_fSpeedWalk )
{
m_fSpeed = m_fSpeedJog;
m_bIdle = true; // Set idle to true so that we can reset the movement animation below
}
}
else
{
if( m_fSpeed == m_fSpeedJog )
{
m_fSpeed = m_fSpeedWalk;
m_bIdle = true; // Set idle to true so that we can reset the movement animation below
}
}
D3DXVECTOR3 vMovePos;
GetFacing( &vMovePos );
D3DXVec3Scale( &vMovePos, &vMovePos, float( m_fSpeed * GetSpeedScale() * dTimeDelta ) );
D3DXVec3Add( &vMovePos, &vMovePos, &m_vPos );
// is our step ahead going to take us out of bounds?
if( IsOutOfBounds( &vMovePos ) )
bCanMove = false;
// are we stepping on someone else?
if( IsBlockedByCharacter( &vMovePos ) )
bCanMove = false;
if( bCanMove )
m_vPos = vMovePos;
}
else
bCanMove = false;
if( m_bIdle && bCanMove )
{
SetMoveKey();
m_bIdle = false;
}
if( !m_bIdle && !bCanMove )
{
SetIdleKey( true );
m_bIdle = true;
}
// turn
if( GetKeyState( 'A' ) < 0 )
m_fFacing = float( m_fFacing + m_fSpeedTurn * dTimeDelta );
if( GetKeyState( 'D' ) < 0 )
m_fFacing = float( m_fFacing - m_fSpeedTurn * dTimeDelta );
}