Controlling the User's Camera

The user's view of the world is represented by a Camera object. You can change the camera behavior to suit your experience in a variety of ways. For example, the camera can react to events in the world, such as shaking when a monster walks by, or locked to the side of the user character, as in a side-scroller.

Creating a First-Person Camera

A first-person camera is a view where the camera stays locked with the character's head, which is more accurate to real life. It's common in shooter and story experiences where the goal is to make the user feel immersed in the world.

First Person Camera
Classic Roblox Camera

In Studio, the StarterPlayer object contains a number of properties that affects the user's camera. The CameraMode property determines how the camera behaves.

  1. Select StarterPlayer.

    alt

  2. Change CameraMode to LockFirstPerson. This ensures the user's camera doesn't move away from their head.

    alt

  3. Playtest to see the first person camera in action.

Creating a Side-Scrolling Camera

A side-scrolling view keeps the camera at a fixed position relative to the side of the character, giving the world a two-dimensional feel.

alt

Scripting the Camera

  1. Expand StarterPlayer, and in StarterPlayerScripts add a LocalScript named CameraManager.

    alt

  2. At the top of the script, copy and paste the following code sample to get the Players service, and then in a new variable get the local user.


    1local Players = game:GetService("Players")
    2
    3local player = Players.LocalPlayer
    4
  3. Create a function called updateCamera. This holds the logic needed to get and set a new position for the camera.


    1local Players = game:GetService("Players")
    2
    3local player = Players.LocalPlayer
    4
    5local function updateCamera()
    6
    7end
    8
  4. Inside the function, get the user's character model and check if it exists by using an if statement.


    1local Players = game:GetService("Players")
    2
    3local player = Players.LocalPlayer
    4
    5local function updateCamera()
    6 local character = player.Character
    7 if character then
    8
    9 end
    10end
    11

Pointing the Camera

All character models contain a part named HumanoidRootPart, which can be used to get the character's position in the world. This sets position the camera points at.

  1. Use FindFirstChild to get the HumanoidRootPart and check it exists using an if statement.


    1local Players = game:GetService("Players")
    2
    3local player = Players.LocalPlayer
    4
    5local function updateCamera()
    6 local character = player.Character
    7 if character then
    8 local root = character:FindFirstChild("HumanoidRootPart")
    9 if root then
    10
    11 end
    12 end
    13end
    14
  2. The position of the HumanoidRootPart is actually 2 studs below the user's head. To fix this, add a new Vector3 with a height of 2 studs to the root's position.


    1local Players = game:GetService("Players")
    2
    3local player = Players.LocalPlayer
    4
    5local HEIGHT_OFFSET = 2
    6
    7local function updateCamera()
    8 local character = player.Character
    9 if character then
    10 local root = character:FindFirstChild("HumanoidRootPart")
    11 if root then
    12 local rootPosition = root.Position + Vector3.new(0, HEIGHT_OFFSET, 0)
    13 end
    14 end
    15end
    16

Setting the Camera Position

The camera also needs a position. To give the user's view a 2D side-scrolling look, the camera needs to look directly at the side of the character. Place the camera to the side of the user by adding depth to just the Z axis of the camera's position using a Vector3.


1local player = Players.LocalPlayer
2
3local CAMERA_DEPTH = 24
4local HEIGHT_OFFSET = 2
5
6local function updateCamera()
7 local character = player.Character
8 if character then
9 local root = character:FindFirstChild("HumanoidRootPart")
10 if root then
11 local rootPosition = root.Position + Vector3.new(0, HEIGHT_OFFSET, 0)
12 local cameraPosition = Vector3.new(rootPosition.X, rootPosition.Y, CAMERA_DEPTH)
13 end
14 end
15end
16
17

Update CurrentCamera

Now that the variables for the camera's position and the camera's target are ready, it's time to update the camera's position. You can access the user's camera through the CurrentCamera property of Workspace. The camera has a CFrame property to determine its position.

You can use CFrame.lookAt() to update the camera. It takes two positions and creates a CFrame located at the first position pointed towards the second. Use CFrame.lookAt() to create a CFrame that is positioned at cameraPosition and pointed toward rootPosition.


1local player = Players.LocalPlayer
2local camera = workspace.CurrentCamera
3
4local CAMERA_DEPTH = 24
5local HEIGHT_OFFSET = 2
6
7local function updateCamera()
8 local character = player.Character
9 if character then
10 local root = character:FindFirstChild("HumanoidRootPart")
11 if root then
12 local rootPosition = root.Position + Vector3.new(0, HEIGHT_OFFSET, 0)
13 local cameraPosition = Vector3.new(rootPosition.X, rootPosition.Y, CAMERA_DEPTH)
14 camera.CFrame = CFrame.lookAt(cameraPosition, rootPosition)
15 end
16 end
17end
18

Sync the Camera

The last step is to run this function repeatedly to keep the camera in sync with the user. The image the user sees is constantly refreshing. The split second it takes to do all of the calculations necessary is called the render step.

RunService:BindToRenderStep() makes it simple to execute a function on every frame by accepting these three parameters:

  • name - The name of this binding, which should be unique so it won't clash with other functions of the same name.
  • priority - The higher the number, the higher the priority. This function should run after Roblox's default camera update, so the priority is set to 1 level higher than the internal camera's RenderPriority.
  • function - The function to be bound to the render step.
  1. Use RunService:BindToRenderStep() to bind the updateCamera function to the render step.


    1local Players = game:GetService("Players")
    2local RunService = game:GetService("RunService")
    3
    4local player = Players.LocalPlayer
    5local camera = workspace.CurrentCamera
    6
    7local CAMERA_DEPTH = 24
    8local HEIGHT_OFFSET = 2
    9
    10local function updateCamera()
    11 local character = player.Character
    12 if character then
    13 local root = character:FindFirstChild("HumanoidRootPart")
    14 if root then
    15 local rootPosition = root.Position + Vector3.new(0, HEIGHT_OFFSET, 0)
    16 local cameraPosition = Vector3.new(rootPosition.X, rootPosition.Y, CAMERA_DEPTH)
    17 camera.CFrame = CFrame.lookAt(cameraPosition, rootPosition)
    18 end
    19 end
    20end
    21
    22RunService:BindToRenderStep("SidescrollingCamera", Enum.RenderPriority.Camera.Value + 1, updateCamera)
    23
  2. Playtest your code. Use the A and D keys to move your character from side to side.

Creating an Isometric Camera

The basic structure of getting the user's position and updating the camera's position every frame can be adapted to many other camera styles, such as an isometric camera. An isometric camera is a 3D view pointing slightly down at a fixed angle towards the user character.

alt

Modifying Position and View

  1. Using the code from the previous example, modify cameraPosition to add the same amount to all 3 dimensions.

    alt


    1local function updateCamera()
    2 local character = player.Character
    3 if character then
    4 local root = character:FindFirstChild("HumanoidRootPart")
    5 if root then
    6 local rootPosition = root.Position + Vector3.new(0, HEIGHT_OFFSET, 0)
    7 local cameraPosition = rootPosition + Vector3.new(CAMERA_DEPTH, CAMERA_DEPTH, CAMERA_DEPTH)
    8 camera.CFrame = CFrame.lookAt(cameraPosition, rootPosition)
    9 end
    10 end
    11end
    12
    13RunService:BindToRenderStep("IsometricCamera", Enum.RenderPriority.Camera.Value + 1, updateCamera)
    14
  2. Changing the camera's FieldOfView property simulates zooming it in and out, which can give the view a flatter look. Try setting it to a value of 20 to zoom in, and increasing the camera's distance from the user to compensate.


    1local Players = game:GetService("Players")
    2local RunService = game:GetService("RunService")
    3
    4local player = Players.LocalPlayer
    5local camera = workspace.CurrentCamera
    6
    7local CAMERA_DEPTH = 64
    8local HEIGHT_OFFSET = 2
    9
    10camera.FieldOfView = 20
    11
    12local function updateCamera()
    13

By changing the way the camera behaves, you can achieve a whole new look for your experience. See if you can change the cameraPosition to achieve a top-down camera with the same script. Try tweaking settings to get a result you like!