I could be wrong when saying this, but I’m pretty certain Touched and TouchEnded are not very reliable and I usually stay away from using them (this doesn’t apply in all cases).
For this type of thing, I suggest using raycasting.
I’m not too sure how familiar you are with scripting, but I tried explaining the code below. I really suggest you take the time to try to understand it instead of just copy & pasting it
This should go in a localscript under StarterPlayerScripts:
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local CollectionService = game:GetService("CollectionService")
local Player = Players.LocalPlayer
local Character = nil
local HumanoidRootPart = nil
local Humanoid = nil
local SpeedChangerTag = "SpeedChanger"
local DefaultSpeed = 16 -- WalkSpeed when not on a speed changer
local DownwardsDirection = Vector3.new(0, -10, 0)
local DownwardsRaycastParams = RaycastParams.new()
DownwardsRaycastParams.FilterType = Enum.RaycastFilterType.Blacklist
DownwardsRaycastParams.FilterDescendantsInstances = {}
------------
local function Heartbeat()
if HumanoidRootPart and Humanoid and Humanoid.Health > 0 then -- If our character is alive
local RaycastResult = workspace:Raycast(HumanoidRootPart.Position, DownwardsDirection, DownwardsRaycastParams) -- Cast a ray below us
local Hit = RaycastResult and RaycastResult.Instance
if Hit and CollectionService:HasTag( Hit, SpeedChangerTag ) then -- If the raycast hit something and it has the SpeedChanger tag
-- Change humanoid speed to the hits "Speed" attribute or otherwise 25
Humanoid.WalkSpeed = Hit:GetAttribute("Speed") or 25
else
-- The raycast didnt hit a speed changer, so change our speed to the default speed
Humanoid.WalkSpeed = DefaultSpeed
end
end
end
local function CharacterAdded(NewCharacter)
-- Update variables for my character
Character = NewCharacter
HumanoidRootPart = Character:WaitForChild("HumanoidRootPart")
Humanoid = Character:WaitForChild("Humanoid")
-- Change params so the new character is blacklisted
DownwardsRaycastParams.FilterDescendantsInstances = {Character}
end
CharacterAdded(Player.Character or Player.CharacterAdded:Wait())
-- Attach our Heartbeat function to RunService.Heartbeat
RunService.Heartbeat:Connect(Heartbeat)
-- Attach our CharacterAdded function to Player.CharacterAdded
Player.CharacterAdded:Connect(CharacterAdded)
So we have the part which checks if we’re on a speed changer, now we have to actually set the parts that are a speed changer. Here is an example of applying the tag and attribute to a part:
local CollectionService = game:GetService("CollectionService")
local SpeedChangerTag = "SpeedChanger"
local ThePart = workspace:WaitForChild("SpeedPart") -- This should be your part
CollectionService:AddTag(ThePart, SpeedChangerTag) -- Add the SpeedChanger tag to the part
ThePart:AddAttribute("Speed", 50) -- Add an attribute to the part called "Speed", and set its value to 50
Now when you stand on the part, the system will detect it, get its Speed attribute and change your speed to it.
The good thing about this system is you can have multiple parts which set your speed while on, you can use the second code example and apply it to as many parts as you’d like.
This is a lot to read and understand, let me know if you have any questions