CameraService: A New Camera for a New Roblox

CameraService :camera_flash:

A New Camera for a New Roblox.
Just a heads-up that this is my first-ever open-source for any of my programming projects, so hopefully I’m doing this right.

For the past few months, I, along with my development team, have been working on an ambitious MMORPG project on the Roblox platform. A key theme we decided early on was to focus on immersion and realism, and as a result, I decided to create a custom camera system that serves that purpose. And as seen by this post, I’ve decided to open-source it, letting developers of all kinds be able to implement new, breathtaking camera views into their games and experiences in just a few lines of code!

See CameraService in Action & Games!

Using CameraService? Wanna be featured? Message me your game, and I’ll add you on here!

Neohex by the Neohex Team (indie team I’m apart of)
:1st_place_medal: 1st Place in the Roblox Inspire 2024 Challenge for Global Citizenship!

Subsist (Survival) by @Lechegaming83
A work-in-progress survival game!

The Features

The list of features goes on and on, some of which include:

  • Different, customizable properties that developers can play around with and implement, including the camera’s smoothness, zoom, offset from the part it’s focusing on, and more.
  • Seamlessly transitioning between different camera views (first-person, third-person, shift-lock, etc.), and letting you create your own!
  • Smooth camera movements, rather than Roblox’s usual instantaneous movements
  • The ability to tilt the camera with ease, opening the door to advanced-like camera manipulation to beginners.
  • Properties that let you enable aesthetically appealing effects on the player’s character, such as having their body follow the mouse.
  • Shaking camera effects that can be used for a multitude of purposes.
  • Ability to lock camera panning on the X and Y axes.
  • Compatible on laptop, mobile, and console.

Demonstrations

Here are videos showcasing some of CameraService’s features and built-in camera views:
You can see a tech demo of CameraService for yourself here.

Third Person

CameraService’s default third person camera view is in sharp contrast with Roblox’s traditional camera, providing additional features such as smooth movements, and character rotation based off mouse input.

First Person

This system provides built-in first person, already doing the work of restricting zoom. Like third person, there is more smoother movements. Additionally, a FirstPersonVariant is also present as another camera view, which allows you to see your character’s own body while in first-person mode.

Shift Lock

CameraService supports a camera view that imitates shift lock’s offset. Using the API, you, the developer, are able to customize the smoothness, offset, and much more in addition.

Custom Views

CameraService enables you to create your own camera views, allowing for what would’ve been tedious hours of camera manipulation programming to be condensed into creating something like this in just a couple minutes!

Shaking and Tilting

These two are embedded as methods that can be called through CameraService.

Documentation

:SetCameraView(__type: string)
Sets the camera to a certain view, such as first person, shift-lock, or some other.
Will error if CameraService cannot find the camera view.
A camera view MUST be set in order to use the rest of the CameraService API.

:CreateNewCameraView(id: string, settingsArray: table)
Adds a new camera view that the camera can be set to.
settingsArray should have values for camera view properties as seen below in :Change().
If no value is provided, a default one will be placed within.

:LockCameraPanning(xAxis: bool, yAxis: bool, lockAtX: number, lockAtY: number)
Locks camera movement from right-to-left (x-axis) or up-down (y-axis) 3rd and 4th parameters are optional. If the camera is locked, it’ll lock at the rotation of those parameters. Input should be in degrees for that.

:SetCameraHost(newHost: BasePart)
Has the camera focus in on the input part. Must be a BASEPART (not a model).
To reset the host back to the player’s character, you can leave the parameters blank.

:Change(property: string, val: any, changeDefaultProperty: boolean)
Properties include:
"CharacterVisibility" (string): Determines what part of the character is visible.
when it’s the host. “All” shows all parts, “Body” hides the head, & “None” hides the whole body.
"MinZoom" (number): Determines how close the player can zoom in. In studs.
"MaxZoom" (number): Determines how far the player can zoom out. In studs.
"Zoom" (number): The current distance the camera is away from the host.
"Smoothness" (number): Determines how smooth the camera movement is.
Intervals from 0-1 are suggested. Intervals higher could be used to create a “cinematic” effect.
"Offset" (CFrame): Determines the offset/positioning away from the camera host.
Can be used to simulate shift-lock.
"LockMouse" (boolean): Has the mouse locked in at the center.
"AlignChar" (boolean): If set to true, the character will rotate itself based off the camera (highly advised for shift-locks and first person)
"BodyFollow" (boolean): If AlignChar is NOT enabled, BodyFollow allows for an effect that has the upper body slightly rotate based off the mouse location. (only works for R15 rigs)

:ChangeSensitivity(val: number)
Changes the rate at which the camera moves.
Merely adjusts the UserInputServiceService.MouseDeltaSensitivity property.
NOTICE: Players CAN change this themselves manually through the Roblox menu.

:ChangeFOV(val: number, instant: boolean)
Gradually changes the field-of-view of the current camera.
If you want the change to be instantaneous, add a second parameter marked true.
Changing FOV directly with the actual camera object is still possible.

:Shake(intensity: number, duration: number)
Note: This function does yield for the duration of time inputted.
Creates a shaking camera effect in which the screen is, well, shaking. Like an earthquake.
Intensity should be a number greater than 0, preferably in the 0-1 range. Duration is in seconds.

:Tilt(degree: number)
Tilts the camera across the z-axis on whatever object it is currently focusing on.
Useful for creating camera effects. Input a number in degrees.

:Tilt(degree: number)
Tilts the camera across the z-axis on whatever object it is currently focusing on.
Useful for creating camera effects. Input a number in degrees.

:TiltAllAxes(x: number, y: number, z: number)
Like :Tilt, but allows you to adjust all 3 axes. Most likely use-case would be for creating camera effects. Inputs in X,Y,Z order

:SetWobbling(value: number)
Determines the amount of dynamic wobbling enabled. The larger the value, the less wobbling. To disable it, set the value to 0.

Examples

Say you wanted to recreate the cinematic camera effect seen at the very top and in demonstrations. To create something like that, your program would look like:

local CameraService = require(script.Parent.WhereverThisIsPlaced.ShouldBeOnTheClient)
local information = {
	Smoothness = 10,
	CharacterVisibility = "All",
	MinZoom = 10,
	MaxZoom = 10.001, --> To avoid running into math errors, make sure MaxZoom and MinZoom have a difference of at least 0.001.
	Zoom = 10,
	AlignChar = false,
	Offset = CFrame.new(),
	LockMouse = false,
	BodyFollow = false
}

CameraService:CreateNewCameraView("Cinematic", information)
CameraService:SetCameraView("Cinematic") --> Tada!
CameraService:ChangeFOV(90, false) --> You could also add a bit more with changing the FOV.

And let’s say you wanted you wanted to just simply have players start in CameraService’s third-person when they join. It’s simply a matter of just a couple lines.

local CameraService = require(script.Parent.WhereverThisIsPlaced.ShouldBeOnTheClient)
CameraService:SetCameraView("ThirdPerson")
--> Other built-in camera views include: FirstPerson, FirstPersonVariant, and ShiftLock

--> And if we wanted to spice it up, and have it feel like an explosion?
--> When the character steps on a certain part, it can go like this:
local player = game.Players.LocalPlayer
local debounce = false
workspace.ExplosionPart.Touched:Connect(function(hit)
    if not debounce and hit and player and player.Character and hit.Parent == player.Character then
         debounce = true 
         CameraService:Shake(1, 5) --> Shakes heavily for 5 seconds.
    end
end)

Disclaimer: Due to UserInputService not recognizing the classic (not dynamic) Roblox thumbstick on mobile devices as a GameProcessedEvent, there may be some unusual behavior when using CameraService on mobile IF using the old thumbstick (the current dynamic thumbstick has no issues).

Where to Obtain CameraService

Latest Update (v2.0):

You can also contact me on Discord at @lugical.me and on Twitter.
I’m always looking to help showcase & support any games using CameraService. If you are, feel free to let me know, so I can shout you out in the post!

290 Likes

Amazing resource, however Shake() should have more features like EZcamerashake does. EZCameraShake has built in presets named Bump, Explosion, etc. and also has more customization for the Shake(). Also does this work with FPS unlockers? (specifically the Shake()) EZCameraShake

4 Likes

At the moment, I’m currently unaware of whether this will work with FPS un-lockers, as I don’t have one downloaded myself. The system runs on RenderStepped, if that helps with anything.

I do appreciate your thoughts on :Shake*(, though I doubt I’d be able to dedicate much further time on this to implement that. I’d definitely recommend using EZCameraShake if the main goal for you would be something involving a lot of shaking effects.

3 Likes

Do you use DeltaTime at all? if not then it wont work with FPS unlockers.

Yeah but EZCameraShake has the same problem with the FPS unlocker, however your resource is very good especially with the smooth cameras!

2 Likes

The only camera service I’d use would be the one where mobile cameras were fixed :unamused: hint hint roblox it’s been a couple years

3 Likes

Yes, DeltaTime is used to lerp the camera’s CFrame if the smoothness property is higher than 0, if I recall correctly.

6 Likes

Looks like a really nice resource to add that extra immersive :ok_hand: to an experience! Really love seeing camera resources released - I think it’s a niche that a lot of people struggle with and consequently avoid, despite the fact that it can really make a game pop!

@F0xBirdmansBFF gentle reminder that OP doesn’t have to make his module a swiss army knife of features nor does a resource have to eclipse all other existing/alternative resources. It’s okay for modules to have specific use cases

9 Likes

Thank you so much for sharing this awesome module with the community, I really liked it and I will definitely use this in my future projects. I also have a small question though, when I was testing the demo place I encountered something. In shiftlock view if you move your mouse over a proximity prompt, you are not able to use your mouse anymore. If you move your character away and proximity prompt disappears it is back to normal. Here is what I am talking about:

Edit: Also could you please make the demo place editable?

Edit2: Are you going to update this module? If so TiltFinished event would be awesome.

3 Likes

Hey! Great resource! I was wondering if this would work with a “2D” game while maintaining its functions (shift lock not needed) and camera smoothness.

3 Likes

Great work my man, keep it up!

2 Likes

I honestly don’t see why not. All these except for shift lock don’t seem to effect the character itself so you should be able to.

2 Likes

Thanks for the responses! Updated the module to v1.1.0, which expands a few features.

  • Fixed compatibility issues with R6
  • Adjusted the issue on laptops where camera froze on button interactions (thank you @Helyras)
  • New :TiltAllAxes(y, x, z) method that expands :Tilt to all axes. While most use-cases should rely on just tilting the z-axis with :Tilt, why not add this as well?
  • New parameters for :LockCameraPanning(xAxis, yAxis, lockAtX, lockAtY) - The third and fourth parameters allow you to specify the rotation at which the camera should be if panning it on that axis is locked. This can be useful in the case of 2D games.

I added the extra parameters for :LockCameraPanning in this new release for that purpose! Here’s how a 2D game could look with a couple lines of CameraService, along with the code you can use to replicate that:

local CameraService = require(whereverthisison.theclient)
local info = {
	Smoothness = 3,
	CharacterVisibility = "All",
	MinZoom = 15,
	MaxZoom = 15,
	Zoom = 15,
	AlignChar = false,
	Offset = CFrame.new(0,0,0),
	LockMouse = false,
	BodyFollow = false
}

CameraService:CreateNewCameraView("2D_test", info)
CameraService:SetCameraView("2D_test")
CameraService:LockCameraPanning(true, true, 90, 0) --> You may want to tweak that 3rd parameter to what works best for your use-case.

Heads-Up: If you plan to use this heavily in your games, I would suggest setting StarterPlayer properties to something similar to this, to prevent the system breaking because the player changed their own camera mode settings:

10 Likes

I do not want to know how long this took to make.

Jokes aside, this looks great, and I definitely will use it in the future! Good job on it!

2 Likes

I haven’t even dropped it in game to test it yet and I can already tell you this will be 10x more useful then the current toolset given to us, just the camera shake and smoothing options alone makes this worth the +rep.

2 Likes

In love with this. The idea of a cinematic camera just gave me a ton of inspirations in order to implement a more immersive cutscenes in my games.

Amazing resource!

2 Likes

Absolutely amazing resource!

It’s a steal that it is open-sourced and will add so much value to cut-scenes in the future! Thanks for this.

3 Likes

Thanks for the fix! This new 2D update looks great. I have a suggestion though, is it possible make it like when you are watching from the cliff in the demo game, your camera is locked to your character, like in detroit become human.

2 Likes

This is amazing, and will make manipulating camera easier!! Thank you :slight_smile:
I’m trying to implement this service in my game now i working on, and I have a question…

I have normal camera that Player can manipulate in game.
Like I already have some scripts to manipulate camera as shift lock cam, and sometimes It create Camera CFrame tween animation.
and I want to run your camera service to specific situation.

For instance, Here’s a GUI button that will make game as cinematic mode for local player.
Normally I use this script.

-- Camera View Change Information
local information = {
	Smoothness = 5,
	CharacterVisibility = "All",
	Zoom = 10,
	AlignChar = true,
	LockMouse = false,
	BodyFollow = false
}

btn.MouseButton1Click:Connect(function()
	if btn.BackgroundColor3 == Color3.fromRGB(255, 255, 255) then --when it's not cinematic mode
		CameraService:CreateNewCameraView("Cinematic", information) -- make game cinematic
		btn.BackgroundColor3 = Color3.fromRGB(255, 28, 130) -- change button background color
	else 
		CameraService:SetCameraView(destroy) -- HOW CAN I DESTROY OR STOP THIS SERVICE?
		btn.BackgroundColor3 = Color3.fromRGB(255, 255, 255) -- change button background color
		end
end)

Well… I want to know HOW CAN I DESTROY OR STOP THIS CAM SERVICE? or how can make camera view back to before?

Thank you for this amazing work! Let me know if you have some thought about my question :slight_smile:

2 Likes

Hey!
What you can do is set the camera view to “Default” when wanting to halt CameraService. It should reset you back to original Roblox camera. From there, you should be able to manipulate the camera however you need to on your own!

2 Likes

hey so i actually noticed something: this does not work with FPS unlockers, i tested this in 2 ways.
when testing with a Camera Bobbing script that WORKS with fps unlockers and CameraService isnt being used, the script works fine with all FPS. however, if the script is being used and CameraService is also being used, the CameraBobbing script now doesnt not work with all FPS.

basically: when using camera service, the higher fps the higher sensitivity and vise versa
@Lugical

1 Like