I am trying to make a mortar for my game. Unlike most weapons that shoot projectiles, it does not shoot parts in a straight line. Since the projectiles are affected by gravity the mortar has to adjust its trajectory so that it will hit the player. For example, if a player is standing right by the Mortar it will have to aim almost straight up to hit the player. Here is how its intended to work:
When a player enters within Mortar’s range it rotates the base to face the player and then rotates the barrel to adjust for gravity and distance.
Here is a picture to help visualize the intended motion and the model of the Mortar.
We need more context in order to help you out. What code is responsible for the mortar’s functionalities? I know it is embedded in the model, but adding it to the topic makes it easier for other people to understand the situation.
Ok, good idea! Here is all the code used for the Mortar:
--Made by Its4Realzies
local sP = script.Parent
--Attack settings
local projectileSpeed = 75
local attackDamage = script.AttackDamage.Value
local attackRate = script.AttackRate.Value
local attackRange = script.AttackRange.Value
--For rotating Mortar
local base = sP.RotateBase
local baseCFrame = base.CFrame
--For angleing Mortar
local heart = sP.Heart
local heartCFrame = heart.CFrame
--Aims the Mortar toward player
local function aimMortar(player)
print("Aiming Mortar")
local playerCharacter = player.Character
--Faces mortar towards player
local charTorso = player.Character.Torso
base.Gyro.CFrame = CFrame.new(base.Position, charTorso.Position)
--Angles mortar towards player
local origin = heart.Position
local targetPosition = charTorso.Position
local gravity = Vector3.new(0, -game.Workspace.Gravity, 0)
local velocity = (targetPosition - origin - 0.5 * gravity)
heart.Gyro.CFrame = CFrame.new(heart.Position, heart.Orientation + velocity)
end
--Finds nearest Player
local function findNearestPlayer()
local lastDistance = math.huge
local toReturn
for _,plr in ipairs(game.Players:GetChildren()) do
local plrCharacter = plr.Character
if (plrCharacter ~= nil) and plrCharacter.PrimaryPart ~= nil then
local currentDistance = (plrCharacter:GetPrimaryPartCFrame().p - heart.Position).Magnitude
if currentDistance < lastDistance then
toReturn = plr
lastDistance = currentDistance
end
end
end
return toReturn, lastDistance
end
--Shoots projectile where the barrel is facing
local function fireProjectile()
local newProjectile = Instance.new('Part', sP)
newProjectile.Name = "Projectile"
newProjectile.TopSurface = 0
newProjectile.BottomSurface = 0
newProjectile.Color = Color3.fromRGB(140, 255, 148)
newProjectile.CanCollide = false
newProjectile.Reflectance = -0.5
newProjectile.Shape = 'Ball'
newProjectile.Size = Vector3.new(3, 3, 3)
newProjectile.Position = heart.Position
newProjectile.Orientation = heart.Orientation
newProjectile.Velocity = newProjectile.CFrame.lookVector * projectileSpeed
newProjectile.Touched:Connect(function(part)
if part ~= heart and part ~= sP.Stripe and part ~= sP.Barrel and part ~= sP.HingedSupport then
local particleHolder = Instance.new("Attachment", sP.AnchorBase)
particleHolder.Name = "ParticleHolder"
particleHolder.Position = newProjectile.Position
particleHolder.WorldPosition = newProjectile.Position
local newParticle = script.SplashEffect:Clone()
newParticle.Parent = particleHolder
newProjectile:Destroy()
wait(1)
newParticle.Enabled = false
wait(3)
newParticle:Destroy()
particleHolder:Destroy()
end
end)
end
local RunService = game:GetService("RunService")
RunService.Heartbeat:Connect(function()
local targetingPlayer, playerDistance = findNearestPlayer()
if targetingPlayer ~= nil and playerDistance < attackRange then
aimMortar(targetingPlayer)
else
base.Gyro.CFrame = baseCFrame
heart.Gyro.CFrame = heartCFrame
end
end)
while wait(1) do
local targetingPlayer, playerDistance = findNearestPlayer()
if targetingPlayer ~= nil and playerDistance < attackRange then
fireProjectile()
end
end
Edit for some reason the mortar lags a bit, but that could just be my low-end computer. There are no errors, It just the mortar is not angling the barrel in the way demonstrated in the photo above.
-- Setting it to heart.Gyro.CFrame would look unrealistic
newProjectile.CFrame = heart.CFrame
Now it should fire the projectile perpendicular to ‘heart’. If it does not solve your problem, then local function aimMortar(player) is responsible for that.
The idea is that you need to find the initial velocity vector for your projectile. You can then aim your cannon in the direction of that vector and finally fire the projectile with the magnitude of that vector.
I am having problems applying just about everything. Here is what I have so far:
–Start and end of projectiles path
local startPosition = sP.Position
local targetPosition = target.Position
–We don’t care about the y-component of the initial and target position.
local projectileXZPos = Vector3.new(heart.Position.X, nil, heart.Position.Z)
local targetXZPos = Vector3.new(targetPosition.Position.X, nil, targetPosition.Position.Z)
--Shorthands for the formula
local R = Vector3.Distance(projectileXZPos, targetXZPos)
local G = workspace.Gravity
local tanAlpha = math.Tan(LaunchAngle * math.Deg2Rad)
local H = targetPosition.Y - startPosition.Y
--Calculate the local space components of the velocity
--Required to land the projectile on the target object
local Vz = Mathf.Sqrt(G * R * R / (2.0f * (H - R * tanAlpha)) );
local Vy = tanAlpha * Vz;
Alright, so what you are trying to solve is a parabolic arc. @EgoMoose made a great article covering parabolic arcs and it should help you. You should check it out, as it’s a great tutorial.
A less complicated way of doing this is rotating the motor so it’a facing the player, calculating the magnitude of the motor and the player. (For example if the player X and Z axis is negative - then rotate the motor a little backwards by * the magnitude. You will have to play around to see which orientation is most accurate) Then add a VectorForce straight up into the sky and destroying the VectorForce a second later.
I am aware. In fact, I have posted that exact article as a source I was trying to use in my previous post trying to fix this Mortar. How do I angle a projectile to hit a player I don’t how to apply that logic to the angle of the Mortar.