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