Gravity Pull Effect

I did that and it’s not changing much here’s the code I used.

while true do
	wait()
	
	if Partinbox == true then
		linear_velocity.Enabled = true
	local A = Character.PrimaryPart.Position
	local B = Part.Position
	local CharVel = Character.PrimaryPart.AssemblyLinearVelocity
	local force = 4000 * (A - B).Magnitude
	local VectorVel = (B - A).Unit * force
		
	linear_velocity.VectorVelocity = VectorVel

	
		
	else
		linear_velocity.Enabled = false
	end
end

The Main thing Im trying to stop is this back-and-fort motion that happens when you hold the w key, you should be able to walk out.

1 Like

Try decreasing the value 4000 to something like 2500

Here you update the velocity to be applied to the player with each iteration of the loop. Instead, you want to calculate the velocity to be applied when the player first enters the gravitational field and then apply the velocity. That way, instead of updating the velocity in a loop, you remove the velocity when the player has left the gravitational field.

Let me know if you need some pseudocode demonstrating this!

Can you demonstrate what you mean with some code?

First of all, avoid using variable names like “A” and “B.” Use “characterPosition” and “partPosition” instead; these names are longer but nobody has to go back through the code to figure out what they are. Styling your code correctly is essential. (Including indentation and spacing)

Youtube link to why you use full detailed names in code: Naming Things in Code - YouTube

Don’t use wait, use task.wait(); pretty sure it performs better in every way possible. You can also do: while task.wait() do instead of while true do task.wait().

Lastly, relating to your actual problem, your force is getting stronger the further from the center you are, that’s why you’re getting that back-and-forth motion you referred to. Instead, the force should get weaker the further the player is. You can use division for this, though I assume you still want it to suck in the player momentarily at the beginning; you can do what you’re currently doing at the start, wait for a second or 2, then switch to the other one. OR, just math.max() the force to something reasonable.

Code for math.max() method
while task.wait() do

	linear_velocity.Enabled = Partinbox

	if not Partinbox then continue end

	-- Get properties
	local characterPosition = Character.PrimaryPart.Position
	local partPosition = Part.Position

	-- Calculate force
	local force = 4000 * (characterPosition - partPosition).Magnitude
	local forceMaxed = math.max(force, 20000)

	-- Apply force
	linear_velocity.VectorVelocity = (partPosition - characterPosition).Unit * forceMaxed

end
4 Likes

Thank you for the tips!

Using this method however I haven’t seen much change, I still get the back-and-forth movement. I tried messing with the force values but that didn’t help I could tweak them a little more but I’m unsure if that would actually fix the issue. Additionally, I still get moments where I walk into the circle and get pulled walk halfway out and then the force pulling me into the circle is less strong than the initial pull. I want the force to be consistent if that makes sense, I don’t want it to get lesser or greater the farther from the center you get but rather a consistent force being applied.

Heres my full code again to see if there’s something else that’s wrong.

--Services  
local Replicated = game:GetService('ReplicatedStorage')
local UIS = game:GetService('UserInputService')
--
--Character/Player
local Players = game:GetService('Players')
local Player = Players.LocalPlayer
local Character = Player.Character or Player.CharacterAdded:Wait()
local Humanoid = Character:WaitForChild('Humanoid')
local Animator = Humanoid:WaitForChild('Animator')
local RootPart = Character:WaitForChild('HumanoidRootPart')
local Mouse = Player:GetMouse()
local Animator = Humanoid:WaitForChild('Animator')
local TweenService = game:GetService("TweenService")
local Partinbox = false
--Body

local Part = workspace.UmbraField
local linear_velocity = Instance.new("LinearVelocity")
local Att1 = Instance.new("Attachment")
local Att0 = Instance.new("Attachment")
Att1.Name = "Att1"
Att0.Name = "Att0"
Att0.Parent = RootPart
Att1.Parent = Part

linear_velocity.Parent = Character.PrimaryPart
linear_velocity.Attachment0 = Att0
linear_velocity.Attachment1 = Att1
linear_velocity.Enabled = true
linear_velocity.MaxForce = 4032

local params = OverlapParams.new()
params.FilterType = Enum.RaycastFilterType.Include
params.FilterDescendantsInstances= {RootPart}

coroutine.wrap(function()
while task.wait() do
	local PartsInBox = workspace:GetPartBoundsInRadius(Part.Position,24.6,params)
		if PartsInBox[1] == RootPart then
			Partinbox = true
		else
			Partinbox = false	
		end
	end
end)()

while task.wait() do
	linear_velocity.Enabled = Partinbox
	if not Partinbox then continue end
	
	-- Get properties
	local characterPosition = Character.PrimaryPart.Position
	local partPosition = Part.Position

	-- Calculate force
	local force = 4000 * (characterPosition - partPosition).Magnitude
	local forceMaxed = math.max(force, 20000)

	-- Apply force
	linear_velocity.VectorVelocity = (partPosition - characterPosition).Unit * forceMaxed
end

Thank you so much for your time <3

1 Like

For a constant force applied (no matter how far away you are), you’ll want to use this code:

Constant force code
while task.wait() do
	linear_velocity.Enabled = Partinbox
	if not Partinbox then continue end
	
	-- Get properties
	local characterPosition = Character.PrimaryPart.Position
	local partPosition = Part.Position

	-- Calculate force
	local force = 4000
	local characterToPartVector = (partPosition - characterPosition).Unit

	-- Apply force
	linear_velocity.VectorVelocity =  characterToPartVector * force
end

It just sets the force to 4000 instead of the complicated math. You’ll have to change the force value to something greater if it doesn’t do anything.

Just a suggestion, but instead of using the LinearVelocity body mover you could adjust the velocity of the character directly; something like:

Adding force to character code

This likely has errors.

--[[ Services ]]--

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")

--[[ Variables ]]--

local localPlayer = Players.LocalPlayer

local character = localPlayer.Character or Player.CharacterAdded:Wait()
local humanoidRootPart = character:WaitForChild("HumanoidRootPart")

local umbraField = workspace.UmbraField

local params = OverlapParams.new()
params.FilterType = Enum.RaycastFilterType.Include
params.FilterDescendantsInstances= {RootPart}

--[[ Functions ]]--

while task.wait() do

	-- Check if the character is touching part
	local umbraFieldPosition = umbraField.Position
	PartsInBox = workspace:GetPartBoundsInRadius(umbraFieldPosition, 24.6, params)

	if PartsInBox[1] ~= humanoidRootPart then continue end -- sus >_>
	
	-- Get properties
	local characterPosition = humanoidRootPart.Position

	-- Calculate force
	local characterToPartVector = (umbraFieldPosition - characterPosition).Unit
	local force = characterToPartVector * 5

	-- Apply force
	humanoidRootPart.AssemblyLinearVelocity += force
	--[[or "humanoidRootPart:ApplyImpulse(force)"]]

end

Again, if it doesn’t do anything, increase the force.

1 Like

Well I believe you should switch how the distance is calculated as the further you are the stronger it gets because of how you set up this:

local force = 4000 * (A - B).Magnitude 
--example: 4000 * 70(further away) = 280,000 , 4000 * 4 (closer) = 16,000
-- I believe it should be divided maybe that'll work,
- I believe this will work:
local force = 4000 / (A - B).Magnitude 
1 Like

After trying all the solutions you recommended, I found that adjusting the character’s velocity directly worked best. However, the only issue I found with that was when you get dragged into the middle of the circle walk a few steps towards the edge and stop you don’t get pulled back to the center with the same amount of force you got pulled in with. I’m content with leaving this as it is because I’m starting to think that maybe my goal isn’t achievable. If you guys have any clue on how to fix that issue, please tell me but if not, thanks for the help!

1 Like

Interesting, not sure why that’d be happening, but here are my two guesses:

  1. The line of code if PartsInBox[1] ~= humanoidRootPart then continue end is passing true more than it should be after the beginning. This would cause the code not to apply force to the character despite them being in the radius. If you want to fix this, then you’d have to check every part the GetPartsInRadius returned to see if it’s the humanoidRootPart.

or

  1. The character stands still, and there isn’t a counterforce in the beginning like when you’re walking away.

It also might be that something else is adjusting the force of the character like a separate script.

1 Like

I think this would work better:

local maxDistance = 100
local force = 4000 * (1 - math.min((partPosition - playerPosition).Magnitude, maxDistance) / maxDistance)

You avoid dividing by 0 too.

1 Like

Nice change although, I would like to know why you subtracted 1 by the math.min? Is it to make it percentage value?

Yes, it is a percentage, but the “1 -” doesn’t make it a percentage.

When I divide the player distance by the max distance it gives me a percentage value depending on how far the player is. 0% if the player is in the center, 100% if the player is on the edge. Though we want the opposite, therefore I do 1 - the original percentage value to get the inverse of that percentage. Now it’s 100% in the center and 0% on the edge.

Using the example above, if the player is 10 studs away then we get:
local force = 4000 * (1 - 10 / 100)
local force = 4000 * (1 - .1)
local force = 4000 * .9
local force = 3600

if the player is 90 studs away then we get:
local force = 4000 * (1 - 90 / 100)
local force = 4000 * (1 - .9)
local force = 4000 * .1
local force = 400

The math.min is to make sure we don’t multiply with negative numbers and the percentage value is between 0 and 1.

Thanks for the explanation! Although I don’t think you would be able to get negative numbers through magnitude checking.

I meant if the distance is a 110 and you divide by 100 your going to get 1.1. Then when you do 1 - 1.1 you get a negative number of -.1 making the force -400.

1 Like

Alright even after trying both solutions I’m still getting the back-and-forth motion. I don’t know what could possibly be wrong. If you are still willing to help, I strongly encourage you to edit the place in the link yourself because I feel I might be doing something wrong.

Here is the link, its open access.

Again, Thank you for your help.

The solution here is very close to how I would solve it, but not quite right to me. The Linear Velocity constant is handy because it calculates a force that keeps a constant velocity, instead of applying a constant force, as constant force is constant acceleration. So My answer would be:

	-- grab the direction.unit and multiply by force
	local force = ((partPosition - Character.PrimaryPart.Position) * Vector3.new(1,0,1)).Unit * 5000 --Vector3.new(1,0,1) is used to cancel out any downward force

	if partPosition - Character.PrimaryPart.Position > 0.1 then--prevents jittering at the center of the circle
		force = Vector3.zero
	end

	-- Apply force
	linear_velocity.VectorVelocity = force

Yes this does mean that it only works properly flat on the ground, but that can be changed. Hope this helps! :grin:

I got an error for the line

if partPosition - Character.PrimaryPart.Position > 0.1 then--prevents jittering at the center of the circle
		force = Vector3.zero
	end

“Attempt to do math on vector three”

I forgot to take the magnitude, whoops!

if (partPosition - Character.PrimaryPart.Position).Magnitude < 0.1 then--prevents jittering at the center of the circle
		force = Vector3.zero
	end