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.
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.
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.
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.
local spherePosition = Vector3.new(0, 10, 0)
local sphereRadius = 20
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)
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)
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.
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
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 startRadius = isEvenRay and EVEN_DOWN_RAY_START_RADIUS or ODD_DOWN_RAY_START_RADIUS
local endRadius = isEvenRay and EVEN_DOWN_RAY_END_RADIUS or ODD_DOWN_RAY_END_RADIUS
local downRayLength = centerRayLength
local offset = CFrame.fromAxisAngle(oldGravityUp, dtheta) * radialVector
local dir = (LOWER_RADIUS_OFFSET * -oldGravityUp + (endRadius - startRadius) * offset)
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 dir = (FEELER_RADIUS * offset + LOWER_RADIUS_OFFSET * -oldGravityUp).unit
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.