Assets
The Idle Turn LMG needs three assets:
Rules
LMG
Game\Animations\human_male\lmg_files
.The Input should be of the type int and range from -1 to 1. The default value is 0, and the priority is 150 for the SDK graph. You can choose a different and maybe lower priority if you have your own custom graph or do not use IdleBreaks or "any value" state parameterizations. Below is a picture of the completely set up input.
The node details of the state are very similar to one of a oneshot or transition. It is important that the checkbox allowing the animation to be restarted is set active - this will allow the character to do multiple steps if he needs to (by re-entering the state).
The Selection Criteria of the Idle Turn state are very similar to the ones of the regular idle. You can set this up quickly by either creating this state as a clone from one of the idle states, or set them as a parent state. The only difference is the DesiredTurnSpeed, which must be set to a non-zero value. For zero values, the regular idle states should be selected.
This Selection Criteria must be matched by the idle state(s) in your graph.
Lastly the Movement Control Methods of all idle states need to be changed to even allow the animation and entity angles to deviate from another at all.
The default position deviation of -1 will use a hardcoded default value of 0.5 or in a debug build it will use the console variable value of: ac_animErrorMaxDistance.
Below is a picture on how the setup on each idle state and the idle turn state should look:
You can modify the angle at which the idle turn is triggered here, or integrate the code, if you have your own player implementation.
Change TRIGGER_TURN_ANGLE if you want the idle turns to be triggered sooner or later.
The code to calculate whether or not an idle turn is needed can be found in Player.cpp inside the GameDLL:
if ((frameTime != 0.0f) && (m_inputDesiredTurnSpeed != IAnimationGraph::InputID(-1)))
{
Quat offset = m_pAnimatedCharacter->GetAnimLocation().q.GetInverted() * pEnt->GetRotation();
float angle = RAD2DEG(offset.GetRotZ());
float angleMag = cry_fabsf(angle);
const float TRIGGER_TURN_ANGLE = 35.0f;
const float STOP_TURN_ANGLE = 0.05f;
if ( angleMag > TRIGGER_TURN_ANGLE)
{
m_lastReqTurnSpeed = (float) __fsel(angle, 1.0f, -1.0f);
}
else if ( angleMag > STOP_TURN_ANGLE)
{
// Check to see if we have reached our target (when the turn speed is in the opposite direction to the angle diff)
m_lastReqTurnSpeed = (float) __fsel(m_lastReqTurnSpeed*angle, m_lastReqTurnSpeed, 0.0f);
}
else
{
m_lastReqTurnSpeed = 0.0f;
}
GetAnimationGraphState()->SetInput(m_inputDesiredTurnSpeed, m_lastReqTurnSpeed);
}