Clients/Client2018/content/internal/AppShell/Modules/Shell/Components/Overscan/Edges.lua

230 lines
7.6 KiB
Lua

local GameOptionsSettings = settings():FindFirstChild("Game Options")
local UserInputService = game:GetService("UserInputService")
local PlatformService = nil
pcall(function() PlatformService = game:GetService("PlatformService") end)
local Modules = game:GetService("CoreGui").RobloxGui.Modules
local Roact = require(Modules.Common.Roact)
local Utility = require(Modules.Shell.Utility)
local ContextActionEvent = require(Modules.Shell.Components.ContextActionEvent)
local ExternalEventConnection = require(Modules.Common.RoactUtilities.ExternalEventConnection)
local RenderStep = require(Modules.Shell.Components.RenderStep)
local MIN_EDGE_PERCENT = Vector2.new(0.85, 0.85)
local START_EDGE_PERCENT = Vector2.new(0.9, 0.9)
local CONSOLE_RESOLUTION = Vector2.new(1920, 1080)
local ZERO_VEC2 = Vector2.new(0,0)
local MAX_STICK_ACCELERATION = 3
local ACCELERATION_RATE = 1
local DPAD_STEP_AMOUNT = 2
local DPAD_CODE_TO_EDGE_PUSH = {
[Enum.KeyCode.DPadDown] = Vector2.new(0, DPAD_STEP_AMOUNT);
[Enum.KeyCode.DPadUp] = Vector2.new(0, -DPAD_STEP_AMOUNT);
[Enum.KeyCode.DPadLeft] = Vector2.new(-DPAD_STEP_AMOUNT, 0);
[Enum.KeyCode.DPadRight] = Vector2.new(DPAD_STEP_AMOUNT, 0);
}
local function EdgeImage(props)
return Roact.createElement("ImageLabel", {
Size = UDim2.new(0, 95, 0, 95),
Position = props.Position,
AnchorPoint = props.AnchorPoint,
BackgroundTransparency = 1,
Rotation = props.Rotation,
Image = "rbxasset://textures/ui/Shell/ScreenAdjustment/ScreenAdjustmentArrow.png",
})
end
local Edges = Roact.Component:extend("Edges")
function Edges:init()
local function getCurrentEdgePercent(newEdgePercent)
return Utility.ClampVector2(MIN_EDGE_PERCENT, Vector2.new(1, 1), newEdgePercent)
end
local function getCurrentEdgeSize(edgePercent)
local absoluteEdgeSize = edgePercent * CONSOLE_RESOLUTION
local roundedAbsoluteEdgeSize = Vector2.new(Utility.Round(absoluteEdgeSize.X/2), Utility.Round(absoluteEdgeSize.Y/2)) * 2
return Utility.ClampVector2(ZERO_VEC2, CONSOLE_RESOLUTION, roundedAbsoluteEdgeSize)
end
self.onAdjustThumbstick = function(actionName, inputState, inputObject)
self._stickPosition = Utility.GamepadLinearToCurve(Vector2.new(inputObject.Position.X, -inputObject.Position.Y), 0.2)
end
self.onAdjustDPad = function(actionName, inputState, inputObject)
if inputState == Enum.UserInputState.Begin then
local pushAmount = DPAD_CODE_TO_EDGE_PUSH[inputObject.KeyCode]
if pushAmount then
pushAmount = pushAmount / CONSOLE_RESOLUTION
if Utility.IsFinite(pushAmount.X) and Utility.IsFinite(pushAmount.Y) then
self._edgePercent = getCurrentEdgePercent(self._edgePercent + pushAmount)
self:setState({
currentSize = getCurrentEdgeSize(self._edgePercent)
})
end
end
end
end
self.onReset = function(actionName, inputState, inputObject)
if inputState == Enum.UserInputState.End then
self._stickPosition = ZERO_VEC2
self._edgePercent = getCurrentEdgePercent(START_EDGE_PERCENT)
self._acceleration = 1
self:setState({
currentSize = getCurrentEdgeSize(self._edgePercent),
})
end
end
self.onAccept = function(actionName, inputState, inputObject)
if inputState == Enum.UserInputState.Begin then
self._seenAPressed = true
elseif inputState == Enum.UserInputState.End and self._seenAPressed then
local success, err = pcall(function()
GameOptionsSettings.OverscanPX = math.min(1, self._edgePercent.X)
GameOptionsSettings.OverscanPY = math.min(1, self._edgePercent.Y)
end)
if self.props.onSetEdges then
self.props.onSetEdges()
end
end
end
self.onRenderStep = function()
local now = tick()
if self._lastUpdate then
if self._stickPosition ~= ZERO_VEC2 then
local delta = now - self._lastUpdate
local transformedStick = (self._stickPosition) * self._acceleration * delta * 0.05
self._edgePercent = getCurrentEdgePercent(transformedStick + self._edgePercent)
self._acceleration = math.min(self._acceleration + delta * ACCELERATION_RATE, MAX_STICK_ACCELERATION)
self:setState({
currentSize = getCurrentEdgeSize(self._edgePercent)
})
else
self._acceleration = 1
end
end
self._lastUpdate = now
end
self.onSuspended = function()
pcall(function()
GameOptionsSettings.OverscanPX = self._lastSavedOverscan.X
GameOptionsSettings.OverscanPY = self._lastSavedOverscan.Y
end)
end
local overscansetting = getCurrentEdgePercent(START_EDGE_PERCENT)
local startSize = getCurrentEdgeSize(overscansetting)
if UserInputService:GetPlatform() == Enum.Platform.XBoxOne then
pcall(function()
if GameOptionsSettings.OverscanPX > 0 and GameOptionsSettings.OverscanPY > 0 then
overscansetting = Vector2.new(GameOptionsSettings.OverscanPX, GameOptionsSettings.OverscanPY)
overscansetting = getCurrentEdgePercent(overscansetting)
startSize = getCurrentEdgeSize(overscansetting)
-- set the overscan settings to max so the user can accurately estimate their TVs overscan
-- save previous settings so we can save on suspend
self._lastSavedOverscan = Vector2.new(GameOptionsSettings.OverscanPX, GameOptionsSettings.OverscanPY)
GameOptionsSettings.OverscanPX = 1
GameOptionsSettings.OverscanPY = 1
end
end)
end
self._stickPosition = ZERO_VEC2
self._edgePercent = overscansetting
self._lastUpdate = nil
self._acceleration = 1
self._seenAPressed = false
self.state = {
currentSize = startSize,
}
end
function Edges:render()
return Roact.createElement("Frame", {
Size = UDim2.new(0, self.state.currentSize.X, 0, self.state.currentSize.Y),
Position = UDim2.new(0.5, 0, 0.5, 0),
AnchorPoint = Vector2.new(0.5, 0.5),
BackgroundTransparency = 1,
}, {
SelectionImage = Roact.createElement("ImageLabel", {
Size = UDim2.new(1, 2, 1, 2),
Position = UDim2.new(0, -1, 0, -1),
BackgroundTransparency = 1,
ScaleType = Enum.ScaleType.Slice,
SliceCenter = Rect.new(21, 21, 41, 41),
Image = "rbxasset://textures/ui/Shell/ScreenAdjustment/ScreenRangeOverlay.png",
}),
TopLeft = Roact.createElement(EdgeImage, {
Rotation = 0,
Position = UDim2.new(0, 0, 0, 0),
AnchorPoint = Vector2.new(0, 0),
}),
TopRight = Roact.createElement(EdgeImage, {
Rotation = 90,
Position = UDim2.new(1, 0, 0, 0),
AnchorPoint = Vector2.new(1, 0),
}),
BottomRight = Roact.createElement(EdgeImage, {
Rotation = 180,
Position = UDim2.new(1, 0, 1, 0),
AnchorPoint = Vector2.new(1, 1),
}),
BottomLeft = Roact.createElement(EdgeImage, {
Rotation = 270,
Position = UDim2.new(0, 0, 1, 0),
AnchorPoint = Vector2.new(0, 1),
}),
Render = Roact.createElement(RenderStep, {
name = "UpdateAdjustmentScreen",
priority = Enum.RenderPriority.Input.Value,
callback = self.onRenderStep,
}),
AdjustConnectorThumbstick = Roact.createElement(ContextActionEvent, {
name = "ThumbstickAdjustmentScreen",
callback = self.onAdjustThumbstick,
binds = { Enum.KeyCode.Thumbstick2 },
}),
AdjustConnectorDPad = Roact.createElement(ContextActionEvent, {
name = "DPadAdjustmentScreen",
callback = self.onAdjustDPad,
binds = { Enum.KeyCode.DPadDown, Enum.KeyCode.DPadUp, Enum.KeyCode.DPadLeft, Enum.KeyCode.DPadRight },
}),
ResetConnector = Roact.createElement(ContextActionEvent, {
name = "ResetAdjustmentScreen",
callback = self.onReset,
binds = { Enum.KeyCode.ButtonX },
}),
AcceptConnector = Roact.createElement(ContextActionEvent, {
name = "AcceptAdjustmentScreen",
callback = self.onAccept,
binds = { Enum.KeyCode.ButtonA },
}),
SuspendedCn = PlatformService and Roact.createElement(ExternalEventConnection, {
event = PlatformService.Suspended,
callback = self.onSuspended,
}),
})
end
return Edges