Classic Roblox Animation With Movement System
Key RequiredUniversal

Classic Roblox Animation With Movement System

Universal ScriptGuest_43854Guest_43854 1.8K views 1.9K executesUpdated Feb 15, 2026
5.0/ 5(2 votes)
20100% Positive
Lua Script•634 lines (16874 chars)
--[[
	WARNING: Heads up! This script has not been verified by ScriptBlox. Use at your own risk!
]]
-- Combined Animation + Movement Script (R6 & R15 Compatible)
-- Auto-respawns with all features enabled

local Players = game:GetService("Players")
local player = Players.LocalPlayer

-- Movement Configuration
local MASS_MULTIPLIER = 1
local CLASSIC_CLIMB_SPEED = 12

-- Track if this is the first setup
local isFirstSetup = true

local function setupCharacter(character)
	-- Wait for essential parts
	local humanoid = character:WaitForChild("Humanoid")
	local rootPart = character:WaitForChild("HumanoidRootPart")
	
	-- Detect if R6 or R15
	local isR6 = character:FindFirstChild("Torso") ~= nil
	local isR15 = character:FindFirstChild("UpperTorso") ~= nil
	
	-- ============================================
	-- ANIMATION SCRIPT SETUP (R6 ONLY)
	-- ============================================
	
	if isR6 then
		-- Only break joints on FIRST setup, not on respawns
		if isFirstSetup then
			isFirstSetup = false
			character:BreakJoints()
			player.Character = nil
			
			-- Wait for respawn
			repeat wait() until player.Character
			character = player.Character
			humanoid = character:WaitForChild("Humanoid")
			rootPart = character:WaitForChild("HumanoidRootPart")
		end
		
		-- Disable default animations
		local AnimConnection = game.Workspace.DescendantAdded:Connect(function(c)
			if c.Name == "Animate" then
				c.Disabled = true
			end
		end)
		
		-- Also disable any existing Animate script
		local existingAnimate = character:FindFirstChild("Animate")
		if existingAnimate then
			existingAnimate.Disabled = true
		end
		
		wait(0.1)
		
		function waitForChild(parent, childName)
			local child = parent:findFirstChild(childName)
			if child then return child end
			while true do
				child = parent.ChildAdded:wait()
				if child.Name == childName then return child end
			end
		end

		-- Animation declarations
		local Figure = character
		local Torso = waitForChild(Figure, "Torso")
		local RightShoulder = waitForChild(Torso, "Right Shoulder")
		local LeftShoulder = waitForChild(Torso, "Left Shoulder")
		local RightHip = waitForChild(Torso, "Right Hip")
		local LeftHip = waitForChild(Torso, "Left Hip")
		local Neck = waitForChild(Torso, "Neck")
		local pose = "Standing"

		local toolAnim = "None"
		local toolAnimTime = 0
		local jumpMaxLimbVelocity = 0.75

		-- Animation functions
		function onRunning(speed)
			if speed > 0 then
				pose = "Running"
			else
				pose = "Standing"
			end
		end

		function onDied()
			pose = "Dead"
		end

		function onJumping()
			pose = "Jumping"
		end

		function onClimbing()
			pose = "Climbing"
		end

		function onGettingUp()
			pose = "GettingUp"
		end

		function onFreeFall()
			pose = "FreeFall"
		end

		function onFallingDown()
			pose = "FallingDown"
		end

		function onSeated()
			pose = "Seated"
		end

		function onPlatformStanding()
			pose = "PlatformStanding"
		end

		function onSwimming(speed)
			if speed > 0 then
				pose = "Running"
			else
				pose = "Standing"
			end
		end

		function moveJump()
			RightShoulder.MaxVelocity = jumpMaxLimbVelocity
			LeftShoulder.MaxVelocity = jumpMaxLimbVelocity
			RightShoulder:SetDesiredAngle(3.14)
			LeftShoulder:SetDesiredAngle(-3.14)
			RightHip:SetDesiredAngle(0)
			LeftHip:SetDesiredAngle(0)
		end

		function moveFreeFall()
			RightShoulder.MaxVelocity = jumpMaxLimbVelocity
			LeftShoulder.MaxVelocity = jumpMaxLimbVelocity
			RightShoulder:SetDesiredAngle(3.14)
			LeftShoulder:SetDesiredAngle(-3.14)
			RightHip:SetDesiredAngle(0)
			LeftHip:SetDesiredAngle(0)
		end

		function moveFallingDown()
			RightShoulder.MaxVelocity = jumpMaxLimbVelocity
			LeftShoulder.MaxVelocity = jumpMaxLimbVelocity
			RightShoulder:SetDesiredAngle(3.14)
			LeftShoulder:SetDesiredAngle(-3.14)
			RightHip:SetDesiredAngle(0)
			LeftHip:SetDesiredAngle(0)
		end

		function moveSit()
			RightShoulder.MaxVelocity = 0.15
			LeftShoulder.MaxVelocity = 0.15
			RightShoulder:SetDesiredAngle(3.14 / 2)
			LeftShoulder:SetDesiredAngle(-3.14 / 2)
			RightHip:SetDesiredAngle(3.14 / 2)
			LeftHip:SetDesiredAngle(-3.14 / 2)
		end

		function getTool()
			for _, kid in ipairs(Figure:GetChildren()) do
				if kid.className == "Tool" then return kid end
			end
			return nil
		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

		function animateTool()
			if (toolAnim == "None") then
				RightShoulder:SetDesiredAngle(1.57)
				return
			end

			if (toolAnim == "Slash") then
				RightShoulder.MaxVelocity = 0.5
				RightShoulder:SetDesiredAngle(0)
				return
			end

			if (toolAnim == "Lunge") then
				RightShoulder.MaxVelocity = 0.5
				LeftShoulder.MaxVelocity = 0.5
				RightHip.MaxVelocity = 0.5
				LeftHip.MaxVelocity = 0.5
				RightShoulder:SetDesiredAngle(1.57)
				LeftShoulder:SetDesiredAngle(1.0)
				RightHip:SetDesiredAngle(1.57)
				LeftHip:SetDesiredAngle(1.0)
				return
			end
		end

		function move(time)
			local amplitude
			local frequency

			-- Check if player is NOT in idle, walking, or sitting state
			if pose ~= "Standing" and pose ~= "Running" and pose ~= "Seated" then
				moveFreeFall()
				return
			end

			if (pose == "Seated") then
				moveSit()
				return
			end

			local climbFudge = 0

			if (pose == "Running") then
				if (RightShoulder.CurrentAngle > 1.5 or RightShoulder.CurrentAngle < -1.5) then
					RightShoulder.MaxVelocity = jumpMaxLimbVelocity
				else
					RightShoulder.MaxVelocity = 0.15
				end
				if (LeftShoulder.CurrentAngle > 1.5 or LeftShoulder.CurrentAngle < -1.5) then
					LeftShoulder.MaxVelocity = jumpMaxLimbVelocity
				else
					LeftShoulder.MaxVelocity = 0.15
				end
				amplitude = 1
				frequency = 9
			elseif (pose == "Climbing") then
				RightShoulder.MaxVelocity = 0.5
				LeftShoulder.MaxVelocity = 0.5
				amplitude = 1
				frequency = 9
				climbFudge = 3.14
			else
				amplitude = 0.1
				frequency = 1
			end

			desiredAngle = amplitude * math.sin(time * frequency)

			RightShoulder:SetDesiredAngle(desiredAngle + climbFudge)
			LeftShoulder:SetDesiredAngle(desiredAngle - climbFudge)
			RightHip:SetDesiredAngle(-desiredAngle)
			LeftHip:SetDesiredAngle(-desiredAngle)

			local tool = getTool()

			if tool then
				animStringValueObject = getToolAnim(tool)

				if animStringValueObject then
					toolAnim = animStringValueObject.Value
					animStringValueObject.Parent = nil
					toolAnimTime = time + 0.3
				end

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

				animateTool()
			else
				toolAnim = "None"
				toolAnimTime = 0
			end
		end

		-- Connect animation 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)

		-- Start animation loop
		local animationActive = true
		task.spawn(function()
			while Figure.Parent ~= nil and animationActive do
				local _, time = wait(0.1)
				pcall(function()
					move(time)
				end)
			end
		end)
		
		-- Cleanup animation on death
		humanoid.Died:Connect(function()
			animationActive = false
			if AnimConnection then
				AnimConnection:Disconnect()
			end
		end)
	else
		-- R15: Just disable default animations for the effect
		local existingAnimate = character:FindFirstChild("Animate")
		if existingAnimate then
			existingAnimate.Disabled = true
		end
		
		print("R15 character detected - animations disabled for effect")
	end
	
	-- ============================================
	-- MOVEMENT SCRIPT SETUP (WORKS FOR BOTH R6 AND R15)
	-- ============================================
	
	-- Function to modify a single part
	local function modifyPart(part)
		if part:IsA("BasePart") and part.Name ~= "HumanoidRootPart" then
			part.CanCollide = true
			part.CanTouch = true
			part.CanQuery = true
			part.Massless = false

			local currentProps = part.CustomPhysicalProperties
			local density = currentProps and currentProps.Density or 0.7
			local friction = currentProps and currentProps.Friction or 0.3
			local elasticity = currentProps and currentProps.Elasticity or 0.5

			part.CustomPhysicalProperties = PhysicalProperties.new(
				density * MASS_MULTIPLIER,
				friction * 2,
				elasticity * 0.2,
				1,
				1
			)
		end
	end

	-- Disable default Roblox climbing
	humanoid:SetStateEnabled(Enum.HumanoidStateType.Climbing, false)

	-- Apply to all body parts
	for _, part in pairs(character:GetDescendants()) do
		modifyPart(part)
	end

	-- Create BodyGyro (only active during jumps)
	local bodyGyro = Instance.new("BodyGyro")
	bodyGyro.Name = "UprightGyro"
	bodyGyro.MaxTorque = Vector3.new(0, 0, 0)
	bodyGyro.P = 50000
	bodyGyro.D = 5000
	bodyGyro.CFrame = rootPart.CFrame
	bodyGyro.Parent = rootPart

	local isJumping = false
	local jumpMomentum = Vector3.new(0, 0, 0)

	-- Classic climbing variables
	local isClimbing = false
	local climbingPart = nil
	local UserInputService = game:GetService("UserInputService")

	local function checkForClimbableSurface()
		local touchingParts = workspace:GetPartsInPart(rootPart)
		for _, part in pairs(touchingParts) do
			if part:IsA("BasePart") and not part:IsDescendantOf(character) and part.CanCollide then
				local normal = (rootPart.Position - part.Position).Unit
				if math.abs(normal.Y) < 0.5 then
					return part
				end
			end
		end
		return nil
	end

	local climbConnection
	local function startClimbing(surface)
		if isClimbing then return end

		isClimbing = true
		climbingPart = surface
		humanoid.PlatformStand = true

		local bodyVelocity = Instance.new("BodyVelocity")
		bodyVelocity.Name = "ClimbVelocity"
		bodyVelocity.MaxForce = Vector3.new(0, 4000, 0)
		bodyVelocity.Velocity = Vector3.new(0, 0, 0)
		bodyVelocity.Parent = rootPart

		climbConnection = game:GetService("RunService").Heartbeat:Connect(function()
			if not isClimbing or not bodyVelocity or not bodyVelocity.Parent then
				return
			end

			local touchingSurface = checkForClimbableSurface()
			if not touchingSurface then
				if climbConnection then
					climbConnection:Disconnect()
				end
				isClimbing = false
				humanoid.PlatformStand = false
				if bodyVelocity and bodyVelocity.Parent then
					bodyVelocity:Destroy()
				end
				return
			end

			local moveDirection = humanoid.MoveDirection
			local climbVelocity = Vector3.new(0, 0, 0)

			if moveDirection.Magnitude > 0 then
				local upInput = -moveDirection.Z
				climbVelocity = Vector3.new(0, upInput * CLASSIC_CLIMB_SPEED, 0)
			end

			bodyVelocity.Velocity = climbVelocity
		end)
	end

	local function stopClimbing()
		if not isClimbing then return end

		isClimbing = false
		climbingPart = nil
		humanoid.PlatformStand = false

		if climbConnection then
			climbConnection:Disconnect()
			climbConnection = nil
		end

		local climbVel = rootPart:FindFirstChild("ClimbVelocity")
		if climbVel then
			climbVel:Destroy()
		end
	end

	-- Detect climbing
	game:GetService("RunService").Heartbeat:Connect(function()
		if not isJumping and not isClimbing then
			local surface = checkForClimbableSurface()
			if surface and humanoid.MoveDirection.Magnitude > 0 then
				startClimbing(surface)
			end
		end
	end)

	-- Jump to stop climbing
	UserInputService.InputBegan:Connect(function(input, gameProcessed)
		if not gameProcessed and input.KeyCode == Enum.KeyCode.Space then
			if isClimbing then
				stopClimbing()
				humanoid:ChangeState(Enum.HumanoidStateType.Jumping)
			elseif humanoid.PlatformStand == true then
				humanoid.PlatformStand = false
				humanoid:ChangeState(Enum.HumanoidStateType.Running)
			end
		end
	end)

	-- Update gyro - ONLY active during jumps
	game:GetService("RunService").Heartbeat:Connect(function()
		if bodyGyro and bodyGyro.Parent and rootPart then
			local state = humanoid:GetState()

			if state == Enum.HumanoidStateType.Jumping or state == Enum.HumanoidStateType.Freefall then
				if not isJumping then
					isJumping = true
					bodyGyro.MaxTorque = Vector3.new(500000, 500000, 500000)
					local lookVector = rootPart.CFrame.LookVector
					local uprightLook = Vector3.new(lookVector.X, 0, lookVector.Z).Unit
					bodyGyro.CFrame = CFrame.lookAt(Vector3.zero, uprightLook) * CFrame.Angles(0, math.pi, 0)
				end
			else
				if isJumping then
					isJumping = false
					bodyGyro.MaxTorque = Vector3.new(0, 0, 0)
				end
			end
		end
	end)

	-- State changes
	humanoid.StateChanged:Connect(function(oldState, newState)
		if newState == Enum.HumanoidStateType.Jumping then
			jumpMomentum = rootPart.AssemblyVelocity
			rootPart.AssemblyAngularVelocity = Vector3.new(0, 0, 0)
			if isClimbing then
				stopClimbing()
			end
		elseif newState == Enum.HumanoidStateType.Freefall then
			rootPart.AssemblyAngularVelocity = Vector3.new(0, 0, 0)
		elseif newState == Enum.HumanoidStateType.Landed then
			isJumping = false
			bodyGyro.MaxTorque = Vector3.new(0, 0, 0)
			jumpMomentum = Vector3.new(0, 0, 0)
		end
	end)

	local isAirborne = false

	-- Air control management with momentum preservation
	humanoid.StateChanged:Connect(function(oldState, newState)
		if newState == Enum.HumanoidStateType.Jumping then
			isAirborne = true
			task.wait(0.05)
			if humanoid:GetState() == Enum.HumanoidStateType.Jumping or
				humanoid:GetState() == Enum.HumanoidStateType.Freefall then
				humanoid.PlatformStand = true
			end
		elseif newState == Enum.HumanoidStateType.Freefall then
			isAirborne = true
			if not humanoid.PlatformStand then
				humanoid.PlatformStand = true
			end
		elseif newState == Enum.HumanoidStateType.Landed then
			task.wait(0.1)
			isAirborne = false
			humanoid.PlatformStand = false
			humanoid:ChangeState(Enum.HumanoidStateType.Running)
		end
	end)

	-- Safety auto-recover
	task.spawn(function()
		while character.Parent and humanoid.Health > 0 do
			task.wait(0.5)
			if humanoid.PlatformStand == true and
				humanoid:GetState() ~= Enum.HumanoidStateType.Jumping and
				humanoid:GetState() ~= Enum.HumanoidStateType.Freefall and
				not isClimbing then
				humanoid.PlatformStand = false
				humanoid:ChangeState(Enum.HumanoidStateType.Running)
			end
		end
	end)

	-- Force collisions - Works for both R6 and R15
	local function forcePartCollisions(part)
		if part:IsA("BasePart") then
			-- R6 limb detection
			local isR6Limb = part.Name:lower():find("arm") or
				part.Name:lower():find("leg")
			
			-- R15 limb detection
			local isR15Limb = part.Name:lower():find("hand") or
				part.Name:lower():find("lowerarm") or
				part.Name:lower():find("upperarm") or
				part.Name:lower():find("lowerleg") or
				part.Name:lower():find("upperleg") or
				part.Name:lower():find("foot")
			
			-- Torso detection for both
			local isTorso = part.Name:lower():find("torso") or
				part.Name:lower():find("uppertrunk") or
				part.Name:lower():find("lowertrunk")

			local isHead = part.Name:lower() == "head"
			local isAccessory = part.Parent and part.Parent:IsA("Accessory")

			if ((isR6Limb or isR15Limb or isTorso or isHead) and not isAccessory) then
				pcall(function()
					part.CollisionGroup = "Default"
				end)

				part.CanCollide = true
				part.CanTouch = true
				part.CanQuery = true

				-- More aggressive collision enforcement especially for legs
				task.spawn(function()
					while part and part.Parent and character.Parent do
						-- Force collision EVERY frame for legs to fix landing issues
						if part.Name:lower():find("leg") or part.Name:lower():find("foot") then
							if not part.CanCollide then
								part.CanCollide = true
							end
							task.wait() -- Every frame check
						else
							if not part.CanCollide then
								part.CanCollide = true
							end
							task.wait(0.1) -- Regular check for other parts
						end
					end
				end)
			end
		end
	end

	for _, part in pairs(character:GetDescendants()) do
		forcePartCollisions(part)
	end

	character.DescendantAdded:Connect(function(descendant)
		if descendant:IsA("BasePart") then
			task.wait(0.1)
			modifyPart(descendant)
			forcePartCollisions(descendant)
		end
	end)

	-- Cleanup on death
	humanoid.Died:Connect(function()
		if bodyGyro then
			bodyGyro:Destroy()
		end
		stopClimbing()
	end)

	if isR6 then
		print("Combined script loaded - R6 animations + heavy physics!")
	else
		print("Combined script loaded - R15 movement physics (animations disabled for effect)!")
	end
end

-- Setup on spawn/respawn
player.CharacterAdded:Connect(function(character)
	setupCharacter(character)
end)

-- Setup current character if it exists
if player.Character then
	setupCharacter(player.Character)
end

Features & Information

This script is designed to be a looping animation script similar to the classic animations that were released by fyck except it allows for it to be respawnable and to be mixed with the movement system I created. This was reworked using Claude 4.5 Sonnet.
#Cl*ic#old roblox#animation

Community Comments (3)

AirookzAirookzFeb 18, 2026

is it only client sided?

Replying to @Airookz
Guest_43854Guest_43854Feb 22, 2026

@Airookz No, I've tested this before and other should be able to see it since it's just an animation script.

IzNoliYTIzNoliYTApr 5, 2026

Pretty Nice

More Scripts for Universal Scripts