# Planetary Gravity on Players

The Issue:
I want a gravity system where players are able to walk around a roughly spherical object perpendicular to the center of the object, with their cameras rotating with the player as well, like the game Solar System Exploration 2.

What I’ve tried:
EgoMoose’s custom character: Suppose I create a planet with a mountain, Egomoose’s module will make my character latch onto the angled terrain itself, plus my character will also latch onto everything remotely angled.

(Excuse my art skills)
The yellow brick represents the character, and the red line represents the direction the feet are facing down on.
This image shows what EgoMoose’s module does, the character will latch onto any sort of angle. I want my character to be walking perpendicular to the center of the planet, not the ground.

4 Likes

Haven’t dealt with that sort of thing before, but you could possibly use a combination of AlignPosition (to get the player to stick to the surface), as well as a constantly updating AlignOrientation to position them parralel to the normal.

1 Like

Couldn’t you just CFrame the players feet to point at the center of the sphere? I’m guessing you could also give them a VectorForce that always pushes them to the center of the sphere so if they jump off at any weird angle they won’t fall off the planet.

1 Like

I’ve modified EgoMoose’s Gravity Controller before, and added a zone like system. You can find the part where it controls the pushing direction (UpVector), and just make it return the zone’s CorePoint looking at the user (CFrame.lookAt, and the lookvector of it) when they’re in the zone.

2 Likes

1 Like

Blind guess …

``````local spherePosition = Vector3.new(0, 10, 0)

local function calculateGravityDirection(player)
local playerPosition = player.Character.HumanoidRootPart.Position
local direction = (spherePosition - playerPosition).unit
return direction
end

game:GetService("RunService").Heartbeat:Connect(function()
for _, player in pairs(game:GetService("Players"):GetPlayers()) do
local character = player.Character
if character then
local humanoid = character:FindFirstChild("Humanoid")
if humanoid then
humanoid.WalkToPoint = character.HumanoidRootPart.Position + calculateGravityDirection(player) * sphereRadius
humanoid:Move(Vector3.new(0, 0, 0), false)
humanoid:Move(Vector3.new(0, 0, 0), true)
character:SetPrimaryPartCFrame(CFrame.new(spherePosition, player.Character.HumanoidRootPart.Position))
end
end
end
end)
``````
2 Likes

Here’s a video of my modified variant of EgoMoose’s Gravity Controller, to have zones.

1 Like

Ah, thanks! Could you give me a tutorial on how you modified it?

In the local script of the gravity controller, I set up a table at the top

``````local ValueTable = {
["Part"] = nil;
["DownFromPart"] = true;
["PullTowardsMiddle"] = false;
["StickOnThings"] = false;
}

``````

Which updated everytime the player would enter a zone (using GetPartsInPart with an overlayparam). These are properties that are in a folder, which is inside of the zone, which states its purpose.
in the function “GetGravityUp” I had checks for the StickOnThings, which is just to not allow it to Stick to things, if it’s false.
ValueTable is also in the module’s “self” storage, so it can be read.
in the Module, there’s a function by the title OnGravityStep, where I did this

``````local oldGravity = Vector3.new(0,1,0)
if self.ValueTable then
-- get the normal
if self.Character.HumanoidRootPart then
if self.ValueTable["DownFromPart"] == true then
if self.ValueTable["Part"] ~= nil then
oldGravity = self.ValueTable["Part"].CFrame.UpVector
else
oldGravity = Vector3.new(0,1,0)
end
end
if self.ValueTable["DownFromPart"] == false then
if self.ValueTable["PullTowardsMiddle"] == true then
if self.ValueTable["Part"] ~= nil then
oldGravity = (CFrame.lookAt(self.ValueTable["Part"].Position, self.Character.Torso.Position).LookVector)
else
oldGravity = Vector3.new(0,1,0)
end
end
end
end
end
``````

That’s basically all I did. Write it your own way however, as I made this a while back, and it’s old. (and unclean)

1 Like

I tried modifying using your instructions, but instead of GetPartsInPart, I used ZonePlus to detect a player’s presence inside a zone instead. The modified script did not work.

Here’s the file to see what’s going on:
Gravity Controller 2.0.rbxl (142.6 KB)

Are you also setting up the `self.ValueTable`?
Look at the getgravityup function to see how self is used there and just set self.ValueTable to ValueTable

Yes, i’ve set it up here:

Here’s GetGravityUp in the local script, the ValueTable is already set as `ValueTable`.

With the modification, the gravity controller functions like it did before modifying.

Also, how did you get the camera to orientate with the character?

I had an issue with the camera prior. You may be using an older version of Gravity Controller.

Which version did you use? I’m using this open one: Gravity Controller - Roblox

I know something’s wrong here, because your zone is set, yet you’re not immediately pulled. It’s better off for you to figure out the end point for yourself, but you’re not setting up the gravity upwards direction correctly, at least by the look of it. You’re still sticking to things, because you haven’t closed in the raycast.

Here’s how my GravityUp looks like.

``````local Character = game.Players.LocalPlayer.Character or game.Players.LocalPlayer.CharacterAdded

function GetGravityUp(self, oldGravityUp)

self.ValueTable = ValueTable
local ignoreList = {}
for i, player in next, PLAYERS:GetPlayers() do
ignoreList[i] = player.Character
end

-- get the normal

local hrpCF = self.HRP.CFrame
local isR15 = (self.Humanoid.RigType == Enum.HumanoidRigType.R15)

local origin = isR15 and hrpCF.p or hrpCF.p + 0.35*oldGravityUp
local radialVector = math.abs(hrpCF.LookVector:Dot(oldGravityUp)) < 0.999 and hrpCF.LookVector:Cross(oldGravityUp) or hrpCF.RightVector:Cross(oldGravityUp)

local centerRayLength = 25
local centerRay = Ray.new(origin, -centerRayLength * oldGravityUp)
local centerHit, centerHitPoint, centerHitNormal = workspace:FindPartOnRayWithIgnoreList(centerRay, ignoreList)

--DrawClass:Clear()
--DrawClass.Draw3D.Ray(centerRay.Origin, centerRay.Direction)

local downHitCount = 0
local totalHitCount = 0
local centerRayHitCount = 0
local evenRayHitCount = 0
local oddRayHitCount = 0

local mainDownNormal = ZERO
if (centerHit) then
mainDownNormal = centerHitNormal
centerRayHitCount = 0
end

local downRaySum = ZERO
for i = 1, NUM_DOWN_RAYS do
local dtheta = PI2 * ((i-1)/NUM_DOWN_RAYS)

local angleWeight = 0.25 + 0.75 * math.abs(math.cos(dtheta))
local isEvenRay = (i%2 == 0)
local downRayLength = centerRayLength

local offset = CFrame.fromAxisAngle(oldGravityUp, dtheta) * radialVector
local ray = Ray.new(origin + startRadius * offset, downRayLength * dir.unit)
local hit, hitPoint, hitNormal = workspace:FindPartOnRayWithIgnoreList(ray, ignoreList)

--DrawClass.Draw3D.Ray(ray.Origin, ray.Direction)

if (hit) then
if hit.CanCollide == true then
if ValueTable["StickOnThings"] == true then
downRaySum = downRaySum + angleWeight * hitNormal
downHitCount = downHitCount + 1
if isEvenRay then
evenRayHitCount = evenRayHitCount + 1
else
oddRayHitCount = oddRayHitCount + 1
end
end
end
end
end

local feelerHitCount = 0
local feelerNormalSum = ZERO

for i = 1, NUM_FEELER_RAYS do
local dtheta = 2 * math.pi * ((i-1)/NUM_FEELER_RAYS)
local angleWeight =  0.25 + 0.75 * math.abs(math.cos(dtheta))
local offset = CFrame.fromAxisAngle(oldGravityUp, dtheta) * radialVector
local feelerOrigin = origin - FEELER_APEX_OFFSET * -oldGravityUp + FEELER_START_OFFSET * dir
local ray = Ray.new(feelerOrigin, FEELER_LENGTH * dir)
local hit, hitPoint, hitNormal = workspace:FindPartOnRayWithIgnoreList(ray, ignoreList)

--DrawClass.Draw3D.Ray(ray.Origin, ray.Direction)

if (hit) then
if hit.CanCollide == true then
if ValueTable["StickOnThings"] == true then
feelerNormalSum = feelerNormalSum + FEELER_WEIGHTING * angleWeight * hitNormal --* hitDistSqInv
feelerHitCount = feelerHitCount + 1
end
end
end
end

if (centerRayHitCount + downHitCount + feelerHitCount > 0) then
local normalSum = mainDownNormal + downRaySum + feelerNormalSum
if (normalSum ~= ZERO) then
return normalSum.unit
end
end

return oldGravityUp
end

Controller.GetGravityUp = GetGravityUp
``````

If it still doesn’t work, this presumably means your Gravity Controller is an outdated one compared to mine. I dont remember where I got my variant of it, but it has the working camera.

1 Like

Could you provide me a file to the place you showcased it in?
I’m struggling to find the right version.

I’ve figured it out.
If anyone wants it:
Gravity.rbxl (1.2 MB)

3 Likes

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