How to create accurate Bullet drop?

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)
1 Like

Have you checked the Roblox gun in the Combat map? It has that if I’m not wrong

Something like this,

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)

Something like that.

1 Like

This works pretty well, but I am wondering how I could decrease the speed and still be able to increase the distance with this method. Thanks!

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 is scientific notation, but because it’s using e to denote *10^, it is actually called E-notation. There are many different ways to write it:

--these all mean 1,000
1e3
1e+3
1E3
1E+3

And comparing it to regular scientific notation:

1000 = 1e3 = 1 * 10^3

1234000 = 1.234e6 = 1.234 * 10^6

0.001 = 1e-3 = 1 * 10^-3

By reducing the bulletSpeed value

I believe using Heartbeat is better to reduce jittering and any further bugs.

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

Well yes, but if I decrease the bulletSpeed value the distance also becomes shorter.

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.

That’s physics [ Stupid character limit ]

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