Gravity Pull Effect

Im trying to achieve a Gravity Pull effect that sucks players into the center but the force isn’t so strong so they can walk out. here’s an example

https://i.gyazo.com/ffd9a793baf653d8534c3cee2c019ef5.mp4

Ive been switching between Body POsition and AlignPosition I’ve been able to recreate it so some extent. The issue is that sometimes you cant move laterally at all really and after you’ve been sucked into the middle you walk right out like the gravity doesn’t exist, I tried altering the force many times but I just cant seem to get it right or another problem arises here’s an example and my code: https://i.gyazo.com/773371b66d02b17f4dd1c16a2ea9f55d.mp4

local AlignPosition = Instance.new(“AlignPosition”)
local Att1 = Instance.new(“Attachment”)
local Att0 = Instance.new(“Attachment”)
Att1.Name = “Att1”
Att0.Name = “Att0”
Att0.Parent = RootPart
Att1.Parent = Part
AlignPosition.Attachment1 = Att1
AlignPosition.Attachment0 = Att0
AlignPosition.Position = Part.Position
AlignPosition.Parent = Att0
AlignPosition.MaxForce = 3700
AlignPosition.Enabled = true

anyone know a fix thank you <3

3 Likes

.Position is only when the mode is one attachment, also the way i do it is set .MaxForce to math.huge then use MaxVelocity to set the speed

1 Like

It might be worth taking a different approach with LinearVelocity here, too.

You can use something like this to pull a body towards another:

local a: Vector3 = player.Character.PrimaryPart.Position
local b: Vector3 = gravity_sphere.Position

local force = 50

local linear_velocity: LinearVelocity = Instance.new("LinearVelocity")
linear_velocity.VectorVelocity = (b - a).Unit * force
linear_velocity.Parent = player.Character.PrimaryPart

That way, you don’t have to worry about forces and can adjust the value of force to suit what strength you need.

1 Like

Using this Method I find that the character cant move at all and cant walk out of it

1 Like

Well as the player jumps the pull affects them more as they aren’t grounded so you would need a way to fix that, though that would be a difficult task. As you would need it to make it think as if it was still grounded when the character is jumping.

1 Like

Using this method ive gotten very close to what I’m trying to achieve, my only issue is that the velocity doesn’t seem to be constant, what I mean is when you stay still inside the field the pull isn’t as strong as the initial pull as well as when you can only walk a certain distance before the force starts to dissipate Heres my code any ideas?

local Part = workspace.UmbraField
local CharVel = Character.PrimaryPart.AssemblyLinearVelocity

local force = 1000
local linear_velocity: LinearVelocity = 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.MaxForce = 3930
linear_velocity.Attachment0 = Att0
linear_velocity.Attachment1 = Att1
linear_velocity.Enabled = true

while true do
	local A = Character.PrimaryPart.Position
	local B = Part.Position
	local CharVel = Character.PrimaryPart.AssemblyLinearVelocity
	wait()
	
	linear_velocity.VectorVelocity = (B - A).Unit * force 	
	linear_velocity.VelocityConstraintMode = Enum.VelocityConstraintMode.Vector	
	linear_velocity.RelativeTo = Enum.ActuatorRelativeTo.World
end

You would need to multiply the force with the distance between the player and constraint.

1 Like

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?