I’m trying to change the run & walk animations when a player is in a certain area.
I’ve tried lots of approaches of similar functions I’ve found on here across the past week but I’m stumped and keep bashing my head into layers of “knowledge lacking”!
So… I’ve tried Scripts & LocalScripts in ServerScriptService, StarterCharacterScript, and in the workspace.Part
I’ve tried local function onCharacterAdded(character) … area.Touched:Connect(function(…) … local function onTouch(part) … cloning animations from ServerStorage …
Here’s my latest attempt tweaked from a working change animation when character is added script in ServerScriptStorage.
I might have gotten closer with some previous attempts but I have a gaggle of disabled scripts ugly-crying throughout the folders and I don’t want to get my socks wet.
local Players = game:GetService("Players")
local player = Players.LocalPlayer
local character = player.Character or player.CharacterAdded:Wait()
local area = workspace.Zone.area
local function onTouched(area)
-- Get animator on humanoid
local humanoid = character:WaitForChild("Humanoid")
local animator = humanoid:WaitForChild("Animator")
-- Stop all animation tracks
for _, playingTrack in animator:GetPlayingAnimationTracks() do
playingTrack:Stop(0)
end
local animateScript = character:WaitForChild("Animate")
animateScript.run.RunAnim.AnimationId = "rbxassetid://16002698111"
animateScript.walk.WalkAnim.AnimationId = "rbxassetid://16002698111"
end
area.Touched:Connect(onTouched)
Uhh I don’t think u need to get the player service. I think it is better if u add a parameter to the function when u call it by the touched event with the same name as the function you created. After that, you can use that parameter to detect whether the player is walking through that area. If so, then you will change the animation
Thanks! I thought I needed to get the Players service so I could use LocalPlayer and character, and thus the Animate scripts so they can be changed.
So you think something more like this? Maybe with a debounce and TouchEnded to swap back after they leave?
I feel like once I understand why this isn’t working I could change it to a Region3, just depends on what’ll run smoother.
How would you define the variable “character” here?
-- define character somewhere somehow
local area = workspace.Zone.area
local function playerInArea()
local humanoid = character:WaitForChild("Humanoid")
local animator = humanoid:WaitForChild("Animator")
for _, playingTrack in animator:GetPlayingAnimationTracks() do
playingTrack:Stop(0)
end
local animateScript = character:WaitForChild("Animate")
animateScript.run.RunAnim.AnimationId = "rbxassetid://16002698111"
animateScript.walk.WalkAnim.AnimationId = "rbxassetid://16002698111"
end
area.Touched:Connect(playerInArea)
I personally define the character by using the touched event. So how I do is when I do the touched event, I check whether the object that has hit is a player by using the hit parameter and then finding a child Humanoid. If so, this means that there is player in that zone and if so, your animation will change which look something like this
local area = game.Workspace:WaitForChild("Area")
area.Touched:Connect(function(hit)
if hit.Parent:WaitForChild("Humanoid") then
local humanoid = hit.Parent:WaitForChild("Humanoid")
local character = hit.Parent
-- Your code
end
end)
The way I called the function is just my preferred way to do so as it can get the item that hit the object
Alrighty! Was getting lots of hits of course - legs going this way, head going that way 'n all.
I tried adding a debounce but it just made it work intermittently.
Added an extra filter hit.Name == “HumanoidRootPart” and now it’s working much better.
18:27:43.297 touched HumanoidRootPart - Server - ServScriSkatev4:4*
18:28:03.816 ended HumanoidRootPart - Server - ServScriSkatev4:19*
18:28:10.366 touched HumanoidRootPart - Server - ServScriSkatev4:4*
18:28:12.932 ended HumanoidRootPart - Server - ServScriSkatev4:19*
Script’s in ServerScriptServices
local area = game.Workspace.Zone:WaitForChild("Area")
area.Touched:Connect(function(hit)
print("touched", hit.Name)
if hit.Name == "HumanoidRootPart" and hit.Parent:WaitForChild("Humanoid") then
local humanoid = hit.Parent:WaitForChild("Humanoid")
local character = hit.Parent
local animator = humanoid:WaitForChild("Animator")
for _, playingTrack in animator:GetPlayingAnimationTracks() do
playingTrack:Stop(0)
end
local animateScript = character:WaitForChild("Animate")
animateScript.run.RunAnim.AnimationId = "rbxassetid://16002698111"
animateScript.walk.WalkAnim.AnimationId = "rbxassetid://16002698111"
end
end)
area.TouchEnded:Connect(function(onEnd)
print("ended", onEnd.Name)
if onEnd.Name == "HumanoidRootPart" and onEnd.Parent:WaitForChild("Humanoid") then
local humanoid = onEnd.Parent:WaitForChild("Humanoid")
local character = onEnd.Parent
local animator = humanoid:WaitForChild("Animator")
for _, playingTrack in animator:GetPlayingAnimationTracks() do
playingTrack:Stop(0)
end
local animateScript = character:WaitForChild("Animate")
animateScript.run.RunAnim.AnimationId = "rbxassetid://913376220" -- default
animateScript.walk.WalkAnim.AnimationId = "rbxassetid://913402848" -- default
end
end)
If I decide to change it to Region3 I’ll pop back in with another script.
Another approach from @tralalah works too, as below.
(only issue I have now is that the animation doesn’t change until the player stops walking/running)
Woot! I figured out how to make the animation change while still getting input! Updated the script below.
Link to devforum post
A ServerStorage folder with all the contents of the Animate folder
A ServerStorage folder with all the contents of the Animate folder WITH any animation changes
A Script in ServerScriptService as below to swap them out
local area = workspace.Zone.Area
-- Area is a part that covers the whole area where animation is to occur, tall enough
-- so jumping doesn't cause TouchEnded. Transparency 1 and CanCollide false.
local defaultAnimsFolder = game:GetService("ServerStorage").AnimDefault
local newAnimsFolder = game:GetService("ServerStorage").AnimNew
area.Touched:Connect(function(hit)
if hit.Name == "HumanoidRootPart" and hit.Parent:WaitForChild("Humanoid") then
local humanoid = hit.Parent:WaitForChild("Humanoid")
local animate = hit.Parent:WaitForChild("Animate")
for _, animateFolderKids in pairs(animate:GetChildren()) do
animateFolderKids:Destroy()
end
for _, newAnims in pairs(newAnimsFolder:GetChildren()) do
local newStuff = newAnims:Clone()
newStuff.Parent = animate
end
local animator = humanoid:WaitForChild("Animator")
for _, playingTrack in animator:GetPlayingAnimationTracks() do
playingTrack:Stop(1)
end
humanoid.WalkSpeed = 20
end
end)
area.TouchEnded:Connect(function(hit)
if hit.Name == "HumanoidRootPart" and hit.Parent:WaitForChild("Humanoid") then
local humanoid = hit.Parent:WaitForChild("Humanoid")
local animate = hit.Parent:WaitForChild("Animate")
for _, animateFolderKids in pairs(animate:GetChildren()) do
animateFolderKids:Destroy()
end
for _, newA in pairs(defaultAnimsFolder:GetChildren()) do
local newStuff = newA:Clone()
newStuff.Parent = animate
end
local animator = humanoid:WaitForChild("Animator")
for _, playingTrack in animator:GetPlayingAnimationTracks() do
playingTrack:Stop(1)
end
humanoid.WalkSpeed = 16
end
end)
Alrighty, I’ve been working hard hyperfocusing on this somewhat intensely.
I’ve just made this Script (in ServerScriptStorage) execute when a RemoteEvent (in ReplicatedStorage) is fired by a LocalScript (in StarterCharacter).
I ran into issues when I wanted to expand and complicate the area for the Touch event. Even combining the parts into a union I was getting TouchEnded events when the player was still in the “zone”.
Lemme try to summarise what I did and explain (I’m no pro, so sorry if terminology is incorrect)
Put a RemoteEvent in ReplicatedStorage, I renamed it RemEventFloor
LocalScript in StarterCharacter to change the movement sound effects
I used this guide by Itz_FloppyFish on youtube, they made the code able to be copied from the description (very helpful!).
--- added these variables above the function
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteEvent = ReplicatedStorage:FindFirstChild("RemEventFloor")
function updateFootstepsSound()
local FloorMaterial = Humanoid.FloorMaterial
-- after the variable for the FloorMaterial in the function I fired the Enum to the RemoteEvent
remoteEvent:FireServer(FloorMaterial)
Script in ServerScriptStorage to swap out the animations in Humanoid.Animate
I had to change this code a fair bit from what I had above. There are lots of similarities and lots of differences so I’ll put the whole script below.
-- Again, added variables for the RemoteEvent at the top
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteEvent = ReplicatedStorage:FindFirstChild("RemEventFloor")
local defaultAnimsFolder = game:GetService("ServerStorage").AnimDefault
local newAnimsFolder = game:GetService("ServerStorage").AnimNew
-- Instead of Touched and TouchEnded functions I could use one function
-- connected to the RemoteEvent and the other arguments passed to it
-- by the LocalScript. I had to change how we got the Humanoid because
-- I no longer had that Touched event. The event handler on the server
-- always sends through the Player parameter first so...
local function onFloorMaterialChange(Player, FloorMaterial)
local character = Player.Character -- (Player from RemoteEvent)
local humanoid = character:WaitForChild("Humanoid")
local animate = character:WaitForChild("Animate")
-- if the FloorMaterial is ice
if FloorMaterial == Enum.Material.Ice then -- (FloorMaterial from RemoteEvent)
-- for all the animations in the Humanoid's Animate folder
for _, animateFolderKids in pairs(animate:GetChildren()) do
-- destroy them
animateFolderKids:Destroy()
end
-- for all the new animations backed up in ServerStorage
for _, newAnims in pairs(newAnimsFolder:GetChildren()) do
-- clone them
local newStuff = newAnims:Clone()
-- and put them into the Humanoids' Animate folder
newStuff.Parent = animate
end
-- stop playing the current track so the cloned one can start
local animator = humanoid:WaitForChild("Animator")
for _, playingTrack in animator:GetPlayingAnimationTracks() do
playingTrack:Stop(1)
end
-- increase the speed
humanoid.WalkSpeed = 22
-- if the above conditions aren't met put defaults back into Animate
else
for _, animateFolderKids in pairs(animate:GetChildren()) do
animateFolderKids:Destroy()
end
for _, newA in pairs(defaultAnimsFolder:GetChildren()) do
local newStuff = newA:Clone()
newStuff.Parent = animate
end
local animator = humanoid:WaitForChild("Animator")
for _, playingTrack in animator:GetPlayingAnimationTracks() do
playingTrack:Stop(1)
end
humanoid.WalkSpeed = 16
end
end
-- Connect the RemoteEvent to the above function
remoteEvent.OnServerEvent:Connect(onFloorMaterialChange)