Jump to content

How to get animation's current frame, even if not playing ?


Recommended Posts

I'm trying to get playback position within animation that is stopped (either at beggining or the end).

AnimationState.time and AnimationState.normalizedTime always return 0 and i need to check at which playback position is animation, even when stopped.

Example :
 

public Animation partAnimation = part.FindModelAnimators()[]; //for sake of completness
public AnimationState ast = partAnimation["Gate1Animation"]; // get animation state
[KSPEvent(name = "gate1open", active = true, guiActive = true, guiName = "gate 1 open", externalToEVAOnly = false, guiActiveUnfocused = true, guiActiveEditor = true)]
public void Gate1OpenEvent()
{
partAnimation["Gate1Animation"].speed = 1f; //if animation is already playing, apply forward playback speed
//the below should check if animation is not already playing and at starting position, but time and normalizedTime never have value above 0, so i can't check actual playback position
//the consequence is that if player presses several times "gate 1 open" button in part context menu, animation will play from starting position instead of not activating at all (gate 1 is open and stays open on "open" command)
if (!partAnimation.IsPlaying("Gate1Animation") && (ast.time == 0.0f)) partAnimation.Play("Gate1Animation");
}

So, how do i get animation playback position ? Even if i use some kind of tracking mechanism, it will either have to use coroutines or animation events, either of those seem overkill for this problem.

I've found some posts over on unity and stackexchange sites about cloned AnimationStates that are not properly referenced (when using blending and crossfade), but i use only simple Play() function, it should not be a problem ?

Edited by fatcargo
Link to comment
Share on other sites

Update

After some tinkering i've found out that animation clip time is 0 when it has finished playing, while it plays, time value is properly updated.

So, i have to find out how to get last played frame of animation clip. Same applies for clips that have been stopped with Stop().

Edited by fatcargo
Link to comment
Share on other sites

Thanks for the reply.

I tried again and still nothing, also i removed some of the setup of clips but still nothing.

I also tried in Unity itself and same again, time and normalizedTime stay at 0 after animation has finished or after Stop().

Here is code i used, if there is a bug, i don't see it.

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace AnimationChaining
{
    public class ChainedAnimationsModule : PartModule
    {
        public override void OnLoad(ConfigNode node)
        {
            base.OnLoad(node);
            Debug.Log("chained animations module OnLoad() fired");
        }
        public Animation partAnimation;
        public string animationName;
        public override void OnStart(StartState state)
        {
            base.OnStart(state);
            partAnimation = part.FindModelAnimators()[];
            if (partAnimation != null)
            {
                //animation take 2
                animationName = "Gate1Animation";
                partAnimation[animationName].speed = 1f;
                partAnimation[animationName].normalizedTime = 0f;
                partAnimation[animationName].wrapMode = WrapMode.Once;
                partAnimation[animationName].layer = 8;
                partAnimation[animationName].AddMixingTransform(part.FindModelTransform("gate_1_root"));
            }
        }
        [KSPEvent(name = "gate 1 open", active = true, guiActive = true, guiName = "gate 1 open", externalToEVAOnly = false, guiActiveUnfocused = true, guiActiveEditor = true)]
        public void Gate1OpenEvent()
        {
            Debug.Log ("gate 1 open");
            partAnimation["Gate1Animation"].speed = 1f;
            if (partAnimation.IsPlaying("Gate1Animation") == false)
                partAnimation.Play("Gate1Animation", PlayMode.StopSameLayer);
        }
        [KSPEvent(name = "gate 1 close", active = true, guiActive = true, guiName = "gate 1 close", externalToEVAOnly = false, guiActiveUnfocused = true, guiActiveEditor = true)]
        public void Gate1CloseEvent()
        {
            Debug.Log ("gate 1 close");
            partAnimation["Gate1Animation"].speed = -1f;
            if ((partAnimation.IsPlaying("Gate1Animation") == false) &&
                (partAnimation["Gate1Animation"].normalizedTime == 1f))
            {
                partAnimation["Gate1Animation"].normalizedTime = 1f;
                partAnimation.Play("Gate1Animation", PlayMode.StopSameLayer);
            }
        }
        [KSPEvent(name = "debug log", active = true, guiActive = true, guiName = "debug log", externalToEVAOnly = false, guiActiveUnfocused = true, guiActiveEditor = true)]
        public void MyDebugLog()
        {
            Debug.Log ("debug log");
            Debug.Log ("dbg norm time = " + partAnimation["Gate1Animation"].normalizedTime.ToString() + "\n" +
                       "dbg speed = " + partAnimation["Gate1Animation"].speed.ToString () + "\n" +
                       "dbg norm speed = " + partAnimation["Gate1Animation"].normalizedSpeed.ToString ());
        }
    }

If i can't get this to work, i might try to create a class that expands Animation and adds extra info, though on my first try IDE threw error about not being able to extend a sealed class.

 

PS: thanks chris for seeing through my badly written code example in OP for my true intent.

Edited by fatcargo
Link to comment
Share on other sites

I'm not sure if you can get an animation's time when it isn't playing.

If you want to change the speed or direction of an animation without worrying about it starting over, you can check if it's playing; if it is then only change the speed, if it isn't then set the time, too.

You could also try setting the wrapmode to clamp forever, then it will keep playing the last frame over and over, and since it is still playing you should be able to get the time.

Link to comment
Share on other sites

DMagic thanks ! Setting wrapmode to clampforever enabled me to keep track of playback position with one caveat - normalizedTime variable will continue beyond 0f .. 1f range, so when applying Play() (and setting speed parameter for forward/reverse accordingly), it will "play" but no animation will occur until normalizedTime reaches within 0f .. 1f range. To remedy that i've applied Mathf.Clamp01() to "iron out" normalizedTime inside range and effectively get immediate animation when playback is at either clamped frame.

Here is a snippet that solved it for me :
 

partAnimation = part.FindModelAnimators()[];
animationName = "Gate1Animation";
partAnimation[animationName].wrapMode = WrapMode.ClampForever;
aState = partAnimation[ animationName ];

[KSPEvent(name = "gate 1 open", active = true, guiActive = true, guiName = "gate 1 open", externalToEVAOnly = false, guiActiveUnfocused = true, guiActiveEditor = true)]
     public void Gate1Open()
     {
          Debug.Log ("gate 1 open");
          aState.speed = 0f; //first stop animation
          aState.normalizedTime = Mathf.Clamp01 (aState.normalizedTime); // now clamp it within 0f .. 01f range, if speed not 0 it may change
          aState.speed = 1f; //resume animation
          partAnimation.Play(animationName, PlayMode.StopSameLayer); // Play() it, though it is required only the first time player clicks in menu
     }
[KSPEvent(name = "gate 1 close", active = true, guiActive = true, guiName = "gate 1 close", externalToEVAOnly = false, guiActiveUnfocused = true, guiActiveEditor = true)]
     public void Gate1Close()
     {
          Debug.Log("gate 1 close");
          aState.speed = 0f;
          aState.normalizedTime = Mathf.Clamp01 (aState.normalizedTime);
          aState.speed = -1f;
          partAnimation.Play(animationName, PlayMode.StopSameLayer);
     }
[KSPEvent(name = "gate 1 stop", active = true, guiActive = true, guiName = "gate 1 stop", externalToEVAOnly = false, guiActiveUnfocused = true, guiActiveEditor = true)]
     public void Gate1Stop()
     {
          Debug.Log("gate 1 stop");
          aState.speed = 0f; //works as good as Stop() and leaves normalizedTime intact
     }

I tried clicking on "gate 1 open" button several times, there were no noticable jumps/jerks in animation - i guess code gets executed quick enough to give appereance of smooth animation. I don't know if it will stay smooth in scenes with complex crafts.

Link to comment
Share on other sites

This thread is quite old. Please consider starting a new thread rather than reviving this one.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...