Simulated Gravity Force

Hey, I am trying to make a system to change the direction of the gravity. I did make the normal force to work properly but the force that simulates gravity to another direction doesn’t work. I need the vector’s direction to be towards a certain angle, which is the angle of the part’s surface.

This is the code I currently have, it is located in game.StarterPlayer.StarterCharacterScripts and it’s a local script.

local g = 196.2
local mass = 0
local NormalVector = Vector3.new(0,0,0)
local FakeGravityVector = Vector3.new(0,0,0)
local BodyForcesVelocity = 0

local NormalForce = script:WaitForChild("NormalForce")
local GravityForce = script:WaitForChild("GravityForce")
local Player = game.Players.LocalPlayer
local WallWalkingOn

local UserInputService = game:GetService("UserInputService")

function refreshMass()
	local calcMass = 0
	for i,v in pairs(Player.Character:GetDescendants()) do
		if v:FindFirstChild("CanCheckForMass") then
			if v.CanCheckForMass:IsA("BoolValue") then
				if v.CanCheckForMass.Value == true then
					calcMass += v:GetMass()
				end
			end
		end
	end
	mass = calcMass
end

function checkForForces()
	if script.Parent.PlayerIsWallWalking.Value == true then
		if not script.Parent.HumanoidRootPart:FindFirstChild("newNormal") then
			local newNormal = NormalForce:Clone()
			newNormal.Name = "newNormal"
			newNormal.Parent = script.Parent.HumanoidRootPart
		end
		if not script.Parent.HumanoidRootPart:FindFirstChild("newGravity") then
			local newGravity = GravityForce:Clone()
			newGravity.Name = "newGravity"
			newGravity.Parent = script.Parent.HumanoidRootPart
		end
	else
		if script.Parent.HumanoidRootPart:FindFirstChild("newNormal") then
			script.Parent.HumanoidRootPart.newNormal:Destroy()
		end
		if script.Parent.HumanoidRootPart:FindFirstChild("newGravity") then
			script.Parent.HumanoidRootPart.newGravity:Destroy()
		end
	end
end

function updateVectors()
	BodyForcesVelocity = g*mass
	NormalVector = Vector3.new(0,BodyForcesVelocity,0)
	FakeGravityVector = Vector3.new(BodyForcesVelocity,BodyForcesVelocity,BodyForcesVelocity)
end

function updateForces()
	local Normal = script.Parent.HumanoidRootPart:FindFirstChild("newNormal")
	if Normal then
		Normal.Force = NormalVector
	end
	local Gravity = script.Parent.HumanoidRootPart:FindFirstChild("newGravity")
	if Gravity then
		local a,b,c,alpha,results = findSurface()
		if math.cos(alpha) == math.cos(alpha) then
			Gravity.Force = Vector3.new(
				BodyForcesVelocity * math.cos(alpha),
				0,
				BodyForcesVelocity  *math.cos(alpha)
			) * FakeGravityVector
			print("Vector3.new( ".. Gravity.Force.X .." , ".. Gravity.Force.Y .." , ".. Gravity.Force.Z .." )")
		end
	end
end

function findAllWallWalkables()
	local walkables = {}
	
	for i,v in pairs(game.Workspace:GetDescendants()) do
		if isWalkable(v) then
			table.insert(walkables,v)
		end
	end
	
	return walkables
end

function findSurfaceSurfaceAngle(Results)
	local pos0 = Results.LeftFoot.Position
	local pos1 = Results.RightFoot.Position
	local pos2 = Results.HumanoidRootPart.Position
	
	local a = (-(pos0.Y - pos2.Y + (((pos0.Y - pos1.Y) * (pos2.Z - pos0.Z)) / (pos0.Z - pos1.Z)))) / (pos0.X - pos2.X + (((pos0.X - pos1.X) * (pos2.Z - pos0.Z)) / (pos0.Z - pos1.Z)))
	local b = 1
	local c = (a * (pos1.X - pos0.X) + (pos1.Y - pos0.Y)) / (pos0.Z - pos1.Z)
	
	local alpha = math.deg(math.acos(b/math.sqrt(a^2+b^2+c^2)))
	
	return a,b,c,alpha
end

function findSurface()
	local RayCastParams = RaycastParams.new()
	RayCastParams.FilterDescendantsInstances = findAllWallWalkables()
	RayCastParams.FilterType = Enum.RaycastFilterType.Whitelist
	RayCastParams.IgnoreWater = false
	
	local Results = {
		LeftFoot = game.Workspace:Raycast(
			game.Players.LocalPlayer.Character.LeftFoot.Position,
			WallWalkingOn.Position,
			RayCastParams
		),
		RightFoot = game.Workspace:Raycast(
			game.Players.LocalPlayer.Character.RightFoot.Position,
			WallWalkingOn.Position,
			RayCastParams
		),
		HumanoidRootPart = game.Workspace:Raycast(
			game.Players.LocalPlayer.Character.HumanoidRootPart.Position,
			WallWalkingOn.Position,
			RayCastParams
		),
	}
	
	for i,v in pairs(Results) do
		local part = Instance.new("Part")
		part.Name = "CheckerPart"
		part.Shape = "Ball"
		part.Size = Vector3.new(0.5,0.5,0.5)
		part.Transparency = 0.75
		part.Position = v.Position
		part.Anchored = true
		part.CanCollide = true
		part.CanTouch = true
		part.Parent = game.Workspace
		spawn(function()
			wait(0.5)
			part:Destroy()
		end)
	end
	
	local a,b,c,alpha = findSurfaceSurfaceAngle(Results)
	
	return a,b,c,alpha,Results
end

Player.Character:WaitForChild("HumanoidRootPart")
spawn(function()
	while wait() do
		local function a(su,er)
			refreshMass()
			checkForForces()
			updateVectors()
			updateForces()
		end
		local function b(su,er)
			warn(su,er)
		end
		
		local su,er = xpcall(a,b)
	end
end)

function isWalkable(obj)
	if obj:FindFirstChild("WallWalkable") then
		if obj.WallWalkable:IsA("BoolValue") then
			if obj.WallWalkable.Value == true then
				return true
			end
		end
	end
	return false
end

function refreshWallWalkingState()
	local part = Instance.new("Part")
	part.Name = "CheckerPart"
	part.Shape = "Ball"
	part.Size = Vector3.new(7.5,7.5,7.5)
	part.Transparency = 0.75
	part.Position = Player.Character.HumanoidRootPart.Position
	part.Anchored = true
	part.CanCollide = true
	part.CanTouch = true
	part.Parent = Player.Character.HumanoidRootPart

	local TouchingParts = part:GetTouchingParts()
	part:Destroy()

	local changeTo = false
	if #TouchingParts >= 1 then
		for i,v in pairs(TouchingParts) do
			changeTo = isWalkable(v)
			if changeTo then
				WallWalkingOn = v
				break
			end
		end
	end
	script.Parent.PlayerIsWallWalking.Value = changeTo
end

UserInputService.InputBegan:Connect(function(input)
	if input.KeyCode == Enum.KeyCode.Space then
		if script.Parent.PlayerIsWallWalking.Value == true then
			script.Parent.PlayerIsWallWalking.Value = false
		else
			spawn(function()
				repeat
					refreshWallWalkingState()
					wait()
				until script.Parent.PlayerIsWallWalking.Value == false
			end)
		end
	end
end)
2 Likes

Try using this.

2 Likes

Forgot you need a wall walking, and not a wall climbing. You can use that new link, and just take out the camera part.

2 Likes

That’s not what I need, I need the vector’s direction to be towards a certain angle, which is the angle of the part’s surface. The system you referenced me to doesn’t use body forces.

If you want wall-walking you can use @EgoMoose’s wall-walking or gravity controller.

They each will work on part surfaces but the gravity controller is also easier to implement and works on terrain too.

I want my own one for being able to customize it and have full control over it. Thanks anyways, I will check this out.

Good luck with that. All I know you’ll need is most likely need to complete this project of your’s is a BodyGyro | Roblox Creator Documentation and maybe a BodyForce | Roblox Creator Documentation. I do not know though. Due to how Roblox handles humanoids this might be pretty difficult to implement.

From someone who has actually made their own n body physics simulation in multiple game engines multiple times everyone here is giving you wrong answers. There is basically like 2 ways to do this but seeing as you want the player to walk on it u gonna want to use body force. Seeing as you know the magnitude of this vector the force is simply the vector from the planet to the sun (normalized). You add velocities.

I need for that a BodyForce for the normal (gravity counter), which I’ve already done. The BodyForce for the simulated gravity is already calculated but the direction isn’t and this is what I have left.