2
\$\begingroup\$

With mecanim, if you try to set a parameter that doesn't exist, it logs a warning. It doesn't throw an exception or return null or anything useful like that. So if I set a parameter very often that doesn't exist, a lot of CPU time is spent logging warnings. How can I tell if a parameter exists in an animatorcontroller? It would be great if there was a method like ProceduralMaterial.HasProceduralProperty (which allows you to check if the ProceduralMaterial has the property in question).

\$\endgroup\$
  • 1
    \$\begingroup\$ What function are you using to set a parameter? Also, HasProceduralProperty returns a true if it has that property. Is that not what you're looking for? \$\endgroup\$ – UnderscoreZero Aug 16 '13 at 15:36
  • \$\begingroup\$ No, HasProceduralProperty works on ProceduralMaterials. There isn't anything like that for Animators or animator controllers. And for whatever it's worth, I'm using SetFloat. Reworded question to emphasise mecanim. \$\endgroup\$ – Adam R. Grey Aug 16 '13 at 16:27
2
\$\begingroup\$

Simpler version, involve GC alloc on Animator.parameters, not cool for repeated call.

public static bool HasParameter( string paramName, Animator animator )
{
    foreach( AnimatorControllerParameter param in animator.parameters )
    {
        if( param.name == paramName )
            return true;
    }
    return false;
}

// Usage sample
public void SetFloatParamWithCheck( string paramName, float v )
{
    // animator defined elsewhere.
    Animator animator;     

    if( HasParameter( animator, paramName ) )
    {
        animator.SetFloat( paramName , v );
    }
}

Extension version, still involve GC alloc every call.

public static class AnimatorHelper
{
    public static bool ContainsParam( this Animator _Anim, string _ParamName )
    {
        foreach( AnimatorControllerParameter param in _Anim.parameters )
        {
            if( param.name == _ParamName ) return true;
        }
        return false;
    }
}

// Usage sample
public void SetFloatParamWithCheck( string paramName, float v )
{
    // animator defined elsewhere.
    Animator animator;     

    if( animator.ContainsParam( paramName ) )
    {
        animator.SetFloat( paramName , v );
    }
}

An over-engineered version. With caching and resolving parameter hash in one go. Premature optimization is evil but you will need it in (some) practice.

// Animator parameters query involve GC, cache it
// Animator.GetParameter( index ) might also internally use it, so no better.

Animator m_LastAnimatorCache; // Assume typically working with 1 animator, could extending to collect more cache.
Dictionary<string,int> m_AnimatorParamCache = new Dictionary<string,int>( ); // <key=paramname,value=hash>

private bool TryGetAnimatorParam( Animator animator, string paramName, out int hash )
{
    if( (m_LastAnimatorCache == null || m_LastAnimatorCache != animator) && animator != null ) // Rebuild cache
    {
        m_LastAnimatorCache = animator;
        m_AnimatorParamCache.Clear( );
        foreach( AnimatorControllerParameter param in animator.parameters )
        {
            int paramHash = Animator.StringToHash( param.name ); // could use param.nameHash property but this is clearer
            m_AnimatorParamCache.Add( param.name, paramHash );
        }
    }

    if( m_AnimatorParamCache != null && m_AnimatorParamCache.TryGetValue( paramName, out hash ) )
    {
        return true;
    }
    else
    {
        hash = 0;
        return false;
    }
}

// Usage sample
public void SetFloatParamWithCheck( string paramName, float v )
{
    // animator defined elsewhere.
    Animator animator;
    int hash;

    if( TryGetAnimatorParam( animator, paramName, out hash ) )
    {
        animator.SetFloat( hash, v );
    }
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.