input.Position isn't returning an accurate screen position?

After a couple of tests, I kept having bullets go to a different place than the one I clicked, so I created this script where I tried a bunch of things to try and get the bullet to be accurate.

I tried both input.Position and UserInputService:GetMouseLocation(), ScreenPointToRay instead of ViewportPointToRay (I also tried changing the depth for both of those to various different numbers), and I tried subtracting the gui inset for all combinations. For the gui inset, I tested both Vector2.new(0, 36) and GuiService:GetGuiInset().

I’m pretty sure it’s not because of the way I’m moving the bullets, because I tried a couple of different methods for that as well.

It’s not because of workspace:Raycast() either, because I tried everything that I mentioned before with Ray.new() and they had the same results.

tl;dr: I tried literally every combination of everything that I could think of that related to this, and I still don’t know why my bullets are offsetted. The name of this post is what I think is happening at this point.

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

local Player = game:GetService("Players").LocalPlayer
local Character = Player.Character or Player.CharacterAdded:Wait()
local Camera = workspace.CurrentCamera

local zeroVector = Vector3.new()
local random = Random.new()
local tau = math.pi * 2

local bullet = script:WaitForChild("Bullet")
local bulletSpread = 0
local bulletSpeed = 90
local bulletCount = 0
local range = 400

local raycastParams = RaycastParams.new()
raycastParams.IgnoreWater = false
raycastParams.FilterDescendantsInstances = {Character}
raycastParams.FilterType = Enum.RaycastFilterType.Blacklist

function randomOffset(vector, maxAngle)
	local rand1 = random:NextNumber(0, tau)
	local rand2 = random:NextNumber(math.cos(maxAngle / 1e3), 1)

	local res = (CFrame.new(zeroVector, vector)
		* CFrame.Angles(0, 0, rand1)
		* CFrame.Angles(math.acos(rand2), 0, 0)
	).LookVector

	print(res:Dot(vector.Unit)) -- this always prints 1
	-- since i set maxAngle to 0 for testing
	return res
end

local function get3DPosition(screenPosition)
	local oray = Camera:ViewportPointToRay(screenPosition.X, screenPosition.Y, 0)
	return workspace:Raycast(oray.Origin, randomOffset(oray.Direction, bulletSpread) * range, raycastParams)
end

UserInputService.InputBegan:Connect(function(input, ignore)
	if ignore then return end
	if input.UserInputType ~= Enum.UserInputType.MouseButton1 then return end
	
	local raycastResult = get3DPosition(input.Position)
	if not raycastResult then return end
	
	local position = raycastResult.Position
	
	local bullet = bullet:Clone()
	bullet.Position = Character:GetPrimaryPartCFrame().Position + Vector3.new(4, 0, 4)
	bullet.CFrame = CFrame.new(bullet.Position, position)
	bullet.Anchored = true
	bullet.Parent = workspace
	bulletCount = bulletCount + 1
	
	local startPosition = bullet.Position
	local distance = (startPosition - position).Magnitude
	local name = "RenderBullet" .. tostring(bulletCount)
	
	RunService:BindToRenderStep(name, Enum.RenderPriority.Input.Value, function(deltaTime)
		bullet.CFrame = bullet.CFrame + (bullet.CFrame.LookVector * deltaTime * bulletSpeed)
		
		if (bullet.Position - startPosition).Magnitude >= distance then
			bullet:Destroy()
			RunService:UnbindFromRenderStep(name)
		end
	end)
end)

Player.CharacterAdded:Connect(function(newCharacter)
	Character = newCharacter
end)
--// thanks for stopping by

btw the offset function isn’t related, I temporarily disabled that for testing.

1 Like

Update: for some reason mouse.Hit.Position is perfectly accurate.