How can I make a force of attraction based on distance?

Hello!

Currently I have a large ball part in a certain location. My goal is to make it so the closer the player gets to this part, the stronger the force of attraction is. I want the part to create a force of attraction so the player’s characters begin to get pulled towards the middle of this part, however if they are far away they don’t feel this effect, if they are kinda close they do but can escape through movement, and if they are too close they cannot move as fast to escape against this force.

I’ve tried using body movers and alignposition, which I think are most likely something to do with the solution, however I was unable to figure out how to go about changing the strength of attraction.

With trying to use align position:

  • The character would be able to walk away extremely easy, but when they jumped or tried turning the force would become much stronger (I’m trying to achieve the same force for when they are walking away or at least a bit similar)
  • I couldn’t figure out a good way of adjusting the force based on distance. If I had 50 players in the game, would I have to have a very fast loop for EACH player determining the distance away from this attracting part, and then change the force accordingly? Surely this is laggy?
  • If I have more than one attracting part, would this potentially cause even more lag, or a conflict of forces or something?

It may not have anything to do with alignposition, I’m just looking for an effective way of replicating this effect of a pulling force on a player to a certain position based on distance.

Thank you!

You’ll probably need to experiment with a few options – the way roblox handles character movement and how it interacts with physics calculations is better today than it ever has been, but there’s still gonna be weird interactions.

For example, from the AlignmentPosition wiki page:

Note

If this constraint attaches one part ( A ) to another part ( B ) that is anchored or connected to an anchored part ( Z ), part A will not be locally simulated when interacting with a player.

Now, since character movement is locally simulated, that could be a cause of some weird interactions.

Also,

If I had 50 players in the game, would I have to have a very fast loop for EACH player determining the distance away from this attracting part, and then change the force accordingly? Surely this is laggy?

No, probably not. Luau is fast, and so are computers. This small calculation every frame would have a negligible impact on performance.

Personally, I would try adding a BodyForce to the HumanoidRootParts and just do the force calculation every frame. It might still suffer from the same character-movement weirdness as AlignPosition, though.

1 Like

You can use a Body force and the equation of Newton’s Law Of Universal Gravitation, which is:

local force = gravitational_constant*mass1*mass2/distance^2

So how you’d use it is by doing:

local playerMass = 0

-- Looping through the player's character for baseparts that have mass and account for their masses
for _, v in ipairs(Character:GetDescendants()) do
    if v:IsA("BasePart") and not v.Massless then
        playerMass += v:GetMass()
    end
end

local g = 100 -- in unit Nm^2 / kg^2
local vector = (LargeBall.Position - Character.HumanoidRootPart.Position)
local f = g * playerMass * LargeBall:GetMass() / vector.Magnitude ^ 2
BodyForce.Force = vector.Unit * f

I don’t know what’ll happen here though, but you’d know when you test it

1 Like

Thank you for the equation, I tried using this and body forces, applying the new force on every Heartbeat, but the force is way too strong (I go flying off the map). I tried adjusting gravity to be a bit less strong and I saw no force at all at a distance (which I liked) but when I got closer the transition from no force to a strong force was almost instant. I’m not sure what I should be modifying in this equation to decrease the strength or have a smoother transition from no force to a strong force, unless this is just weird character movement stuff?

@nicemike40 Thanks for the information, the character movement weirdness makes sense. I’m glad this calculation does not impact performance! I am setting the force for a bodyforce with the equation above that @Rare_tendo gave me every frame but it seems to have a weird transition from being strong and being weak for the force on distance. Is this another character movement weirdness thing that I can’t easily solve?

EDIT: I have also noticed when the player is standing there’s no force (at a certain distance) but when they jump they fly towards the part. Is this just something I can’t fix?

EDIT 2: Experimenting with line force I achieved an effect where the player would still be slowly attracted while on the floor not jumping, not sure if it’s the best way to replicate the effect though, just been experimenting for the right effect.

Maybe I need to clamp a max force to prevent forces way stronger than I actually want for my game?

The gravity equation is useful if you’re trying to simulate a solar system. If you don’t need realism, and you just are moving players around, it might be simpler to hardcode the gravitational_constant*mass1*mass2 value, and just divide by distance^2 (or even just distance, depending on what you want). You don’t need to calculate mass or anything that way. Example.

Some more things to explore:

  • If you aren’t already, try binding your physics calcs and force setting to RunService.Stepped – this will trigger the updates before each physics step.
  • Create totally custom characters, or at least a custom ControlScript. This might not be necessary, but here’s a cool article (part of larger series) about force-based movement for characters that solves a similar problem.
  • Kind of a hack (but you might need one :slight_smile: ), but you could detect what the humanoid is currently doing (i.e. running) and handle those cases separately.

The problem you’re facing is that you want to apply forces to characters, while ROBLOX characters use Humanoid:MoveTo, which (probably) uses velocity directly – meaning that it’s overriding whatever forces you’re trying to apply.

1 Like

Tried again with the different equations and using Stepped, wasn’t really able to achieve an effect I wanted. Custom characters also seem like an option I’m not advanced enough for.

I’ve actually been able to replicate a more accurate effect with line forces, having ApplyAtCenterOfMass and InverseSquareLaw set to true. I’ve been experimenting with MaxForce and Magnitude values to have a point where the player does not get too much force acted on them whilst also getting pulled a reasonable amount. The InverseSquareLaw property allows me to just set it to true and it handles distance based strength of magnitude which is a lot more simple as well.

I assume this could be a solution, but wanted to see if this is potentially a bad method in which I’m missing something?

Sorry, I didn’t realize that a LineForce existed now :slight_smile: . Definitely seems like the best and fastest option without resorting to custom characters, seeing as how you’re just letting ROBLOX handle the calculations on the actual backend, rather than yourself!

2 Likes