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\$
2
  • 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\$ Aug 16, 2013 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\$ Aug 16, 2013 at 16:27

1 Answer 1

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\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .