Can I AddClip() to Animation component during GameLoop?
Hi!
Game Engineering Student here.
Designer requested to be able to design individual cam-shakes + SFX which can be triggered by various in-game events, from whereever, whenever.
Somehow the idea of tidily pre-built animations doesn't appeal to him . . .
so, I am using the pop-up EditorGUICurveField from here. in conjunction with my adapted SetAnimCurvesAndBuildClip so the designer can add this to any object he wants.
He can design his ideal Shake, add the Trigger script, and rest easy knopwing his bespoke camShake will be triggered by whatever even he wants.
Anyway, the animationClip jsut WILL NOT be added to he Animation component of the camera...
I am beginning to suspect that Clips can only be added in the Inspector or latest at Start().
can anyone browse this sea of C# and enlighten me as to where I am going wrong?
public class SetAnimCurvesAndBuildClip : MonoBehaviour
{
[SerializeField] private AnimationCurve curveX;
[SerializeField] private AnimationCurve curveY;
[SerializeField] private AnimationCurve curveZ;
[HideInInspector] public AnimationClip thisAnimation;
// called by the Editor SCript ShakeTriggerEditor
public void SetCurves(AnimationCurve xC, AnimationCurve yC, AnimationCurve zC)
{
// Set curves for visibility in Inspector
curveX = xC;
curveY = yC;
curveZ = zC;
}
private void Awake()
{
// create clip and assign curves
thisAnimation = new AnimationClip();
thisAnimation.SetCurve("", typeof(Transform), "localPosition.x", curveX);
thisAnimation.SetCurve("", typeof(Transform), "localPosition.y", curveY);
thisAnimation.SetCurve("", typeof(Transform), "localPosition.z", curveZ);
}
}
As you can see, on Awake() these curves are built into an AnimationClip.
Now, I have a Trigger Script, which builds one of these on Start()
public class AnimAndSFXPair
{
public string effectName;
public AnimationClip anim;
public AudioClip audio;
public AnimAndSFXPair(string newName, AnimationClip newAnim, AudioClip newAudio)
{
effectName = newName;
anim = newAnim;
audio = newAudio;
}
}
The idea is that when I press my test button, or the trigger is activated, the Trigger script sends the AnimAndSFCPair to the named Game Object.
public class ShakeTrigger : MonoBehaviour
{
[SerializeField] string effectPairName;
[SerializeField] private string objectToTrigger;
PlayAnimAndSFX componentToCall;
SetAnimCurvesAndBuildClip animationCreator;
AnimationClip animClip;
[SerializeField] private AudioClip audioClip;
AnimAndSFXPair FXobject;
//..................... In-Game Functionality .................................................
private void Update()
{
if (Input.GetKeyDown(KeyCode.RightShift))
{
componentToCall.SendMessage("BeginShakeEffect", FXobject);
}
}
void OnTriggerEnter(Collider other)
{
if(other.CompareTag("Player"))
{
Debug.Log("Shake trigger activated!");
componentToCall.SendMessage("BeginShakeEffect", FXobject);
}
}
//..................... In-Game Functionality END .............................................
//..................... Construction @ Start ..........................................
void FindObjectToEffect()
{
componentToCall = GameObject.Find(objectToTrigger).GetComponent<PlayAnimAndSFX>();
if (componentToCall == null)
{
Debug.LogError("Trigger " + transform.name +
" cannot find " + objectToTrigger);
}
}
void FindAnimationClip()
{
animationCreator = GetComponent<SetAnimCurvesAndBuildClip>();
if(animationCreator == null)
{
Debug.LogError("Trigger " + transform.name +
" cannot find its SetAnimCurvesAndBuildClip");
}
else
{
animClip = animationCreator.thisAnimation;
animClip.name = effectPairName;
if(animClip == null)
{
Debug.LogError("Trigger " + transform.name +
" cannot find its animation Clip");
}
}
}
private void Start()
{
FindObjectToEffect();
FindAnimationClip();
FXobject = new AnimAndSFXPair(effectPairName, animClip, audioClip);
Debug.Log("FXobject.EffectName: " + FXobject.effectName +
"\nClip Object Name: " + FXobject.anim +
"\nAudioName:" + FXobject.audio);
}
//..................... Construction @ Start END ......................................
}
This is the script it finds on the named game Object (in this case the main camera)
public class PlayAnimAndSFX : MonoBehaviour
{
private Animation animator;
private AudioSource audioSouce;
// called by Trigger
public void BeginShakeEffect(AnimAndSFXPair FXdata)
{
AnimationClip tempClip = FXdata.anim;
string tempName = FXdata.effectName;
if(!animator.GetClip(tempName))
{
animator.AddClip(tempClip, tempName);
}
AnimationClip weeTest = animator.GetClip(tempName);
if(weeTest == null)
{
Debug.LogError("Clip failed to be added to " + transform.name + " animation object");
}
if (!animator.isPlaying)
{
PlayFX(FXdata);
}
}
void PlayFX(AnimAndSFXPair FXdata)
{
animator.Play(FXdata.effectName);
audioSouce.PlayOneShot(FXdata.audio);
}
void Awake()
{
animator = GetComponent<Animation>();
if(animator == null)
{
Debug.LogError(transform.name + " animator thing cant be found!");
}
audioSouce = GetComponent<AudioSource>();
if (audioSouce == null)
{
Debug.LogError(transform.name + "audioSouce thing cant be found!");
}
}
}
The problem is that NON of my ErrorLogs are printed until we get to this last script, when I get
Debug.LogError("Clip failed to be added to " + transform.name + " animation object");
Followed quickly by
The animation state BoomTest could not be played because it couldn't be found!
Anyhoo, WHY?! DAGNAMMIT WHY!?!??! AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARG!
Can Animation components only have Clips added at Start()? or in the Editor/Inspector?
Please, CodeWizards of Far Lands... help me..