Camera Split Screen Effect based on UI

  1. What do you want to achieve?
    I have a topdown RPG game where 35% of the screen is taken up by a user interface (either horizontally, or vertically, which depends on screen size). To make the game not feel bizarre and cumbersome to control, I have devised a method of offsetting the camera by the amount of screen space taken by the UI, essentially mimicking a sort of split-screen effect.
  2. What is the issue?
    I can’t seem to find a good enough method of detecting screen size in 3D space, allowing me to calculate the missing area in world space.
  3. What solutions have you tried so far?
    I have attempted to use ScreenPointToRay to determine the corners of the camera to get the total size, I have used the ViewPortSize and Field Of View, etc. And no, I have not found much on here in relation to the devforum either.
1 Like

If anyone is wondering, this is the current code, though it’s not very useful, as I don’t believe this method works:

local CAMERA_OFFSET = (Vector3.yAxis * 2)

local RunService = game:GetService("RunService")

local dialogueMenuUpdatedEvent = game:GetService("Players").LocalPlayer.PlayerGui.UIHandler.DialogueMenuUpdated

local character = script.Parent
local rootPart = character.PrimaryPart
local camera = workspace.CurrentCamera

local zoom = 8

camera.CameraType = Enum.CameraType.Scriptable

local function getCameraSize()
	local camera = workspace.CurrentCamera
	local topLeft = camera:ViewportPointToRay(0, 0).Origin
	local topRight = camera:ViewportPointToRay(camera.ViewportSize.X, 0).Origin
	local bottomLeft = camera:ViewportPointToRay(0, camera.ViewportSize.Y).Origin
	return (topRight - topLeft).magnitude, (bottomLeft - topLeft).magnitude
end

local function calculateCameraOffset(horizontal)
	local camera = workspace.CurrentCamera
	local width, height = getCameraSize()
	print(width,height)
	return if horizontal then Vector3.xAxis * (width * 0.175) else Vector3.yAxis * (height * 0.175)
end

local function updateSplitScreen(enabled, horizontal)
	print(enabled)
	CAMERA_OFFSET = (Vector3.yAxis * 2) + (if enabled then calculateCameraOffset(horizontal) else Vector3.zero)
end

RunService:BindToRenderStep("UpdateCamera", Enum.RenderPriority.Character.Value , function()
	if not character.Parent then RunService:UnbindFromRenderStep("UpdateCamera") end
	camera.CFrame = CFrame.lookAt(rootPart.Position + (Vector3.one * zoom), rootPart.Position) * CFrame.new(CAMERA_OFFSET)
end)

dialogueMenuUpdatedEvent.Event:Connect(updateSplitScreen)
updateSplitScreen(true, (camera.ViewportSize.X > camera.ViewportSize.Y))

Hi! Correct me if I am wrong but do you think you can use this to help you adjust the screen size? I can’t remember when I came across this solution, I will try to find the link if it helps. I don’t know if you particularly need to calculate 3D space as you can probably achieve the same, in 2D space.

local player = game.Players.LocalPlayer

local mouse = player:GetMouse()
x = mouse.ViewSizeX
y = mouse.ViewSizeY


print(x,y)

The camera itself needs to be offset in 3D space for the effect to work:
3dviewport
The camera is centered on the main character, but since the UI cover up 35% of the screen, it is not centered relative to what the player can actually see. I would like to center the camera on the character in the space still available (hence the offset, and why I need to move the camera itself).

Moving the actual game Viewport via Udim2 or any other method isn’t something doable, as the game Viewport isn’t an actual UI object. What you’re showing me is also identical to Camera.ViewportSize (which is already used in the offset calculation). While I really do appreciate the help, this doesn’t do much to solve it.

The issue seems to be with camera:ViewportPointToRay, surprisingly enough, as they’re all weirdly clumped together, completely unlike their intended origin behavior of appearing on the edges?
green = topLeft, yellow = topRight, red = bottomLeft

The values are the following, if anyone is interested:
topLeft (green): -0.13548733294010162, 8.113245964050293, 5.029464244842529
topRight (yellow): 0.13548733294010162, 8.113245964050293, 5.029464244842529
bottomLeft (red): -0.13548733294010162, 8.003891944885254, 5.116947650909424

You can loop through the UIs that are shown on the players screen and then calculate the edges of the viewable area and shift the camera based on that

These are not ViewportFrames, there is only one Camera. The actual UI that covers the screen is meant to be a toggle-able chat log, but due to its prevalence in the game, offsetting the camera is the only real way to make it enjoyable and non-clunky to play.

The problem with calculating the edges for the camera here is that I do not know of a good method of doing this, and as you can see in the above reply, the current method is not working as intended.

The UIs have position and size properties so you can calculate their edges and then use the closest edge s to the center to calculate how much the camera should be offset

If you are suggesting calculating the difference between edges for the UI element (top left to top right for example), how would I go about converting the returned pixel values into studs, for use in the camera offset Vector3?

Make it proportional to the zoom of the camera and then try multiplying it by different constants

Could you please provide example code on how this could be done, by any chance?