Cannon's trajectory completely inaccurate

I’m designing a cannon AI that fires projectiles in an arc toward your position once you get within its aggro range. I based my approach on this video and when I implement it just like this (with an anchored orb shooting the projectiles) it works perfectly. However, I don’t want a floating ball, I want an AI like this to shoot the projectiles:
image

This AI is supposed to orient its barrel in the direction of the arc and fire the projectile high into the air like an artillery cannon. However, when I test it in-game, this is what happens:


I’ve double-checked my code and used print() statements to look at the position it’s firing at, and they both match in the code. I cannot figure out why it’s firing at someplace else. Notice that the turret’s barrel isn’t necessarily facing me, either.

Here’s all the relevant code. I’ll tell you right now that this is all on the client (hence the remote events) and that the welds are not what is causing the issue, as I tested the cannon firing head-on at me and it aimed the barrel properly.

-- calculates the pathway of a cannon bullet
local function calculateFlightPath(target, turret)
	local start = turret:FindFirstChild("Barrel", true).WorldCFrame.Position
	local destination = target
	print(players.LocalPlayer.Character.PrimaryPart.Position)
	local direction = destination - start

	local duration = 5.5

	destination = target * duration
	direction = destination - start

	local force = direction / duration + Vector3.new(0, workspace.Gravity * duration * 0.5, 0)
	return force
end
-- fires a turret bullet
local function fire(turret)
	local bullet = projectiles:FindFirstChild(turret.Name) and projectiles[turret.Name]:Clone() if not bullet then return end
	bullet.CFrame = turret:FindFirstChild("Barrel", true).WorldCFrame
	bullet.Parent = workspace
	if turret.Name == "Cannon" then
		bullet:ApplyImpulse(calculateFlightPath(turret.Parent:GetAttribute("Target"), turret) * bullet.Mass)
		task.wait(1)
		bullet.Touched:Connect(function(part)
			if not turret:FindFirstChild(part, true) then
				enemyAttack:FireServer(turret.Parent, turret.PrimaryPart.Position, part.Name, bullet.Position)
				bullet:Destroy()
			end
		end)
	end
end

local aimer = turret:FindFirstChild("Aimer", true)
local cFrame = CFrame.lookAt(aimer.WorldPosition, calculateFlightPath(folder:GetAttribute("Target"), turret))
local relativeCFrame = turret.PrimaryPart.CFrame:ToObjectSpace(cFrame)
local x, y, z = relativeCFrame:ToOrientation()
weldUpDown.C0 = offsetUD * (CFrame.Angles(x, 0, 0)):ToWorldSpace()
weldLeftRight.C0 = offsetLR * (CFrame.Angles(y, 0, 0)):ToWorldSpace()

Please let me know if you need any more information.

Bit of an update, but I’ve tested the same script as in the original post while changing the duration in the calculateFlightPath() function to 1. It seems to fix the trajectory of the projectile somewhat, but the aiming of the cannon’s head is still inaccurate, and I don’t want the duration to be 1, but 5.5 like in the original script. Any ideas on what the issue might be are appreciated.

I believe you can just set the cannon’s CFrame to be CFrame.new(Cannon.Position,HumanoidRootPart.Position)

If you want the cannon to point a bit higher then you can offset the CFrame.Angles after.

This wasn’t it. It turns out I was just having the barrel look at the force vector and not the cannon’s position plus the force vector. The orientation of the cannon head has been fixed, but the issue of the duration of projectile flight affecting where the cannon aims is still present.

Did some more testing. The target is miscalculated any time duration is not 1. If duration is greater than 1, it will add to the Z axis. If it is less than 1, it will subtract from the Z axis. It calculates both the X and Y axes correctly. I have absolutely no idea where this Z axis addition is being made in the code. I’ve already posted all of the relevant snippets to those calculations. I really need help figuring this out; the only place duration is used is in the calculateFlightPath() function.

But why on earth are you multiplying the destination position by duration? You are quite literally changing the destination position then. Ofc it only works at duration = 1!

And your print statement is before this, ofc it prints the right position!

maybe this is it? I’d like to know where your print statements where when you said that.

Yeah, this was it. I figured it out at almost the exact same time as you did as I was rewatching the video I posted in the OP. In that video, the target position was calculated inside the function, while I calculated it outside the function in another script. Another reason to always comment your code!

1 Like

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