Projectile Physics

The past two days I have been studying the physics of projectile motion; for the sake of learning and applications in game development. I have been looking over coding examples from other developers on the forum from the past, and I came across this example by @Oseday:

local Part1 = workspace.Part1
local Part2 = workspace.Part2  	
local Heartbeat = game:GetService("RunService").Heartbeat
local G = Vector3.new(0, -50, 0)
local Proj = {p = Part1.Position, v = Part2.Position}
	
while Part1.CFrame.Y > 1 do
	local dt = Heartbeat:wait()
	Proj.p = Proj.p + (Proj.v * dt)
	Proj.v = Proj.v + (G * dt)
	Part1.CFrame = CFrame.new(Proj.p, Proj.p + Proj.v)
end

For the past few hours iv’e been studying how it functions. I have also tried to make it work from starting locations other than just the origin of the WorldPlace; yet I have been experiencing a great deal of trouble on doing the following. If anyone could help to lead me in the right direction that would be great, thanks.

4 Likes

Hello, I like projectile physics. What this code is doing is basically creating a class that has a p (position) component, and v (velocity) component. Every heartbeat, the position is changed by the velocity*dt which is the change in time since the last heartbeat. This is from the equation distance = rate*time. The second thing it does is change the velocity with the acceleration, which is defined as gravity in this case. The change in velocity is measured by acceleration, so it basically multiplies the acceleration by the change in time to get the current velocity, which will be used the next time heartbeat is called to calculate the position. Finally it sets the CFrame of the part to equal the calculated position, but looking in the direction of the velocity vector.

While this works, I prefer to think of the projectile as the output of a continuous function.

function position(a, vi, xi, t)
	return .5*a*t^2 + vi*t + xi
end

This is basically what that code was doing, but as a single operation. With this you can plug in the variables for acceleration, initial velocity, initial position, and time elapsed to get the position that a projectile will be along a parabola.

An example of a simulation would be:

local part = workspace.Part1
local heartbeat = game:GetService("RunService").Heartbeat

local acceleration = Vector3.new(0,-workspace.Gravity,0)
local initialVelocity = Vector3.new(100,100,100)
local initialPosition = part.Position

function position(a, vi, xi, t)
	return .5*a*t^2 + vi*t + xi
end

local startTime = tick()
local elapsedTime = 0

while elapsedTime < 10 do
	heartbeat:wait()
	elapsedTime = tick()-startTime
	part.CFrame = CFrame.new(position(acceleration, initialVelocity, initialPosition, elapsedTime))
end

This does pretty much what the previous code does, except the velocity is defined as 100,100,100, which means launch in the direction of (1,1,1) at a speed of the square root of 30,000 or something. Also the break case for the while loop is if the total elapsed time exceeds 10 seconds, rather than if it goes below 0 Y.

10 Likes

Very interesting, thanks for taking the time to create an example and explain it in detail.

p.s. I just did the breaking at 0Y for quick testing purposes.

1 Like