local humanoid = script.Parent:WaitForChild("Humanoid") local character = script.Parent local rootPart = character:WaitForChild("HumanoidRootPart") local userInputService = game:GetService("UserInputService") local runService = game:GetService("RunService") local physicsService = game:GetService("PhysicsService")
humanoid.BreakJointsOnDeath = false humanoid.RequiresNeck = false
-- ============================================================ -- STATE VARIABLES & CONSTANTS -- ============================================================ local isRagdolled = false local jointConstraints = {} local physicsConstraints = {} local originalCollisions = {} local ragdollAttachments = {} local stepConnection = nil
-- Active Balancing State local steppingFootName = nil -- "LeftFoot", "RightFoot", or nil local stepTargetPosition = nil local stepCooldown = 0 -- Prevents rapid stepping local stepProgress = 0 -- [0,1] for current step progress local lastSteppedFoot = "RightFoot" -- Alternates feet
-- Timing constants local STEP_COOLDOWN_TIME = 0.7 -- Longer cooldown for deliberate steps local STEP_DURATION = 0.8 -- Total time to complete a step local STEP_COMPLETION_DISTANCE = 0.4 -- Threshold to complete a step
-- Balancing thresholds & parameters local BALANCE_LeanThreshold_FB = 0.3 -- Forward/backward lean threshold local BALANCE_LeanThreshold_LR = 0.25 -- Left/right lean threshold local BALANCE_StepDistanceFactor = 1 -- Step distance factor local BALANCE_StepForce = 5000 -- Force for stepping local BALANCE_StepResponsiveness = 100 -- Responsiveness for foot correction local BALANCE_StanceWidth = 1.0 -- Stance width local BALANCE_LiftHeight = 0.3 -- Maximum foot lift height
-- Smoothing factors (lower = slower, more gradual corrections) local TORSO_LERP_BASE = 0.03 -- Base factor for torso correction (will be scaled dynamically) local ARM_LERP_FACTOR = 0.03 -- For arm corrections local FOOT_DAMPING_FACTOR = 2 -- For foot planting target smoothing local COM_SMOOTHING = 0.15 -- Center-of-mass prediction damping
-- ============================================================ -- SAVE ORIGINAL COLLISION SETTINGS -- ============================================================ for _, part in pairs(character:GetDescendants()) do if part:IsA("BasePart") then originalCollisions[part] = { CanCollide = part.CanCollide, CollisionGroupId = part.CollisionGroupId, Massless = part.Massless } part.Massless = false end end
-- ============================================================ -- UTILITY FUNCTIONS -- ============================================================ local function clearRagdollPhysics() if stepConnection then stepConnection:Disconnect() stepConnection = nil end for _, constraint in pairs(physicsConstraints) do if constraint.Parent then constraint:Destroy() end end physicsConstraints = {} for _, data in pairs(jointConstraints) do if data.constraint and data.constraint.Parent then data.constraint:Destroy() end if data.a1 and data.a1.Parent then data.a1:Destroy() end if data.a2 and data.a2.Parent then data.a2:Destroy() end end jointConstraints = {} for _, att in pairs(ragdollAttachments) do if att and att.Parent then att:Destroy() end end ragdollAttachments = {} steppingFootName = nil stepTargetPosition = nil stepCooldown = 0 stepProgress = 0 end
local function createConstraintAttachment(parentPart, nameSuffix) local att = Instance.new("Attachment") att.Name = "RagdollAttachment_" .. (nameSuffix or parentPart.Name) att.Parent = parentPart table.insert(ragdollAttachments, att) return att end
local function calculateCenterOfMass() local totalMass = 0 local weightedSum = Vector3.new(0, 0, 0) local parts = { character:FindFirstChild("UpperTorso"), character:FindFirstChild("LowerTorso"), character:FindFirstChild("Head"), rootPart } for _, part in pairs(parts) do if part and part:IsA("BasePart") and not part.Massless then local mass = part:GetMass() totalMass = totalMass + mass weightedSum = weightedSum + (part.Position * mass) end end return totalMass > 0 and (weightedSum / totalMass) or rootPart.Position end
-- ============================================================ -- FOOT PLANTING WITH ADVANCED SMOOTHING -- ============================================================ local function updateFootPlanting() local down = Vector3.new(0, -1, 0) local raycastParams = RaycastParams.new() raycastParams.FilterDescendantsInstances = {character} raycastParams.FilterType = Enum.RaycastFilterType.Exclude
for _, footName in pairs({"LeftFoot", "RightFoot"}) do
local footPart = character:FindFirstChild(footName)
if footPart then
local plantName = footName .. "_Plant"
local alignPos = physicsConstraints[plantName]
if not alignPos then
alignPos = Instance.new("AlignPosition")
alignPos.Name = plantName
alignPos.Mode = Enum.PositionAlignmentMode.OneAttachment
alignPos.Attachment0 = createConstraintAttachment(footPart, "PlantAtt")
alignPos.MaxForce = 3000
alignPos.Responsiveness = 15
alignPos.Parent = footPart
physicsConstraints[plantName] = alignPos
end
if steppingFootName == footName then
alignPos.Enabled = false
else
local origin = footPart.Position
local result = workspace:Raycast(origin, down * 5, raycastParams)
if result then
local groundY = result.Position.Y
local targetPos = Vector3.new(footPart.Position.X, groundY + 0.05, footPart.Position.Z)
alignPos.Position = alignPos.Position:Lerp(targetPos, FOOT_DAMPING_FACTOR)
alignPos.Enabled = true
else
alignPos.Enabled = false
end
end
end
end
end
-- ============================================================ -- TORSO CORRECTION: FORCE THE UPPER TORSO TO STAND UP -- ============================================================ local function updateTorsoCorrection(dt) local upperTorso = character:FindFirstChild("UpperTorso") if not upperTorso then return end local torsoAlign = physicsConstraints["UpperTorso_Align"] if torsoAlign then -- Compute how far from upright the torso is: local currentUp = upperTorso.CFrame:vectorToWorldSpace(Vector3.new(0,1,0)) local uprightDot = currentUp:Dot(Vector3.new(0,1,0)) -- 1 = perfectly upright local aggressiveness = math.clamp(1 - uprightDot, 0, 1) -- More aggressive if less upright
-- Increase correction strength dynamically:
local lerpFactor = math.clamp(TORSO_LERP_BASE + aggressiveness * 0.2, 0.03, 0.5)
local targetLook = rootPart.CFrame.LookVector -- use root's forward direction
local targetCFrame = CFrame.fromMatrix(upperTorso.Position, targetLook, Vector3.new(0,1,0))
torsoAlign.CFrame = torsoAlign.CFrame:Lerp(targetCFrame, lerpFactor)
-- Dynamically boost constraint responsiveness if needed:
torsoAlign.Responsiveness = math.clamp(20 + aggressiveness * 50, 20, 70)
torsoAlign.MaxTorque = math.clamp(15000 + aggressiveness * 15000, 15000, 30000)
end
end
-- ============================================================ -- ADVANCED ACTIVE BALANCING LOGIC (EUPHORIA-INSPIRED) -- ============================================================ local function updateActiveBalance(dt) stepCooldown = math.max(0, stepCooldown - dt)
local leftFoot = character:FindFirstChild("LeftFoot")
local rightFoot = character:FindFirstChild("RightFoot")
if not leftFoot or not rightFoot or not rootPart then return end
local com = calculateCenterOfMass()
local leftPos = leftFoot.Position
local rightPos = rightFoot.Position
local avgFootPos = (leftPos + rightPos) / 2
local groundY = math.min(leftPos.Y, rightPos.Y)
local forwardXZ = Vector3.new(rootPart.CFrame.LookVector.X, 0, rootPart.CFrame.LookVector.Z).Unit
local rightXZ = Vector3.new(rootPart.CFrame.RightVector.X, 0, rootPart.CFrame.RightVector.Z).Unit
local comXZ = Vector3.new(com.X, 0, com.Z)
local avgFootXZ = Vector3.new(avgFootPos.X, 0, avgFootPos.Z)
local offsetVector = comXZ - avgFootXZ
local velocityXZ = Vector3.new(rootPart.AssemblyLinearVelocity.X, 0, rootPart.AssemblyLinearVelocity.Z)
local velInfluence = velocityXZ * COM_SMOOTHING
local combinedOffset = offsetVector + velInfluence
local backwardOffset = -(combinedOffset):Dot(forwardXZ)
local forwardOffset = combinedOffset:Dot(forwardXZ)
local rightwardOffset = combinedOffset:Dot(rightXZ)
local leftwardOffset = -(combinedOffset):Dot(rightXZ)
local raycastParams = RaycastParams.new()
raycastParams.FilterDescendantsInstances = {character}
raycastParams.FilterType = Enum.RaycastFilterType.Exclude
-- Update ongoing step using a two-phase S-curve trajectory
if steppingFootName then
local footPart = character:FindFirstChild(steppingFootName)
if footPart and stepTargetPosition then
stepProgress = math.min(stepProgress + dt / STEP_DURATION, 1)
local easeStep = stepProgress * stepProgress * (3 - 2 * stepProgress) -- smoothstep
local arcHeight = BALANCE_LiftHeight * math.sin(easeStep * math.pi)
local lerpFactor = (stepProgress < 0.8) and 0.15 or 0.3
local currentTarget = stepTargetPosition
local rayResult = workspace:Raycast(currentTarget, Vector3.new(0, -5, 0), raycastParams)
local targetY = rayResult and rayResult.Position.Y or groundY
currentTarget = Vector3.new(currentTarget.X, targetY + arcHeight, currentTarget.Z)
local constraintName = steppingFootName .. "_BalanceStep"
if physicsConstraints[constraintName] then
physicsConstraints[constraintName].Position = physicsConstraints[constraintName].Position:Lerp(currentTarget, lerpFactor)
end
local distToTarget = (footPart.Position - currentTarget).Magnitude
local leanCorrected = math.abs(backwardOffset) < (BALANCE_LeanThreshold_FB * 0.5) and math.abs(rightwardOffset) < (BALANCE_LeanThreshold_LR * 0.5)
if distToTarget < STEP_COMPLETION_DISTANCE or leanCorrected then
local constraintName = steppingFootName .. "_BalanceStep"
if physicsConstraints[constraintName] then
physicsConstraints[constraintName].Enabled = false
end
lastSteppedFoot = steppingFootName
steppingFootName = nil
stepTargetPosition = nil
stepProgress = 0
-- Gradually reset arm corrections
local rightArmAV = physicsConstraints["RightUpperArm_Swing"]
local leftArmAV = physicsConstraints["LeftUpperArm_Swing"]
if rightArmAV then
rightArmAV.AngularVelocity = rightArmAV.AngularVelocity:Lerp(Vector3.new(0,0,0), ARM_LERP_FACTOR)
end
if leftArmAV then
leftArmAV.AngularVelocity = leftArmAV.AngularVelocity:Lerp(Vector3.new(0,0,0), ARM_LERP_FACTOR)
end
end
else
steppingFootName = nil
stepTargetPosition = nil
stepProgress = 0
end
updateTorsoCorrection(dt)
return
end
if stepCooldown > 0 then
updateTorsoCorrection(dt)
return
end
-- STEP DECISION
local stepUrgency = 0
local stepDirFB = 0
local stepDirLR = 0
if backwardOffset > BALANCE_LeanThreshold_FB then
stepDirFB = -1
stepUrgency = stepUrgency + (backwardOffset - BALANCE_LeanThreshold_FB)
elseif forwardOffset > BALANCE_LeanThreshold_FB then
stepDirFB = 1
stepUrgency = stepUrgency + (forwardOffset - BALANCE_LeanThreshold_FB)
end
if rightwardOffset > BALANCE_LeanThreshold_LR then
stepDirLR = 1
stepUrgency = stepUrgency + (rightwardOffset - BALANCE_LeanThreshold_LR)
elseif leftwardOffset > BALANCE_LeanThreshold_LR then
stepDirLR = -1
stepUrgency = stepUrgency + (leftwardOffset - BALANCE_LeanThreshold_LR)
end
if stepUrgency >= 0.15 then
local stepDistFB = math.max(0, math.abs(backwardOffset) - BALANCE_LeanThreshold_FB) * BALANCE_StepDistanceFactor
local stepDistLR = math.max(0, math.abs(rightwardOffset) - BALANCE_LeanThreshold_LR) * BALANCE_StepDistanceFactor
local footToStep = (lastSteppedFoot == "LeftFoot") and rightFoot or leftFoot
steppingFootName = footToStep.Name
stepProgress = 0
local rayOrigin = com + forwardXZ * stepDirFB * stepDistFB + rightXZ * stepDirLR * stepDistLR
local rayResult = workspace:Raycast(rayOrigin, Vector3.new(0, -5, 0), raycastParams)
local targetY = rayResult and rayResult.Position.Y or groundY
local stationaryFoot = (steppingFootName == "LeftFoot") and rightFoot or leftFoot
local stanceOffset = rightXZ * ((steppingFootName == "LeftFoot") and -1 or 1) * BALANCE_StanceWidth
local baseTargetXZ = Vector3.new(stationaryFoot.Position.X, 0, stationaryFoot.Position.Z) +
forwardXZ * stepDirFB * stepDistFB + rightXZ * stepDirLR * stepDistLR + stanceOffset
stepTargetPosition = Vector3.new(baseTargetXZ.X, targetY + BALANCE_LiftHeight, baseTargetXZ.Z)
local constraintName = steppingFootName .. "_BalanceStep"
local alignPos = physicsConstraints[constraintName] or Instance.new("AlignPosition")
alignPos.Name = constraintName
alignPos.Mode = Enum.PositionAlignmentMode.OneAttachment
alignPos.Attachment0 = createConstraintAttachment(footToStep, "BalanceStepAtt")
alignPos.MaxForce = BALANCE_StepForce
alignPos.Responsiveness = BALANCE_StepResponsiveness
alignPos.Position = stepTargetPosition
alignPos.Parent = footToStep
alignPos.Enabled = true
physicsConstraints[constraintName] = alignPos
stepCooldown = STEP_COOLDOWN_TIME
end
updateTorsoCorrection(dt)
end
-- ============================================================ -- INITIALIZE RAGDOLL & BALANCING SYSTEM -- ============================================================ local function makeRagdoll() if isRagdolled then return end isRagdolled = true clearRagdollPhysics()
local totalMass = 0
for _, child in pairs(character:GetChildren()) do
if child:IsA("BasePart") and not child.Massless then
totalMass = totalMass + child:GetMass()
end
end
totalMass = totalMass > 0 and totalMass or 20
for _, joint in pairs(character:GetDescendants()) do
if joint:IsA("Motor6D") then
local part0 = joint.Part0
local part1 = joint.Part1
if part0 and part1 then
local a1 = Instance.new("Attachment")
a1.Name = "RagdollJointAttachment"
a1.Parent = part0
a1.CFrame = joint.C0
local a2 = Instance.new("Attachment")
a2.Name = "RagdollJointAttachment"
a2.Parent = part1
a2.CFrame = joint.C1
local constraint = Instance.new("BallSocketConstraint")
constraint.Parent = part0
constraint.Attachment0 = a1
constraint.Attachment1 = a2
constraint.LimitsEnabled = true
constraint.UpperAngle = (part1.Name:find("Upper") and 80) or 45
constraint.TwistLimitsEnabled = true
constraint.TwistLowerAngle = -30
constraint.TwistUpperAngle = 30
table.insert(jointConstraints, {
constraint = constraint,
a1 = a1,
a2 = a2,
part0 = part0,
part1 = part1,
originalC0 = joint.C0,
originalC1 = joint.C1,
jointName = joint.Name,
jointParent = joint.Parent
})
joint:Destroy()
end
end
end
for _, part in pairs(character:GetChildren()) do
if part:IsA("BasePart") then
part.CanCollide = true
part.Massless = false
if part.Name == "HumanoidRootPart" then
part.CanCollide = false
end
end
end
humanoid:ChangeState(Enum.HumanoidStateType.Physics)
local standForce = Instance.new("VectorForce")
standForce.Name = "AntiGravityForce"
standForce.Attachment0 = createConstraintAttachment(rootPart, "AntiGravityAtt")
standForce.RelativeTo = Enum.ActuatorRelativeTo.World
standForce.Force = Vector3.new(0, totalMass * workspace.Gravity * 0.98, 0)
standForce.Parent = rootPart
physicsConstraints[standForce.Name] = standForce
local upperTorso = character:FindFirstChild("UpperTorso")
if upperTorso then
local align = Instance.new("AlignOrientation")
align.Name = "UpperTorso_Align"
align.Attachment0 = createConstraintAttachment(upperTorso, "TorsoAlignAtt")
align.MaxTorque = 30000
align.Responsiveness = 30
align.CFrame = CFrame.new(Vector3.zero, rootPart.CFrame.LookVector, Vector3.new(0,1,0))
align.Parent = upperTorso
physicsConstraints[align.Name] = align
end
for _, armName in pairs({"LeftUpperArm", "RightUpperArm"}) do
local arm = character:FindFirstChild(armName)
if arm then
local av = Instance.new("AngularVelocity")
av.Name = armName .. "_Swing"
av.Attachment0 = createConstraintAttachment(arm, "SwingAtt")
av.MaxTorque = 500
av.AngularVelocity = Vector3.new(0, 0, 0)
av.Parent = arm
physicsConstraints[av.Name] = av
end
end
stepConnection = runService.Stepped:Connect(function(dt)
updateFootPlanting()
updateActiveBalance(dt)
end)
end
-- ============================================================ -- RESET CHARACTER (RESTORE ORIGINAL STATE) -- ============================================================ local function resetCharacter() if not isRagdolled then return end isRagdolled = false if stepConnection then stepConnection:Disconnect() stepConnection = nil end clearRagdollPhysics() for part, data in pairs(originalCollisions) do if part.Parent then part.CanCollide = data.CanCollide part.Massless = data.Massless end end humanoid:ChangeState(Enum.HumanoidStateType.GettingUp) end
-- ============================================================ -- EVENT HANDLERS -- ============================================================ humanoid.Died:Connect(function() if not isRagdolled then task.wait(0.05) makeRagdoll() end end)
userInputService.InputBegan:Connect(function(input, gameProcessed) if not gameProcessed and input.UserInputType == Enum.UserInputType.Keyboard then if input.KeyCode == Enum.KeyCode.R and humanoid.Health > 0 then if isRagdolled then resetCharacter() else makeRagdoll() end end end end) edit this balancing localscript so it balances more realistically and human like, do major changed, and remove the camera shaking