Theres not much to explain the title pretty much sums it up but heres the script
function fireBullet(start, target, maxLength) --settings some constants local directionVector = (target - start).unit local direcitonCFrame = CFrame.new(start, start + directionVector) --settings values that we're going to update throughout local delta, lastTick, startTime = 0, tick(), tick() local hit, position, lastPosition = nil, target, start local totalDistance = 0 local function loop() local ignore2 = { character; M4; camera; } while not hit and totalDistance < maxLength do --basically stop if we hit our max or we hit something delta = tick() - lastTick --get the time delta, aka time between last iteration and now lastTick = tick() --set this to keep out delta calculations accurate local travelDistance = delta * gunset.mvelocity --getting our distance for this iteration --velocity being in studs per second --Just a simple physics equation, distance = time * velocity --Doing this makes for constant velocity, but not consistent ray distance --all this does it get rid of potential lag influences really travelDistance = travelDistance < 999 and travelDistance or 999 --just limiting our distance, this way is faster than math.min totalDistance = totalDistance + travelDistance --just adding on to our total local dropAmount = 9.81/2 * (tick() - startTime)^2 --gravity/2 * the square of our total time to get our bullet drop amount local incremented = --see break down of what transformations are done below direcitonCFrame * --start from our directionCFrame constant CFrame.new(0, 0, -totalDistance) - --move forward our total distance Vector3.new(0, dropAmount, 0) --move down based on our bullet drop amount --doing this should give us an idea of where we want to be based on our calculations local direction = CFrame.new(lastPosition, incremented.p).lookVector --getting a look vector from where we are, to where we want to be --the rest you more or less had, fairly basic raycasting code local ray = Ray.new(lastPosition, direction * travelDistance) local hit,pos,normal,material = workspace:FindPartOnRayWithIgnoreList(ray,ignore2) --{workspace.Weapons, character, camera}) if hit then handleBulletHit(hit,pos,normal,material) break end lastPosition = position wait(0) --would recommend waiting for one of the runservice events instead end if not hit then print("Distance maxed out, we hit nothing") end end -- handle bullet part of script -- local handleBulletHit = function(hitPart, hitPoint, hitNormal,hitMaterial) if hitPart then print(hitPart) local humPart = character:FindFirstChild("HumanoidRootPart") local targetHumPart = hitPart.Parent:FindFirstChild("HumanoidRootPart") local hithumanoid = hitPart.Parent:FindFirstChild("Humanoid") if hithumanoid and targetHumPart and humPart and hithumanoid.Health > 0 then if hitPart.Name == "LeftLowerArm" or hitPart.Name == "LeftUpperArm" or hitPart.Name == "RightLowerArm" or hitPart.Name == "RightUpperArm" then remoteEvents.Hit:FireServer(hithumanoid,gunset.limbdamage,hitPart) ApplyTags(hithumanoid) else remoteEvents.Hit:FireServer(hithumanoid,gunset.damage,hitPart) ApplyTags(hithumanoid) end end if not hithumanoid then end) end end