Animate Module -- The New Animate Script

Animate Local Script, why it’s limited

The Animate LocalScript is limited, but why? Let’s say you wanted to update animations, but you wanted to change the animation or you wanted to stop all playing animations. How would you do it? Here comes the Animate Module!

Animate Module

The Animate Module makes everything easier. It has a module for AnimateValues instead of StringValues with Animations in it. This is a module which has all the functions in the animation LocalScript.

Why This Module is Better Than Animate LocalScript

This module is much better than the Animate LocalScript because:

  1. This is a ModuleScript, and it does not work with values that hold animations, but with another module (except for the ScaleDampeningPercent).

  2. (adding onto 1) You can communicate with this since it is a ModuleScript, unlike the LocalScript. You would need to copy and paste the LocalScript to handle animations, especially changing them. You shouldn’t have to do this. If you were to do complex tasks, you would definitely need a module for this, especially when you need to follow DRY (Don’t Repeat Yourself). This is the reason why I made this module.

  3. Compatible with both R6 and R15, so you don’t have to worry about separate scripts with R15.

Animate.AnimateValues

This is a module which holds animations (similar to the animNames variable in the Animate LocalScript). There are two separate tables for animations, R6_animNames and R15_animNames. These two tables include a getter function (GetAnimation) and a function you can use to configure the animation (ConfigureAnimation). The return value is a dictionary, which has three values in it: animNames, dances, emoteNames. animNames is a multi-dimensional dictionary that holds R6 for R6_animNames and R15 for R15_animNames. dances is simply a table that holds the dances ("dance1", "dance2", "dance3"). emoteNames is another dictionary which holds all the emote names as keys and booleans as values.

animNames:GetAnimation

This method takes in an animation name as its first argument. It will return a given animation. You shouldn’t use this method for configuring animations since there’s already another method for that.

local Character = script.Parent
local AnimationValues = require(Character.Animate.AnimationValues)

-- There may be different tables of animation info for a certain
-- animation.

print(AnimationValues.animNames.R6:GetAnimation("walk")[1].id)

animNames:ConfigureAnimation

This method calls :GetAnimation with its name parameter. Then, it needs to find out the which animation you want (You’ll see later). Finally, the last argument is the new id. The snippet below is an example you can find in the Model.

 -- assuming you have made a variable for the AnimationValue module
 AnimationValues.animNames.R6:ConfigureAnimation(
     "walk",
     1,
     AnimationValues.animNames.R6:GetAnimation("dance2") [1].id
 )

If you wanted to configure the R15 animations, you would have to do that manually since R6 and R15 are separate rigs.

Animate

This is a Module which returns the :Initialize method of the module. The method, of course, returns self, the Animate class. It detects if emotes are played, and it connects the Humanoid state types. Since this module is very long, you should only need to know the most important functions.

Animate.new

A constructor which takes in the Figure parameter, usually a character. It returns a metatable.

Animate:EndCurrentAnimTrack

A method used to stop the current playing animation. May be used to keep the
Figure static.

Animate:GetAnim

Although this is used for self.animNames, it may be useful for getting animations according to the Figure's rig type (R6 or R15)

Animate:createAnimationSet

Creates an animation set in self.animTable; getting a fileset in self.animNames, and the dictionary name is the name argument.

Animate:setupAnimations

Sets up all the animations by calling self:createAnimationSet. Iterates through all the animations in self.animNames and passes the arguments to the method accordingly.

Animate:stopAllAnimations

Another way to stop animations, but truly. It disconnects the self.currentAnimKeyframeHandler and resets animations.

Animate:playAnimation

Gets animation using self:GetAnim and the name argument of the method. It also calls self:rollAnimation (an internal function) that gets which index to get from the animation table. The method stops the self.currentAnimTrack with the transitionTime argument. The animation will load and play from the humanoid argument (I’m not sure why there is a humanoid argument in the Animate LocalScript. I may remove it from the ModuleScript).

Animate:playToolAnimation

Similar to self:playAnimation, but it has an extra paremeter (priority), and it works with tools.

Animate:stopToolAnimations

Similar to self:stopAllAnimations, but it only works with Tool animations

Animate:SetPose

A setter for the pose property. It is set to the NewPose argument of the method.

Animate State Types

There are many functions (onRunning, onSwimming etc.). These functions are connected to many Humanoid state types. They also call self:SetPose to update the pose.

Animate:move

The most important part of the API. This checks the poses and plays animations according to the pose. In the Animate:Initialize function, this function is called infinitely until the Figure is nil.

Animate:Initialize

This is a Module which returns the :Initialize method of the module. The method, of course, returns self, the Animate class. It detects if emotes are played, and it connects the Humanoid state types to the functions mentioned in the “Animate State Types” subtitle.

Here’s the link: Animate Module

91 Likes

I think it is very nice of you to make this; I wonder why Roblox didn’t modualize it themselves in the control and camera 2018 playerscripts update

Though, how do you deal with the Roblox animation script changing?
I also currently overwrite the default Animate script, but I do so in such a way that I make minimal patches which I can easily copy and paste when a new update occurs
At the moment, I have three changes which I delineate with comments of ‘MODIFICATION’
https://pastebin.com/7RGc6wDW

8 Likes

I agree, it seems out of place to modularize everything else, but not this script, which holds animations.

Please elaborate more about what you meant, or I probably misread it.

I noticed in your code that the modifications you used include _G, which is not recommended nor good practice. In addition, you don’t take into account which Figure you are using. This is why Modules are good. You know what you are working with. Mixing this with classes and OOP, you will achieve a lot more. With modules, you can edit and communicate easily with other scripts. Anyway, some people have custom animations, or you need to change animations during run-time, you shouldn’t have to copy and paste the Animate script to do simple changes (like you did) and especially not use _G or shared. You should be able to do simple changes simply (like calling require(AnimationValues).animNames.R15:ConfigureAnimation) and more complex changes to include looking at the code.

TL;DR: Modules are easy to work with (communicating and changing), prevent use of bad practices (_G, shared), and they make it easier to do changes that don’t need to take much steps.

3 Likes

When Roblox pushes out an update to their animate script what do you/will you do? Will you update your script accordingly or is it left up to us? I was explaining that I try to make as little as possible changes to the Roblox Animate script so it’s a very easy update for me (I just have to copy and paste my three MODIFICATIONs)

By the way, I do have custom animations, I just run them through a different set of modules
The modifications I made to the Roblox Animate script allow this overloading of the movement animations
Here is my modulescript that handles the core movement animations if you are interested: https://pastebin.com/6i1u13RA

I use _G because it is easier to communicate between modules with it (I do not need to preface each module with a local loader=require(Path.To.My.Shared.State.Loader)

4 Likes

I’m not sure about if I’ll always update it, but I don’t think the Animate script would be updated in a long time (unless it is modularized). I may just update it myself, but I don’t know what I’ll be doing until the Animate script is updated. Honestly, it depends.

2 Likes

I still don’t understand why I should put in the extra effort to use this Module.

How and Why is it better than the Default?

I read the entire OP, I need to be persuaded more

3 Likes

The most important difference between the ModuleScript Animate and LocalScript Animate is that with the ModuleScript, you can communicate with other scripts, which is a huge plus. On the other hand, LocalScript Animate is alone, you cannot communicate (except with _G and shared, which are not recommended).

Animate has a lot of useful functions which can help developers with their animations.

I will make this Module compatible with non-player characters (NPC’s). If that works out, then it would be a huge plus for developers.

  -- Example 1
  local Part = workspace.Part
 
  local function OnTouched(Hit)
       local Humanoid = Hit.Parent:FindFirstChild("Humanoid")
       if not Humanoid then
           return
       end

        local AnimationValues = require(Hit.Parent.Animate.AnimationValues)
        if not AnimationValues then
           return
        end
        
        AnimationValues.animNames.R6:ConfigureAnimation(
            "dance1",
             1,
             AnimationValues.animNames.R6:GetAnimation("walk")[1].id
        )
  end
 Part.Touched:Connect(OnTouched)

Would you rather do it like the code above, or would you rather copy the Animate script and paste the “touch” code in the Animate script. That doesn’t make sense.

    -- Example 2: Unequipped Tools
    local Tool = script.Parent
    local Backpack = Tool.Parent
    local Player = Backpack.Parent
    local Character = Player.Character
    
    local Animate = require(Character.Animate) (Character)

    local function OnUnequipped()
       -- Let's assume we have "unequip" defined in our AnimationValues
       Animate:playToolAnimation("unequip", Animate.toolTransitionTime, Character.Humanoid, Enum.AnimationPriority.Core)
    end 

    Tool.Unequipped:Connect(OnUnequipped)

I’m sorry, because this is my first post in “Community Resources”, and I never thought about people who would ask these types of questions, so I may have a weak argument.

6 Likes

It’s fine, You just convinced me!

The reason I asked is because my use case is simple, I can play the tool Animation in it’s own script, however your Module seems like it will be good use to people who want complexity and depth to their Animation controls.


You should make the OP more compact, hide the Functions section and convince people why they should use your module and point out how & why the default Animation script Sucks then describe how your Module is superior.

4 Likes

(Sorry that I bumped this post)
I remade this module. It is up to date with the current Animate module and it works so much better than the old version. Should I update this post to follow the API of the new Animate module?

6 Likes

Its great that you’ve come up with this module. :smile:
I gave it a little try, but I ended up getting across some little errors which made me stop using it. If you’d update it would be great to give it another try.

3 Likes

Yeah, this module is kind of bad. It’s really messy.

2 Likes

I highly recommend you remove the “wait()” inside the Animation:rollAnimation() function. I was working with this module and noticed some problems (like animations not being changeable) but one of the main ones was the walk animation not being played because the walk animation plays while the idle animation is still “rolling”. This causes the idle to play when the roll is done, which then plays over the walk.

Thanks for the module though, saved me a lot more time that it would’ve

7 Likes

Thanks so much for making this! I was trying to run a bunch of animations for 100+ NPC’s on the client and couldn’t find an efficient way to run local scripts for doing so - this module is a very tidy solution

there was a few broken stuff there and there maybe you could send us an updated script?