Deadline bullet physics?

I was wondering if anyone knew here what type of bullet physics that deadline used, I’m trying to make an fps game with as realistic as possible physics.

Currently in using raycasting off of a part but have no bullet drop and it feels pretty “fake” if that makes any sense.

So I was hoping that someone could point me in a direction or help make such a script WITHOUT using fastcast or any other premade gun physics as I prefer to make my own scripts.

Any help is appreciated,
Feel free to post questions or DM me.

my current code:

local replicatedStorage = game:GetService("ReplicatedStorage")
local serverStorage = game:GetService("ServerStorage")
local fireGun = replicatedStorage:WaitForChild("fireGun")

local function createBullet(startPos, rotation, speed, damage, mass, damageDropDistance, maxDistance)
	
	--creates the bullet from replicated storage
	local bullet = game:GetService("ReplicatedStorage"):WaitForChild("bullet"):Clone()
	bullet.Position = startPos
	bullet.Rotation = rotation
	bullet.Anchored = true
	bullet.CanCollide = false
	bullet.Parent = workspace
	
	--casts the bullet ray for hit detection
	local function castBulletRay()
		local rayOrigin = bullet.CFrame.Position
		local rayDirection = bullet.CFrame.XVector
		local rayParameters = RaycastParams.new()
		rayParameters.FilterDescendantsInstances = {bullet, game.StarterPack["Glock 18c"]}
		rayParameters.FilterType = Enum.RaycastFilterType.Exclude
		rayParameters.IgnoreWater = true
		local hit = workspace:Raycast(rayOrigin, rayDirection * speed, rayParameters)
		local position = bullet.Position
		
		local damageDrop = (position - startPos).Magnitude/damageDropDistance
		local newDamage = damage/damageDrop

		if newDamage > damage then
			newDamage = damage
		end
		
		if newDamage < 1 then
			newDamage = 0
			game:GetService("Debris"):AddItem(bullet, 0.01)
			bullet = nil
		end
		
		
		--damage multipliers based on body part
		if hit and bullet then
			local humanoid = hit.Instance.Parent:FindFirstChildWhichIsA("Humanoid")
				if humanoid then
				if hit.Instance.Name == "Head" then
					humanoid:TakeDamage(newDamage * 2)
				end
				if hit.Instance.Name == "HumanoidRootPart" then
					humanoid:TakeDamage(newDamage * 1.5)
				end
				if hit.Instance.Name == "LeftUpperArm" then
					humanoid:TakeDamage(newDamage / 1.5)
				end
				if hit.Instance.Name == "LeftLowerArm" then
					humanoid:TakeDamage(newDamage / 1.5)
				end
				if hit.Instance.Name == "LeftHand" then
					humanoid:TakeDamage(newDamage / 2)
				end
				if hit.Instance.Name == "LeftUpperLeg" then
					humanoid:TakeDamage(newDamage)
				end
				if hit.Instance.Name == "LeftLowerLeg" then
					humanoid:TakeDamage(newDamage)
				end
				if hit.Instance.Name == "LeftFoot" then
					humanoid:TakeDamage(newDamage / 2)
				end
				if hit.Instance.Name == "RightUpperArm" then
					humanoid:TakeDamage(newDamage / 1.5)
				end
				if hit.Instance.Name == "RightLowerArm" then
					humanoid:TakeDamage(newDamage / 1.5)
				end
				if hit.Instance.Name == "RightHand" then
					humanoid:TakeDamage(newDamage / 2)
				end
				if hit.Instance.Name == "RightUpperLeg" then
					humanoid:TakeDamage(newDamage)
				end
				if hit.Instance.Name == "RightLowerLeg" then
					humanoid:TakeDamage(newDamage)
				end
				if hit.Instance.Name == "RightFoot" then
					humanoid:TakeDamage(newDamage / 2)
				end
			end
			game:GetService("Debris"):AddItem(bullet, 0.01)
			bullet = nil
		end
	end
	
	castBulletRay()
	
	--moves the bullet forward based on velocity
	local createBulletTrajectory = coroutine.wrap(function()
		while bullet do
			bullet.CFrame = bullet.CFrame * CFrame.new(speed, 0, 0)
			castBulletRay()
			wait()
		end
	end)
	
	createBulletTrajectory()
end


--sets damage, speed, etc... variables based on which gun is 
fireGun.OnServerEvent:Connect(function(player, startPos, rotation, state: string)
	local speed
	local damage
	local mass
	local damageDropDistance
	local maxDistance
	
	if state == "pistol" then
		speed = 370
		damage = 20
		mass = 0.0085
		damageDropDistance = 30
		maxDistance = 3000
	end
	
	createBullet(startPos, rotation, speed, damage, mass, damageDropDistance, maxDistance)
end)

you’d have to raycast the bullet like you already are but do it in short increments and move the bullet forward if it doesn’t hit something, if it does hit something you have a hit. as for bullet drop, you’d have to update the velocity of the raycast trajectory to take gravity into account

I already have the bullet moving in small increments but I still feels very different then it does in deadline. Bullet drop and velocity change is still a mystery of how to code properly for me, hopefully after a bit of learning on how projectile motion works in real life I’ll get a better understanding.

I’ll post my current code once Roblox studio decides to load

you don’t gotta wait to learn how projectile motion works its relatively simple. also im not an expert on making FPS frameworks but i’d recommend putting bullet rendering and handling on the client as the server isn’t best suited for that type of thing.

as for projectile motion, lets say i’m at Vector3.new(0,2,0) (cliché point of origin) now lets say i press M1 and fire a bullet from my gun.

local initialPos = Vector3.new(0, 2, 0) -- variable to say where the bullet originated from (my rootPart position at the origin)
local initialDir = Vector3.new(0, .1, 1) -- variable to make a direction where I'm firing down the Z axis of the world with a little but of upwards direction to it.
local bulletSpeed = 160 -- initialize a variable of which the bullet will travel at in studs per second
local initialVel = initialDir * bulletSpeed -- this is the current velocity of the bullet as soon as I press m1

local worldGrav = Vector3.new(0, 32.26, 0) -- gravity that the bullet will be affected by (i did 32.26 ft/s can be tweaked to any number you want)

-- imagine that theres code to detect firing here, this is just code on handling bullet movement

local rs = game:GetService("Run Service") -- initialize this service as we'll be using RenderStepped

local bulletVel = initialVel -- the current velocity of the bullet
local bulletPos = initialPos -- the current position of the bullet

rs.RenderStepped:connect(function(delta)
    local rayRes = workspace:Raycast(bulletPos, bulletVel * delta) -- cast a ray in the direction of the bullet from the bullets location

    if not rayRes then
        bulletPos += bulletVel * delta -- move the bullet to where it should be after the frame
        bulletVel -= worldGrav * delta -- subtract the worlds gravity from the bullets velocity multiplying by how much time has passed since last rendered frame
    else
        -- hit detection code
    end
end)

now this isn’t perfect and i wrote it right now without studios so i dont know if it’ll work, but its the general idea of it. you move update the bullet’s velocity as you continue rendering it so it’ll drop by a predetermined gravity amount. if you wanna get fancy you can multiple the grav velocity by the mass of the bullet to make heavier bullets drops faster than light ones too :wink:

just a quick question, what do you mean by delta in

since delta is never an established variable and is also not an accessible feature on roblox studio. i assume it is a simple fix or interpretation error but i just can’t seem to figure it out at the moment
NEVERMIND THE DELTA, i just noticed it in the function parameters lol

this also does nothing to account for bullet drop as the bullet is never moved down, only slowed over time due to gravity it would seem in this case

worldGrav is defined as Vector3.new(0, 32.26, 0) and if not rayRes i do bulletVel -= worldGrav * delta

since worldGrav has only a Y component and the X and Z are 0, it’ll never alter the course of the bullet on any direction other than up or down. the 32.26 being subtracted from the bullet velocity brings it downward.

Right my bad, it’s been a while since I made an attempt at this issue.

One issue with the code is it gives an error of “attempt to perform (mul) on nil and vector” I’d guess that it is referring to the multiplication of delta but I am unsure as to why delta is null. I don’t have time to look it over since my lunch break just ended though. If you have any ideas why then it would be appreciated and I can test them out later today

i’d have to wait until i’m able to get home and check roblox myself, delta should just pass the time passed since last frame, at least thats what the renderstepped forum page says it’d return. rip

Oh, I’m not using renderstepped lol, just a function. That explains why it’s not working if you look at my code that I posted I put the bullet position stuff in the function createbullettrajectory

oh yeah, the code i gave was just an example for how you’d incorporate bullet drop. if you wanna make your own delta its easy to do as well. before calling the castBulletRay() function, create a variable like local start = tick() or something, at the start of the ray function write something along the lines of:

local delta = tick() - start
start = tick()

tick returns the time passed since like epoch which is unrelated, but it returns precise time. logging tick and subtracting tick from the logged variable will tell you how much time has passed since tick was last called on that variable. setting that variable to tick after you called it allows you to constantly track how much time has passed since you called that function.

Alright thanks, I’ll try that later today

script doesn’t give my desired result, I’ll keep poking around at this issue till I eventually figure out a way to do it. thanks for the help though

A popular freemodel gunsystem (ACS) uses instance.new with acceleration property. It then uses a sort of handler that relies on collision or something along the lines of that.

i said i didnt want to use anything like fastcast or similar

Its an example of how a popular system does it. Not saying you should or should not use it

Is there a way to view the script without adding it to my game/inventory? Since I’ve played a few of their games and the physics did feel amazing

You can delete it after insertion, however its a modulescript with something like this
keep in mind, im an idiot and just calling this off my head and do not know how to script very well.

"local bullet = instance.new(Part)
bullet.name=player  .. "'s bullet" -- not exactly sure where player is defined and how
bullet.Acceleration=settings.BulletVelocity -- this is taken from the tools setting pack on muzzlevelocity and etc

I might look into a way to replicate and alter it for what I need, thanks for the suggestion

1 Like