Trajectory given max initial speed, initial position, and target position?

How would you compute the most optimal trajectory (one that has the smallest initial speed/magnitude) given the maximum initial speed, initial position, and target position.

Also if it is impossible to find a trajectory with speed <= max speed, it should return a trajectory that gets as close to the target position as possible (probably smallest 3D magnitude)

I already saw: https://devforum.roblox.com/t/free-trajectory-calculation-code/11630
But it only lets you calculate a trajectory with the EXACT initial speed and it returns nil if you need more speed to reach the goal.

You can probably just approximate it using binary searching, but I’m wondering if theres any way to achieve this behavior with some kind of magical formula or something :stuck_out_tongue:

1 Like

You need to define “optimal” better here. The computed trajectory will inherently be a tradeoff—if you have a smaller initial velocity then you’ll have a larger distance traveled before reaching the target, neither of those options is inherently more “optimal” than the other.

Unless you’re exactly on the edge case, there will be a family of solutions with initial speed less than the maximum initial speed, you need some way to decide between them.

2 Likes

If you know the most optimal for both initial speed AND the most optimal for fastest arrival time, is there a clear way to interpolate between them and get a result that is like (this assumes linear interpolation I think) 90% as fast as fastest arrival but uses 10% less speed than fastest arrival?

Yeah, both of those solutions will have an initial velocity. You can then choose velocity = 0.9*clampedMaxVelocity + 0.1*minVelocity, and solve back for the angle that you have to use given that velocity.

This Wikipedia page has all the equations you should need if you want to implement it yourself (The “Angle theta required to hit coordinate (x,y)” section… holy obnoxious link that’s actually impossible to post in a Markdown comment): https://en.wikipedia.org/wiki/Projectile_motion

How would that help? Doesn’t it just find the angle needed for a given initial speed? (what the code in the link in the OP does) I want the option to use a speed smaller (if possible) and the ability to overshoot undershoot as well if the required speed is too great.

This equation gives you the lowest possible launch velocity for the projectile to reach the target.

v_min = sqrt((y + sqrt(y^2 + x^2))/g)

There is no “maximum velocity” to reach the target, you can always use more velocity as long as you have an unobstructed path to the target (ie: You’re not trying to lob something over a wall). So the max velocity to reach the target is just whatever your desired max velocity is.

v_max = [your max velocity]

Then apply a mix of the two based on what you want

v_to_use = f(v_min, v_max) -- f returns something between v_min and v_max

Then finally you solve the angle for that velocity:

theta_inclination = arctan((v^2 +/- sqrt(v^4 - g*(g*x^2 + 2*y*v^2))) / (g*x))

Where v = v_to_use Now you can use the theta_inclination and v_to_use to construct a velocity vector to fire the projectile with.

1 Like

Am I doing something wrong finding the minimal velocity (calling it InitialSpeed since I’m just plugging it into AxisAngle’s code)?

local x = ((target.X - origin.X)^2 + (target.Z - origin.Z)^2)^0.5
local y = (target.Y - origin.Y)
local InitialSpeed = ((y + (y^2 + x^2))^0.5/g)^0.5

The numbers seem to be really small

Looks the same as the Wikipedia page. Are you sure you have the right constant for g? I think it’s 20*9.81 on Roblox—though that would only make your result smaller.

Try it out and see if it works, the difference between the max velocity and min velocity should be pretty large.

This is the code I’m using xd:

If you uncomment the part at the end then it will use the formula to find the min initial speed but it doesn’t work at all.

--By Axis Angle
--function Trajectory(Vector3 Origin,Vector3 Target,Number InitialVelocity)
--Returns two possible paths from Origin to Target where the magnitude of the initial velocity is InitialVelocity
--The first returned Vector3 is the Low Trajectory, the second Vector3 is the High Trajectory
--If no trajectory can be calculated, it returns nil
local Trajectory
do
	local v3=Vector3.new
	local g=-196.2
	function Trajectory(Origin,Target,InitialVelocity)
		local ox,oy,oz=Origin.x,Origin.y,Origin.z
		local rx,rz=Target.x-ox,Target.z-oz
		local tx2=rx*rx+rz*rz
		local ty=Target.y-oy
		if tx2>0 then
			local v2=InitialVelocity*InitialVelocity
			local c0=tx2/(2*(tx2+ty*ty))
			local c1=g*ty+v2
			local c22=v2*(2*g*ty+v2)-g*g*tx2
			if c22>0 then
				local c2=c22^0.5
				local t0x2=c0*(c1+c2)
				local t1x2=c0*(c1-c2)
				local tx,t0x,t1x=tx2^0.5,t0x2^0.5,t1x2^0.5
				local v0x,v0y,v0z=rx/tx*t0x,(v2-t0x2)^0.5,rz/tx*t0x
				local v1x,v1y,v1z=rx/tx*t1x,(v2-t1x2)^0.5,rz/tx*t1x
				local v0=v3(v0x,ty>g*tx2/(2*v2) and v0y or -v0y,v0z)
				local v1=v3(v1x,v1y,v1z)
				return v0,v1
			end
		else
			local v=v3(0,InitialVelocity*(ty>0 and 1 or ty<0 and -1 or 0),0)
			return v,v
		end
	end
end
--Example
wait(1)

local g = 196.2
local Origin=Vector3.new(0,10,0)
local TargetPart=game.Players.LocalPlayer.Character.HumanoidRootPart
local InitialSpeed=100
while true do
	wait()
	local target = TargetPart.Position
	--[[local x = ((target.X - Origin.X)^2 + (target.Z - Origin.Z)^2)^0.5
	local y = (target.Y - Origin.Y)
	local InitialSpeed = ((y + (y^2 + x^2))^0.5/g)^0.5]]
	
	local LowTrajectory,HighTrajectory=Trajectory(Origin,target,InitialSpeed)	
	local Part=Instance.new("Part",game.Workspace)
	Part.CanCollide=false
	Part.Position=Vector3.new(0,10,0)
	Part.Velocity=LowTrajectory
	local Part=Instance.new("Part",game.Workspace)
	Part.CanCollide=false
	Part.Position=Vector3.new(0,10,0)
	Part.Velocity=HighTrajectory
end

Well that’s your problem. Everyone knows you shouldn’t use my code!

8 Likes