local Players = game:GetService("Players") local RunService = game:GetService("RunService") local Workspace = game:GetService("Workspace") local LocalPlayer = Players.LocalPlayer local Character = LocalPlayer.Character or LocalPlayer.CharacterAdded:Wait() local BoomBoxRemote local COLLISION_COOLDOWN = 0.3 local BOUNCE_SPEED = 50 local WALL_DETECTION_RANGE = 3 local WALK_SPEED_BASE = 5 local WALK_SPEED_MAX = 40 local ACCELERATION_RATE = 20 local DECELERATION_RATE = 40 local isColliding = false local currentVelocity = Vector3.zero local lastMoveDirection = Vector3.new(0, 0, -1) local ANIMATION_ID = "rbxassetid://116772752010894" local animation = Instance.new("Animation") animation.AnimationId = ANIMATION_ID local animationTrack local currentAnimator local HumanoidRootPart local function setupCharacter(char) Character = char local Humanoid = Character:WaitForChild("Humanoid") HumanoidRootPart = Character:WaitForChild("HumanoidRootPart") currentAnimator = Humanoid:WaitForChild("Animator") Humanoid.WalkSpeed = 0 if animationTrack then animationTrack:Stop() animationTrack = nil end BoomBoxRemote = nil local success, track = pcall(function() return currentAnimator:LoadAnimation(animation) end) if success and track then animationTrack = track animationTrack.Looped = true animationTrack.Priority = Enum.AnimationPriority.Action4 animationTrack:Play() animationTrack:AdjustSpeed(0) -- Start animation stopped else warn("Failed to load animation - invalid or unowned ID.") end currentVelocity = Vector3.zero isColliding = false end setupCharacter(Character) LocalPlayer.CharacterAdded:Connect(setupCharacter) local function getBoomBoxRemote() if BoomBoxRemote then return BoomBoxRemote end if not Character then return nil end for _, tool in ipairs(Character:GetChildren()) do if tool:IsA("Tool") and tool.Name == "BoomBox" then local remote = tool:FindFirstChild("Remote") if remote and remote:IsA("RemoteEvent") then BoomBoxRemote = remote return remote end end end return nil end local toucedConnection local function handleCollision(otherPart) if isColliding or not HumanoidRootPart or not otherPart or otherPart:IsDescendantOf(Character) then return end isColliding = true local bounceDirection = -currentVelocity.Unit if currentVelocity.Magnitude < 0.1 then bounceDirection = -lastMoveDirection.Unit if lastMoveDirection.Magnitude < 0.1 then bounceDirection = -HumanoidRootPart.CFrame.LookVector end end HumanoidRootPart.AssemblyLinearVelocity = bounceDirection * BOUNCE_SPEED currentVelocity = HumanoidRootPart.AssemblyLinearVelocity local remote = getBoomBoxRemote() if remote then local args = { "PlaySong", 1897654568 } remote:FireServer(unpack(args)) task.wait(COLLISION_COOLDOWN) remote:FireServer(" ") end isColliding = false end local function connectTouchedEvent() if toucedConnection then toucedConnection:Disconnect() toucedConnection = nil end if HumanoidRootPart then toucedConnection = HumanoidRootPart.Touched:Connect(handleCollision) end end connectTouchedEvent() LocalPlayer.CharacterAdded:Connect(function(char) setupCharacter(char) connectTouchedEvent() end) RunService.Heartbeat:Connect(function(deltaTime) if not (Character and Character.Parent) then return end local Humanoid = Character:FindFirstChild("Humanoid") if not (Humanoid and HumanoidRootPart and currentAnimator and animationTrack) then return end if Humanoid.WalkSpeed ~= 0 then Humanoid.WalkSpeed = 0 end local moveDirection = Humanoid.MoveDirection if moveDirection.Magnitude > 0.1 then lastMoveDirection = moveDirection.Unit local targetSpeed = WALK_SPEED_MAX local newSpeedMagnitude = math.min(targetSpeed, currentVelocity.Magnitude + ACCELERATION_RATE * deltaTime) currentVelocity = lastMoveDirection * newSpeedMagnitude else local currentSpeedMagnitude = currentVelocity.Magnitude if currentSpeedMagnitude > 0 then local decelerationAmount = DECELERATION_RATE * deltaTime local newSpeedMagnitude = math.max(0, currentSpeedMagnitude - decelerationAmount) if newSpeedMagnitude < 0.5 then currentVelocity = Vector3.zero else currentVelocity = currentVelocity.Unit * newSpeedMagnitude end else currentVelocity = Vector3.zero end end HumanoidRootPart.AssemblyLinearVelocity = currentVelocity local minAnimationSpeedThreshold = 0.5 local animationSpeedMultiplier = 0.05 local currentSpeed = currentVelocity.Magnitude if currentSpeed > minAnimationSpeedThreshold then animationTrack:AdjustSpeed(currentSpeed * animationSpeedMultiplier) else animationTrack:AdjustSpeed(0) end local lookDirection = lastMoveDirection local targetCFrame = CFrame.lookAt(HumanoidRootPart.Position, HumanoidRootPart.Position + lookDirection, Vector3.new(0, 1, 0)) local turnSpeed = 0.15 HumanoidRootPart.CFrame = HumanoidRootPart.CFrame:Lerp(targetCFrame, turnSpeed) end)