How to make a horizontal scroll

Снимок экрана 2023-11-26 004550
How do I make something like this?

I cannot seem to replicate this effect using ScrollingFrames, plus then I would have no clue how I would get the value needed, the CanvasSize needed and a lot of small stuff that will get super frustrating.

Think of it in like this.
If you have your scroll bar, as pictured, and lets say its size in pixels is 300 (sizeX)
and lets say it starts more near the middle of your screen, so its x position (of the image) is 800 (startX)

if the mouse clicks on the bar or is held down, we get the mouse x, lets say we clicked on the bar, a little two thirds down the scroll bar, at screen location 1000 (mouseX)

We need to do 2 things, get the marker position and get the value

first we take a percentage of where we are
Percentage = (mouseX - startX) / sizeX
would be (1000 - 800) / 300 = .66666 or two thirds down the length of the scroll bar.

We can use this percentage to place the marker with a UDim2(percentage, 0, .5, 0) or something like that.

For the value, we need to know the minimum and maximum value. This is FOV, so lets set a range,
minFOV = 30
maxFOV = 120
Range = (maxFOV - minFOV) this range is telling us how many ‘values’ are in the length of the bar in this case 90

Now we need to get the percentage of this ‘range’ (90) and we get this by multiplying our Precentage value from earlier and multiply it to the Range, and call this our multiplied value.
MultipliedValue = Range * Percentage (90 * .666666 = 59.99999 or 60 for simplicity)
now to make the value accurate we have to account for the starting value of 30
FinalValue = MultipliedValue + MinFOV (60 + 30 = 90)

So we end up displaying a value of 90 for the 2/3 position down the scroll bar of a range from 30 to 120

Hope this helps

1 Like

Ok but how would I create it? ScrollingFrame’s bar is extremely inconsistent.

You would set up a ‘Frame’ for the whole thing, such as showing the bar and value.
Then you would set up a child ‘ImageFrame’ to hold the ‘bar’ image.
Then a child of that ImageFrame to be ANOTHER ImageFrame to hold the round little marker.

1 Like

This is just a slider, you can make a simple one or use my SliderClass, it comes with an example that shows how to make an FOV slider which is exactly what you want,

Thanks for help. I managed to get it to work properly.
Thank you @msix29 too, but I prefer writing my own scripts.

If anyone is interested, here’s the final code (with comments where needed):

local RunService = game:GetService("RunService")
local Players = game:GetService("Players")
local player = Players.LocalPlayer
local mouse = player:GetMouse()

local cam = workspace.CurrentCamera
workspace:GetPropertyChangedSignal("CurrentCamera"):Connect(function()
	local newCam = workspace.CurrentCamera
	if newCam then
		cam = newCam
	end
end)
local vpSize = cam.ViewportSize

local frame:Frame = script.Parent
local marker:TextButton = frame:WaitForChild("Marker")
local valueLabel:TextLabel = frame:WaitForChild("Value")
local minVal:IntValue = frame:WaitForChild("minVal")
local maxVal:IntValue = frame:WaitForChild("maxVal")

-- converts offset to scale
local function offsetToScale(x, y, parentFrame)
	vpSize = cam.ViewportSize
	if parentFrame then
		x /= parentFrame.AbsoluteSize.X
		y /= parentFrame.AbsoluteSize.Y
	else
		x /= vpSize.X
		y /= vpSize.Y
	end
	return {x, y}
end

-- get the value from marker
-- min: the floor value of the scroll bar
-- max: the roof value of the scroll bar
-- markerPrecentage: marker precentage (marker.Position.X.Scale)
-- round: if the value should be rounded or not
local function getValue(min:number, max:number, markerPrecentage:number, round:boolean)
	local returning = min + (math.abs(max-min)*markerPrecentage)
	if round then
		return math.round(returning)
	end
	return returning
end

-- where the marker should be according to value (used for setting the marker when changing the value)
-- min: the floor value of the scroll bar
-- max: the roof value of the scroll bar
-- val: value to calculate from
local function getMarker(min:number, max:number, val:number)
	return UDim2.fromScale((val-min)/math.abs((-min)+max), -0.5)
end

-- setting the position of the marker according to value
-- for parameters, refer to "getMarker()"
local function setMarker(min:number, max:number, val:number)
	local newPos = getMarker(min, max, val)
	marker.Position = UDim2.fromScale(newPos.X.Scale-(newPos.X.Scale*offsetToScale(marker.AbsoluteSize.X, 0, frame)[1]), newPos.Y.Scale)
end

local inputsAccepting = {Enum.UserInputType.MouseButton1, Enum.UserInputType.Touch}

local holding = false
local moveCon:RBXScriptConnection = nil

-- handles markre dragging
local function dragHorizontal()
	if holding == false then moveCon:Disconnect() return end
	local leftBorder = frame.AbsolutePosition.X
	local markerSize = marker.AbsoluteSize.X
	local rightBorder = leftBorder + frame.AbsoluteSize.X
	local newX = 1-offsetToScale(rightBorder-math.clamp(mouse.X-(markerSize/2), leftBorder, rightBorder-markerSize), 0, frame)[1]

	local pos = UDim2.new(mouse.X/vpSize.X, 0, 0, 0)
	marker.Position = UDim2.new(newX, 0, -0.5, 0)
end

-- checking if dragged
marker.InputBegan:Connect(function(inpObj)
	if table.find(inputsAccepting, inpObj.UserInputType) then
		holding = true
		vpSize = cam.ViewportSize
		
		moveCon = mouse.Move:Connect(dragHorizontal)
	end
end)
marker.InputEnded:Connect(function(inpObj)
	if table.find(inputsAccepting, inpObj.UserInputType) then
		holding = false
	end
end)

local function updateValueText()
	local newPosX = marker.Position.X.Scale
	valueLabel.Text = getValue(minVal.Value, maxVal.Value, newPosX+(newPosX*offsetToScale(marker.AbsoluteSize.X, 0, frame)[1]), true)
end
updateValueText()

-- updating value whenever the marker is moved
marker:GetPropertyChangedSignal("Position"):Connect(updateValueText)

setMarker(minVal.Value, maxVal.Value, 70)

This is how it looks in the Explorer:
Снимок экрана 2023-11-26 163618

And how it looks in-game:
Снимок экрана 2023-11-26 163701

(while the game is running)

Снимок экрана 2023-11-26 163757

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.