How to do gun spread if the ray does not hit an object (when gun is out of its shooting range)

Hello.

I am mostly done with my gun system, but I have one problem.

I don’t have any problems with the spread when the ray DOES hit something, but I can’t figure out how to do my gun spread when the ray, that I cast from the Muzzle of the gun to where the player clicked, DOES NOT hit anything (which means the gun is out of its range since each of my guns can shoot only a certain range).

Right now the code works so that if the ray does not hit any objects this code runs, which just visualizes the bullet tracer based on the maximum range the gun has:

			else--THIS CODE PLAYS WHEN THE GUN IS OUT OF RANGE, MEANING THE RAY DID NOT HIT ANYTHING
				
				--WHERE DO I PUT THE SPREAD IN THIS CFrame? MAYBE CALCULATE THE CFrame A DIFFERENT WAY??
				CachedBullet.CFrame = CFrame.lookAt(muzzlePos + ((mouseRPos - muzzlePos).Unit * range)/2 , muzzlePos + ((mouseRPos - muzzlePos).Unit * range)) * CFrame.Angles(0, math.rad(90), 0)
				-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
				
				CachedBullet.Size = Vector3.new(range, 0.15, 0.15)

			end 

As you can see I don’t know where and how to put the spread in the CFrame calculation if the ray does not hit any object. My spread is just a Vector3.new with randomized numbers. Maybe I should use a totally different approach for calculating out of range bullet tracers?

Here is the full code (By the way I use the PartCache module to help visualize bullet tracers but it’s not important to the problem so just ignore it, I just need the right formula to calculate the CFrame of the part itself)

function ShootBullet(viewRay, muzzle)

	local GunName = muzzle.Parent.Name
	local GunDataInT = ChosenGunsDataT[GunName]

	if GunDataInT.Ammo > 0 then

		local range = GunDataInT.Stats.Range
		local sNum = GunDataInT.Stats.Spread
		math.randomseed(SpreadSeed)
		local spread = Vector3.new((math.random(-sNum, sNum)*.01), (math.random(-sNum, sNum)*.01), (math.random(-sNum, sNum)*.01))
		SpreadSeed += 1

		local mouseRay = workspace:Raycast(viewRay.Origin, viewRay.Direction * 1000)
		local CachedBullet = BulletCache:GetPart()

		if mouseRay then

			local muzzlePos = muzzle.Position
			local mouseRPos = mouseRay.Position
			local gunRay = workspace:Raycast(muzzlePos, ((mouseRPos - muzzlePos).Unit + spread) * range)

			if gunRay then

				local gunRayPosition = gunRay.Position
				CachedBullet.Size = Vector3.new((muzzlePos - gunRayPosition).Magnitude, 0.15, 0.15)
				CachedBullet.CFrame = CFrame.lookAt(muzzlePos + (gunRayPosition - muzzlePos)/2, gunRayPosition) * CFrame.Angles(0, math.rad(90), 0)--Turn it 90 degrees around

			else--NEED HELP WITH SPREAD OVER HERE. THIS CODE RUNS WHEN THE GUN IS OUT OF RANGE, MEANING THE RAY DID NOT HIT ANYTHING
				
				--WHERE DO I PUT THE SPREAD IN THIS CFrame? MAYBE CALCULATE THE CFrame A DIFFERENT WAY??
				CachedBullet.CFrame = CFrame.lookAt(muzzlePos + ((mouseRPos - muzzlePos).Unit * range)/2 , muzzlePos + ((mouseRPos - muzzlePos).Unit * range)) * CFrame.Angles(0, math.rad(90), 0)-- (spread) Add a spread to the position of where the player clicked since the original mouse position does not account for that
				-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
				
				CachedBullet.Size = Vector3.new(range, 0.15, 0.15)

		end
		BulletCache:ReturnPart(CachedBullet1)
	end

end

Any help will be appreciated! :grinning:

1 Like

If I’m understanding this correctly, you should be able to substitute what would be gunRayPosition with muzzlePos + rayDirection

I’d make a small change to your code’s structure, just to make direction its own variable so it can be referenced later if need be (in our case if the ray doesn’t hit anything):

local direction = ((mouseRPos - muzzlePos).Unit + spread) * range
local gunRay = workspace:Raycast(muzzlePos, direction)

if gunRay then
    -- ...
else
    -- Here, we can substitute 'gunRayPosition' above for muzzlePos + direction
    local gunRayPosition = muzzlePos + direction
    
    CachedBullet.CFrame = CFrame.lookAt(muzzlePos + (gunRayPosition - muzzlePos)/2, gunRayPosition) * CFrame.Angles(0, math.rad(90), 0)

Let me know if this is what you’re looking for

2 Likes

I’ve copied your code and the bullet tracer does have a spread now, but it doesn’t start at the muzzle position but rather slightly off.

scrnsht1
scrnsht2
scrnsht3

Bumping this as I still need help

It might have to do with this part in the CFrame.lookAt:

muzzlePos + (gunRayPosition - muzzlePos)/2

If you just do (muzzlePos + gunRayPosition) / 2 does that work?

1 Like

Doesn’t change anything. Same effect :disappointed_relieved: