Allow player to move camera freely inside of car while staying relative to the car's orientation

[read full thread for answer]

  1. What do you want to achieve? Keep it simple and clear!

I would like to create a first-person camera for a vehicle that follows the orientation of the car while also allowing the player to smoothly look around. For example, if I’m looking to the left at my driver-side window, when I turn the vehicle I should still be looking directly at that window. My camera should stay in-place relative to the orientation of the vehicle.

  1. What is the issue? Include screenshots / videos if possible!

When looking around in first person in a vehicle, the camera is constantly trying to snag back to a forward-facing position, which makes it impossible to look around. Below is an example of this.

robloxapp-20230731-1841499.wmv (1.4 MB)

  1. What solutions have you tried so far? Did you look for solutions on the Developer Hub?

I was able to eliminate this ‘camera snag’ by welding a Part to the player’s face when they join, which is used as the CameraSubject when the player enters the vehicle. This also allows the player to move the camera freely inside of the vehicle. However, this comes with a new problem: The camera no longer follows the orientation of the car. Below I have linked an example of this.

robloxapp-20230731-1830436.wmv (2.0 MB)

I’m a complete noob to scripting, so I don’t even know where to start with this.

4 Likes

This probably isn’t the most efficient method, but if you were to bind to RunService’s RenderStep (which fires every frame, hence the inefficiency), you could probably then use a couple variables to calculate the change in the Y-axis rotation (which is the side-to-side movement), and then adding that onto the camera’s CFrame.
It would probably look something like this:

local RunService = game:GetService("RunService") -- Get RunService
local camera = workspace.CurrentCamera -- Get the camera
local carBase = -- PATH TO BASE OF CAR

local _, lastRY, _ = carBase.CFrame:ToOrientation() -- Get the rotation of the car at spawn

-- Put this code somewhere that runs when the player sits in the car
local handle = RunService.RenderStepped:Connect(function(_))
	local _, newRY, _ = carBase.CFrame:ToOrientation() -- Get the new rotation of the car
	
	local diff = newRY - lastRY -- Might need to swap this
	
	camera.CFrame *= CFrame.Angles(0,diff,0) -- Add to camera's CFrame
end

-- Put this code somewhere that runs after the player gets out of the car
handle:Disconnect() -- Stops the code above so the camera doesn't break

Put this in a LocalScript in StarterCharacterScripts, and you should be good to go.
Excuse any errors, I wrote this in Notepad++, not in Studio :sweat_smile:. Tell me if you find any.

2 Likes

I incorporated your stuff into my script and this happened
robloxapp-20230731-1916252.wmv (2.7 MB)

The camera freaks out whenever the car turns, no errors in output tho

1 Like

Right, I forgot to add a line. Just add local _, lastRY, _ = carBase.CFrame:ToOrientation() to the bottom of that RenderStepped function.

1 Like

Still freaks out, this is what my script looks like

event.OnClientEvent:Connect(function() --RemoteEvent triggers from ServerScript when I sit in VehicleSeat
	head.Transparency = 1 --ignore this and the line below
	head.face.Transparency = 1
	workspace.CurrentCamera.CameraSubject = copy --sets CameraSubject to the welded face part
	player.CameraMaxZoomDistance = 0.5 
	handle = RunService.RenderStepped:Connect(function(_)
		local _, newRY, _ = carBase.CFrame:ToOrientation() -- Get the new rotation of the car

		local diff = newRY - lastRY -- Might need to swap this

		workspace.CurrentCamera.CFrame *= CFrame.Angles(0,diff,0) -- Add to camera's CFrame
		local _, lastRY, _ = carBase.CFrame:ToOrientation()
	end)
end)

My fault again, remove the local in the last line, that just means it doesn’t actually change the lastRY outside of that function, which means it still stays as 0 when the function starts again.

2 Likes

Works perfectly! Thank you so much :smiley:

1 Like

For any future readers, the aforementioned script will only work with your horizontal movement, so if you’re driving up a hill, your camera will not follow the car vertically. I modified the script to compensate for this:

local carBase = workspace.Jeep.Chassis --Change this to the base of your vehicle
local lastRX, lastRY, _ = carBase.CFrame:ToOrientation() 
local RunService = game:GetService("RunService")

event.OnClientEvent:Connect(function() --I'm using a RemoteEvent to call this script whenever I sit in the VehicleSeat
	handle = RunService.RenderStepped:Connect(function(_) 
		local newRX, newRY, _ = carBase.CFrame:ToOrientation() 
		local diff = newRX - lastRX
		local diff2 = newRY - lastRY
		workspace.CurrentCamera.CFrame *= CFrame.Angles(diff,diff2,0)
		lastRX, lastRY, _ = carBase.CFrame:ToOrientation()
	end)
end)

event2.OnClientEvent:Connect(function() --Using another RemoteEvent that triggers when player exits the VehicleSeat
	handle:Disconnect() --Stops car camera
end)

You can also add a variable for the Z axis of the camera, but it makes driving the car quite disorienting:

  1. Replace the _ on line 7 with newRZ
  2. Replace the 0 on line 10 with newRZ

Please tell me if this doesn’t work, I removed some parts of my actual script that weren’t relevant but I could have deleted something important in the process

3 Likes

Just a quick addition, you can replace the first underscore in local _, lastRY, _ with local lastRX, lastRY, _ instead of giving it a completely seperate line. An underscore just tells the script that you won’t be using that variable.

1 Like

Oh right lol, thanks for catching that

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.