Hi, I am trying to make an accurate and realistic bullet drop/loop drop for my gun/lasso, but I don’t know where to start. I have tried using this Devforum post (Modeling a projectile's motion) made by @EgoMoose. I do know about FastCast and how to use it, but I am trying to make my very own custom bullet drop system. All help is appreciated, Thanks!
Current code (script inside of gun tool);
local TweenService = game:GetService("TweenService")
local Tool = script.Parent
local Handle = Tool:FindFirstChild("Handle")
local OnCooldown = false
local handle = script.Parent:WaitForChild("Handle")
local t = 1;
script.Parent.RemoteEvent.OnServerEvent:Connect(function(plr, mouse, hrp)
local g = Vector3.new(0, -240, 10);
local x0 = hrp.CFrame * Vector3.new(0, 1.3, -2)
local v0 = (mouse.Position - x0 - 0.32*g*t*t)/t
for i,v in pairs(Handle:GetChildren()) do
if v.Name == "LassoLoopClone" then
v:Destroy()
end
end
handle.LassoLoop.Transparency = 1
local c = handle.LassoLoop:Clone()
c.Name = "LassoLoopClone"
c.Velocity = v0
c.CFrame = CFrame.new(x0)
c.CanCollide = true
c.Parent = script.Parent.Handle
c.Transparency = 0
handle.RopeStart.RopeConstraint.Attachment1 = c:FindFirstChild("Attachment")
handle.RopeStart.RopeConstraint.Length = 100 --(plr.Character.Head.Position - mouse.Position).Magnitude - 0.13
c.Touched:Connect(function(part)
if game.Players:FindFirstChild(part.Parent.Name) then
if part.Parent.Name ~= plr.Name then
if script.Parent.CaughtPlr.Value == false then
part.Parent.Humanoid.WalkSpeed = 0
part.Parent.Humanoid.JumpPower = 0
part.Parent.Humanoid.PlatformStand = true
print("caught")
script.Parent.CaughtPlr.Value = true
Handle:FindFirstChild("LassoLoopClone").Position = part.Parent:FindFirstChild("UpperTorso").Position
local weld = Instance.new("Weld", Handle:FindFirstChild("LassoLoopClone"))
weld.Part0 = Handle:FindFirstChild("LassoLoopClone")
weld.Part1 = part.Parent:FindFirstChild("UpperTorso")
return "Plr"
end
end
else
if script.Parent.CaughtPlr.Value == false then
if part.Name == workspace.Baseplate.Name then
print("Baseplate")
wait(1.3)
for i,v in pairs(Handle:GetChildren()) do
if v.Name == "LassoLoopClone" then
v:Destroy()
Handle.LassoLoop.Transparency = 0
Handle.RopeStart.RopeConstraint.Attachment1 = Handle.LassoLoop.Attachment
Handle.RopeStart.RopeConstraint.Length = 7.3
end
end
for descI, descandant in pairs(part.Parent:GetDescendants()) do
if descandant:IsA("BasePart") then
descandant.Massless = true
end
end
script.Parent.CaughtPlr.Value = false
return "Baseplate"
end
end
end
end)
for i,v in pairs(c:GetChildren()) do
if v:IsA("CFrameValue") or v:IsA("Weld") then
v:Destroy()
end
end
end)```
As I said before, I don’t really want to use FastCast due to the fact I may sell this in the future. If I were to sell it with FastCast it wouldn’t really be my own code.
You could generate the trajectory procedurally via a loop instead of using a quadratic. Would definitely be less performant but it gives more room for customization. Here’s a pseudocode of it:
local position: Vector3 = part.Position --starting position
local velocity: Vector3 = part.CFrame.LookVector * 1e3 --starts at 1000 studs per second
local drag: number = 0.05 --lose 5% of velocity each second
local gravity: Vector3 = Vector3.yAxis * workspace.Gravity
RenderStepped:Connect(function(dt: number)
velocity += gravity * dt --gravitional acceleration
velocity *= 1 - drag * dt --drag
position += velocity * dt --move the projectile
part.CFrame = CFrame.lookAt(position, position + velocity)
end)
local cam = workspace.CurrentCamera
local bulletSpeed = 100
function applyGravity(force : number)
return force * -workspace.Gravity
end
local force = cam.CFrame.lookVector * applyGravity(bulletSpeed)
bullet:ApplyImpulse(force)
This method is decent, but I have a few questions. Firstly, how do I get the DeltaTime on the server? Secondly, I have tried to increase and decrease the drag, but nothing happens, I do not know if that is because of the velocity. Lastly, what does 1e3 stand for in the velocity? Thanks!
Use .Stepped instead of .RenderStepped if it’s on the server. Note that for .Stepped the deltatime is actually the 2nd parameter, not the first
RunService.Stepped:Connect(function(_, dt: number) --2nd one
...
It’s probably because the drag you set is too minuscule for you to notice an effect. Referring to the equation used, velocity is multiplied by 1 - drag*dt. So if the game is running at 60 Hz and you set the drag to 10, you would get:
-- 1 / 60 fps = 0.016666... frame time
velocity *= 1 - 10*0.0166666
velocity *= 1 - 0.166666
velocity *= 0.833333 --velocity will drop by 16.6% percent this frame
That would be the speed of the bullet. You multiply that by the LookVector of a gun barrel to get the bullet’s muzzle velocity.
For example, if the gun’s LookVector is (1, 0, 0) and the speed is 1e3, the muzzle velocity would be (1e3, 0, 0).
Reminder: Speed is a scalar value, while velocity is a vector value
Thank you, For the last question though I meant what does the e stand for? I have heard some people say it stands for 1000 and others say it stands for 1^3.
It really depends on the use case. .Stepped is if you want to simulate the bullet prior to the physics engine, and .Heartbeat is the opposite. Roblox renders the frame before simulating physics, so by logic if the OP wants the bullet to be visuals-only then it should also precede physics. But if the bullet is being used for hitreg in an FPS game, then it should come after physics simulation.
TL;DR: Visuals-only bullet should use .RenderStepped, bullet with hitreg should use .Heartbeat
To create a custom bullet drop system, you will need to calculate the trajectory of the bullet based on its initial velocity, gravity, and the distance it travels. Here is an example of how to calculate the bullet drop for a given distance:
-- constants
local GRAVITY = 9.81 -- meters per second squared
local VELOCITY = 800 -- meters per second
local DISTANCE = 1000 -- meters
local HEIGHT = 1.5 -- meters
-- calculate time of flight
local t = (2 * VELOCITY * math.sin(math.rad(45))) / GRAVITY
-- calculate horizontal and vertical components of velocity
local vx = VELOCITY * math.cos(math.rad(45))
local vy = VELOCITY * math.sin(math.rad(45))
-- calculate bullet drop at each time step
local dt = 0.01 -- seconds
local y = HEIGHT -- initial height
local x = 0 -- initial distance
local bulletDrop = {}
for i = 1, t/dt do
local dy = vy*dt - 0.5*GRAVITY*dt*dt
y = y + dy
vy = vy - GRAVITY*dt
x = x + vx*dt
bulletDrop[i] = {x, y}
end
-- display bullet drop data
for i, data in ipairs(bulletDrop) do
print(string.format("Time: %.2f seconds, Distance: %.2f meters, Height: %.2f meters", i*dt, data[1], data[2]))
end
In this example, we assume a muzzle velocity of 800 meters per second, a range of 1000 meters, and an initial height of 1.5 meters. We calculate the time of flight based on the initial velocity and gravity, and then use trigonometry to calculate the horizontal and vertical components of velocity. We then loop over each time step and calculate the bullet drop based on the vertical velocity and gravity.
You can integrate this calculation into your script for your gun or lasso to create a custom bullet drop system. Note that the specific implementation may depend on the physics engine used in your game, and you may need to experiment with different parameters to achieve the desired effect.
Thank you for this code, I do not care if it is ai generated or not, it will be helping me very much! @Prototrode gave me a good example first so I will give the solution to them.