Predict projectile ballistics, including gravity and motion

I don’t think anyone here would want to learn how it works, and I don’t blame you. I plagiarized this from the internet and somehow botched it into a working package so that you don’t have to.

What is this?

An actual, accurate projectile ballistic trajectory calculator. If you’ve ever played WarThunder, you should be familiar with this (the little reticle that leads ahead of an enemy craft? That’s exactly what this is.)
image

What can this be used for?

If you’re designing a war-themed game with things like guns, artilleries, and batteries, you’ll find this especially useful. It can be used for, as just mentioned, a little aiming reticle for your players to aim at to make the game more engaging and predictable.

Some other examples of use:

  • Bullseye artillery
  • CIWS guns
  • NPC battleships
  • Automatic defense turrets
  • Aimbot :joy:


I don’t really think a dedicated module was necessary for this because of how trivially easy it is to use. But I made it anyways.

CalculateTrajectory.rbxm (3.4 KB)

Module

See Credits for the sourcecode of the quartic module

local module = {}

local quartic = require(script.CardanoFerrari).solveQuartic

function module.SolveTrajectory(origin: Vector3, projectileSpeed: number, targetPos: Vector3, targetVelocity: Vector3, gravity: number?): Vector3?
	local g: number = gravity or workspace.Gravity

	local disp: Vector3 = targetPos - origin
	local p, q, r: number = targetVelocity.X, targetVelocity.Y, targetVelocity.Z
	local h, j, k: number = disp.X, disp.Y, disp.Z
	local l: number = -.5 * g 

	local solutions = quartic(
		l*l,
		-2*q*l,
		q*q - 2*j*l - projectileSpeed*projectileSpeed + p*p + r*r,
		2*j*q + 2*h*p + 2*k*r,
		j*j + h*h + k*k
	)
	if solutions then
		local t: number? --pick the smallest positive root of the quartic
		for _, v in solutions do
			if v > 0 then
				t = v 
				break
			end
		end
		if t then
			local d: number = (h + p*t)/t
			local e: number = (j + q*t - l*t*t)/t
			local f: number = (k + r*t)/t
			return origin + Vector3.new(d, e, f)
		end
	end
	return
end

return module

<Vector3?> module.SolveTrajectory(
	<Vector3> origin,
	<number> projectileSpeed,
	<Vector3> targetPos,
	<Vector3> targetVelocity,
	<number?> gravity
)

origin
The location of where the projectile was fired from. (i.e. the gun)

projectileSpeed
The scalar speed of the projectile (muzzle velocity)

targetPos
The world position of the target.

targetVelocity
The velocity of the target. If you plan on implementing velocity inheritance, this needs to change accordingly.

gravity
Optional. The scalar acceleration of gravity, uses the workspace’s gravity as default.

Returns A position in worldspace representing the point to which to aim the gun at. If no solution exists, it returns nil.

Usage example:

local function aim()
	local aimAt: Vector3? = calcTrajectory.SolveTrajectory(gun.Position, muzzleV, target.Position, target.AssemblyLinearVelocity)
	if aimAt then
		gun.CFrame = CFrame.lookAt(gun.Position, aimAt)
	end
end

Demo file:

projectileBallistics.rbxl (42.3 KB)

Credits

24 Likes

DANG, i think i will use this some time! very cool!

Hi I literally made a post about Arrow Projection Rotation Help could you look at scripting help topic and see if you could advise me on how to do it? ;/

Nvm this script doesn’t even use rotation and is overcomplicated

Gee, Rule 17 is coming for you

Update! I swapped out the old quartic formula (which used Newton Iteration) for another one that is much more efficient (Cardano’s formula & Ferrari’s method). See Credits for the source.

You should be able to squeeze out even more performance now!

1 Like