Animation Problem with Custom Dog Character / Rig

I made a custom dog character and my goal is to have this character played as the Starter Character using my custom run, walk, jump, and idle animations.

For getting started, I just animated a simple Tail Wag animation, and, tried to get that running on the character as the default idle.

Here’s my problem:

I tried working with the Animation script that most people use, replacing my custom idle with the existing idles in the script. This sounded simple, but didn’t work, so test a bit further, I setup a GUI text button to call a remote event that would force the idle animation to play for 4 seconds.

The GUI button does make the animation play. But the animation script does not work, which is the main goal. To test a bit further, I tried a more simplified script that only attempts to play the custom Idle animation. This did not work either and I’m guessing (I’m a novice with no CS degree, so, grasping at straws as I dig through forums) I may have made an error in the rigging, animation, or character setup, but I’m unable to resolve.

Any thoughts?

Here’s a video showing that the script animation doesn’t play, but that the GUI button works:
ezgif-2-793e9b188428

Here’s my simplified animation script:
local Players = game:GetService(“Players”)

local function onCharacterAdded(character)
	local humanoid = character:WaitForChild("Humanoid")
 
	for _, playingTracks in pairs(humanoid:GetPlayingAnimationTracks()) do
		playingTracks:Stop(0)
	end
 
	local animateScript = character:WaitForChild("Animate")
	animateScript.idle.IdleAnim.AnimationId = "rbxassetid://4860871408"
end
 
local function onPlayerAdded(player)
	player.CharacterAppearanceLoaded:Connect(onCharacterAdded)
end
 
Players.PlayerAdded:Connect(onPlayerAdded)

Here’s my Character Setup:


Here’s my normal Animation script (I tested both scripts independently, neither worked).
local Character = script.Parent
local Humanoid = Character:WaitForChild(“Humanoid”)
local pose = “Standing”

    local currentAnim = ""
    local currentAnimInstance = nil
    local currentAnimTrack = nil
    local currentAnimKeyframeHandler = nil
    local currentAnimSpeed = 1.0

    local runAnimTrack = nil
    local runAnimKeyframeHandler = nil

    local animTable = {}
    local animNames = { 
    	idle = 	{	
    				{ id = "rbxassetid://4860871408", weight = 1 },
    				{ id = "rbxassetid://4860871408", weight = 1 },
    				{ id = "rbxassetid://4860871408", weight = 9 }
    			},
    	walk = 	{ 	
    				{ id = "http://www.roblox.com/asset/?id=507777826", weight = 10 } 
    			}, 
    	run = 	{
    				{ id = "http://www.roblox.com/asset/?id=507767714", weight = 10 } 
    			}, 
    	swim = 	{
    				{ id = "http://www.roblox.com/asset/?id=507784897", weight = 10 } 
    			}, 
    	swimidle = 	{
    				{ id = "http://www.roblox.com/asset/?id=507785072", weight = 10 } 
    			}, 
    	jump = 	{
    				{ id = "http://www.roblox.com/asset/?id=507765000", weight = 10 } 
    			}, 
    	fall = 	{
    				{ id = "http://www.roblox.com/asset/?id=507767968", weight = 10 } 
    			}, 
    	climb = {
    				{ id = "http://www.roblox.com/asset/?id=507765644", weight = 10 } 
    			}, 
    	sit = 	{
    				{ id = "http://www.roblox.com/asset/?id=507768133", weight = 10 } 
    			},	
    	toolnone = {
    				{ id = "http://www.roblox.com/asset/?id=507768375", weight = 10 } 
    			},
    	toolslash = {
    				{ id = "http://www.roblox.com/asset/?id=522635514", weight = 10 } 
    			},
    	toollunge = {
    				{ id = "http://www.roblox.com/asset/?id=522638767", weight = 10 } 
    			},
    	wave = {
    				{ id = "http://www.roblox.com/asset/?id=507770239", weight = 10 } 
    			},
    	point = {
    				{ id = "http://www.roblox.com/asset/?id=507770453", weight = 10 } 
    			},
    	dance = {
    				{ id = "http://www.roblox.com/asset/?id=507771019", weight = 10 }, 
    				{ id = "http://www.roblox.com/asset/?id=507771955", weight = 10 }, 
    				{ id = "http://www.roblox.com/asset/?id=507772104", weight = 10 } 
    			},
    	dance2 = {
    				{ id = "http://www.roblox.com/asset/?id=507776043", weight = 10 }, 
    				{ id = "http://www.roblox.com/asset/?id=507776720", weight = 10 }, 
    				{ id = "http://www.roblox.com/asset/?id=507776879", weight = 10 } 
    			},
    	dance3 = {
    				{ id = "http://www.roblox.com/asset/?id=507777268", weight = 10 }, 
    				{ id = "http://www.roblox.com/asset/?id=507777451", weight = 10 }, 
    				{ id = "http://www.roblox.com/asset/?id=507777623", weight = 10 } 
    			},
    	laugh = {
    				{ id = "http://www.roblox.com/asset/?id=507770818", weight = 10 } 
    			},
    	cheer = {
    				{ id = "http://www.roblox.com/asset/?id=507770677", weight = 10 } 
    			},
    }

    -- Existance in this list signifies that it is an emote, the value indicates if it is a looping emote
    local emoteNames = { wave = false, point = false, dance = true, dance2 = true, dance3 = true, laugh = false, cheer = false}

    math.randomseed(tick())

    function configureAnimationSet(name, fileList)
    	if (animTable[name] ~= nil) then
    		for _, connection in pairs(animTable[name].connections) do
    			connection:disconnect()
    		end
    	end
    	animTable[name] = {}
    	animTable[name].count = 0
    	animTable[name].totalWeight = 0	
    	animTable[name].connections = {}

    	local allowCustomAnimations = true
    	local AllowDisableCustomAnimsUserFlag = false

    	local success, msg = pcall(function()
    		AllowDisableCustomAnimsUserFlag = UserSettings():IsUserFeatureEnabled("UserAllowDisableCustomAnims2")
    	end)

    	if (AllowDisableCustomAnimsUserFlag) then
    		local success, msg = pcall(function() allowCustomAnimations = game:GetService("StarterPlayer").AllowCustomAnimations end)
    		if not success then
    			allowCustomAnimations = true
    		end
    	end

    	-- check for config values
    	local config = script:FindFirstChild(name)
    	if (allowCustomAnimations and config ~= nil) then
    		table.insert(animTable[name].connections, config.ChildAdded:connect(function(child) configureAnimationSet(name, fileList) end))
    		table.insert(animTable[name].connections, config.ChildRemoved:connect(function(child) configureAnimationSet(name, fileList) end))
    		local idx = 1
    		for _, childPart in pairs(config:GetChildren()) do
    			if (childPart:IsA("Animation")) then
    				table.insert(animTable[name].connections, childPart.Changed:connect(function(property) configureAnimationSet(name, fileList) end))
    				animTable[name][idx] = {}
    				animTable[name][idx].anim = childPart
    				local weightObject = childPart:FindFirstChild("Weight")
    				if (weightObject == nil) then
    					animTable[name][idx].weight = 1
    				else
    					animTable[name][idx].weight = weightObject.Value
    				end
    				animTable[name].count = animTable[name].count + 1
    				animTable[name].totalWeight = animTable[name].totalWeight + animTable[name][idx].weight
    				idx = idx + 1
    			end
    		end
    	end

    	-- fallback to defaults
    	if (animTable[name].count <= 0) then
    		for idx, anim in pairs(fileList) do
    			animTable[name][idx] = {}
    			animTable[name][idx].anim = Instance.new("Animation")
    			animTable[name][idx].anim.Name = name
    			animTable[name][idx].anim.AnimationId = anim.id
    			animTable[name][idx].weight = anim.weight
    			animTable[name].count = animTable[name].count + 1
    			animTable[name].totalWeight = animTable[name].totalWeight + anim.weight
    --			print(name .. " [" .. idx .. "] " .. anim.id .. " (" .. anim.weight .. ")")
    		end
    	end
    end

    -- Setup animation objects
    function scriptChildModified(child)
    	local fileList = animNames[child.Name]
    	if (fileList ~= nil) then
    		configureAnimationSet(child.Name, fileList)
    	end	
    end

    script.ChildAdded:connect(scriptChildModified)
    script.ChildRemoved:connect(scriptChildModified)


    for name, fileList in pairs(animNames) do 
    	configureAnimationSet(name, fileList)
    end	

    -- ANIMATION

    -- declarations
    local toolAnim = "None"
    local toolAnimTime = 0

    local jumpAnimTime = 0
    local jumpAnimDuration = 0.31

    local toolTransitionTime = 0.1
    local fallTransitionTime = 0.2

    -- functions

    function stopAllAnimations()
    	local oldAnim = currentAnim

    	-- return to idle if finishing an emote
    	if (emoteNames[oldAnim] ~= nil and emoteNames[oldAnim] == false) then
    		oldAnim = "idle"
    	end

    	currentAnim = ""
    	currentAnimInstance = nil
    	if (currentAnimKeyframeHandler ~= nil) then
    		currentAnimKeyframeHandler:disconnect()
    	end

    	if (currentAnimTrack ~= nil) then
    		currentAnimTrack:Stop()
    		currentAnimTrack:Destroy()
    		currentAnimTrack = nil
    	end

    	-- clean up walk if there is one
    	if (runAnimKeyframeHandler ~= nil) then
    		runAnimKeyframeHandler:disconnect()
    	end
    	
    	if (runAnimTrack ~= nil) then
    		runAnimTrack:Stop()
    		runAnimTrack:Destroy()
    		runAnimTrack = nil
    	end
    	
    	return oldAnim
    end

    function getHeightScale()
    	if Humanoid then
    		local bodyHeightScale = Humanoid:FindFirstChild("BodyHeightScale")
    		if bodyHeightScale and bodyHeightScale:IsA("NumberValue") then
    			return bodyHeightScale.Value
    		end
    	end
    	
    	return 1
    end

    local smallButNotZero = 0.0001
    function setRunSpeed(speed)
    	if speed < 0.33 then
    		currentAnimTrack:AdjustWeight(1.0)		
    		runAnimTrack:AdjustWeight(smallButNotZero)
    	elseif speed < 0.66 then
    		local weight = ((speed - 0.33) / 0.33)
    		currentAnimTrack:AdjustWeight(1.0 - weight + smallButNotZero)
    		runAnimTrack:AdjustWeight(weight + smallButNotZero)
    	else
    		currentAnimTrack:AdjustWeight(smallButNotZero)
    		runAnimTrack:AdjustWeight(1.0)
    	end
    	
    	local speedScaled = speed * 1.25

    	local heightScale = getHeightScale()	
    	
    	runAnimTrack:AdjustSpeed(speedScaled / heightScale)
    	currentAnimTrack:AdjustSpeed(speedScaled / heightScale)
    end


    function setAnimationSpeed(speed)
    	if speed ~= currentAnimSpeed then
    		currentAnimSpeed = speed
    		if currentAnim == "walk" then
    			setRunSpeed(speed)
    		else
    			currentAnimTrack:AdjustSpeed(currentAnimSpeed)
    		end
    	end
    end

    function keyFrameReachedFunc(frameName)
    	if (frameName == "End") then
    		if currentAnim == "walk" then
    			runAnimTrack.TimePosition = 0.0
    			currentAnimTrack.TimePosition = 0.0
    		else
    			local repeatAnim = currentAnim
    			-- return to idle if finishing an emote
    			if (emoteNames[repeatAnim] ~= nil and emoteNames[repeatAnim] == false) then
    				repeatAnim = "idle"
    			end
    			
    			local animSpeed = currentAnimSpeed
    			playAnimation(repeatAnim, 0.15, Humanoid)
    			setAnimationSpeed(animSpeed)
    		end
    	end
    end

    function rollAnimation(animName)
    	local roll = math.random(1, animTable[animName].totalWeight) 
    	local origRoll = roll
    	local idx = 1
    	while (roll > animTable[animName][idx].weight) do
    		roll = roll - animTable[animName][idx].weight
    		idx = idx + 1
    	end
    	return idx
    end

    function playAnimation(animName, transitionTime, humanoid) 	
    	local idx = rollAnimation(animName)
    	local anim = animTable[animName][idx].anim

    	-- switch animation		
    	if (anim ~= currentAnimInstance) then
    		
    		if (currentAnimTrack ~= nil) then
    			currentAnimTrack:Stop(transitionTime)
    			currentAnimTrack:Destroy()
    		end

    		if (runAnimTrack ~= nil) then
    			runAnimTrack:Stop(transitionTime)
    			runAnimTrack:Destroy()
    		end

    		currentAnimSpeed = 1.0
    	
    		-- load it to the humanoid; get AnimationTrack
    		currentAnimTrack = humanoid:LoadAnimation(anim)
    		currentAnimTrack.Priority = Enum.AnimationPriority.Core
    		 
    		-- play the animation
    		currentAnimTrack:Play(transitionTime)
    		currentAnim = animName
    		currentAnimInstance = anim

    		-- set up keyframe name triggers
    		if (currentAnimKeyframeHandler ~= nil) then
    			currentAnimKeyframeHandler:disconnect()
    		end
    		currentAnimKeyframeHandler = currentAnimTrack.KeyframeReached:connect(keyFrameReachedFunc)
    		
    		-- check to see if we need to blend a walk/run animation
    		if animName == "walk" then
    			local runAnimName = "run"
    			local runIdx = rollAnimation(runAnimName)

    			runAnimTrack = humanoid:LoadAnimation(animTable[runAnimName][runIdx].anim)
    			runAnimTrack.Priority = Enum.AnimationPriority.Core
    			runAnimTrack:Play(transitionTime)		
    			
    			if (runAnimKeyframeHandler ~= nil) then
    				runAnimKeyframeHandler:disconnect()
    			end
    			runAnimKeyframeHandler = runAnimTrack.KeyframeReached:connect(keyFrameReachedFunc)	
    		end
    	end

    end

    -------------------------------------------------------------------------------------------
    -------------------------------------------------------------------------------------------

    local toolAnimName = ""
    local toolAnimTrack = nil
    local toolAnimInstance = nil
    local currentToolAnimKeyframeHandler = nil

    function toolKeyFrameReachedFunc(frameName)
    	if (frameName == "End") then
    		playToolAnimation(toolAnimName, 0.0, Humanoid)
    	end
    end


    function playToolAnimation(animName, transitionTime, humanoid, priority)	 		
    		local idx = rollAnimation(animName)
    		local anim = animTable[animName][idx].anim

    		if (toolAnimInstance ~= anim) then
    			
    			if (toolAnimTrack ~= nil) then
    				toolAnimTrack:Stop()
    				toolAnimTrack:Destroy()
    				transitionTime = 0
    			end
    					
    			-- load it to the humanoid; get AnimationTrack
    			toolAnimTrack = humanoid:LoadAnimation(anim)
    			if priority then
    				toolAnimTrack.Priority = priority
    			end
    			 
    			-- play the animation
    			toolAnimTrack:Play(transitionTime)
    			toolAnimName = animName
    			toolAnimInstance = anim

    			currentToolAnimKeyframeHandler = toolAnimTrack.KeyframeReached:connect(toolKeyFrameReachedFunc)
    		end
    end

    function stopToolAnimations()
    	local oldAnim = toolAnimName

    	if (currentToolAnimKeyframeHandler ~= nil) then
    		currentToolAnimKeyframeHandler:disconnect()
    	end

    	toolAnimName = ""
    	toolAnimInstance = nil
    	if (toolAnimTrack ~= nil) then
    		toolAnimTrack:Stop()
    		toolAnimTrack:Destroy()
    		toolAnimTrack = nil
    	end

    	return oldAnim
    end

    -------------------------------------------------------------------------------------------
    -------------------------------------------------------------------------------------------
    -- STATE CHANGE HANDLERS

    function onRunning(speed)
    	if speed > 0.5 then
    		local scale = 16.0
    		playAnimation("walk", 0.2, Humanoid)
    		setAnimationSpeed(speed / scale)
    		pose = "Running"
    	else
    		if emoteNames[currentAnim] == nil then
    			playAnimation("idle", 0.2, Humanoid)
    			pose = "Standing"
    		end
    	end
    end

    function onDied()
    	pose = "Dead"
    end

    function onJumping()
    	playAnimation("jump", 0.1, Humanoid)
    	jumpAnimTime = jumpAnimDuration
    	pose = "Jumping"
    end

    function onClimbing(speed)
    	local scale = 5.0
    	playAnimation("climb", 0.1, Humanoid)
    	setAnimationSpeed(speed / scale)
    	pose = "Climbing"
    end

    function onGettingUp()
    	pose = "GettingUp"
    end

    function onFreeFall()
    	if (jumpAnimTime <= 0) then
    		playAnimation("fall", fallTransitionTime, Humanoid)
    	end
    	pose = "FreeFall"
    end

    function onFallingDown()
    	pose = "FallingDown"
    end

    function onSeated()
    	pose = "Seated"
    end

    function onPlatformStanding()
    	pose = "PlatformStanding"
    end

    -------------------------------------------------------------------------------------------
    -------------------------------------------------------------------------------------------

    function onSwimming(speed)
    	if speed > 1.00 then
    		local scale = 10.0
    		playAnimation("swim", 0.4, Humanoid)
    		setAnimationSpeed(speed / scale)
    		pose = "Swimming"
    	else
    		playAnimation("swimidle", 0.4, Humanoid)
    		pose = "Standing"
    	end
    end

    function animateTool()
    	if (toolAnim == "None") then
    		playToolAnimation("toolnone", toolTransitionTime, Humanoid, Enum.AnimationPriority.Idle)
    		return
    	end

    	if (toolAnim == "Slash") then
    		playToolAnimation("toolslash", 0, Humanoid, Enum.AnimationPriority.Action)
    		return
    	end

    	if (toolAnim == "Lunge") then
    		playToolAnimation("toollunge", 0, Humanoid, Enum.AnimationPriority.Action)
    		return
    	end
    end

    function getToolAnim(tool)
    	for _, c in ipairs(tool:GetChildren()) do
    		if c.Name == "toolanim" and c.className == "StringValue" then
    			return c
    		end
    	end
    	return nil
    end

    local lastTick = 0

    function stepAnimate(currentTime)
    	local amplitude = 1
    	local frequency = 1
      	local deltaTime = currentTime - lastTick
      	lastTick = currentTime

    	local climbFudge = 0
    	local setAngles = false

      	if (jumpAnimTime > 0) then
      		jumpAnimTime = jumpAnimTime - deltaTime
      	end

    	if (pose == "FreeFall" and jumpAnimTime <= 0) then
    		playAnimation("fall", fallTransitionTime, Humanoid)
    	elseif (pose == "Seated") then
    		playAnimation("sit", 0.5, Humanoid)
    		return
    	elseif (pose == "Running") then
    		playAnimation("walk", 0.2, Humanoid)
    	elseif (pose == "Dead" or pose == "GettingUp" or pose == "FallingDown" or pose == "Seated" or pose == "PlatformStanding") then
    		stopAllAnimations()
    		amplitude = 0.1
    		frequency = 1
    		setAngles = true
    	end

    	-- Tool Animation handling
    	local tool = Character:FindFirstChildOfClass("Tool")
    	local requireHandleCheck = not UserSettings():IsUserFeatureEnabled("UserToolR15Fix")
    	if tool and ((requireHandleCheck and tool.RequiresHandle) or tool:FindFirstChild("Handle")) then
    		local animStringValueObject = getToolAnim(tool)

    		if animStringValueObject then
    			toolAnim = animStringValueObject.Value
    			-- message recieved, delete StringValue
    			animStringValueObject.Parent = nil
    			toolAnimTime = currentTime + .3
    		end

    		if currentTime > toolAnimTime then
    			toolAnimTime = 0
    			toolAnim = "None"
    		end

    		animateTool()		
    	else
    		stopToolAnimations()
    		toolAnim = "None"
    		toolAnimInstance = nil
    		toolAnimTime = 0
    	end
    end

    -- connect events
    Humanoid.Died:connect(onDied)
    Humanoid.Running:connect(onRunning)
    Humanoid.Jumping:connect(onJumping)
    Humanoid.Climbing:connect(onClimbing)
    Humanoid.GettingUp:connect(onGettingUp)
    Humanoid.FreeFalling:connect(onFreeFall)
    Humanoid.FallingDown:connect(onFallingDown)
    Humanoid.Seated:connect(onSeated)
    Humanoid.PlatformStanding:connect(onPlatformStanding)
    Humanoid.Swimming:connect(onSwimming)

    -- setup emote chat hook
    game:GetService("Players").LocalPlayer.Chatted:connect(function(msg)
    	local emote = ""
    	if (string.sub(msg, 1, 3) == "/e ") then
    		emote = string.sub(msg, 4)
    	elseif (string.sub(msg, 1, 7) == "/emote ") then
    		emote = string.sub(msg, 8)
    	end
    	
    	if (pose == "Standing" and emoteNames[emote] ~= nil) then
    		playAnimation(emote, 0.1, Humanoid)
    	end
    end)



    -- initialize to idle
    playAnimation("idle", 0.1, Humanoid)
    pose = "Standing"

    -- loop to handle timed state transitions and tool animations
    while Character.Parent ~= nil do
    	local _, currentGameTime = wait(0.1)
    	stepAnimate(currentGameTime)
    end
1 Like

I recently talked about the issue here, check this post out:

Hope I helped!

If I knew how to do any of that, it would probably be a HUGE help! :smiley: I’ll dig around and see if I can figure out how to do what you’re saying and see if it helps. That said, I did try putting my scripts into the Starter Character Scripts but that didn’t work for me. I may have not done that correctly though.
Thanks!!!

My discord is @Drac#5808 send me a message and I can fix everything for you.

1 Like

That would be awesome, thanks!
It definitively helps when I can look at a working example.
Just sent the discord request.