How titling scripts works?

i want to make player tilt when he jumps but i dont really understand on how is tilting works

here what i want to be like

i have something to use as a base

local Tilt = CFrame.new()
runService.RenderStepped:Connect(function(Delta)
local MoveDirection = rootPart.CFrame:VectorToObjectSpace(humanoid.MoveDirection)
Tilt = Tilt:Lerp(CFrame.Angles(math.rad(-MoveDirection.Z) * MaxTiltAngle, math.rad(-MoveDirection.X) * MaxTiltAngle, 0), 0.2 ^ (1 / (Delta * 60)))
RootJoint.C0 = RootC0 * Tilt
end)

but i need help as im not really experienced scripter and other articles confuses me

if you do leave a script that makes player tilt when jumps please leave explanation i want to learn

1 Like

The RootJoint is a Motor6D used for animation and moving around the character. It’s commonly used for animations, but in the odd case can be used for CFrame Manipulation, which sounds really cool but in reality it’s just glorified animating. It’s basically animating things by modifying their Motor6D C0 and C1 properties instead of just… animating. People usually do this for games which don’t allow you to import your animations (e.g Lua Sandbox, a Roblox game where you can create your own scripts and execute them inside of it with other people). In your case though, this makes sense. You don’t want to create an animation for that.

I can’t really provide much code, since I don’t usually do stuff like this, but I can tell you how it works.

-- Properly indent your code please!
local Tilt = CFrame.new()

runService.RenderStepped:Connect(function(Delta)
	local MoveDirection = rootPart.CFrame:VectorToObjectSpace(humanoid.MoveDirection) -- This returns the "direction" of your movement. When testing, I found that walking straight forward without any rotation returns around Vector3.new(0, 0, -1) or similar.
	Tilt = Tilt:Lerp(CFrame.Angles(math.rad(-MoveDirection.Z) * MaxTiltAngle, math.rad(-MoveDirection.X) * 	MaxTiltAngle, 0), 0.2 ^ (1 / (Delta * 60)))
	-- This converts your "move direction" into a CFrame by converting your move direction into an angle. 
	-- math.rad(-MoveDirection.Z) is saying "convert this vector into a rotation value readable by the machine, and then amplify the effect of the movement by the specified angle the player provides"
	-- :Lerp() is commonly used for CFrame Manipulation. It provides a smooth movement, as that second argument tells the game how much percentage you want to move the tilt to their destination. I explain it after this code block.
	RootJoint.C0 = RootC0 * Tilt
end)

Lerping is a function that can be executed on CFrames by calling the method, and then providing two arguments. The first argument is the CFrame you want the final destination to be, and the second argument is the percentage of how much you want to move it. It’s a bit odd, though, since 100% in the second argument of Lerp is just 1. So you need to divide the percent you want by 100. So if you wanted the CFrame to move to 10% of the way to the CFrame destination specified, you would say 0.1. Odd, I know.

“Wouldn’t lerping just provide a linear movement?”
Yep! In this case, though, the developer changes the Tilt value every frame and then lerps it again! This means that every time you’re basically making it smooth. Let me try and explain in simple terms:
Imagine you’re cutting a pie in half every swing of your knife. Swing it once, it’s in half. Swing it again, now it’s in quarters. Eights, so on, and so on. That’s basically what’s happening. It continuously halves itself (or atleast, I think it is in the code. I am NOT figuring out that math even if it’s actually probably really simple lol) until it inevitably reaches the destination. An issue with this method of smooth lerping: it never truly reaches its destination. Lets go back to that pie analogy: you continuously cut the pie in half and half and half and half, eights, sixteenths, thirty-twos, and so on. But you never truly finish cutting the pie. You just keep going and going and going. It might look like you’re there, but you really not. So if you’re relying on checking if a :Lerp() method has reached its destination, don’t.

Not a very good explanation, but it was the best I could do. Hope I helped even a tiny bit!

1 Like

soo from what i understand,

tilting codes are just animations made with scripts

does that mean i can just create animation for it and put little bit of scripts just for it to work without math

The RootJoint is a Motor6D used for animation and moving around the character. It’s commonly used for animations, but in the odd case can be used for CFrame Manipulation , which sounds really cool but in reality it’s just glorified animating. It’s basically animating things by modifying their Motor6D C0 and C1 properties instead of just… animating. People usually do this for games which don’t allow you to import your animations (e.g Lua Sandbox, a Roblox game where you can create your own scripts and execute them inside of it with other people). In your case though, this makes sense. You don’t want to create an animation for that.

and what i have understanded lerp not really a good solution to what i want to make

so if i even try to do that results something like
character jumps it starts to tilt then it countinues tilting and doesnt finishes

anyways big thanks for explaning

Well, kinda? You aren’t going to get the effect you want by using animations. What I would do is grab a fall damage script and find the code that can detect how long a player is falling for. Maybe math.clamp how fast the player can fall? And then you can just change the :Lerp() CFrame based off of the amount of time you were falling for. Actually, let me just write some code for it and explain it all in-depth.

-- Some code is stolen (https://create.roblox.com/store/asset/13415650101)
-- This is a regular Script inside of StarterCharacterScripts (NOT a LocalScript, regular Script)
local RunService = game:GetService("RunService")

local Char = script.Parent
local Humanoid = Char:WaitForChild("Humanoid")
local HumanoidRootPart = Char:WaitForChild("HumanoidRootPart")
local RootJoint = HumanoidRootPart:WaitForChild("RootJoint")
-- Everything above this comment is self-explanatory.
local RootC0 = RootJoint.C0 -- This is the default C0 of the Motor6D. This will be what gets modified in the code. The reason this variable exists is because if we tried to multiply the Motor6D C0 in real time it would just multiply on itself and get a bloated mess.
local MaxTiltAngle = 20 -- The maximum amount (in degrees) the script will let your character turn.

local Tilt = CFrame.new() -- This is just a blank CFrame that gets changed pretty much instantly.
RunService.Heartbeat:Connect(function(dt)
	local PlrVelocity = -HumanoidRootPart.AssemblyLinearVelocity.Y -- Velocity of the character on the Y axis
	-- Value goes positive when falling, and is negative when going up instead of down
	
	-- Ignore how weird this looks. It just works, ignore it.
	Tilt = Tilt:Lerp( -- Immediately overwrites the Tilt variable
		CFrame.Angles(
			math.rad( -- Converts our value into a radian
				math.clamp(math.deg(PlrVelocity), -MaxTiltAngle,  MaxTiltAngle) -- Converts our PlrVelocity into a value of degrees (so, 20 studs of velocity is 20 degrees of turning) and then clamps it to our specified MaxTiltAngle.
			),
			0, -- our Y axis stays blank
			0 -- our Z axis stays blank
		),
		0.2 ^ (1 / (dt * 60)) -- Not gonna bother explaining this. Somebody else can lmao
	)
	RootJoint.C0 = RootC0 * Tilt -- Finally, update our RootJoint's C0 to our new Tilt
end)

Only issue now is that this code conflicts with your other code (the example code you provided) but I have no idea if you’re actually using that or if it’s just an example. Let me know if you’re using that and I can give you some help with it!

nah i just wanted to use that part of the code for the base to make my own script

1 Like

Alright then. Good luck on your future projects!

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.