Weapon shooting on mobile is wonky

I am currently working on a raycast projectile shooting system. So far, the result of using the weapon on pc is much smoother than using the weapon on mobile. When I use the weapon on mobile, I am able to tap on the screen, but the bullet does not end up moving in the direction where I tapped. I am wondering how this could be fixed.

Here are two videos showcasing what I mean.

Shooting on PC using a mouse:

You can notice that wherever I click, the bullet aims in that direction. If I click on one of the npcs, they will lose damage. This is exactly what I want.

Shooting on mobile using TouchTap:

You can notice that I miss every shot even though I am tapping on the npcs. As well, the white bullet laser does not line up with where I tapped.

The weapon contains two main scripts: one on client and one on the server. The damage being done on the npcs is done on the server, while everything else is done on the client.

Client script:

local tool = script.Parent
local handle = tool:WaitForChild("Handle")
local origin1 = handle:WaitForChild("MuzzleFlash")
local event = tool:WaitForChild("RemoteEvent")
local event2 = tool:WaitForChild("RemoteEvent2")
local player = game.Players.LocalPlayer
local camera = game.Workspace.Camera
local hit

local usi = game:GetService("UserInputService")
local debris = game:GetService("Debris")
local lastTap2d

local equipped = false
local canfire = true

local RELOAD_TIME = 0.4
local rate = 1 / 35
local RANGE = 150

tool.Equipped:Connect(function()
	equipped = true
end)

tool.Unequipped:Connect(function()
	equipped = false
end)

local function raycast(mousePos, location)
	print(mousePos)
	local origin = player.Character:FindFirstChild("HumanoidRootPart").Position
	local bulletorigin = origin
	local direction = (mousePos - origin).Unit * RANGE 
	local params = RaycastParams.new()
	params.FilterDescendantsInstances = {tool, player.Character or player.CharacterAdded:Wait()}
	params.FilterType = Enum.RaycastFilterType.Exclude
	
	local result = workspace:Raycast(origin, direction, params)
	
	if result then
		hit = result.Instance
	end
	
	event:FireServer(mousePos, usi, hit, location)
end

function getMousePos()
	local mouseLocation2d = usi:GetMouseLocation()
	local unitray = camera:ScreenPointToRay(mouseLocation2d.X, mouseLocation2d.Y-36, 0)
	local ray = Ray.new(unitray.Origin, unitray.Direction * 200)
	local target, position = workspace:FindPartOnRay(ray, player.Character or nil)
	return position
end

function getTapPos(touchPositions)
	local unitray = camera:ScreenPointToRay(lastTap2d.X, lastTap2d.Y-36, 0)
	print(unitray)
	local ray = Ray.new(unitray.Origin, unitray.Direction * 200)
	local target, position = workspace:FindPartOnRay(ray, player.Character or nil)
	return position
end

usi.InputBegan:Connect(function(input, gameProcessed)
	if gameProcessed then
		return
	end
	if input.UserInputType == Enum.UserInputType.MouseButton1 and equipped and canfire then
		canfire = false
		local mousePos = getMousePos()
		local mouseLocation2D = usi:GetMouseLocation()
		raycast(mousePos, mouseLocation2D)
		wait(RELOAD_TIME)
		canfire = true
	elseif input.KeyCode == Enum.KeyCode.ButtonR1 and equipped and canfire then
		canfire = false
		local mousePos = getMousePos()
		local mouseLocation2D = usi:GetMouseLocation()
		raycast(mousePos, mouseLocation2D)
		wait(RELOAD_TIME)
		canfire = true
	end
end)

usi.TouchTap:Connect(function(positions, processed)
	if processed then return end

	lastTap2d = Vector2.new(positions[1].X, positions[1].Y)
end)

usi.TouchTapInWorld:Connect(function(positions, processed)
	if processed then return end
	
	local mousePos = getTapPos(positions, processed)
	
	if equipped and canfire then
		canfire = false
		local mousePos = getTapPos(positions, processed)
		raycast(mousePos, lastTap2d)
		wait(RELOAD_TIME)
		canfire = true
	end
end)

event2.OnClientEvent:Connect(function(player, mousepos, fadedelay)
	local Ignore = {player.Character, tool}
	local ray = Ray.new(tool.Handle.CFrame.p, (mousepos - tool.Handle.CFrame.p).unit * 300)
	local part, position = workspace:FindPartOnRayWithIgnoreList(ray, Ignore, false, true)
	
	local origin = player.Character:FindFirstChild("HumanoidRootPart").Position
	local direction = (mousepos - origin).Unit * RANGE

	local attchPart = Instance.new("Part", workspace)
	attchPart.Name = "AttachmentPart"
	attchPart.CanCollide = false
	attchPart.CanTouch = false
	attchPart.Anchored = true
	attchPart.Transparency = 0
	attchPart.Material = Enum.Material.Neon
	attchPart.BrickColor = BrickColor.new("White")

	local distance = (tool.Handle.CFrame.p - position).magnitude
	attchPart.Size = Vector3.new(0.6, 0.6, distance)
	attchPart.CFrame = CFrame.new(origin1.Position, mousepos) * CFrame.new(0, 0, -distance / 2)

	debris:AddItem(attchPart, fadedelay * 3)
	
	wait(0.1)
	
	local frames=fadedelay/rate
	
	for frame=1,frames do
		wait(rate)
		local percent=frame/frames
		attchPart.Transparency=.5+(percent*.5)
	end
	
	wait(1)
	
	attchPart:Remove()
end)

Help would be much appreciated, thanks.

Try to actually play from mobile. It could be cause you’re testing it with a cursor.