Raycast doesn't damage enemies from far away

Hello forum, today i decided to make a isometric gun system for my game. Basically, the gun will shoot straight in front of the player and damage humanoid if the bullet hit any character. I did that by using raycasting and check if the hit instance is a humanoid then damages them. The problem is, the gun only damages character from far away but work completely well in cqc. How can i fix this and what is the problem to this?
here’s the script:

local tool = script.Parent
local module = require(tool:WaitForChild("GunSettingsModule"))
local ShootEvent = tool:WaitForChild("ShootEvent")

local function createMuzzleFlash(handle)
	local attachment = handle:FindFirstChild("MuzzleAttachment")
	if attachment then
		local muzzleFlash = attachment:FindFirstChild("Muzzle")
		if muzzleFlash then
			muzzleFlash:Emit(2)
		else
			warn("Muzzle particle emitter not found in attachment")
		end
	else
		warn("MuzzleAttachment not found in handle")
	end
end

local function playSound(handle)
	local sound = handle:FindFirstChild("Fire")
	if sound then
		sound:Play()
	else
		warn("GunSound not found in handle")
	end
end

local function onShoot(player)
	if not player then
		warn("Invalid player")
		return
	end

	local character = player.Character
	if not character then return end

	local handle = tool:FindFirstChild("Handle")
	if handle then
		local camera = workspace.CurrentCamera
		local direction = camera.CFrame.LookVector

		createMuzzleFlash(handle)
		playSound(handle)
		tool.Handle.PointLight.Enabled = true
		task.wait(0.05)
		tool.Handle.PointLight.Enabled = false

		local startPos = handle.Position
		local raycastParams = RaycastParams.new()
		raycastParams.FilterDescendantsInstances = {character} 

		local raycastResult = workspace:Raycast(startPos, direction * 2000, raycastParams)
		if raycastResult then
			local hitPart = raycastResult.Instance
			local humanoid = hitPart.Parent:FindFirstChildOfClass("Humanoid") or hitPart.Parent.Parent:FindFirstChildOfClass("Humanoid")

			if humanoid then
				humanoid:TakeDamage(module.Settings.Damage)
				print("Damage dealt to:", humanoid.Parent.Name)
			end
		end
	else
		warn("Handle not found in tool")
		return
	end
end

ShootEvent.OnServerEvent:Connect(onShoot)

Here’s the video showcasing the gun.

robloxapp-20240714-1328048.wmv (2.7 MB)

(im sorry if the video is laggy and the script looks annoying due to the ammount of debug prints, i had some problem with fixing the script.)

Judging by the code, the casting direction is based on the camera’s forward direction, not determined from the gun’s tip (or source of the bullets) to the cursor’s 3D space. In other words, your gun is shooting at the ground with a limited radius.

You’ll have to do a little more maths and an extra raycast by using the camera’s ViewportPointToRay(), which returns a Ray (not to be confused with RaycastResults).

When retrieving the resulting Ray, use its Direction property and use it to cast from the position of the cursor towards the direction of the Ray. From the RaycastResults, you can cast from the handle to the 3D position of the mouse.

Do note that solving for the 3D mouse position should be done on the client side, and received by the server to calculate the projectile’s direction. Also, the code below was not tested, so let me know if there are issues with it that you need some assistance with.

-- from the client (note that this implementation is just an example.
-- you may have to tweak this client-side code to fit yours)

local UserInputService = game:GetService("UserInputService")
local Players = game:GetService("Players")

local tool = script.Parent
local shootEvent = tool:WaitForChild("ShootEvent") :: RemoteEvent

local raycastParams = RaycastParams.new()

local function shoot()
	local camera = workspace.CurrentCamera

	-- we need to find a hit position from the mouse, so solve for the cursor's direction
	-- from the camera.
	local mouseScreenPosition = UserInputService:GetMouseLocation()
	local mouseWorldRay = workspace.CurrentCamera:ViewportPointToRay(
		mouseScreenPosition.x, mouseScreenPosition.Y,
		0
	)
	
	raycastParams = {Players.LocalPlayer.Character}

	local mouseWorldPosition = workspace:Raycast(
		mouseWorldRay.Origin,
		mouseWorldRay.Direction * 2000,
		raycastParams
	)

	-- get the position of the hit. we'll use this for finding the direction from the
	-- handle to the expected direction of the bullet.
	local mouseHitPosition
	if (mouseWorldPosition ~= nil) then
		mouseHitPosition = mouseWorldPosition.Position
	else
		-- recover from lack of results by using the max distance instead.
		mouseHitPosition = mouseWorldRay.Origin + mouseWorldRay.Direction * 2000
	end
	
	-- send the mouse's 3D position.
	shootEvent:FireServer(mouseHitPosition)
end

-- from the server script (specifically the function "onShoot")

local function onShoot(player : Player, mousePosition : Vector3)
	-- the RemoteEvent is guaranteed to return a player when calling FireServer from the client.
	
	if not mousePosition then return end
	
	local character = player.Character
	if not character then return end

	local handle = tool:FindFirstChild("Handle")
	if handle then
		createMuzzleFlash(handle)
		playSound(handle)
		tool.Handle.PointLight.Enabled = true
		task.wait(0.05)
		tool.Handle.PointLight.Enabled = false
		
		local startPos = handle.Position
		local directionFromHandle = (mousePosition - startPos).Unit

		local raycastFromHandle = workspace:Raycast(
			startPos,
			directionFromHandle * 2000,
			raycastParams
		)

		-- finally, we can check if the hit is a humanoid.
		if (raycastFromHandle ~= nil) then
			local hitHasHumanoid = raycastFromHandle.Instance.Parent:FindFirstChildWhichIsA("Humanoid")
			if (hitHasHumanoid) then
				hitHasHumanoid:TakeDamage(module.Settings.Damage)
				print("Damage dealt to:", hitHasHumanoid.Parent.Name)
			end
		end
	else
		warn("Handle not found in tool")
		return
	end
end
1 Like

yes im so sorry for the late respond, but that is indeed true. I (somehow) managed to make the raycast follow mouse. Thank you for your help!

1 Like

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