- Home /
Adding falling and landing animations to the Locomotion System
I would appreciate a little help adding a falling and landing animation to the JumpAndIdle script. I have added two public variables for the additional animations and I am modifying the sections commented "If character has landed" and "If character is falling". I have also changed some of the wrapmodes for the other animations and the scene I am using is the demo Crate Climb Scene.
I am trying to crossfade to the landing animation after the jump and falling states. At the moment it crossfades after a jump, but also whenever the character is grounded and not moving, which looks quite bad.
For the falling state I have a looping falling animation which I would like to crossfade to after the character has fallen for a certain period of time. For some reason it is never triggered, and only the jump animation plays the entire way down. Do the "Jump Time Start" and "Fall Time Threshold" parameters have something to do with this? I have both set to zero since I am not exactly sure what their function is. I cannot find any documentation or information detailing the function of these parameters either.
Here is my JumpAndIdle script:
using UnityEngine;
using System.Collections;
[RequireComponent(typeof(AlignmentTracker))]
public class JumpAndIdle : MonoBehaviour {
public AnimationClip jumpingAnimation;
public AnimationClip landingAnimation;
public AnimationClip fallingAnimation;
public float jumpTimeStart = 0.0f;
public float fallTimeThreshold = 0.2f;
public AnimationClip waitingAnimation;
private bool doJumping = false;
private bool doWaiting = false;
//private LegAnimator legA;
private AlignmentTracker align;
private CharacterMotor cm;
private bool grounded;
private bool waiting = false;
private float idleTimer = 0.0f;
private float fallingTimer = 0.0f;
// Use this for initialization
void Start () {
//legA = GetComponent(typeof(LegAnimator)) as LegAnimator;
align = GetComponent(typeof(AlignmentTracker)) as AlignmentTracker;
cm = GetComponent(typeof(CharacterMotor)) as CharacterMotor;
grounded = false;
// Only use jumping if the jumping animation has ben set
if (jumpingAnimation!=null) {
animation[jumpingAnimation.name].wrapMode = WrapMode.Once;
doJumping = true;
}
// Only use idle animation if it has been set
if (waitingAnimation!=null) {
animation[waitingAnimation.name].wrapMode = WrapMode.ClampForever;
doWaiting = true;
}
// Start with locomotion
//animation.Play("locomotion");
}
void OnEnable () {
if (animation["locomotion"]!=null) animation["locomotion"].weight = 1;
}
// Update is called once per frame
void Update () {
float speed = align.velocity.magnitude;
// CrossFade quick to jumping animation while not grounded
if (doJumping) {
// If the jump button has been pressed
if (cm.jumping) {
grounded = false;
waiting = false;
// Fade to jumping animation quickly
animation.CrossFade(jumpingAnimation.name, 0.1f);
animation[jumpingAnimation.name].time = jumpTimeStart;
animation[jumpingAnimation.name].wrapMode = WrapMode.Once;
}
// If the character has walked over a ledge and is now in air
else if (grounded && !cm.grounded) {
grounded = false;
waiting = false;
}
// If the character has landed on the ground again
else if (!grounded && cm.grounded) {
grounded = true;
waiting = false;
fallingTimer = 0;
animation.CrossFade(landingAnimation.name, 0.1f);
// Fade to locomotion motion group quickly
animation.CrossFadeQueued("locomotion", 0.1f);
}
// If the character is falling
else if (!grounded && fallingTimer<fallTimeThreshold) {
fallingTimer += Time.deltaTime;
if (fallingTimer>=fallTimeThreshold) {
// Fade to jumping motion group slowly
animation.CrossFade(fallingAnimation.name, 0.2f);
animation[fallingAnimation.name].time = jumpTimeStart;
animation[fallingAnimation.name].wrapMode = WrapMode.Loop;
}
}
}
// CrossFade to waiting animation when inactive for a little while
if (doWaiting) {
if (speed==0) {
idleTimer += Time.deltaTime;
if (idleTimer>3) {
// if the idle animation is not in the middle of playing
if (
animation[waitingAnimation.name].time==0
|| animation[waitingAnimation.name].time>=animation[waitingAnimation.name].length
) {
// Then rewind and play it
animation[waitingAnimation.name].time = 0;
animation.CrossFade(waitingAnimation.name);
animation[waitingAnimation.name].wrapMode = WrapMode.ClampForever;
waiting = true;
}
// Don't play again for a little random while
idleTimer = -(2+4*Random.value);
}
}
// If we have started to move again
else if (speed>0 && waiting ) {
// Crossfade to locomotion
animation.CrossFade("locomotion");
waiting = false;
idleTimer = 0;
}
}
}
}
Would appreciate any help with what I am doing wrong, I'm sure it is something simple but I can't see it at the moment.
Don't know the answer, I used a custom script to handle my jumping and landing for locomotion. I think the bootcamp soldier has a script that handles jump landing. Checked that?
Yes it does, but it is the same script that handles all of the animation states and so it's quite difficult for me to dissect the parts I would need. Also the bootcamp soldier uses a different character motor which means I would have to go through and rename all the necessary booleans and add the ones used by the locomotion character motor. That would mean pretty much writing my own version from scratch.
I like the JumpAndIdle script it suits my project. I think it is a matter of setting the right order of booleans (ie grounded, waiting etc) to get the right effect. I have tried so many different combinations, but as I said above I think the "Jump Time Start" and "Fall Time Threshold" have to be set correctly so that the motor knows that it is in a falling state; it seems it thinks it's in the jump state the entire way down. It'd be really helpful if someone could explain to me what exactly "Jump Time Start" and "Fall Time Threshold" do.
Sure. I think you're going to have to make a few more booleans to differentiate between when the character is grounded normally and when they are grounded after a jump. By default I think they're setup to be pretty much the same thing which is why your landing animation is playing when you simulate the game; because it doesn't know whether you jumped before hand or not.
Thank you for your advice UnityDeveloper99. I have setup several new booleans, falling being one of them, in order to break down the jump, fall and landing. The "Fall Time Threshold" seems to be working correctly know as before it didn't have any effect what so ever, but that could've been because the jumping animation was overwriting it. I set the falling flag to true just after the check for the Fall Time Threshold >= to the falltimer. Now I've managed to get the looping falling animation to play properly. :)
The landing animation however is beco$$anonymous$$g a little nightmare. It always plays automatically when I run the game. In your system, how did you detect the difference between being grounded and landing after a jump?
Thank you again for your help so far.
Answer by UnityDeveloper99 · Feb 09, 2012 at 04:29 PM
Have another look at the bootcamp soldier and see how it is handling the same situation. I'm pretty sure that when you simulate bootcamp the soldier stands perfectly straight and doesn't do a landing crouch unless he jumps first. One way you could do it is check which animation has played before triggering a land boolean. If the jump animation has played go to a land animation, else go to a grounded animation. Use Animation.IsPlaying for that.
I looked at Bootcamp, and if one looks very closely, when the demo loads the soldier DOES actually do a little crouching bob. The crouch is a little harder to see because of the fade in from black, and so only the last few frames are visible, but the soldier definitely does not stand completely straight at the beginning.
Perhaps then this could simply be a limitation of the locomotion system. This is unfortunate though as without a landing animation all the jumping motions look incredibly stiff and unrealistic. Even the bootcamp soldier (not to be insulting) has a very unrealistic landing system in my opinion, compared to other systems I have scene in Unity. It seems quite a shame that such a sophisticated system has no way of implementing a proper landing animation.
I will have a look at the "IsPlaying" link again. The way you describe it seems it may be the only viable way to do this.
Thank you again for all your advice. Really glad at least someone is willing to help with this. Thanks a lot.