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).
-
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\$– UnderscoreZeroAug 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\$– Adam R. GreyAug 16, 2013 at 16:27
1 Answer
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 );
}
}