Play Animation through normal Script problem

I am trying to play an Idle animation with a tool through a normal script (not a local one) but I don’t know how or if you can do this.

However, it will always say ‘Attempt to index nil with Character’
I do not know any ways to do this, can someone help?

Here is the code

local Players = game:GetService("Players")

local localPlayer = Players.LocalPlayer

while not localPlayer.Character do wait() end

local character = localPlayer.Character
local humanoid = character:WaitForChild("Humanoid")

local Idle = humanoid:LoadAnimation(script.Idle)
Idle.Looped = true

local equipped

script.Parent.Equipped:Connect(function(Player)
	equipped = true
	Idle.Priority = Enum.AnimationPriority.Movement
	Idle:Play()
end)

Thank you!

Hi, LocalPlayer does not exist on server scripts because they cannot access data that is relevant to a client. To get around this, you can do

local tool = script.Parent
local character = tool.Parent
local player = game.Players:GetPlayerFromCharacter(character) -- however, it seems that this variable is not being used currently
local humanoid = character:WaitForChild("Humanoid")

local Idle = humanoid:LoadAnimation(script.Idle)
Idle.Looped = true

local equipped

tool.Equipped:Connect(function(Player)
	equipped = true
	Idle.Priority = Enum.AnimationPriority.Movement
	Idle:Play()
end)
1 Like

Well you get “Attempt to index nil with Character” because your LocalPlayer is a nil value too
You’ll get the same error if you try

print(LocalPlayer.Name)

and that’s because Players.LocalPlayer
is only defined for LocalScript.

With this script it no longer gives the error but the script itself doesn’t work, I put a print function before Idle.Priority and it printed nothing

Ah my bad. I don’t think equipped connections work on server scripts. You will have to put your code into a local script and then send a server event to the server script. It would probably be easier to just run this whole script on a local script anyways, and then fire data to the server only when it is necessary

this involves two scripts and a remote event, but I think this is the easiest way to accomplish what you want.

-- in a local script:
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local AnimationEvent = game:GetService("") -- add a RemoteEvent into ReplicatedStorage and then enter its name into the quations
local localPlayer = Players.LocalPlayer
local character = Player.Character or Player.CharacterAdded:Wait()
local humanoid = character:WaitForChild("Humanoid")
local Idle = humanoid:LoadAnimation(script.Idle)

Idle.Looped = true
local equipped

script.Parent.Equipped:Connect(function(Player)
	equipped = true
	AnimationEvent:FireServer()
end)

-- in a server script
AnimationEvent.OnServerEvent:Connect(function(Player)
	local character = Player.Character
	if character then
		local humanoid = character:WaitForChild("Humanoid")
		local Idle = humanoid:LoadAnimation(script.Idle)
		Idle.Priority = Enum.AnimationPriority.Movement
		Idle:Play()
	end
end)

No, Equipped works on the Server.

Here’s the issue though:
The Character variable isn’t a Character. It’s possibly the players Backpack, or something else entirely.

You just need to do this:

local tool = script.Parent
local Character,Humanoid

local Idle

tool.Equipped:Connect(function()
  -- tool.Parent only equals Player.Character when Equipped.
  -- We do not need the Player object, since the Animation is all we are concerned with.
  if Character and Character ~= tool.Parent then
    Character = nil
    Humanoid = nil
    Idle:Destroy()
    -- This cleans up old instances and clears variables if the tool is, for example, dropped to another person.
  end
  -- If we do not have an Idle Animation or a Character then we need to create Idle and set the Character.
	if not Idle or not Character then
    Character = tool.Parent
    Humanoid = Character:FindFirstChildOfClass("Humanoid") -- Humanoid could always be renamed, unlikely but possible.
    if Humanoid then -- Did we find a humanoid?
      Idle = Humanoid:WaitForChild("Animator"):LoadAnimation(script.Idle) -- Load animation through the Humanoid's Animator. See why below.
      Idle.Looped = true -- Set looped.
    end
  end
  -- Do we have an Idle AnimationTrack?
  if Idle then
    -- If so, set the Priority and Play it.
    Idle.Priority = Enum.AnimationPriority.Movement
    Idle:Play()
  end
end)

tool.Unequipped:Connect(function()
  -- Do we have an active Idle AnimationTrack?
  if Idle then
    -- If so, stop the animation.
    Idle:Stop()
  end
end)

Why not to use Humanoid:LoadAnimation() for this: Animator | Roblox Creator Documentation

1 Like

it plays the animation but it doesn’t loop, I know that it is set to looping so I don’t know how to fix this, but the script works :+1:

Ah right, I should’ve remembered this.

Setting .Looped in a script is unlikely to work. Instead, set the animation to Looping in the Animation Editor before you export it for use.

Unfortunately this is the only reasonable way to go about this since AnimationTrack.Looped is quite iffy when modified by a script.

Edit to clarify:
The reason behind this is because the AnimationTrack does not take into account .Looped until it has loaded, and when it finishes loading, it sets the properties back to their exported values, so if you exported the animation with Looping disabled, it will set .Looped to false after roughly 6 seconds (Avg. load time)

Also, if you do not wish to export a new version of your Idle with Looping enabled, here’s a simple fix for it:

local tool = script.Parent
local Character,Humanoid

local Idle
local IdleLoop

tool.Equipped:Connect(function()
  -- tool.Parent only equals Player.Character when Equipped.
  -- We do not need the Player object, since the Animation is all we are concerned with.
  if Character and Character ~= tool.Parent then
    Character = nil
    Humanoid = nil
    Idle:Destroy()
    if IdleLoop then
      IdleLoop:Disconnect()
    end
    -- This cleans up old instances and clears variables if the tool is, for example, dropped to another person.
  end
  -- If we do not have an Idle Animation or a Character then we need to create Idle and set the Character.
	if not Idle or not Character then
    Character = tool.Parent
    Humanoid = Character:FindFirstChildOfClass("Humanoid") -- Humanoid could always be renamed, unlikely but possible.
    if Humanoid then -- Did we find a humanoid?
      Idle = Humanoid:WaitForChild("Animator"):LoadAnimation(script.Idle) -- Load animation through the Humanoid's Animator. See why below.
      -- Alternative to setting .Looped
      IdleLoop = Idle.Stopped:Connect(function()
        if tool.Parent == Character then
          Idle.Priority = Enum.AnimationPriority.Movement
          Idle:Play()
        end
      end)
    end
  end
  -- Do we have an Idle AnimationTrack?
  if Idle then
    -- If so, set the Priority and Play it.
    Idle.Priority = Enum.AnimationPriority.Movement
    Idle:Play()
  end
end)

tool.Unequipped:Connect(function()
  -- Do we have an active Idle AnimationTrack?
  if Idle then
    -- If so, stop the animation.
    Idle:Stop()
  end
end)

Hope this helped.

1 Like

Animations on a client’s character should be played on that client, not the server.

yes but then others wouldn’t see the animation