mirror of
https://github.com/copyrighttxt/watrbx-game-engine.git
synced 2026-09-04 20:57:49 +00:00
451 lines
14 KiB
Lua
451 lines
14 KiB
Lua
-- Written by Kip Turner, Copyright ROBLOX 2015
|
|
|
|
local TextService = game:GetService('TextService')
|
|
|
|
local CoreGui = game:GetService("CoreGui")
|
|
local GuiService = game:GetService('GuiService')
|
|
local RunService = game:GetService('RunService')
|
|
local ContextActionService = game:GetService("ContextActionService")
|
|
local PlatformService = nil
|
|
pcall(function() PlatformService = game:GetService('PlatformService') end)
|
|
|
|
local GameOptionsSettings = settings():FindFirstChild("Game Options")
|
|
|
|
local GuiRoot = CoreGui:FindFirstChild("RobloxGui")
|
|
local Modules = GuiRoot:FindFirstChild("Modules")
|
|
|
|
local Utility = require(Modules:FindFirstChild('Utility'))
|
|
local GlobalSettings = require(Modules:FindFirstChild('GlobalSettings'))
|
|
local ScreenManager = require(Modules:FindFirstChild('ScreenManager'))
|
|
|
|
local AssetManager = require(Modules:FindFirstChild('AssetManager'))
|
|
local Strings = require(Modules:FindFirstChild('LocalizedStrings'))
|
|
|
|
local BACKGROUND_COLOR = Color3.new(3/255,3/255,3/255)
|
|
local START_EDGE_SIZE = UDim2.new(0.9,0,0.9,0)
|
|
local MIN_EDGE_SIZE = UDim2.new(0.85,0,0.85,0)
|
|
local MAX_EDGE_SIZE = UDim2.new(1,0,1,0)
|
|
local ZERO_VEC2 = Vector2.new(0,0)
|
|
local THUMBSTICK_BORDER_SENSITIVITY = 0.05
|
|
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.0, DPAD_STEP_AMOUNT);
|
|
[Enum.KeyCode.DPadUp] = Vector2.new(0.0, -DPAD_STEP_AMOUNT);
|
|
[Enum.KeyCode.DPadLeft] = Vector2.new(-DPAD_STEP_AMOUNT, 0.0);
|
|
[Enum.KeyCode.DPadRight] = Vector2.new(DPAD_STEP_AMOUNT, 0.0);
|
|
}
|
|
|
|
|
|
local function CreateOverscanAdjustmentScreen(parent)
|
|
local this = {}
|
|
|
|
this.StickPosition = ZERO_VEC2
|
|
this.StickAcceleration = 1
|
|
local lastUpdate = nil
|
|
local lastParent = parent
|
|
|
|
local lastSavedOverscanPX = START_EDGE_SIZE.X.Scale
|
|
local lastSavedOverscanPY = START_EDGE_SIZE.Y.Scale
|
|
|
|
local function StorePreviousOverscanValues()
|
|
local success, errormsg = pcall(function()
|
|
lastSavedOverscanPX = GameOptionsSettings.OverscanPX
|
|
lastSavedOverscanPY = GameOptionsSettings.OverscanPY
|
|
end)
|
|
if not success then
|
|
print("Error, StorePreviousOverscanValues: OverscanPX and OverscanPY" , errormsg)
|
|
end
|
|
end
|
|
StorePreviousOverscanValues()
|
|
|
|
local MainContainer = Utility.Create'Frame'
|
|
{
|
|
Name = 'OverscanAdjustmentScreen';
|
|
Size = UDim2.new(1, 0, 1, 0);
|
|
BorderSizePixel = 1;
|
|
BackgroundTransparency = 0;
|
|
BackgroundColor3 = BACKGROUND_COLOR;
|
|
Visible = false;
|
|
}
|
|
|
|
local BackgroundImage = Utility.Create'ImageLabel'
|
|
{
|
|
Name = 'BackgroundImage';
|
|
Image = 'rbxasset://textures/ui/Shell/ScreenAdjustment/Background.png';
|
|
Size = UDim2.new(1,0,1,0);
|
|
BackgroundTransparency = 1;
|
|
Parent = MainContainer;
|
|
};
|
|
|
|
local Title = Utility.Create'TextLabel'
|
|
{
|
|
Name = 'Title';
|
|
Text = Strings:LocalizedString('ScreenSizeWord');
|
|
Position = UDim2.new(0, 230, 0, 175);
|
|
TextXAlignment = 'Left';
|
|
TextColor3 = GlobalSettings.WhiteTextColor;
|
|
Font = GlobalSettings.LightFont;
|
|
FontSize = GlobalSettings.HeaderSize;
|
|
BackgroundTransparency = 1;
|
|
Parent = MainContainer;
|
|
};
|
|
do
|
|
local titleTextSize = TextService:GetTextSize(Title.Text, Utility.ConvertFontSizeEnumToInt(Title.FontSize), Title.Font, Vector2.new())
|
|
Title.Size = UDim2.new(0, titleTextSize.X, 0, titleTextSize.Y)
|
|
end
|
|
|
|
local Prompt = Utility.Create'TextLabel'
|
|
{
|
|
Name = 'Prompt';
|
|
Text = Strings:LocalizedString('ResizeScreenPrompt');
|
|
Position = UDim2.new(0,230,0,225);
|
|
TextXAlignment = 'Left';
|
|
TextColor3 = GlobalSettings.WhiteTextColor;
|
|
Font = GlobalSettings.RegularFont;
|
|
FontSize = GlobalSettings.ButtonSize;
|
|
BackgroundTransparency = 1;
|
|
Parent = MainContainer;
|
|
};
|
|
|
|
|
|
do
|
|
local ControllerImage = Utility.Create'ImageLabel'
|
|
{
|
|
Name = 'ControllerImage';
|
|
BackgroundTransparency = 1;
|
|
Image = 'rbxasset://textures/ui/Shell/ScreenAdjustment/Controller@1080.png';
|
|
Size = UDim2.new(0,599,0,404);
|
|
Parent = MainContainer;
|
|
};
|
|
Utility.CalculateAnchor(ControllerImage, UDim2.new(0.5,0,0.5,0), Utility.Enum.Anchor.Center)
|
|
|
|
local Line = Utility.Create'Frame'
|
|
{
|
|
Name = 'Line';
|
|
Size = UDim2.new(0.4,0,0,1);
|
|
Position = UDim2.new(0.73, 0, 0.545, 0);
|
|
BackgroundColor3 = Color3.new(1,1,1);
|
|
BorderSizePixel = 0;
|
|
BackgroundTransparency = 0;
|
|
Parent = ControllerImage;
|
|
};
|
|
local InputHint = Utility.Create'TextLabel'
|
|
{
|
|
Name = 'InputHint';
|
|
Text = Strings:LocalizedString('ResizeScreenInputHint');
|
|
Size = UDim2.new(0,0,0,0);
|
|
Position = UDim2.new(1, 3, 0, -1);
|
|
TextXAlignment = 'Left';
|
|
TextColor3 = GlobalSettings.WhiteTextColor;
|
|
Font = GlobalSettings.RegularFont;
|
|
FontSize = GlobalSettings.ButtonSize;
|
|
BackgroundTransparency = 1;
|
|
Parent = Line;
|
|
};
|
|
end
|
|
|
|
local AcceptButtonImage = Utility.Create'ImageLabel'
|
|
{
|
|
Name = 'AcceptButtonImage';
|
|
Size = UDim2.new(0,65,0,65);
|
|
Position = UDim2.new(0.5, 25, 0.75, 0);
|
|
Image = 'rbxasset://textures/ui/Shell/ButtonIcons/AButton.png';
|
|
BackgroundTransparency = 1;
|
|
Parent = MainContainer;
|
|
};
|
|
local AcceptHint = Utility.Create'TextLabel'
|
|
{
|
|
Name = 'AcceptHint';
|
|
Text = Strings:LocalizedString('AcceptWord'):upper();
|
|
Size = UDim2.new(0,0,1,0);
|
|
Position = UDim2.new(1, 5, 0, -3);
|
|
TextXAlignment = 'Left';
|
|
TextColor3 = GlobalSettings.WhiteTextColor;
|
|
Font = GlobalSettings.RegularFont;
|
|
FontSize = GlobalSettings.ButtonSize;
|
|
BackgroundTransparency = 1;
|
|
Parent = AcceptButtonImage;
|
|
};
|
|
|
|
local ResetButtonImage = Utility.Create'ImageLabel'
|
|
{
|
|
Name = 'ResetButtonImage';
|
|
Size = UDim2.new(0,65,0,65);
|
|
Image = 'rbxasset://textures/ui/Shell/ButtonIcons/XButton.png';
|
|
BackgroundTransparency = 1;
|
|
Parent = MainContainer;
|
|
};
|
|
local ResetHint = Utility.Create'TextLabel'
|
|
{
|
|
Name = 'ResetHint';
|
|
Text = Strings:LocalizedString('ResetWord'):upper();
|
|
Size = UDim2.new(0,0,1,0);
|
|
Position = UDim2.new(1, 5, 0, -3);
|
|
TextXAlignment = 'Left';
|
|
TextColor3 = GlobalSettings.WhiteTextColor;
|
|
Font = GlobalSettings.RegularFont;
|
|
FontSize = GlobalSettings.ButtonSize;
|
|
BackgroundTransparency = 1;
|
|
Parent = ResetButtonImage;
|
|
};
|
|
|
|
local Edges = Utility.Create'Frame'
|
|
{
|
|
Name = 'Edges';
|
|
Size = START_EDGE_SIZE;
|
|
BackgroundTransparency = 1;
|
|
Parent = MainContainer;
|
|
};
|
|
do
|
|
local edgesSelectionImage = Utility.Create'ImageLabel'
|
|
{
|
|
Name = 'EdgesSelectionImage';
|
|
Size = UDim2.new(1,2,1,2);
|
|
Position = UDim2.new(0,-1,0,-1);
|
|
Image = 'rbxasset://textures/ui/Shell/ScreenAdjustment/ScreenRangeOverlay.png';
|
|
ScaleType = Enum.ScaleType.Slice;
|
|
SliceCenter = Rect.new(21,21,41,41);
|
|
BackgroundTransparency = 1;
|
|
};
|
|
edgesSelectionImage.Parent = Edges
|
|
end
|
|
for i = 0, 3 do
|
|
local CornerImage = Utility.Create'ImageLabel'
|
|
{
|
|
Name = 'CornerImage';
|
|
Size = UDim2.new(0, 95, 0, 95);
|
|
BackgroundTransparency = 1;
|
|
Rotation = 90 * i;
|
|
Image = "rbxasset://textures/ui/Shell/ScreenAdjustment/ScreenAdjustmentArrow.png";
|
|
Parent = Edges;
|
|
};
|
|
|
|
if i == 0 then
|
|
Utility.CalculateAnchor(CornerImage, UDim2.new(0,0,0,0), Utility.Enum.Anchor.TopLeft)
|
|
elseif i == 1 then
|
|
Utility.CalculateAnchor(CornerImage, UDim2.new(1, 0, 0, 0), Utility.Enum.Anchor.TopRight)
|
|
elseif i == 2 then
|
|
Utility.CalculateAnchor(CornerImage, UDim2.new(1, 0, 1, 0), Utility.Enum.Anchor.BottomRight)
|
|
elseif i == 3 then
|
|
Utility.CalculateAnchor(CornerImage, UDim2.new(0, 0, 1, 0), Utility.Enum.Anchor.BottomLeft)
|
|
end
|
|
end
|
|
|
|
local function RefreshLayout()
|
|
ResetButtonImage.Position = UDim2.new(0.5 - ResetButtonImage.Size.X.Scale, -ResetHint.TextBounds.X - 25 - ResetButtonImage.Size.X.Offset, 0.75, 0);
|
|
Prompt.Size = UDim2.new(0, Prompt.TextBounds.X, 0, Prompt.TextBounds.Y)
|
|
end
|
|
local closedEvent = Instance.new("BindableEvent")
|
|
closedEvent.Name = "ClosedEvent"
|
|
this.Closed = closedEvent.Event
|
|
|
|
local EdgePercent = Vector2.new(START_EDGE_SIZE.X, START_EDGE_SIZE.Y)
|
|
function this:GetAdjustmentEdgesPercent()
|
|
return EdgePercent
|
|
end
|
|
|
|
function this:SetAdjustmentEdges(newEdgeSize)
|
|
EdgePercent = Utility.ClampVector2(Vector2.new(MIN_EDGE_SIZE.X.Scale, MIN_EDGE_SIZE.Y.Scale), Vector2.new(1,1), newEdgeSize)
|
|
|
|
local guiSize = GuiRoot.AbsoluteSize
|
|
local absoluteEdgeSize = EdgePercent * guiSize
|
|
|
|
-- Round to nearest 2 so that we can evenly space above and below
|
|
local roundedAbsoluteEdgeSize = Vector2.new(Utility.Round(absoluteEdgeSize.X/2), Utility.Round(absoluteEdgeSize.Y/2)) * 2
|
|
roundedAbsoluteEdgeSize = Utility.ClampVector2(Vector2.new(), guiSize, roundedAbsoluteEdgeSize)
|
|
|
|
Edges.Size = UDim2.new(0, roundedAbsoluteEdgeSize.X, 0, roundedAbsoluteEdgeSize.Y)
|
|
Edges.Position = UDim2.new(0, (guiSize.X - roundedAbsoluteEdgeSize.X) / 2, 0, (guiSize.Y - roundedAbsoluteEdgeSize.Y) / 2)
|
|
end
|
|
|
|
function this:PushAdjustmentEdges(pushAmount)
|
|
self:SetAdjustmentEdges(self:GetAdjustmentEdgesPercent() + pushAmount)
|
|
end
|
|
|
|
function this:PushAdjustmentEdgesByPixels(pixelPushAmount)
|
|
local guiSize = GuiRoot.AbsoluteSize
|
|
local pushAmount = pixelPushAmount / guiSize
|
|
|
|
if Utility.IsFinite(pushAmount.X) and Utility.IsFinite(pushAmount.Y) then
|
|
self:SetAdjustmentEdges(self:GetAdjustmentEdgesPercent() + pushAmount)
|
|
end
|
|
end
|
|
|
|
function this:Update()
|
|
local now = tick()
|
|
if lastUpdate and self.StickPosition ~= ZERO_VEC2 then
|
|
local delta = now - lastUpdate
|
|
local transformedStick = Utility.GamepadLinearToCurve(self.StickPosition, 0.2)
|
|
self:PushAdjustmentEdges(Vector2.new(transformedStick.X, -transformedStick.Y) * self.StickAcceleration * delta * THUMBSTICK_BORDER_SENSITIVITY)
|
|
if transformedStick ~= ZERO_VEC2 then
|
|
self.StickAcceleration = math.min(self.StickAcceleration + delta * ACCELERATION_RATE, MAX_STICK_ACCELERATION)
|
|
else
|
|
self.StickAcceleration = 1
|
|
end
|
|
end
|
|
lastUpdate = now
|
|
end
|
|
|
|
function this:ResetEdges()
|
|
self:SetAdjustmentEdges(Vector2.new(START_EDGE_SIZE.X, START_EDGE_SIZE.Y))
|
|
end
|
|
|
|
local GuiRootChangedConn = nil
|
|
function this:Show()
|
|
MainContainer.Visible = true
|
|
MainContainer.Parent = lastParent
|
|
RefreshLayout()
|
|
self.StickAcceleration = 1
|
|
|
|
if not UserSettings().GameSettings:InStudioMode() and GameOptionsSettings.OverscanPX > 0 and GameOptionsSettings.OverscanPY > 0 then
|
|
this:SetAdjustmentEdges(Vector2.new(GameOptionsSettings.OverscanPX, GameOptionsSettings.OverscanPY))
|
|
else
|
|
self:ResetEdges()
|
|
end
|
|
|
|
local success, errormsg = pcall(function()
|
|
StorePreviousOverscanValues()
|
|
-- Need to do this step so that the player
|
|
-- can accurately estimate their TV's overscan
|
|
GameOptionsSettings.OverscanPX = 1
|
|
GameOptionsSettings.OverscanPY = 1
|
|
end)
|
|
if not success then
|
|
print("Error resetting Overscan Screen Resolution:" , errormsg)
|
|
end
|
|
|
|
Utility.DisconnectEvent(GuiRootChangedConn)
|
|
GuiRootChangedConn = GuiRoot.Changed:connect(function(prop)
|
|
if prop == 'AbsoluteSize' then
|
|
self:PushAdjustmentEdgesByPixels(ZERO_VEC2)
|
|
end
|
|
end)
|
|
self:PushAdjustmentEdgesByPixels(ZERO_VEC2)
|
|
|
|
end
|
|
|
|
function this:Hide()
|
|
MainContainer.Visible = false
|
|
MainContainer.Parent = nil
|
|
GuiRootChangedConn = Utility.DisconnectEvent(GuiRootChangedConn)
|
|
end
|
|
|
|
function this:Focus()
|
|
GuiService.SelectedCoreObject = nil
|
|
RefreshLayout()
|
|
|
|
self.StickPosition = ZERO_VEC2
|
|
self.StickAcceleration = 1
|
|
|
|
local beginSeen = false
|
|
|
|
ContextActionService:BindCoreAction("ResetAdjustmentScreen",
|
|
function(actionName, inputState, inputObject)
|
|
if inputState == Enum.UserInputState.End then
|
|
self:ResetEdges()
|
|
end
|
|
end,
|
|
false,
|
|
Enum.KeyCode.ButtonX)
|
|
|
|
ContextActionService:BindCoreAction("AcceptAdjustmentScreen",
|
|
function(actionName, inputState, inputObject)
|
|
if inputState == Enum.UserInputState.Begin then
|
|
beginSeen = true
|
|
elseif inputState == Enum.UserInputState.End and beginSeen then
|
|
local success, errormsg = pcall(function()
|
|
GameOptionsSettings.OverscanPX = math.min(1, self:GetAdjustmentEdgesPercent().X)
|
|
GameOptionsSettings.OverscanPY = math.min(1, self:GetAdjustmentEdgesPercent().Y)
|
|
StorePreviousOverscanValues()
|
|
end)
|
|
if not success then
|
|
print("Error setting Overscan Screen Resolution:" , errormsg)
|
|
end
|
|
if self == ScreenManager:GetTopScreen() then
|
|
ScreenManager:CloseCurrent()
|
|
closedEvent:Fire()
|
|
end
|
|
end
|
|
end,
|
|
false,
|
|
Enum.KeyCode.ButtonA)
|
|
|
|
ContextActionService:BindCoreAction("ThumbstickAdjustmentScreen",
|
|
function(actionName, inputState, inputObject)
|
|
self.StickPosition = Vector2.new(inputObject.Position.X, inputObject.Position.Y)
|
|
end,
|
|
false,
|
|
Enum.KeyCode.Thumbstick2)
|
|
|
|
ContextActionService:BindCoreAction("DPadAdjustmentScreen",
|
|
function(actionName, inputState, inputObject)
|
|
if inputState == Enum.UserInputState.Begin then
|
|
local pushAmount = DPAD_CODE_TO_EDGE_PUSH[inputObject.KeyCode]
|
|
if pushAmount then
|
|
self:PushAdjustmentEdgesByPixels(pushAmount)
|
|
end
|
|
end
|
|
end,
|
|
false,
|
|
Enum.KeyCode.DPadDown, Enum.KeyCode.DPadUp, Enum.KeyCode.DPadLeft, Enum.KeyCode.DPadRight)
|
|
|
|
RunService:BindToRenderStep("UpdateAdjustmentScreen", Enum.RenderPriority.Input.Value, function() self:Update() end)
|
|
end
|
|
|
|
function this:RemoveFocus()
|
|
self.StickPosition = ZERO_VEC2
|
|
lastUpdate = nil
|
|
|
|
ContextActionService:UnbindCoreAction("ResetAdjustmentScreen")
|
|
ContextActionService:UnbindCoreAction("AcceptAdjustmentScreen")
|
|
ContextActionService:UnbindCoreAction("ThumbstickAdjustmentScreen")
|
|
ContextActionService:UnbindCoreAction("DPadAdjustmentScreen")
|
|
|
|
RunService:UnbindFromRenderStep("UpdateAdjustmentScreen")
|
|
end
|
|
|
|
function this:SetPosition(newPosition)
|
|
MainContainer.Position = newPosition
|
|
end
|
|
|
|
function this:SetParent(newParent)
|
|
MainContainer.Parent = newParent
|
|
lastParent = newParent
|
|
end
|
|
|
|
function this:SetStyleForInGame()
|
|
BackgroundImage.Visible = false
|
|
MainContainer.BackgroundTransparency = 0.2
|
|
|
|
local function setZIndex(guiObject, newZIndex)
|
|
if not guiObject:IsA("GuiObject") then return end
|
|
|
|
guiObject.ZIndex = newZIndex
|
|
|
|
local children = guiObject:GetChildren()
|
|
for i = 1, #children do
|
|
setZIndex(children[i], newZIndex)
|
|
end
|
|
end
|
|
|
|
setZIndex(MainContainer, 9)
|
|
end
|
|
|
|
|
|
if not UserSettings().GameSettings:InStudioMode() then
|
|
pcall(function() PlatformService.Suspended:connect(function()
|
|
GameOptionsSettings.OverscanPX = lastSavedOverscanPX
|
|
GameOptionsSettings.OverscanPY = lastSavedOverscanPY
|
|
end)
|
|
end)
|
|
end
|
|
|
|
return this
|
|
end
|
|
|
|
|
|
return CreateOverscanAdjustmentScreen
|