mixedreality/com.microsoft.mixedreality..../SDK/Experimental/InteractiveElement/StateViz/AnimationTarget.cs

178 lines
6.4 KiB
C#

// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License
using Microsoft.MixedReality.Toolkit.Utilities;
using System;
using System.Collections.Generic;
using UnityEngine;
namespace Microsoft.MixedReality.Toolkit.Experimental.StateVisualizer
{
/// <summary>
/// Definition class for an animation target, utilized in the State Visualizer component.
/// </summary>
[Serializable]
public class AnimationTarget
{
[SerializeField]
[Tooltip("The target game object for animations.")]
private GameObject target;
/// <summary>
/// The target game object for animations.
/// </summary>
public GameObject Target
{
get => target;
set
{
if (IsTargetObjectValid(value))
{
target = value;
}
else
{
target = null;
Debug.LogError("The Target property can only be a child of this game object, the target was set back to null");
}
}
}
[SerializeReference]
[Tooltip("List of animatable properties for the target game object. Scale and material color are examples of animatable properties.")]
private List<IStateAnimatableProperty> stateAnimatableProperties = new List<IStateAnimatableProperty>();
/// <summary>
/// List of animatable properties for the target game object. Scale and material color are examples of animatable properties.
/// </summary>
public List<IStateAnimatableProperty> StateAnimatableProperties
{
get => stateAnimatableProperties;
internal set => stateAnimatableProperties = value;
}
/// <summary>
/// Set the keyframes on an AnimationClip.
/// </summary>
public void SetKeyFrames(AnimationClip animationClip)
{
foreach (var animatableProperty in StateAnimatableProperties)
{
animatableProperty.Target = Target;
animatableProperty.SetKeyFrames(animationClip);
}
}
/// <summary>
/// Remove keyframes for a given animatable property.
/// </summary>
public void RemoveKeyFrames(string animatablePropertyName, AnimationClip animationClip)
{
IStateAnimatableProperty animatableProperty = GetAnimatableProperty(animatablePropertyName);
if (animatableProperty != null)
{
animatableProperty.RemoveKeyFrames(animationClip);
}
}
private IStateAnimatableProperty GetAnimatableProperty(string animatablePropertyName)
{
return StateAnimatableProperties.Find((prop) => prop.AnimatablePropertyName == animatablePropertyName);
}
private bool IsTargetObjectValid(GameObject target)
{
return target.transform.FindAncestorComponent<StateVisualizer>(true);
}
internal StateAnimatableProperty CreateAnimatablePropertyInstance(string animatablePropertyTypeName, string stateName)
{
StateAnimatableProperty animatableProperty;
// Find matching event configuration by state name
var animatablePropertyTypes = TypeCacheUtility.GetSubClasses<StateAnimatableProperty>();
Type animatablePropertyType = animatablePropertyTypes.Find((type) => type.Name.StartsWith(animatablePropertyTypeName));
if (animatablePropertyType != null)
{
if (CanAddAnimatableProperty(animatablePropertyTypeName))
{
// If a state has an associated event configuration class, then create an instance with the matching type
animatableProperty = Activator.CreateInstance(animatablePropertyType) as StateAnimatableProperty;
}
else
{
animatableProperty = null;
Debug.LogError($"Only one {animatablePropertyTypeName} animatable property can be present for this target object.");
}
if (animatableProperty != null)
{
animatableProperty.StateName = stateName;
animatableProperty.Target = Target;
// Generate unique id for shader properties because multiple shader properties can be
// animated on a single target object
if (animatablePropertyTypeName.Contains("Shader"))
{
int shaderPropertyID = GenerateIDShaderProperty();
animatableProperty.AnimatablePropertyName = animatablePropertyTypeName + "_" + shaderPropertyID;
}
StateAnimatableProperties.Add(animatableProperty);
}
}
else
{
animatableProperty = null;
Debug.Log("The animatableProperty property name given does not have a matching configuration type");
}
return animatableProperty;
}
public StateAnimatableProperty AddNewAnimatableProperty(AnimatableProperty animatablePropertyTypeName, string stateName)
{
return CreateAnimatablePropertyInstance(animatablePropertyTypeName.ToString(), stateName);
}
private bool CanAddAnimatableProperty(string animatablePropertyTypeName)
{
// Multiple animatable shader properties can be present on one target object
if (animatablePropertyTypeName.Contains("Shader"))
{
return true;
}
// Ensure that there is only one Scale and Position Offset property per target game object
foreach (var animatableProp in StateAnimatableProperties)
{
if (animatableProp.AnimatablePropertyName == animatablePropertyTypeName)
{
return false;
}
}
return true;
}
private int GenerateIDShaderProperty()
{
int i = 0;
foreach (var animatableProp in StateAnimatableProperties)
{
if (animatableProp is ShaderStateAnimatableProperty)
{
i++;
}
}
return i;
}
}
}