EDIT 2025-01-15: Updated the category so people maybe can find this post as a resource instead of someone looking for help. If this post gets enough people interested, I’ll make a clean, easy to use module script for this.
What do you want to achieve?
I want to achieve an accurate depiction of where the bullets will land using a crosshair.
What is the issue?
The issue comes from the fact I have no idea how to change the size of the crosshair according to the camera’s position and the position of where the bullets originate from.
The issue is clearly visible in the two provided images below:
Third person:
First person:
The 4 bricks that are meant to show the spread are accurately positioned in first person (since that’s where the bullets originate from), but in third person the crosshair is obviously seen not showing the position accurately.
What solutions have you tried so far?
I’ve tried looking for solutions on the web and in the forums but did not find it.
And I also tried getting the ratio between the camera to hit distance and origin to hit distance and multiply it by that, but it didn’t work either.
Here is the piece of code that handles visualizing the spread:
local distancePerPixel = mouse.ViewSizeY/camera.FieldOfView
local spreadToUse = bloomSize
local amountToOffset = distancePerPixel*spreadToUse
crosshairFrame.Position = UDim2.fromOffset(mouse.X,mouse.Y)
crosshairTop.Position = UDim2.new(0.5,0,0.5,-amountToOffset)
crosshairBottom.Position = UDim2.new(0.5,0,0.5,amountToOffset)
crosshairRight.Position = UDim2.new(0.5,amountToOffset,0.5,0)
crosshairLeft.Position = UDim2.new(0.5,-amountToOffset,0.5,0)
After a long while of experimenting, I discovered something that will help with coming up with a solution!
I found a formula(?) that gets me a radius around the center point where the spread will hit.
math.tan(math.rad(5))*(origin-target).Magnitude*2
This formula(?) if applied to a sphere part’s size and setting it’s position to the target, we will get an accurate spread, which will give us a physical visual of how big the crosshair’s spread should be.
If anyone is looking to help me, I hope this discovery may help you find a solution to my problem! <3
Edit: Also just to make sure to add: the ratio between the camera’s position and origin’s position to the target isn’t the solution!
Edit2: Here’s what I mean by a sphere part’s size:
The red highlighted sphere is the part I sized to the given formula.
We can use the previously found formula as the A length, C length is the distance between the camera and the target, I am just having trouble finding the right formula to test this theory!
and this is the crosshair piece of code for anyone to use:
local cameraCFrame = camera.CFrame
local camRay = camera:ScreenPointToRay(mouse.X,mouse.Y,0)
local mouseCFrame = (CFrame.new(camRay.Origin)*cameraCFrame.Rotation):ToObjectSpace(cameraCFrame)
local camPos = Vector2.new(mouseCFrame.Position.X,mouseCFrame.Position.Y)
local distanceA = math.sqrt(camPos.X^2+camPos.Y^2)
local zDistance = -camera.NearPlaneZ
local originP = (humanoidRootPart.CFrame*CFrame.new(0,1.5,0)).Position
local cameraP = cameraCFrame.Position
local targetP = mouse.Hit.Position
local cameraA = math.tan(math.rad(bloomSize))*(originP-targetP).Magnitude
local cameraB = (cameraP-targetP).Magnitude
local distancePerPixel = mouse.ViewSizeY/camera.FieldOfView
local spreadToUse = math.deg(math.atan(cameraA/cameraB))
local amountToOffset = distancePerPixel*spreadToUse*(math.sqrt(distanceA^2+zDistance^2)/zDistance)
crosshairFrame.Position = UDim2.fromOffset(mouse.X,mouse.Y)
crosshairTop.Position = UDim2.new(0.5,0,0.5,-amountToOffset)
crosshairBottom.Position = UDim2.new(0.5,0,0.5,amountToOffset)
crosshairRight.Position = UDim2.new(0.5,amountToOffset,0.5,0)
crosshairLeft.Position = UDim2.new(0.5,-amountToOffset,0.5,0)
Edit: Also if anyone is interested:
I’ll be making this into a open-source module script for free use after I’m finished with making the my gun system!