Fall animation seems to be overriding all over animations

Hi, so i’ve made an expression system for my character. It is a modulescript that has two functions: MouthFaceCamera() and Swap(Eyebrows, Eyes, Mouth, Expression). Let me just say that MouthFaceCam() isn’t really important, we’ll be largely focusing on Swap().

The Swap() simply takes 4 arguments that are all strings. Eyebrows for the type of Eyebrow, Eyes for the type of Eyes, and Mouth for the type of Mouth. The last argument, “Expression”, is simply just the name of the Expression. So, for example, Swap("Happy", "Happy", "HappyClosed", "Idle") will change the Eyebrows, Eyes, Mouth and set the Expression’s name to “Idle”. Now, what this does is it sets the Expression attribute of the Settings Configuration in the Player himself to “Idle”. Simple enough, right?

Well, it does work. For the most part. Everything runs smoothly, the mouth always faces the camera, etc. But there is one issue that i just can’t solve at all. The Fall animation/expression. Simply put, whenever the CurrentAnimation is the default “fall” animation with a priority of “Core” and a weight of 10 (just like all the other default animations), the fall expression will always override the other ones for some reason. So, for example, if the current animation is “Ring”, then the “Fall” expression will either override the Ring expression completely and not even let it appear, or just interrupt it completely before the animation is even finished.

I do not know why this keeps happening? The fall animation’s priority is very well set to “Core”, and it’s weight is just 10. Meanwhile, the other animations (aside from idle, walk & run) are all set to Action4, and even if i change their weight to be infinitely bigger than the fall animation’s, it just won’t work. I’ve tried asking the A.I assistant and looking around the DevForum for help, nothing. Here’s the code and a video showcasing the problem :

  • Local Script that requires the “Expressions” module and uses it to swap the expressions based on the animation playing:
--|Animation Checker
local Check
local CurrentAnim
Check = RunService.Heartbeat:Connect(function()
    if not Character:FindFirstChild("Humanoid") or Humanoid.Health == 0 then
        Check:Disconnect()
    end
    --------------------------------------
    for _, Anim in pairs(Humanoid:GetPlayingAnimationTracks()) do
        local Track
        --------------------------------------
        if Humanoid.RigType == Enum.HumanoidRigType.R15 then
            if Anim.Animation.Parent and Anim.Animation.Parent:IsA("StringValue") then
                Track = Anim.Animation.Parent.Name
                CurrentAnim = Track
            else
                Track = Anim.Animation.Name
                CurrentAnim = Track
            end
        end
        --------------------------------------
        if Track ~= nil then
            print(Track)
        end
    end
end)
--|Expression Handling
RunService.Heartbeat:Connect(function()
    if CurrentAnim == "Ring" and Settings:GetAttribute("Expression") ~= "Ring/Bolt" then
        Expressions:Swap("Surprised", "Happy", "HappyOpen", "Ring/Bolt")
    elseif CurrentAnim == "Cannon" and Settings:GetAttribute("Expression") ~= "Cannon" then
        Expressions:Swap("Happy", "Blink", "HappyClosed", "Cannon")
    elseif CurrentAnim == "Ventilator" and Settings:GetAttribute("Expression") ~= "Ventilator" then
        Expressions:Swap("Happy", "Up", "Curious", "Ventilator")
    elseif CurrentAnim == "Drift" and Settings:GetAttribute("Expression") ~= "Drift" then
        Expressions:Swap("Happy", "Down", "Curious", "Fall/Drift")
    elseif CurrentAnim == "Land" and Settings:GetAttribute("Expression") ~= "Land" then
        Expressions:Swap("Happy", "Blink", "BoredClosed", "Land")
    elseif CurrentAnim == "Tramp" and Settings:GetAttribute("Expression") ~= "Tramp" then
        Expressions:Swap("Angry", "Blink", "BoredClosed", "Tramp")
    elseif CurrentAnim == "Hurt" and Settings:GetAttribute("Expression") ~= "Hurt" then
        Expressions:Swap("Angry", "Blink", "AngryOpen", "Hurt")
    elseif CurrentAnim == "idle" or CurrentAnim == "walk" or CurrentAnim == "run" and Settings:GetAttribute("Expression") ~= "Idle" then
        Expressions:Swap("Happy", "Happy", "HappyClosed", "Idle")
    elseif CurrentAnim == "jump" and Settings:GetAttribute("Expression") ~= "Jump" then
        Expressions:Swap("Happy", "Blink", "HappyClosed", "Jump")
    elseif CurrentAnim == "fall" and Settings:GetAttribute("Expression") ~= "Fall" then
        Expressions:Swap("Happy", "Down", "HappyClosed", "Fall") 
    end
end)
  • The Expressions ModuleScript itself:
--||Services
local Players = game:GetService("Players")
--||Variables
local Player = Players.LocalPlayer
local Character = Player.Character or Player.CharacterAdded:Wait()
local Settings = Player:WaitForChild("Settings")
local EyebrowsV = {
    Character:WaitForChild("LeftEyebrow").GUI,
    Character:WaitForChild("RightEyebrow").GUI
}
local EyesV = {
    Character:WaitForChild("LeftEye").GUI,
    Character:WaitForChild("RightEye").GUI
}
local MouthV = Character:WaitForChild("Mouth").GUI
local MouthSide = ""
--------------------------------------
local Expressions = {}
--||Functions
function Expressions:MouthFaceCamera(Root, Camera)
    local ViewDistance = (Root.Position - Camera.CFrame.Position).Unit
    local Dot = ViewDistance:Dot(Root.CFrame.RightVector)
    if Dot > -1 and Dot < 0 then
        MouthSide = "Left"
    elseif Dot < 1 and Dot > 0 then
        MouthSide = "Right"
    end
end
--------------------------------------
function Expressions:Swap(Eyebrows: string, Eyes: string, Mouth: string, Expression: string)
    Settings:SetAttribute("Expression", Expression)
    --------------------------------------
    for _, Eyebrow : SurfaceGui in ipairs(EyebrowsV) do
        for _, Image : ImageLabel in ipairs(Eyebrow:GetChildren()) do
            if Image.Name ~= Eyebrows then
                Image.Visible = false
            else
                Image.Visible = true
            end
        end
    end
    --------------------------------------
    for _, Eye : SurfaceGui in ipairs(EyesV) do
        for _, Image : ImageLabel in ipairs(Eye:GetChildren()) do
            if Image.Name ~= Eyes then
                Image.Visible = false
            else
                Image.Visible = true
            end
        end
    end
    --------------------------------------
    for _, Image : ImageLabel in ipairs(MouthV:GetChildren()) do
        if not string.match(Image.Name, Mouth) or not string.match(Image.Name, MouthSide) then
            Image.Visible = false
        elseif string.match(Image.Name, Mouth) and string.match(Image.Name, MouthSide) then
            Image.Visible = true
        end
    end
end
--------------------------------------
return Expressions
  • The video showcasing the problem, as we can see the “Drift” expression only stays for a few miliseconds before the “Fall” expressions overrides it?

Bump, need help with this plz!

It might not be very helpful, but the problem could be in how you’re controlling the character’s fall. When the character falls, the “Drift” animation should be triggered, but at the same time, the “idle” animation is also being activated. Since the “idle” animation seems to always be active when the character is on the ground, it instantly overrides the “Drift” animation.

Something that might help is using the Roblox platformer template. It uses attributes to activate specific animations at certain moments. You could modify the FXController from the template to adjust your character’s expressions.


I just realized I misunderstood your issue, so let me correct myself while keeping some of what I mentioned earlier:

From what I can see in the Output, it first prints “Drift” and then “Fall”, which makes me think that the “Fall” animation is overwriting the “Drift” animation.

A possible solution would be to use the Roblox platformer template to see how it handles animations using attributes. This could help you manage animation priorities and avoid one animation overwriting another unintentionally.

Apologies for the late reply. So, okay, i’m assuming you are talking about this part of the FXController?

function FXController:initializeAnimations()
	-- Characters are not replicated atomically so we need to wait for children to replicate
	local humanoid = self.character:WaitForChild("Humanoid")
	local animator = humanoid:WaitForChild("Animator")

	-- Load animations
	for _, animation in animations:GetChildren() do
		local animationTrack = animator:LoadAnimation(animation)
		self.animationTracks[animation.Name] = animationTrack
	end

	-- When the character's action changes, play the associated animation
	table.insert(
		self.connections,
		self.character:GetAttributeChangedSignal(Constants.ACTION_ATTRIBUTE):Connect(function()
			local action = self.character:GetAttribute(Constants.ACTION_ATTRIBUTE)
			self:playActionAnimation(action)
		end)
	)
end

function FXController:playActionAnimation(action: string)
	-- If we're currently playing a looped action animation, stop it
	if self.loopedActionAnimation then
		self.loopedActionAnimation:Stop()
		self.loopedActionAnimation = nil
	end

	-- Check that there's an action module for this action
	local actionModule = Actions[action]
	if not actionModule then
		return
	end

	-- If the action doesn't have a set animation, no need to do anything
	if not actionModule.animation then
		return
	end

	local animationTrack = self.animationTracks[actionModule.animation]
	if not animationTrack then
		warn(`Missing animation: {actionModule.animation}`)
		return
	end

	-- Play the animation
	animationTrack:Play(Constants.ACTION_ANIMATION_FADE_TIME)

	-- If this is a looped animation, keep track of it so we can stop it later
	if animationTrack.Looped then
		self.loopedActionAnimation = animationTrack
	end
end

Yes, you could modify that module to integrate your character’s expressions, but the template as a whole would help you organize your game better.

For example, from what I see in the Output, “Fall” and “Drift” are alternating. Using the module that controls the character’s actions (I can’t remember its name), you could add an action that triggers only when the character is falling, which would be the “Drift” animation. When this action is triggered, it would use a setAction() method to assign an attribute to the character. This attribute would then be read by the FXController, which would activate the corresponding “Drift” animation.

1 Like