How to make a dynamic FPS crosshair?

Yo,

I’m somewhat embarrassed to not know how to do this, but I thought I would ask anyways.
For my FPS weapon system, I’ve never really though about weapon spread until now.

While spread on it’s own is fine and dandy, I’m unsure how I can take the spread amount and convert it into a visual you can see on the crosshair.

Many FPS games will have the crosshair lines space out according to current weapon spread as information to the player regarding where that bullet could land, relative to the screen.

How would I go about creating an accurate dynamic crosshair, where all bullets shot would stay inside the “open area”?

Thanks!

4 Likes

I’m pretty sure you can make 4 frames in a gui and line them up like crosshairs and when the tool is activated you check if its activated again and then change the position using tweenService

Sorry if I wasn’t clear. To clarify, I know Roblox API well enough to set up the animation and look of it, but I’m not sure how to calculate a size/position based on spread.

To calculate the size based on spread you could have the script in the crosshair be something like this in a localscript.

local spread = nil
local lastSpread = nil
local calculateOffset = 1 --Replace this if you want it to be larger or smaller
local rs = game:GetService(“RunService”)
rs.RenderStepped:Connect(function()
spread = gameSpread – put the actual spread here
if spread ~= lastSpread then
rightCrosshairGui:TweenPosition(Udim2.fromOffset(spreadcalculateOffset,0),Enum.EasingDirection.Out,Enum.EasingStyle.Sine,0.2)
leftCrosshairGui:TweenPosition(Udim2.fromOffset(-spread
calculateOffset,0),Enum.EasingDirection.Out,Enum.EasingStyle.Sine,0.2)
upCrosshairGui:TweenPosition(Udim2.fromOffset(0,-spreadcalculateOffset),Enum.EasingDirection.Out,Enum.EasingStyle.Sine,0.2) downCrosshairGui:TweenPosition(Udim2.fromOffset(0,spreadcalculateOffset),Enum.EasingDirection.Out,Enum.EasingStyle.Sine,0.2)
end
lastSpread = spread
end)

I apoligise for the bad code formatting, as I haven’t figured out the devFourm’s code formatting.

2 Likes

Should clear up some more than I know how to change position and such, however I’m unsure how to take a Vector3 spread and convert it into an offset. Thanks for the help tho.

(PS Code formatting is “```”)

Maybe try this:

Value 1 = Spread 2.35

Value 2 = Spread 4.70

Etc

Take value number and use that as offset for crosshair.

Convert spread to value first, then take value as offset, or go straight in and get the spread value and convert it as its being put in for offset.

So rather than convert Vector3 to Vector2, I can use UDIM2/Vector2 to Vector3?
I’ll try it.

I might be wrong, but wouldn’t using a dynamic crosshair like you describe mean that the crosshair visual gets bigger when shooting at longer distances. When shooting into the sky the potential spread would be infinite (we don’t see fps games expanding the crosshair to the size of the screen).

Maybe I am misundersanding? Can you explain better what you mean by

all bullets shot would stay inside the “open area”?

Sorry for the confusion.
The bullets would stay inside the open area for a set distance away, likely 10M or so.

you can count after a tool has been activated to fire an event or change a state vaue of a variable

I’m aware of how to perform movement and such, however I don’t know how I would convert my Vector3 spread into a Vector2 pixel offset.

Please read replies before making a reply yourself, as we otherwise go in circles here. (Thx :slight_smile:)

1 Like

I figured it out. You can use this code to convert crosshair pixel offset to a Vector3 unit direction

local function getSpreadDirection(input)
	local sens = 100
	local screenSizeMid = (cam.ViewportSize - Vector2.new(0,36*2))/2
	local upOff = (math.random(-input*sens,input*sens)/sens)
	local riOff = (math.random(-input*sens,input*sens)/sens)
	local ray = cam:ScreenPointToRay(screenSizeMid.X + riOff,screenSizeMid.Y + upOff)
	
	return ray.Direction
end

You can see in the below video, all bullets shot stay inside the crosshair.
robloxapp-20200726-1104369.wmv (1.9 MB)

Thx for helping, hope the code bit helps!

19 Likes

Yeah i know but that was not what i ment i ment that you could get the vector 2 position and do some simple math by detecting if the player has moved or not without vector3
¨
anyways i am happy that you found out how to make it have a great day :smiley:

1 Like

im really sorry if i disturbed you (this post was like 3 months ago :frowning: )

But may i know what is input used in this function?

local function getSpreadDirection(input)

input is an double, which is a number with decimal places. However, because of pixel calculations, it acts as an integer, which is a whole number.

input is the 2D half-pixel gap of the crosshair. The output is a normalized Vector3 direction of a ray.

For example, an input of “50” would be a 100-pixel-wide crosshair, and the ray would return a direction that remained in that area.

1 Like

I don’t have the time, I am sorry.