I’m making a mortar for my game. (Video of it in action down below so you can visualise is)
And you can adjust the angle and rotation of it to hit targets. The problem is Its hard to visualize the path of the projectile before it fires so I want to make some sort of trail using a ray or particles to show the path of the projectile. I don’t know where to start.
https://streamable.com/wiz4vu
Check out Bézier Curves as I’d approach this by calculating a curve from the cannon to where it hits, then represent it with beams or parts.
Also here is the code for the turret if that helps:
while wait(sP.Delay.Value) do
–Creates and plays Fire
local sound = sP.Fire:Clone()
sound.Name = ‘SoundEffect’
sound.Parent = sP
sound:Play()
game.Debris:AddItem(sound, 5)
local bullet = Instance.new('Part')
bullet.Name = 'Bullet'
bullet.CanCollide = true
bullet.Color = sP.Color
bullet.Material = 'Plastic'
bullet.Shape = 'Ball'
bullet.Size = Vector3.new(holeSize, holeSize, holeSize)
bullet.CFrame = sP.CFrame
bullet.FrontSurface = 'Studs'
bullet.BackSurface = 'Studs'
bullet.RightSurface = 'Studs'
bullet.LeftSurface = 'Studs'
bullet.TopSurface = 'Studs'
bullet.BottomSurface = 'Studs'
bullet.Velocity = bullet.CFrame.lookVector * sP.Speed.Value
bullet.Parent = sP
game.Debris:AddItem(bullet, 30)
end
I’ve done stuff with bezier curves before, but how does that work with gravity and the angle of the mortar?
In this application it may be tricky if the bullet needs physics simulation for the whole path. Bezier curves would replace the trajectory of the bullet and would need animating of some sort, but you’d get both the trajectory visual and the cannon’s hit position in one go.
Egomoose has an excellent tutorial here on the forums for projectiles involving Bezier curves and beams, which is how I’d go about it.
The thing in the post shows an example where the endpoint is the players mouse. I don’t know where the projectile is going to land I just know the angle of mortar and the projectiles speed & mass
Calculating projectile motion for that purpose is possible but a bit beyond what I remember from my physics classes, but I’m positive a formula can be recreated in Roblox for it. It’d certainly work in place of using a bezier curve to animate the bullet’s motion, since the only downside I can think of is the unpredictability of the bullets’ path being clear, but if it’s only for helping aim it should work. Perhaps if the cannon’s variables are always constant you could write your own function to relate the angle and range?
You do not really need the end point, even then you could find it using the projectile motion equation.
As long as you have:
g, v0, x0, endTime
g, v0, x0, t1
gravity :Vector3, initialVelocity : Vector3, initialPosiion: Vector3, nextPointEndTime : number
--t1 can be anything, it's used to find the end position of where the projectile will end up and where the beam is being directed towards
It should be fine, here is the beam functions modularized:
Summary
local function createBeamInProjectileMotionPath()
local attach0 = Instance.new("Attachment")
local attach1 = Instance.new("Attachment")
local beam = Instance.new("Beam")
beam.Color = ColorSequence.new(Color3.new(1, 0.035294, 0.035294))
beam.Attachment0 = attach0
beam.Attachment1 = attach1
beam.Parent = workspace.Terrain
attach1.Parent = workspace.Terrain
attach0.Parent = workspace.Terrain
return beam, attach0, attach1
end
local function beamProjectile(g, v0, x0, t1)
-- calculate the bezier points
local c = 0.5 * 0.5 * 0.5
local p3 = 0.5 * g * t1 * t1 + v0 * t1 + x0
local p2 = p3 - (g * t1 * t1 + v0 * t1) / 3
local p1 = (c * g * t1 * t1 + 0.5 * v0 * t1 + x0 - c * (x0 + p3)) / (3 * c) - p2
-- the curve sizes
local curve0 = (p1 - x0).magnitude
local curve1 = (p2 - p3).magnitude
-- build the world CFrames for the attachments
local b = (x0 - p3).unit
local r1 = (p1 - x0).unit
local u1 = r1:Cross(b).unit
local r2 = (p2 - p3).unit
local u2 = r2:Cross(b).unit
b = u1:Cross(r1).unit
local cf1 = CFrame.new(x0.x, x0.y, x0.z, r1.x, u1.x, b.x, r1.y, u1.y, b.y, r1.z, u1.z, b.z)
local cf2 = CFrame.new(p3.x, p3.y, p3.z, r2.x, u2.x, b.x, r2.y, u2.y, b.y, r2.z, u2.z, b.z)
return curve0, -curve1, cf1, cf2
end
local function createAndSetBeam(g, v0, x0, endTime, color)
local t1 = endTime or 1 -- projectile time when in expires, or any number you want tbh
local curve0, curve1, cf1, cf2 = beamProjectile(g, v0, x0, t1)
local beam, attach0, attach1 = createBeamInProjectileMotionPath()
beam.CurveSize0 = curve0
beam.CurveSize1 = curve1
beam.FaceCamera = true
beam.Segments = 10 * math.round(t1 * 3)
if color then
beam.Color = ColorSequence.new(color)
end
-- convert world space CFrames to be relative to the attachment parent
attach0.CFrame = attach0.Parent.CFrame:Inverse() * cf1
attach1.CFrame = attach1.Parent.CFrame:Inverse() * cf2
end
return createAndSetBeam
Wait why do you need gravity as a parameter? Isn’t Gravity always the same?
Yeah, it’s the same but you will still need to tell the beam the shape of the projectile and where it’s going to which it will calculate using those 4 parameters.
Here is an example tool I took from an old topic I helped out a long time ago.
Create a tool in starter pack, and insert this as a local script
local tool = script.Parent
tool.RequiresHandle = false
local Players = game:GetService("Players")
local player = Players.LocalPlayer
local mouse = player:GetMouse()
local DB = false
local function createBeamInProjectileMotionPath()
local attach0 = Instance.new("Attachment")
local attach1 = Instance.new("Attachment")
local beam = Instance.new("Beam")
beam.Color = ColorSequence.new(Color3.new(1, 0.035294, 0.035294))
beam.Attachment0 = attach0
beam.Attachment1 = attach1
beam.Parent = workspace.Terrain
attach1.Parent = workspace.Terrain
attach0.Parent = workspace.Terrain
return beam, attach0, attach1
end
local function beamProjectile(g, v0, x0, t1)
-- calculate the bezier points
local c = 0.5 * 0.5 * 0.5
local p3 = 0.5 * g * t1 * t1 + v0 * t1 + x0
local p2 = p3 - (g * t1 * t1 + v0 * t1) / 3
local p1 = (c * g * t1 * t1 + 0.5 * v0 * t1 + x0 - c * (x0 + p3)) / (3 * c) - p2
-- the curve sizes
local curve0 = (p1 - x0).magnitude
local curve1 = (p2 - p3).magnitude
-- build the world CFrames for the attachments
local b = (x0 - p3).unit
local r1 = (p1 - x0).unit
local u1 = r1:Cross(b).unit
local r2 = (p2 - p3).unit
local u2 = r2:Cross(b).unit
b = u1:Cross(r1).unit
local cf1 = CFrame.new(x0.x, x0.y, x0.z, r1.x, u1.x, b.x, r1.y, u1.y, b.y, r1.z, u1.z, b.z)
local cf2 = CFrame.new(p3.x, p3.y, p3.z, r2.x, u2.x, b.x, r2.y, u2.y, b.y, r2.z, u2.z, b.z)
return curve0, -curve1, cf1, cf2
end
local function createAndSetBeam(g, v0, x0, endTime, color)
local t1 = endTime or 1 -- projectile time when in expires, or any number you want tbh
local curve0, curve1, cf1, cf2 = beamProjectile(g, v0, x0, t1)
local beam, attach0, attach1 = createBeamInProjectileMotionPath()
beam.CurveSize0 = curve0
beam.CurveSize1 = curve1
beam.FaceCamera = true
beam.Segments = 10 * math.round(t1 * 3)
if color then
beam.Color = ColorSequence.new(color)
end
-- convert world space CFrames to be relative to the attachment parent
attach0.CFrame = attach0.Parent.CFrame:Inverse() * cf1
attach1.CFrame = attach1.Parent.CFrame:Inverse() * cf2
return beam, attach0, attach1
end
tool.Activated:Connect(function()
local hrp = player.Character.HumanoidRootPart
if not DB then
local comet = Instance.new("Part")
comet.Size = Vector3.new(2,2,2)
comet.CanCollide = false
comet.CFrame = hrp.CFrame
comet.Parent = game.Workspace
local antiGravity = Instance.new("BodyForce")
local antiGravityFactor = 0.9--1 = gravity force counteracted, 0 = no force lol
antiGravity.Force = comet:GetMass()*workspace.Gravity*antiGravityFactor *Vector3.new(0,1,0)
antiGravity.Parent = comet
local appliedVelocity = (CFrame.new(hrp.Position,mouse.Hit.Position).LookVector * 50)
comet.AssemblyLinearVelocity = appliedVelocity
local gravity = Vector3.new(0,-Workspace.Gravity*(1-antiGravityFactor),0)
createAndSetBeam(gravity, appliedVelocity, hrp.CFrame.Position, 1)
spawn(function()
DB = false
wait(5)
comet:Destroy()
end)
end
end)
Also you will notice setting the end time as t1 = 1 will create a beam because thats where the projectile will be after one second with the beam will go towards and stop at that point, this is what happens if you set it to t1 = 30 from Ego Mooses beam formula.
well i suppose you could pre-fire a projectile with a trail every second and change the trail’s stuff to make it fit you, its a bit laggy but it works
I applied this to the best of my ability and it seems to be working halfway. The beam is not a smooth curve and I might need to move it down because it seems like it’s 2 studs too high. Here is a model and a video of the model:
If the beam is not a smooth curve then you might need to either reduce t1 and make the beam shorter or increase the number of beam segments
beam.Segments = 10 * math.round(t1 * 3)
Everything works now, the only weird thing is that the beam starts at the top of the turret and not the middle.
Do you know why this would be so?
im super confused on what v0 and x0 is, any help thanks