Discrepancy between calculated and actual projectile impact location

I have made a catapult that launches a flaming rock towards a target. Using a firing control gui, you can set the direction, elevation, and power (speed) of the projectile when it’s launched. The problem is (can be seen in this video) the projectile does not match the curve. It doesn’t go as high, and it goes further than predicted. The formulas used between the prediction and the launch are basically the same so I don’t understand what’s going on here.

Launch Code

		-- Setup for Launch
		button.Transparency = 1
		button.CanCollide = false
		button.CanTouch = false
		button.Fire.Transparency = 1
		hinge.TargetAngle = 0
		local cframe = model:GetPivot()
		projectile.Position = Vector3.new(cframe.X,	cframe.Y + 10, cframe.Z - 5)
		task.wait(0.2)
		
		-- Set the direction of the projectile based on if the player
		-- has the controls visible or not.
		local dir
		local velocity
		if playerGui == nil then
			dir = Vector3.new(forwardDir.X, forwardDir.Y +
				math.sin(math.rad(45)), forwardDir.Z).Unit
			velocity = 350
		else
			if playerGui.Parent == nil then
				dir = Vector3.new(forwardDir.X, forwardDir.Y +
					math.sin(math.rad(45)), forwardDir.Z).Unit
				velocity = 350
			else
				local cframe = model:GetPivot()
				local ax, ay, az = cframe:ToOrientation()
				print(fireDirection, fireElevation, firePower)
				local x = math.cos(math.rad(fireDirection - 90) - ay)
				local z = math.sin(math.rad(fireDirection - 90) - ay)
				local y = math.sin(math.rad(fireElevation * 90) + ax)
				dir = Vector3.new(x, y, z)
				velocity = firePower * 400
			end
		end
		
		-- Launch
		projectile.Velocity = dir * velocity
		task.wait(0)
		projectile.Anchored = false
		sound2:Play()

Prediction Code

-- Computes the target path and position based on direction,
-- elevation, and launch force (power).  Displays markers in
-- the workspace marking the path and target impact location.
local function computeTarget(direction, elevation, power, tpart, ppart)
	-- Get model's location and calculate projectile origin.
	local cframe = catapult:GetPivot()
	local origin = Vector3.new(cframe.X, cframe.Y + 10, cframe.Z - 5)
	
	-- Compute projectile direction on XZ plane.	
	local ax, ay, az = cframe:ToOrientation()
	local dx = math.cos(math.rad(direction - 90) - ay)
	local dz = math.sin(math.rad(direction - 90) - ay)
	local dir = Vector3.new(dx, 0, dz)
	
	-- Compute time-of-flight (t) and range (r).
	local g = game.Workspace.Gravity
	local vx = math.cos(math.rad(elevation * 90) + ax) * power * 400
	local vy = math.sin(math.rad(elevation * 90) + ax) * power * 400
	local t = (vy + math.sqrt(vy * vy + (2 * g * origin.Y))) / g
	local r = vx * t

	-- Raycast from XZ plane impact coordinates to ground to get
	-- ground impact location.  Once that's done, place target
	-- marker at that point.
	local fph = math.abs(game.Workspace.FallenPartsDestroyHeight)
	local target = Vector3.new((dir.X * r) + origin.X, 900, (dir.Z * r) + origin.Z) 
	local rct = Vector3.new(0, -(fph + 900), 0)
	local rcp = RaycastParams.new()
	local rcr = game.Workspace:Raycast(target, rct, rcp)
	if rcr ~= nil then
		tpart.Position = rcr.Position
	end
	
	print(t, r)
	
	-- Remove previous path markers.
	for _, item in ipairs(trajectoryMarkerList) do
		item:Destroy()
	end
	trajectoryMarkerList = {}
	
	-- Compute and place path trajectory markers
	-- from origin to target.
	for i = 0, t, 0.1 do
		local y = -0.5 * g * i * i + vy * i + origin.Y
		local r = vx * i
		local part = ppart:Clone()
		part.Position = Vector3.new((dir.X * r) + origin.X, y, (dir.Z * r) + origin.Z)
		part.Parent = game.Workspace
		table.insert(trajectoryMarkerList, part)
	end
end

im not 100% sure about how roblox handles their physics engine but normal physics calculations require a lot of tweaking to have them match their engine. i could recommend just having the part follow the predicted path using the math you provided and CFraming it and using rays to detect collision but ik its not memory friendly. if you do wish to have normal physics and predict it, i would try accounting for part mass as well in your calculations

Hmm… The thing is though when I took physics in college, mass does not matter. As Galileo (I think) proved, all objects fall at the same speed regardless of mass. So mass only comes into play when the projectile is launched. I’m manipulating the velocity directly. It’s something to do with the elevation, but I’m not sure what because when you watch the video, it launches at an elevation that is lower than what the path is, even though it’s the same number. So something is wrong, I’m just not sure what.

I found something else that’s interesting.

On the server, the directional vector has X as -2.980e-8 while on the client it’s 6.123e-17. Granted, these are generally considered to be 0, but that’s all that I see. The Y velocity for both (141.421356…) is exactly the same on both the client and the server. I manually calculated the unit vector using a calculator and it’s supposed to be <0, 0, -1> which is correct. I have no idea of why cosine of -π/2 or 3π/2 isn’t returning exactly 0 since that is part of the definition of cosine, or why it’s giving two different numbers consistently between client and server for the same input. That looks like a bug to me and one that they should address because it’s not numerically accurate.

It may very well be something with the physics engine. I’ve seen other people complain about some very strange things when dealing with this engine. Things like trying to predict where a player will land when jumping forward is one. So they are doing something non-standard with the math behind the simulation.

im not 100% sure, and as for your previous message, all my physics knowledge is self taught and im starting my first college physics class next sem :sweat_smile:

i do hope you figure something out with it as i’ve been messing around with roblox physics for years making random projects and sports games so. hopefully if i do come up with something of use i can assist you further.

I found something else that’s interesting too. If I lower the elevation (launch angle) to 0, the projectile mostly follows the path with very little error. So it is an issue with the elevation being > 0°. At this point I’m not sure if the discrepancy is linear or non-linear, but I know it doesn’t seem to be constant. I’m going to play with the launch angle and see what I come up with.

i do agree that there are discrepancies with the physics engine, which i presume is a product of NetworkOwnership, my baseball game can accurately predict the ball’s bounce path off a hit and the ball follows it almost 1 to 1, however if a player is nearby it entirely deviates from the course.

clip with no ownership: https://i.gyazo.com/4dc9adc963f95e6ad540900d1c917d85.mp4

clip with ownership: https://i.gyazo.com/0c8a3a4876a370643e019d0e88bb5a25.mp4

this clip w/o ownership has the ball start at the predicted start point and follow it almost perfectly, however with ownership it seems to miscalculate the start point and it falls short? i have 0 clue.

Based on the video, it seems that the issue lies with the prediction code not accurately reflecting the actual trajectory of the projectile. There are a few potential reasons why this could be happening:

  1. In the launch code, the projectile is being given an initial velocity of dir * velocity , whereas in the prediction code, the projectile’s trajectory is being computed based on a launch force of power * 400 . It’s possible that these values are not equivalent and that the actual velocity of the projectile is different from what the prediction code is expecting.
  2. The prediction code is assuming that the projectile is being launched from a flat surface (i.e. the XZ plane), whereas in reality, the catapult may be launching the projectile from an elevated position. This could cause the projectile to travel farther than predicted, since it would have more time to accelerate before hitting the ground.
  3. The prediction code is assuming a constant gravitational acceleration of game.Workspace.Gravity , whereas in reality, the gravitational acceleration may vary based on the height of the projectile. This could cause the projectile’s trajectory to deviate from the predicted path.

To address these issues, you could try the following:

  1. Ensure that the launch velocity and the prediction launch force are equivalent. You could do this by printing out the actual launch velocity in the launch code and comparing it to the predicted velocity computed by the prediction code.
  2. Modify the prediction code to take into account the initial elevation of the projectile. You could do this by computing the initial velocity of the projectile in the launch code and passing it as an argument to the prediction code.
  3. Modify the prediction code to take into account variable gravitational acceleration. You could do this by computing the gravitational acceleration at each point along the projectile’s path based on its height above the ground, and using this to update the projectile’s velocity and position.

@HolisThaDev There’s a few things that I want to mention…

  1. The actual launch and the prediction are both based on velocity. Nothing is using actual physics force like you would in a VectorForce. And I already checked. Look up at my previous posts, The numbers match except the X coordinate, but the numbers are so close to 0 that it doesn’t matter.
  2. The prediction code is using the same code as the actual launch to determine the flight path trajectory of the projectile. Both takes into account the orientation of the catapult in the X, Y, and Z rotations as well as the position of the catapult. That last one it would have to so it can draw from the point of origin to the target.
  3. In reality, yes. But this isn’t reality. It’s a game. I seriously doubt that the game developers would bother making a gravitational gradient based on height from the ground. It would make the physics formulas more complicated than they need to be.

@hotpocket285 Well, guess what? I got it working…correctly. The problem was the launch code. I finally broke down and pulled out my multivariable calculus book to figure out what was going on. Here’s the final launch code:

local cframe = model:GetPivot()
local ax, ay, az = cframe:ToOrientation()
print(ax, ay, az)
local x = math.cos(math.rad(fireDirection - 90) - ay)
local z = math.sin(math.rad(fireDirection - 90) - ay)
local y = math.sin(math.rad(fireElevation * 90) + ax)
local h = math.cos(math.rad(fireElevation * 90) + ax)
print(x, y, z, h)
dir = Vector3.new(x * h, y, z * h)
velocity = firePower * 400

The key point was to realize that you have two angles in a 3D coordinate system. So you have both a XZ plane for the horizontal, and a YZ for the vertical. After making that realization, the fix was simple. Now the projectile follows the predicted path EXACTLY. I even changed the orientation and height of the catapult and it still predicts the projectile’s flight path correctly.

1 Like