How To Get Trajectory Path Of A Projectile's Velocity (Or Just A Vector3 Force)?

I cannot seem to figure out the math behind calculating the trajectory of velocity.

I should note that (at least for my case) the velocity- or namely ‘Force’, is perfectly fine and works in every case I’ve tested it in. My issue arises in the Project function.

The whole code:

local function Project(Force: Vector3, Origin: Vector3, Goal: Vector3)
	local Points = {}
	for Time = 0, 1, .1 do
--// Suspected culprit
		local Point = Origin + (Force * Time)
		Point = Vector3.new(Point.X, 
			Origin.Y + (Force.Y * Time) - ((workspace.Gravity / 2) * Time * Time),
			Point.Z)
--//
		table.insert(Points, Point)
	end

	return Points
end

--// Simple parts in studio, projectile is just a ball
local Origin, Goal, Projectile = workspace.Start.Position, workspace.End.Position, workspace.Projectile

local function GetForceNeeded(Origin: Vector3, Goal: Vector3, Projectile: BasePart?, MaxDistance: number?): Vector3

	local Distance = (Goal - Origin).Magnitude
	MaxDistance = MaxDistance and math.min(MaxDistance, Distance) or Distance

	local Direction = Goal - Origin
	local Duration = math.log(1.001 + Direction.Magnitude * 0.01)
	local Force = Direction.Unit * MaxDistance / Duration + Vector3.new(0, workspace.Gravity * Duration * 0.5, 0)

	return Projectile and Force * Projectile.AssemblyMass or Force
end


local MaxDistance = (Goal - Origin).Magnitude

local Force = GetForceNeeded(Origin, Goal, Projectile, MaxDistance)

local Points = Project(Force, Origin, Goal)

for _, Point in pairs(Points) do

	local Part = Instance.new("Part")
	Part.Anchored = true
	Part.CanCollide = false
	Part.Size = Vector3.one
	Part.Color = Color3.fromRGB(255, 170, 0)

	Part.CFrame = CFrame.new( 
		Point
	)

	Part.Parent = workspace
end

...

--// Force is applied to Projectile part as :ApplyImpulse( Force )

Another important note is I am not using Bezier Curves or anything like that because AFAIK this is different as it’s actual physics. Correct me if I’m wrong though!

Result I’m trying to achieve:
https://gyazo.com/1543a8dfa9fc5ef6683a5fd8c082903e

1 Like

Hey! I wish I knew how to pinpoint what to do in order to exactly achieve this. But your question reminded me of a video I watched that seems almost exactly similar to what you’re trying to do except this person uses tweens to reach his curved points. Hopefully you find this useful enough to be capable of implementing it to your liking!

If you have time to watch this, it may be beneficial. It’s 42 minutes long btw.
https://www.youtube.com/watch?v=OAZvYqbzOWI&t=30s

1 Like

Turns out it in-fact was the Force factor. It returned Force * AssemblyMass which altered the passed Force in Project function that was completely throwing off the calculations.

Updated code:

local function Project(Force: Vector3, Origin: Vector3): {Vector3}
	local Points = {}
	for Time = 0, 1, .1 do
		local Point = Origin + (Force * Time)
		Point = Vector3.new(Point.X, 
			Origin.Y + (Force.Y * Time) - ((workspace.Gravity / 2) * Time * Time),
			Point.Z)

		table.insert(Points, Point)
	end

	return Points
end

--// Simple parts in studio, projectile is just a ball
local Origin, Goal, Projectile = workspace.Start.Position, workspace.End.Position, workspace.Projectile

local function GetForceNeeded(Origin: Vector3, Goal: Vector3, Projectile: BasePart?, MaxDistance: number?): Vector3

	local Distance = (Goal - Origin).Magnitude
	MaxDistance = MaxDistance and math.min(MaxDistance, Distance) or Distance

	local Direction = Goal - Origin
	local Duration = math.log(1.001 + Direction.Magnitude * 0.01)
	local Force = Direction.Unit * MaxDistance / Duration + Vector3.new(0, workspace.Gravity * Duration * 0.5, 0)

	return Force --// Projectile and Force * Projectile.AssemblyMass or Force (This caused issues in trajectory projection calculations
end


local MaxDistance = (Goal - Origin).Magnitude

local Force = GetForceNeeded(Origin, Goal, Projectile, MaxDistance)

local Points = Project(Force, Origin, Goal)

for _, Point in pairs(Points) do

	local Part = Instance.new("Part")
	Part.Anchored = true
	Part.CanCollide = false
	Part.Size = Vector3.one
	Part.Color = Color3.fromRGB(255, 170, 0)

	Part.CFrame = CFrame.new( 
		Point
	)

	Part.Parent = workspace
end

...

--// Force is applied to Projectile part as :ApplyImpulse( Force * AssemblyMass )

Thank y’all for the help and additional resources!

This is for people that are wondering what he exactly did:

It looks like your code is attempting to calculate the trajectory of a projectile given an initial position (Origin ), a target position (Goal ), and the properties of the projectile (such as mass and gravity). The suspected culprit you mentioned is likely related to the calculation of the trajectory points.

local function Project(Force: Vector3, Origin: Vector3, Goal: Vector3)
    local Points = {}
    for Time = 0, 1, .1 do
        local Point = Origin + (Force * Time)
        Point = Vector3.new(Point.X, 
            Origin.Y + (Force.Y * Time) - ((workspace.Gravity / 2) * Time * Time),
            Point.Z)
        table.insert(Points, Point)
    end
    return Points
end

The suspected culprit section seems to be the adjustment of the Y-coordinate of the Point . This adjustment takes into account the effect of gravity over time. However, the term ((workspace.Gravity / 2) * Time * Time) seems to be incorrect. The correct formula for vertical displacement due to gravity is 0.5 * g * t^2 , where g is the acceleration due to gravity. It should be 0.5 * workspace.Gravity * Time * Time .

Origin.Y + (Force.Y * Time) - (0.5 * workspace.Gravity * Time * Time)
local function GetForceNeeded(Origin: Vector3, Goal: Vector3, Projectile: BasePart?, MaxDistance: number?): Vector3
    -- ...
end

It calculates the force needed to reach the goal, taking into account the direction, distance, and gravity.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.