Removing a player's sense of up and down? (Anti-gravity camera)

I have an anti-gravity script you can test here:

The problem is, when a player moves straight up or straight down, their character becomes hard to control. This is because the default camera script seems to “lock” the camera at that point, and prevents the player from moving the camera around freely. It becomes obvious they are moving up or down.

I want to remove the locking feature entirely so the camera can always be moved around freely in any direction. This is so players can have better control and so they lose a sense of direction, making for better immersion.

How would I go about doing this? Is there something in the core scripts I can change?


You can change the max angles in the BaseCamera module, located on line 19 and 20. The camera will break if you set the values to anything over 81 so you’d probably produce more favorable results if you created your own camera.

-- Note: DotProduct check in CoordinateFrame::lookAt() prevents using values within about
-- 8.11 degrees of the +/- Y axis, that's why these limits are currently 80 degrees
local MIN_Y = math.rad(-80)
local MAX_Y = math.rad(80)
1 Like

Changing the angles just breaks moving on the Y axis entirely and it’s useless since I need the angles to be over 80. I would make my own script from scratch but I don’t even know where to begin on something like that.

Thanks though

Have you considered overwriting the CameraModule (or it’s contents) and looking through it? You can copy it from play solo, put it in the same directory you found it, and it’s automatically overwritten.

You can find the CameraModule inside StarterPlayer -> StarterPlayerScripts -> PlayerModule -> CameraModule, I recommend taking the entire PlayerModule.


Yes… I know it’s kind of indirect in the OP but I did go through it. I didn’t find anything helpful besides the lines @regularwolf posted.

I tried to replicate the default roblox camera to the best of my abilities so you could get an idea on how to create your own custom cameras. I didn’t have any time to create any camera zooming functionality but I’m sure you probably already know how to do that on your own.

Place file:
Intended_Pun.rbxl (16.2 KB)

Script hierarchy:

CameraLoader :



local ContextActionService = game:GetService("ContextActionService")
local UserInputService = game:GetService("UserInputService")
local RunService = game:GetService("RunService")

local Camera = {}

	local self = setmetatable(
			__index = function(self, Index)
				if Camera[Index] then
					return Camera[Index]
	self.CurrentCamera = game.Workspace.CurrentCamera
	self.Character = game.Players.LocalPlayer.Character or game.Players.LocalPlayer.CharacterAdded:Wait()
	self.X = 0
	self.Y = 0
	self.Sensitivity = 0.015
	self.CameraOffset =, 3, 12)
	self.IsRightMouseButtonDown = false
	return self

function Camera:Initialize()
	self.CurrentCamera.CameraType = Enum.CameraType.Scriptable

		function(ActionName, InputState, InputObject)
			self:RightClickChanged(ActionName, InputState, InputObject) 
		function(ActionName, InputState, InputObject)
			self:UpdateAngles(ActionName, InputState, InputObject) 
	RunService:BindToRenderStep("UpdateCamera", 200, function()

function Camera:RightClickChanged(ActionName, InputState, InputObject)
	if InputState == Enum.UserInputState.Begin then
		IsRightMouseButtonDown = true
	elseif InputState == Enum.UserInputState.End then
		IsRightMouseButtonDown = false

function Camera:UpdateAngles(ActionName, InputState, InputObject)
	if IsRightMouseButtonDown then
		UserInputService.MouseBehavior = Enum.MouseBehavior.LockCurrentPosition
		self.X = self.X + (InputObject.Delta.X * -self.Sensitivity)
		self.Y = self.Y + (InputObject.Delta.Y * -self.Sensitivity)
		UserInputService.MouseBehavior = Enum.MouseBehavior.Default

function Camera:UpdateCamera()
	self.CurrentCamera.CFrame = * CFrame.fromEulerAnglesXYZ(0, self.X, 0) * CFrame.fromEulerAnglesXYZ(self.Y, 0, 0) *, self.CameraOffset.Y, self.CameraOffset.Z)
	local CameraRay =, self.CurrentCamera.CFrame.Position - self.Character.HumanoidRootPart.Position)
	local Ignore = {self.Character}
	local HitPart, HitPosition = game.Workspace:FindPartOnRayWithIgnoreList(CameraRay, Ignore)
	self.CurrentCamera.CFrame = (self.CurrentCamera.CFrame - (self.CurrentCamera.CFrame.Position - HitPosition)) + (self.Character.HumanoidRootPart.Position - self.CurrentCamera.CFrame.Position).Unit
	self.CurrentCamera.Focus = self.CurrentCamera.CFrame


Wow, thank you so much for taking the time to do that! I will definitely check it out when I have time.

Edit: It works! Thanks again.

So I’ve managed to get it working perfectly except for when a player is moving straight up or down on the Y axis. I want the camera behavior to be identical to when they are moving around the X axis, but instead it’s weird (You can see the strange behavior in the original place link).

After experimenting for a few hours, I’m still not sure how to go about making the behavior identical on the Y axis. I feel like I’m missing something here:

if self.Character.HumanoidRootPart.CFrame.UpVector.Y < 0 then --Controls were inverted when character was upside-down so I fixed that, otherwise code is the same.
	self.X = self.X + (InputObject.Delta.X * self.Sensitivity)
	self.Y = self.Y + (InputObject.Delta.Y * -self.Sensitivity)
	self.X = self.X + (InputObject.Delta.X * -self.Sensitivity)
	self.Y = self.Y + (InputObject.Delta.Y * -self.Sensitivity)

Am I missing some crucial step? What am I doing wrong?

It’s probably because the camera is positioned without taking rotation into account. I’m not really sure how you’d go about doing that since I’ve never tried it.

1 Like

Alright cool. Thanks for the input. I’ll see if I can come up with something >:)