SimpleAnimate | An easy-to-use & flexible module replacement for the default Animate script

Have you tried working with the default Animate script for your game with super cool animations, and got really frustrated because the code was messy and long?
seriously, what even is this??

Well, do I have the solution for you!
Presenting…

SimpleAnimate!

SimpleAnimate is a module that you can require via a LocalScript and it’ll play your animations like the default Animate script would, but it’s more flexible & interactable!

Documentation:

Constructor
  1. SimpleAnimate.new(rig: Model, coreAnimations: AnimationsList?, emoteAnimations: AnimationsList?, stateMachine: any?)

    • To create a new AnimationController that contains all the controllers, you must first call this constructor function, with the rig as the only required argument (I’m sure the other arguments explain themselves!
      If they don’t though, feel free to ask in the replies.)
Core

The Core controller is the controller which handles all core movements of rigs, such as walking, running, jumping, swimming and climbing!

The Core controller itself is divided into 2 more controllers, the Connections controller (which handles state changes) and the PoseController (which handles tracking poses and animations)

Let’s go through the PoseController first since that’s the longest (and probably the one you’re gonna use the most often!)

  1. PoseController:SetCoreActive(value: boolean)

    • Now you may be wondering, what does “active” mean? Why does the PoseController need to be “active” or not?
      Well, essentially what the active property does is it determines wether or not the Connections controller can interact with the PoseController during state changes.
      The reason this is a function is because you may wanna block that interaction to play your own core animations (like swimming using a custom swimming system!)

  2. PoseController:StopCore()

    • Stops all currently running core animations.
      Note that PoseController:SetCoreActive(false) does not stop core automatically!
      This means if you want to stop any ongoing core animations you’ll have to call this function manually.

  3. PoseController:GetCoreActive() : boolean

    • Returns the current active state of the PoseController.

  4. PoseController:ChangePose(pose: PoseType, speed: number?)

    • This method does exactly as it says, it changes the current pose of the PoseController to pose.
      However, if pose is the same as the current pose, it won’t play a new animation!
      Note that if the PoseController is still “active”, it’ll probably override any pose changes.

  5. PoseController:PlayAnimation(pose: PoseType, speed: number?, fadeTime: number?)

    • This method is similar to PoseController:ChangePose(), except it doesnt care wether or not pose is the same as the current pose, it plays the animation anyway!
      May be useful in certain cases.

  6. PoseController:GetRandomAnim(pose: string, animsTable: AnimationsList?)

    • This method uses weighted random selection to get a random AnimationTrack from a list of animations (of type AnimationsList, see the Types module for more details.)

  7. PoseController:GetCurrentTrack()

    • Gets the current running core AnimationTrack.

  8. PoseController:GetPose()

    • Gets the current pose of the PoseController.

And that’s all for PoseController!
Now theres 1 more method for the other controller, Connections

  1. Connections:SetRunThreshold(value: number)

    • This method sets the run threshold for the Connections controller.
      What exactly is the run threshold? Well it’s the walkspeed at which the rig is considered running.
      If the rig is walking slower than this, it’s walking. Otherwise, running!

Action

The Action controller is the controller which handles all actions, such as emotes and well, actions!

Theres not much methods to go over but heres all of them!:

  1. Action:Create(name: string, anim: string | Animation, looped: boolean?, priority: Enum.AnimationPriority?) : AnimationTrack

    • This method loads a new action using anim (an AssetId for an animation or an actual Animation instance) to be used by Action:Play(), Action:Stop(), Action:Remove() and Action:Get() and returns it.
      Note that the first 3 methods will warn you if the action isn’t created first with this method.

  2. Action:Play(name: string, fadeTime: number?, weight: number?, speed: number?) : AnimationTrack

    • This method plays a loaded action and returns it.

  3. Action:Stop(name: string, fadeTime: number?) : AnimationTrack

    • This method stops a loaded action and returns it.

  4. Action:Remove(name: string)

    • This method unloads a loaded action.

  5. Action:Get(name: string) : AnimationTrack?

    • This method returns a loaded action or none if doesn’t exist.

  6. Action:SetEmoteBindable(emote: BindableFunction)

    • This method sets an emote bindable to be used for processing emotes.
      Note that the BindableFunction has to be called PlayEmote to be properly registered by Roblox CoreScripts.

Download SimpleAnimate here! →
AnimationController.rbxm (11.1 KB)

(Make sure to parent the module to StarterCharacterScripts, otherwise replication won’t work!)

And if you haven’t already, please check out my other modules SimpleZone and BufferConverter!

Please report any bugs/issues, and may your code always be blessed! :heart:

18 Likes

If you have any questions on, for example, how to modify certain behaviour of this module, feel free to ask me!

1 Like

I do in fact, how could I modify your module to use already, pre-existing AnimationTracks loaded on the character?

1 Like

Are you trying to use them as core or action animations? Be more specific for what you’re trying to do and I’ll help you out :slightly_smiling_face:

I already have a module under the Player which holds a big table of all animations loaded on the Character, and I want to switch your module’s behavior of creating them at runtime to loading each of those animations with the prefix of “Animate_”
e.g.

Walk = {
	{id = "",weight = 10}
}

to

Walk = nil
-- --> end of Animations table
for Name in Animations do
	Animations[Name] = AnimationsModule:GetAnim("Animate_"..Name)
end
1 Like

Ah, you can simply do this!

for pose, animInfo in Animations do
	for _, idInfo in animInfo do
		idInfo.anim = AnimationsModule:GetAnim("Animate_"..pose)
	end
end

And then just replacing the part that preloads the animation with it
image

Thank you, that’s useful. I was meaning to get rid of the default “id” and “weight” keys in the default Animations table… Can I safely remove those or are there needed params?

Nope, if you remove the default animation preloading theres pretty much nowhere else that uses the id and weight.

2 Likes

If you want to edit it more, I suggest looking under the PoseController module under Core. It controls all the Core animations, and it’s pretty short too!

Update:

  • The weight member of the Animations table is actually used now, everytime a looped animation loops the module will now search a new random animation utilizing the weights and play that (similarly to how the default Animate script does)

  • Added a new Emotes module which allows you to set a PlayEmote BindableFunction to play your emote animations! (more detail below)

  • Made changePose work even if setCoreActive(false) was called (this is done with a is_Core optional argument which the module itself always passes as true, however you don’t need to!)

  • Initialized pose to “Idle” on join (you used to not play any animations upon joining)

  • The locations of the modules storing and preloading AnimationTracks have been moved to a new module called Animations which stores both CoreAnims and EmoteAnims!


    If you wish to add your own custom emotes, simply just add it as a member in the EmoteAnims module.

Example Animate script utilizing the new changes

--[[
	EXAMPLE ANIMATE SCRIPT
	
	Location: StarterCharacterScripts
	Name: Animate
]]

local AnimationController = require(script.Parent.AnimationController)
local Emotes = AnimationController.Emotes
local Core = AnimationController.Core

-- Set the emote BindableFunction to the one inside the script (HAS TO BE CALLED "PlayEmote"!!!)
-- so that the module can use it to play emotes
Emotes.setEmoteBindable(script.PlayEmote)
-- Set the running threshold to 16
-- If the player is moving below this speed, they are walking
-- Else, they are running
Core.setRunThreshold(16)

Core.PoseChanged:Connect(function(old, new)
   if new == "Freefall" then
     print("Player is falling!")
   end
end)

Patch:

  • Fixed emotes not replaying Idle animation upon ending
  • Fixed missing dependencies
  • Added playAnimation as a public static function for Core.
    This function plays an animation for a specific pose no matter if the last pose is the same or not, unlike changePose which will only play the animation if the last pose isn’t the same as the new one.

Does this work for both R6 and R15, and NPC rigs?
I’ve tried to modify the Roblox’s default Animate script for an NPC and I constantly got this EXTREMELY annoying warning:

AnimationTrack limit of 256 tracks for one Animator exceeded, new animations will not be played.

Dispite numberous attempt of trying to fix and because the warning doesn’t point at the problem itself.
I’m running out of hope and I probably have to rewrite my own code again or make a post about it.

Regarding the flaws of Roblox’s Animate script itself, thank you for making this module.

1 Like

I mean hopefully it shouldn’t do that? xd, it preloads the animation tracks so it shouldn’t exceed the animation track limit unless you have a ton for some reason

1 Like

Also yeah it works for both R6 and R15, for NPCs however you are going to have to remove the Emotes module (duh)

1 Like

I just found out that the module must be inside the character for the animations to work.
Wouldn’t it be better that the module can be put somewhere else like in ReplicatedStorage and required using a script instead?

1 Like

You’re suggesting I turn the module from a controller into an OOP object? Hmm that’s a pretty good idea actually

I’ll try it and see if I like how it works

Judging by how you structured the module itself. It should have been an OOP object.
I don’t see why the module itself needs to be parented to a character every time instead of being in one place.

Yeah I based it off an old version I developed, this was kinda meant to be just a remaster xd

I’ll let you know if the OOP implementation works

I would suggest adding the Character parameter when requiring the module by using this common method:

AnimationController.new(Character)

Maybe adding a Humanoid one as well but this is my personal suggestion since I like to rename my NPC’s Humanoid.

The current method works but it seems less feasible when there’s a lot of players in the game and there’s AnimationController inside every character along side the Roblox’s Animate script.

Yes the rig will be passed as the only required parameter to .new() (i also have animation module parameters)

1 Like