How do I put a velocity cap on VectorForces?

I’m creating a soft tracking system for slow projectiles using VectorForces. Everything works as intended so far, but I can’t figure out how to make the projectile travel at a constant velocity.

https://gyazo.com/1c8f6020204bd42d535584979b47edc6

How would I add a velocity cap to this VectorForce? The direction it needs to travel in is constantly updated by rotating the part. As you can see in this gif, the part continues getting faster and faster.

Any help is appreciated.

Create_ServerCopy_Event.OnServerEvent:connect(function(plr, LockedTarget, mousehit)
	local plr_GodPowers = Server_Runtime_GodPowers:WaitForChild(plr.Name)
	local Body_Parts = Universal_Checks.Get_Body_Parts(plr)
			
	local Cloned_Jutsu = Fire_GodPowers:WaitForChild("Server_BlazingFireball"):Clone()
	local pos = Body_Parts["RootPart"].Position + Vector3.new(0, 2.5, 0)
			
			
	Cloned_Jutsu.CFrame = Body_Parts["RootPart"].CFrame * CFrame.new(0, 2.5, 0)
	Cloned_Jutsu.CFrame = Cloned_Jutsu.CFrame + Cloned_Jutsu.CFrame.lookVector * 3
	Cloned_Jutsu.Parent = plr_GodPowers
	Cloned_Jutsu:SetNetworkOwner(nil)
			
	local VectorForce = Cloned_Jutsu:WaitForChild("VectorForce")
			
	RunService.Heartbeat:connect(function()
		local StartCFrame = Cloned_Jutsu.CFrame
		local startX, startY, startZ = StartCFrame:ToOrientation()
		local jutsuPos = Cloned_Jutsu.Position
				
		local target
		if LockedTarget then
			target = game.Players:WaitForChild(LockedTarget).Character:WaitForChild("UpperTorso").Position
		else
			target = mousehit
		end
		local DesiredCFrame = CFrame.new(jutsuPos, target)
		local desiredX, desiredY, desiredZ = DesiredCFrame:ToOrientation()

		local DifferenceX = find_Difference(startX, desiredX)
		local DifferenceY = find_Difference(startY, desiredY)
		local DifferenceZ = find_Difference(startZ, desiredZ)

		local RotatedX = find_Rotation(startX, desiredX, DifferenceX)
		local RotatedY = find_Rotation(startY, desiredY, DifferenceY)
		local RotatedZ = find_Rotation(startZ, desiredZ, DifferenceZ)
		if RotatedX ~= 0 or RotatedY ~= 0 or RotatedZ ~= 0 then
			Cloned_Jutsu.CFrame = Cloned_Jutsu.CFrame * CFrame.Angles(RotatedX, RotatedY, RotatedZ)
			local LookVector = Cloned_Jutsu.CFrame.lookVector
					
			VectorForce.Force = Vector3.new(LookVector.X, LookVector.Y, LookVector.Z) * (10000)
			VectorForce.Force = VectorForce.Force + Vector3.new(0, workspace.Gravity * Cloned_Jutsu:GetMass(), 0)
		end
	end)
end)

The vectorforce is getting faster because it wants to reach it’s max speed, which you listed as
VectorForce.Force = Cloned_Jutsu.CFrame.lookVector * (70) (aka 70 studs a second I THINK.)

If you want, I recommend using BodyVelocity or BodyForce. They have more restriction options available, such as MaxTorque or MaxForce.

The VectorForce is actually constantly updated to VectorForce.Force = Vector3.new(LookVector.X, LookVector.Y, LookVector.Z) * (10000). The 70 was a mistake, and doesn’t actually have any effect on the projectile. The number is 10000 because otherwise it travels at a snail’s pace.

Also, legacy bodymovers are no longer supported. I also found that switching to using VectorForce completely fixed projectiles freezing midair.

I also believe there is no max speed the way I’ve programmed it. It just keeps accelerating. I read some posts talking about having to simulate drag, and I’m not sure how to do that.

You could probably clamp the max velocity with math.clamp().

1 Like

I don’t think that’s possible using VectorForces; it IS possible with AlignPosition, though.

Basically, to understand what’s going on here, you need to understand a bit of physics - particularly, Newton’s laws.

In real life, these laws are not “rules of the universe” - they are observations of how the universe appears to work.

In Roblox, however - they ARE rules of the universe, since Roblox runs on Newtonian principles (AFAIK).

The rules that are important here are Newton’s first and second laws:

1 - “every object will remain at rest or in uniform motion in a straight line unless compelled to change its state by the action of an external force.”

2 - “The rate of change of momentum of a body over time is directly proportional to the force applied, and occurs in the same direction as the applied force.”

In easier to understand terms:

Objects move when “forces” are applied to them. A VectorForce is one such force. Gravity is also one such force.

A body’s “acceleration” (i.e. the change in it’s velocity over time) is defined such:

FORCE = MASS * ACCELERATION

rearranging, using algebra:

ACCELERATION = FORCE / MASS

If you are getting this, you will note that there is no direct relationship between forces and velocities - only between forces and CHANGES in velocities.

Therefore - if an object in a vacuum (like your energy sphere) experiences a constant force, it will constantly accelerate, as nothing is slowing it down!

In reality, on planet earth, there usually is something slowing it down - air resistance, which is a force opposite to the thrust force, which increases in strength as the object speeds up - thus the object eventually reaches an “equilibrium”, at which point the air resistance and thrust forces are equal, and thus the object no longer accelerates.

So to limit the speed of this object - you need to either turn off the force when it reaches the speed (and indeed the object will continue to travel at that speed indefinitely, as it experiences no other forces until it collides - air resistance is not modelled by default AFAIK),

or have something more complicated (control theory - way out of your league if you didn’t understand this. It’s a university level topic and it’s a lot to wrap your head around) .

How you achieve this is up to you. I would go for the first option; bind some function which tracks the spheres to RunService.Heartbeat, that checks if the magnitude of the projectile’s velocity exceeds the max, and turns off the vector force when it does.

Remember - gravity is a thing, though.

1 Like

I appreciate the in depth reply. However, turning off the velocity isn’t an option because that would effectively turn the projectile tracking off, and it needs to continue following its target.

I also chose VectorForces because they’re the closest thing I could find to BodyVelocities, and I was able to set a max increment that the projectile could rotate towards it’s intended target, instead of instantaneously rotating to point towards the target. This is what allowed the wide arc in the gif.

This forum post may help, it shows you how to cap the velocity of a VectorForce using simulated drag, but I’m not sure how to implement that in this use case.