Raycast Hit Detection is off

Hello. I’m making a gun system from scratch and the hit registration is a bit off.
You need to aim in front of the person you are trying to shoot in order to actually hit them. I realize this is because of delays/ping, and I can’t find any good solution.
image
image
Any possible ways to go about this would be appreciated! Note I don’t want to use any libraries such as FastCast, etc.
Also let me know which parts of my scripts (client/server) you need, they might be a bit long to post here.

1 Like

What are you using for your raycast direction? Mouse.Hit.p? If so try using Mouse.Hit.LookVector

1 Like

Thank you, let me try this and I’ll get back to you.

Nope, it was wayyyy off. https://gyazo.com/d986acfad623b9550566bbb27941f018 Didn’t even hit the NPCs I was aiming at.

Is there a visible tracer active to see where your bullet is going?

There is not. I can try doing that, but I think it’s an issue with the ping caused by Roblox servers.

I’m only asking because, assuming your raycast origin is the shootPart of the gun and the direction is Mouse.Hit.LookVector, it could be that the raycast is hitting the gun or your character and detecting a hit, but otherwise it could be that LookVector was just not the solution. The Tracer would guide to see what the issue is.

both of those are blacklisted. Also, even then for the shots that would’ve got through, you still have to aim in front of your target (assuming the target is moving) to hit it. Give me a second and I’ll put a tracer on it.

1 Like

This is using mouse.hit.p
https://gyazo.com/d210823b73c32385b3bd6b41d73bf2f8
This is using lookvector
https://gyazo.com/6578f95ee5bd1fe5e6df833981e63f84

We need to see code in order to see if the raycasting is off or something.

Client Script
local plr = game.Players.LocalPlayer
local mouse = plr:GetMouse()
local uip = game:GetService("UserInputService")
local char = plr.CharacterAdded:Wait()
local h = char:WaitForChild("Humanoid")
local draw = h:LoadAnimation(script.Parent.draw)
local shoot = h:LoadAnimation(script.Parent.shoot)
local reload = h:LoadAnimation(script.Parent.reload)
local maxammo = script.Parent.Ammo.Value

plr.CharacterAdded:Connect(function(Char)
	char = plr.Character or plr.CharacterAdded:Wait()
end)

script.Parent.Equipped:Connect(function()
	local clonedgui = script.Parent:WaitForChild("AmmoCount"):Clone()
	clonedgui.Parent = game.Players.LocalPlayer.PlayerGui
	mouse.Icon = "http://www.roblox.com/asset/?id=6571262827"
	draw:Play()
	wait(0.05)
	draw:AdjustSpeed(0)
end)

script.Parent.Unequipped:Connect(function()
	mouse.Icon = ""
	game.Players.LocalPlayer.PlayerGui.AmmoCount:Destroy()
	draw:Stop()
end)

script.Parent.Activated:Connect(function()
	script.Parent.Fire:FireServer(mouse.Hit.p, true)
	plr.PlayerGui:WaitForChild("AmmoCount").count.Text = script.Parent.Ammo.Value .. "/" .. maxammo
	local part = Instance.new("Part")
	local att = Instance.new("Attachment")
	part.Parent = workspace
	part.Transparency = 1
	part.Anchored = true
	part.CanCollide = false
	part.Size = Vector3.new(0.001,0.001,0.001)
	att.Parent = part
	part.Position = mouse.Hit.p
	script.Parent.FirePart.Beam.Attachment1 = att
end)

uip.InputBegan:Connect(function(key,gameProcessed)
	if key.KeyCode == Enum.KeyCode.R then
		script.Parent.Reload:FireServer()
		plr.PlayerGui:WaitForChild("AmmoCount").count.Text = maxammo .. "/" .. maxammo
	end
end)

script.Parent.HitCheck.OnClientEvent:Connect(function(a)
	mouse.Icon = "http://www.roblox.com/asset/?id=6571499887"
	wait(0.06)
	mouse.Icon = "http://www.roblox.com/asset/?id=6571262827"
end)
Server Script
local fireDistance = 300
local damage = 30
local headshotMultiplier = 1.5
local maxammo = script.Parent.Ammo.Value

script.Parent.Fire.OnServerEvent:Connect(function(player, mousePos)
	local raycast = RaycastParams.new()
	raycast.FilterDescendantsInstances = {player.Character}
	raycast.FilterType = Enum.RaycastFilterType.Blacklist

	local result = game.Workspace:Raycast(script.Parent.Handle.Position,(mousePos - script.Parent.Handle.Position)*fireDistance,raycast)
	
	if script.Parent.Ammo.Value > 0 then
		script.Parent.Ammo.Value -= 1
		local h = player.Character.Humanoid
		local shoot = h:LoadAnimation(script.Parent.shoot)
		shoot:Play()
		if result then
			local hit = result.Instance
			local model = hit:FindFirstAncestorOfClass("Model")

			if model then
				if model:FindFirstChild("Humanoid") then
					if player.Character.Humanoid.Health > 0 then
						if hit.Name == "Head" then
							model.Humanoid.Health -= (damage * headshotMultiplier)
						else
							model.Humanoid.Health -= damage
						end	
						script.Parent.HitCheck:FireClient(player)
					end
				end
			end
		end
		script.Parent.FirePart.Fire:Play()
		script.Parent.FirePart["FlashFX3[Burst]"].Enabled = true
		script.Parent.FirePart["FlashFX[Flash]"].Enabled = true
		script.Parent.FirePart["FlashFX3[Front]"].Enabled = true
		script.Parent.FirePart["FlashFX[Light]"].Enabled = true
		wait(0.03)
		script.Parent.FirePart["FlashFX3[Burst]"].Enabled = false
		script.Parent.FirePart["FlashFX[Flash]"].Enabled = false
		script.Parent.FirePart["FlashFX3[Front]"].Enabled = false
		script.Parent.FirePart["FlashFX[Light]"].Enabled = false
		
		for i = 1, 5 do
			local x = math.random(0,0)/100
			local y = math.random(-10,10)/100
			local z = math.random(0,0)/100
			player.Character.Humanoid.CameraOffset = Vector3.new(x,y,z)
			wait()
		end
	else
		script.Parent.FirePart.Click:Play()
	end

end)

script.Parent.Reload.OnServerEvent:Connect(function(player)
	local h = player.Character.Humanoid
	local reload = h:LoadAnimation(script.Parent.reload)
	if script.Parent.Reloading.Value == false then
		if script.Parent.Ammo.Value < 17 then
			script.Parent.Reloading.Value = true
			reload:Play()
			wait(0.08)
			script.Parent.FirePart.MagOut:Play()
			wait(1.99)
			script.Parent.FirePart.MagIn:Play()
			reload.Stopped:wait()
			script.Parent.FirePart.Slide:Play()
			script.Parent.Ammo.Value = maxammo
			script.Parent.Reloading.Value = false
		end
	end
end)
1 Like

do the raycast on the client and send the part that was hit

then do another one on the server to check if the hit part is not behind a wall or out of range

1 Like

Doing this in a localscript returns result as nil:

	local raycast = RaycastParams.new()
	raycast.FilterDescendantsInstances = {game.Players.LocalPlayer.Character}
	raycast.FilterType = Enum.RaycastFilterType.Blacklist

	local result = game.Workspace:Raycast(script.Parent.Handle.Position,(mouse.Hit.p - script.Parent.Handle.Position)*fireDistance,raycast)

if it hits something it will return RayResult and if it misses then it will return nil

if RayResult exists then sent RayResult.Instance it to the server
and if it misses or hits a non character just send the position

2 Likes

When I print result on the client, it doesn’t return nil - it returns the raycastresult showing it hit the humanoid. However, when I print it on the server, it returns nil… very confused

EDIT: RaycastResult info is lost when sent from Client to Server, so I passed the result.Instance instead and that worked.

1 Like