mecanim keeps on screwing up and i have to do workarounds. my movement just stopped working after i added in new states to my controller, and it keeps randomly playing the move left animation which is not even the default one. i just want to play an animation when i say so in code (usually just in an if statement), i don’t need a gazillion transitions in the controller.
should i try out legacy or is that a bad idea? if i do want to use legacy, HOW do i use legacy?
i’m making a cartoon-like 2d animation with only a few frames per animation and no need for anything fancy. sorry Unity staff for talking crap about mecanim but it has thwarted me for the last time!
While I am a bigger fan of legacy animation than mecanim, it sounds like the problem you are facing is more fundamental.
From my experiments with 3D character customization, the legacy animation system has been easier to wrap my head around opposed to mecanim, although if you aren’t trying to do anything nearly as complex as that, mecanim should be all you need.
Would be better for your readers to have a look at your animator and how you are controlling it using script so far, before evaluating if you really should switch over to legacy animation.
Mecanim takes care of animation blending, and hard limiting what state switches to what, all in an editor window. 2D sprite animation isn’t affected by blending at all, but you will be left with pure scripting switching to legacy, which may actually become harder to cheat and/or debug if you fundamentally lack the understanding of using a finite-state-machine.
The new Playables API in Unity 2017 allows you to play animations on an Animator without using an AnimatorController asset. It’s a bit cumbersome, but you don’t have to fight against the horrendous Animator API or the even worse AnimatiorController interface.
Compared to the legacy Animation stuff, it’s a bit more wordy, but you can implement blend trees and use layer masks and what not. It’s also not due to be removed, which the Animation component probably is.
Here’s playing a single clip on a GameObject with Playables:
using UnityEngine;
using UnityEngine.Animations;
using UnityEngine.Playables;
public class PlayClipOnObject : MonoBehaviour
{
public AnimationClip myClip;
private PlayableGraph graph;
void Start () {
PlayAnimation(gameObject, myClip);
}
public void PlayAnimation(GameObject target, AnimationClip clip) {
// Create the PlayableGraph, which is the root of the Playable API stuff
graph = PlayableGraph.Create();
//We need an Animator to play stuff, even if we're not using an AnimatorController. So just add one:
var animator = target.AddComponent<Animator>();
//Wrap the clip in a thing the Playable system understands:
var clipPlayable = AnimationClipPlayable.Create(graph, clip);
//Create the output, and make the clip be the output's source. This API is a bit wordy :p
var animOutput = AnimationPlayableOutput.Create(graph, "some name", animator);
animOutput.SetSourcePlayable(clipPlayable);
//play the thing
graph.Play();
}
void OnDestroy()
{
// If you don't destroy the graph, it leaks in the engine (and Unity whines), so destroy it!
// IsValid will be false if the graph was never created (ie. this component is never enabled before it's destroyed)
if(graph.IsValid())
graph.Destroy();
}
}
It looks a bit cumbersome compared to just calling Animation.Play on the legacy animation stuff, but the legacy player is… legacy, and due to be removed. It also doesn’t support blend trees, which you can implement rather easily with Playables.
thanks guys! Baste, i think what you posted is exactly what i needed. i don’t know if i have time to change my code right now … the final for my class is tomorrow, after that i’ll have more time.
i put the add component animator code in start, since i only need one animator for one object, but it doesn’t work if i put it there and if i put it outside any functions i’m pretty sure that’s an error. what do i do? this isn’t the first time i’ve had this issue and it isn’t really resolved in my head.
edit: does this work, putting the code outside any functions at the top, in addition to the code in Start?
private Animator animator;
edit2: animation doesn’t work as it currently is … i added in all the animation clips to the slots in my script on the hero game object. it correctly adds in an animator when i run my game.
edit3: ah, found the playables examples … still help finding the error would be cool as i am not seeing it, not really down with the concept yet
@Baste , is there some preparation with the animation clips i have to do? and am i right about how to declare the Animator at the top and in the start function? the animator is created when i run the game without complaint, so i assume this is not the problem that is causing the animations not to play.
public AnimationClip HIdle;
public AnimationClip HMLeft;
public AnimationClip HMRight;
public AnimationClip HMUp;
public AnimationClip HMDown;
private PlayableGraph graph;
private Animator animator;
void Start()
{
var animator = gameObject.AddComponent<Animator>();
}
//the following is in the walktopoint function called in the state switch statement in update
void WalkTowards(Vector3 destination)
{
if (clicked == true)
{
targetPos = destination;
targetPos.z = transform.position.z;
// move towards our destination
transform.localPosition = Vector3.MoveTowards(transform.localPosition,
targetPos, walkSpeed * Time.deltaTime);
// velocity to determine if moving or not
myVelocity = (transform.position - prevPos) / Time.deltaTime;
var heading = targetPos - transform.position;
var distance = heading.magnitude;
var direction = heading / distance; // This is now the normalized direction.
prevPos = transform.position;
// animate movement
if (myVelocity.sqrMagnitude > 0)
{
if (Vector3.Angle(Vector3.right, direction) >= 0 && Vector3.Angle(Vector3.right, direction) <= 45)
{
Debug.Log("walking");
//animator.Play("HeroMoveRight2");
PlayAnimation(gameObject, HMRight);
}
else if (Vector3.Angle(Vector3.up, direction) >= 0 && Vector3.Angle(Vector3.up, direction) < 45)
{
//animator.Play("HeroMoveUp2");
PlayAnimation(gameObject, HMUp);
}
else if (Vector3.Angle(Vector3.left, direction) >= 0 && Vector3.Angle(Vector3.left, direction) <= 45)
{
//animator.Play("HeroMoveLeft2");
PlayAnimation(gameObject, HMLeft);
}
else if (Vector3.Angle(Vector3.down, direction) >= 0 && Vector3.Angle(Vector3.down, direction) < 45)
{
//animator.Play("HeroMoveDown2");
PlayAnimation(gameObject, HMDown);
}
}
else
{
//animator.Play("HeroIdle2");
PlayAnimation(gameObject, HIdle);
}
}
}
public void PlayAnimation(GameObject target, AnimationClip clip)
{
// Create the PlayableGraph, which is the root of the Playable API stuff
graph = PlayableGraph.Create();
//We need an Animator to play stuff, even if we're not using an AnimatorController. So just add one:
//var animator = target.AddComponent<Animator>();
//graph.SetTimeUpdateMode(DirectorUpdateMode.GameTime);
//Wrap the clip in a thing the Playable system understands:
var clipPlayable = AnimationClipPlayable.Create(graph, clip);
//Create the output, and make the clip be the output's source. This API is a bit wordy :p
var animOutput = AnimationPlayableOutput.Create(graph, "Animation", animator);
animOutput.SetSourcePlayable(clipPlayable);
//play the thing
graph.Play();
}
i’ve tested and the code inside the if statements for walking IS being played, but of course the animation isn’t working. the code above is just relevant snippets so you don’t have to wade through all the code.
edit: could the problem be that i’m running the play graph function from update instead of start? i’m not sure how i’d make it work from start. will this not work with my state machine?
edit2: i’m going to try this: SpriteAnimator.cs - Pastebin.com
edit3: okay, that just appears to be a bunch of functions for use with legacy animation. (i think.) so i’m just going to try to figure out legacy now.
okay now i’m using GetComponent().Play(“HeroMoveRight2”);
i set animation to legacy on all clips
in my Animation component i put the idle animation under “Animation” and all 5 walking animations under “Animations”. but the animations still do not play. am i missing something?
Is anything being outputted in the console that is not your own print statements?
You could be calling for the animation to be played on every frame, forcing it to reset to the first frame of the animation on every frame.
A trickier problem would be your animation’s designated objects and hierarchy not matching the objects and hierarchy of the gameobject in the scene. Like maybe you placed your Animator or Animation component on a parent gameobject of the animated model.
i do have the function the animation code is in called every frame. that’s how you do it with mecanim, do i have to alter the debug settings’ Wrap Mode to loop or something (now it’s on default)? i am using a state machine, the core of which is a switch statement in the update function. i could call the function every N frames, where N is the number of frames of the animation … be better if there’s a setting though.
edit: okay, setting wrap mode to loop didn’t help.
You can check if an animation is playing, and should be able to check if the animation playing is the same as the animation to be played, although at that point you might as well revert back to mecanim and make use of the animator controller as a state machine.
It worked before when you were using mecanim because the animator controller only checks for the condition to switch over to another animation, so the checking of whether animation is playing and what animation is playing is handled by the animator controller.
But again, this is all assuming my 2nd speculation in my previous post is right. You should be able to check for the other 2 possibilities more easily. Eliminate or confirm those possibilities first.