Creating smooth terrain and part terrain planet gravity. edit: for a physics based car now

but HOW would that be done. i never done anything like this before and i got no clue how to calculate the forces and rotation

No worries, I was trying to do something very similar to what you are developing right now on my free time… and… Its not working as intended yet ¯_(ツ)_/¯

So… Im not exactly sure how to accomplish it, lets just still trying it until it works!! :yum: :sweat_smile:

Its been done before in unity mimicing games such as super mario galaxy.

The rotation method and unity video is here, I would suggest learning to a point to be able to translate code and studying the advanced CFrame technique:

1 Like

ive converted unity scripts to roblox before for my car scripts

ill try this out later

ok i looked over this and the video and this is what i go so far

but i cant figure out how to make it stay, seems to fall off every time


local planetCenter = workspace.PlanetCenter
local rotationSpeed = 20

local RunService = game:GetService("RunService")

local char = script.Parent
local root = char.HumanoidRootPart

local randomAxis =,0,0)

function getRotationBetween(u, v, axis)
	local dot, uxv = u:Dot(v), u:Cross(v)
	if (dot < -0.99999) then return CFrame.fromAxisAngle(axis, math.pi) end
	return, 0, 0, uxv.x, uxv.y, uxv.z, 1 + dot)

local params =
params.FilterDescendantsInstances = {char}
params.FilterType = Enum.RaycastFilterType.Blacklist

local a ="Attachment", root)
local force ="VectorForce", a)
force.Force =
force.RelativeTo = Enum.ActuatorRelativeTo.World
force.ApplyAtCenterOfMass = true
force.Attachment0 = a

local gyro = script:WaitForChild("BodyGyro"):Clone()
gyro.Parent = root

local planetGravity = 9.81

local mass = 0
for i, v in pairs(char:GetDescendants()) do
	if v:IsA("BasePart") then
		mass += v:GetMass()

	local result = workspace:Raycast(root.Position, -1000 * root.CFrame.UpVector, params)
	if result then
		local rotateToFloorCFrame = getRotationBetween(root.CFrame.UpVector, result.Normal, randomAxis)
		local goalCF = rotateToFloorCFrame * root.CFrame
		gyro.CFrame = goalCF.Rotation + root.CFrame.Position
		force.Force = -result.Normal * planetGravity * mass

the vector force points to the center of the planet which is just a very small part (which will turn into just a vector3 to save part count)

also when falling off the planet or lets say you were orbiting around it. it doesnt pull you into the planet like it should and i dont know how to do that without increasing the force of the vector force but that will mess up walking around and jumping

The issue is that PlatformStand seems to still be disabled and the movement is using the humanoid movement.

Humanoids will resist the BodyGyro and the moment they tilt 90 degrees it will enter ragdoll mode, therefore it is mandatory to toss humanoids out the window for custom movement especially for tilting as there is no property for that.

You will need an entirely new character controller. In the video below I am using my own PhysicsCharacterController and disabled the auto rotate method


However this will require more work as my character controller is basically similar to humanoids only intended for use on the XZ plane with the hipheight raycasting always downwards (0, -1, 0). Consequently, you will need to create a custom AddonComponent or make your own character controller from scratch both methods should work, feel free to make your own if you don’t want to reverse engineer mine.

Also the direction should the the vector towards the center and not necessarily the ray cast which is not want you wanted

This is solved simply using this direction instead:

		local gravityDirection = (planetCenter.Position - root.Position)
	local result = workspace:Raycast(root.Position, -1000 * root.CFrame.UpVector, params)
	if result then
		local gravityDirection = (planetCenter.Position - root.Position)

		local rotateToFloorCFrame = getRotationBetween(root.CFrame.UpVector, -gravityDirection, randomAxis)
		local goalCF = rotateToFloorCFrame * root.CFrame
		gyro.CFrame = goalCF.Rotation + root.CFrame.Position
		force.Force = gravityDirection.Unit * planetGravity * root.AssemblyMass

does your controller work with r6? and your controller is slides around a lot. is there anyway to fix these issues otherwise ill try to make my own

i want the movement to still feel like a regular humanoid

nvm i modified egomoose’s gravity controller to use the movement from that. but there are a few issues

  1. climbing doesnt work (cant figure out how to make this possible, do you know how?)
  2. when upsde down you cant jump (currently working on a fix) fixed

been working on making my physics based car work with going around the planet
right now im changing the up vector of the suspension force to be the same math as the up vector for the player

this works until it gets to a 90 degree rotation.
im using vector forces and its all simulated so there is a base which is the car and its propelled up (so it doesnt fall) to simulate suspension. i cant figure out how to get the correct up vector so it pushes the car up relative to the planet

suspension force = suspensionForce * self.upVector suspensionForce is a number
this is how i calculate the up vector, this time im actually using the normal of the hit result

local result = workspace:Raycast(data.attach.WorldPosition, -1000 * data.attach.WorldCFrame.UpVector, params)
if result then
	local gravityDir = (planetCenter.Position - data.attach.WorldPosition)
	local rotateToFloorCFrame = getRotationBetween(data.attach.WorldCFrame.UpVector, -result.Normal,, 0, 1))

	if gravityDir.Magnitude <= 400 then
		upVector = result.Normal
		upVector =, 1, 0)
data.wheelController.upVector = upVector

this is what happens

You aren’t showing the code for the vehicle that lifts it up. The raycast is fine.

Though, I wonder what this is for:

thats just for the distance the planet can pull you in for

the code for pushing up is pretty simple is just the dampened spring formula
then setting a vector force to that

i need the vector force to push up while providing enough force in the direction of the planet to keep it on the planet
this can be done through multiple vector forces one for the suspension and one for the gravity force, which is what i did

but the gravity force is way too strong or way too weak and not enough to keep it on the planet

i changed some stuff since that post and this is how i calculate the gravity force

function module:calculateGrav(dt)
	local g = workspace.Gravity
	local mass = self.attach.Parent.AssemblyMass + self.mass
	local gForce = g * mass * self.upVector
	return gForce

then thats applied to a vector force

local gravForce = data.wheelController:calculateGrav(dt)
data.gravVector.Force = gravForce

currently this force is way too strong and just keeps it stuck on the ground

You can use your own gravity and set Workspace.Gravity to 0

ok so without the suspension force it stays on the planet this time but now with the suspension force it bounces like crazy

right now i get the vertical speed by the base (invisible part where all the vector forces are attached to) with :vectorToWorldSpace() against the upVector or gravity vector that the gravity calculation uses
then i dot that with the velocity at the point of the vector force

this works fine with gravity like the normal one of 196.2 but im using 9.81 since 196.2 is way too strong for the car

It should be 0 if you are using custom gravity for the planet you need to pull the car inwards.

workspace.gravity is 0

this is what i mean

Ah, I see. Why can’t you use LineForce to apply the gravity separately then? I don’t think the car suspension should be entitled to managing gravity.

its not

each wheel has a bunch of vectors each with a purpose

forward, friction and right are nothing to do with gravity
up vector is the suspension force
grav vector is the gravity vector

causing this

Alright. From the video it looks like the car’s suspension is simply being clamped down to a positive value and not a negative value.

I don’t suppose this is the case, but you should check for it, because the constraints in the video disappear when this happens (meaning it is disabled).

the vector forces will only become 0 if no ground by the raycast is met
so i do this so it stops pushing on the vehicle because it aint touching the ground

the gravity force is always applied no matter what
i set the gravity back to 196.2 because i want the player and the vehicle to be the same

the workspace.Gravity is still 0
here a video of what is currently going on

update: scrap everything i said
just realized i dont need a gravity force at each wheel, plus the calculation of the force requires on where the force to be applied at the center of mass

so i did that, there is now only one gravity force in the center of mass of the entire model
now its just bouncing

  1. Use EgoMoose’s gravity controller:
  1. Store a list of positions for the center of the planets.
  2. Each physics update:
    • Get the nearest planet position
    • Set the direction of gravity to be in that direction (planet position - player position) in the gravity controller
  3. Done!

i already made the controller for the player
im now trying to get this working for my physics based car

i should edit the title…

force for the gravity on the Y is -294k (ish)
force for the suspension on the Y is somewhere above that (it changes a lot)

edit 2:
stiffness = 60000
damping = 5000
too much makes it bounce

stiffness = 40000
damping = 2500
too little

1 Like