Make a first person camera rotate with the vehicle the player is in

Hello all,

I am building a space ship model with a realistic working cockpit. As part of this ambitious goal, the player can swap between 3rd person / 1st person views by pressing a key. In first person view, the player can view instruments, flip switches, etc.

The problem I have is that the camera does not maintain orientation with the vehicle.

Here is an image highlighting the effect I am looking for:

Here is how that looks in my game:

Notice how in the first picture the aircraft is banking right, but the cockpit appears to be upright. That is, the camera is treating up as the cockpit’s up (rotating with the cockpit), rather than the ground’s up. My ROBLOX camera is doing the exact opposite. The baseplate is “upright” while the cockpit rotates around the camera. As you can imagine, this is quite unusable whenever the craft is maneuvering quickly.

I have tried several things:

  • Changing the camera to every possible CameraType
  • Changing CameraSubject from the VehicleSeat to the player’s Humanoid, player’s Head, or a part on the ship
  • Using a Scriptable camera and setting the camera’s CFrame to a ship part’s CFrame every RenderStep (in this mode, the camera does rotate with the ship, but curiously that effect goes away whenever I zoom all the way in)

In any case it appears I cannot get the camera to respect the ship’s rotation. Am I overlooking something obvious? I feel like this has to be possible!

Using the scriptable camera type is the only way. I’ve worked on making planets and had to deal with lots of camera, humanoid, and physics issues on the spherical terrain. Most flying games have a special key to toggle between cockpit and third person views. I assume this is in part to avoid having the player’s camera zoom through the ship to get to first person. Having multiple types of views isn’t a bad idea either, one where mouse movement moves the ship and another where it changes the camera orbit.

TLDR: Roblox is pesky about which way is “up”. You’ll have to script it yourself.

1 Like

I have a couple resources for you. For the most direct answer to you question check this out:

For a more general approach to defining the camera’s up (this applies to @IdiomicLanguage too) see this post/explanation.

[Release] Custom character controller - #117 by EgoMoose

Hope that helps! Good luck! :+1: :grin:

3 Likes

@EgoMoose I think I may be using your script wrong, not sure. I tried the place you linked in the first thread (and I greatly appreciate you going out of your way to build it) but it doesn’t seem to recreate the effect I want.

To recreate using your linked place:

  • Enter the vehicle
  • Add a BodyForce with a large Y force to the vehicle’s primary part
  • Zoom in to first person
  • Notice how the vehicle still rotates around the camera rather than the other way around

Any ideas?

I have also tried using the custom character controller @EgoMoose built in his other place, but unfortunately that too does not appear to work with VehicleSeats. I know this effect must be possible as it is present in Wigeon’s game, AirX:

The cockpit camera in this game is exactly what I am looking for.

To add to that, it seems like @Crazyman32’s Angels Fifteen does the same thing:

https://www.roblox.com/games/169116390/Angels-Fifteen

I got something working!

game:GetService("RunService").RenderStepped:Connect(function()
		if workspace.Camera.CameraType ~= Enum.CameraType.Scriptable then
			workspace.Camera.CameraType = Enum.CameraType.Scriptable
		end
		local h = workspace.Techboy6601.Head
		local newH = h.CFrame 
		workspace.Camera.CFrame = newH + newH.UpVector * 1.1
	end)

This allows me to offset the camera a bit above my character’s head. It’s a great start, but unfortunately I cannot pan in this mode (the camera stays pointing forward). I’m assuming I’m going to have to implement my own camera panning feature. I’ll try to do that tomorrow.

1 Like

I love doing this in games. As @Techboy6601 mentioned, I do this in Angels Fifteen. In fact, that’s the first time I ever did it. I do it in all my vehicles now.

The trick is simple: Rotate the camera based on the RotVelocity of the vehicle. That’s it.

For each render update, do the following:

  1. Get the RotVelocity (e.g. rotVel = primaryPart.RotVelocity)
  2. Translate it to local space (rotVel = primaryPart.CFrame:VectorToObjectSpace(rotVel))
  3. Multiply it by delta time & some constant (e.g. rotVel = rotVel * dt * 10)
  4. Rotate the camera using the negatives of that rotVel vector:
    cam.CFrame = cam.CFrame * CFrame.Angles(-rotVel.X, -rotVel.Y, -rotVel.Z)

In total:

-- Get rotational velocity:
local rotVel = primary.RotVelocity

-- Rotate the vector to object space:
rotVel = primary.CFrame:VectorToObjectSpace(rotVel)

-- Multiply by delta time & some constant:
rotVel = rotVel * dt * 10

-- Ideally run 'rotVel' through smoothing algorithm right here

-- Set the camera's position:
camera.CFrame = primary.CFrame * CFrame.Angles(-rotVel.X, -rotVel.Y, -rotVel.Z)

Typically it looks better to smooth out the rotVel value though too. I use a special smoothing module to do this, but there’s lots of examples on Roblox and on the internet to smooth out an input value.

3 Likes

This is great! Thanks so much.

I now have an equivalent effect to what Angels Fifteen does with its HUD. The only part missing now is that i need to pan around the cockpit - basically like what you can do in normal first person view. Because we manually set the camera’s CFrame every frame, the player has no ability to move it around.

I tried to do:

camera.CFrame = camera.CFrame * CFrame.Angles(-rotVel.X, -rotVel.Y, -rotVel.Z)

To account for the player having moved the camera around the cockpit, but that went horrifically wrong. I think I need to modify the final CFrame to take into account the existing camera’s CFrame so that the user’s pan is not overwritten.

Apologies for the 8 month necro,

Have you had any luck in keeping the camera relevant to the vehicle while maintaining free panning from the client? I, too, am quite confused on how to go about this and have something that’d definitely benefit from (player controlled AC-130). I know there’s some way, but I’m nearing the end of my rope here in some kind of solution to the problem.

This is about as close as I can get, the camera panning is messed up but it still accounts for it.

local RunService = game:GetService("RunService")
local CurrentCamera = game.Workspace.CurrentCamera
local Model = script.Object.Value
local Seat = Model.Seat
local User = game.Players.LocalPlayer

RunService:BindToRenderStep("UpdateLoop", Enum.RenderPriority.Camera.Value, function()

local Cam_CFrame = CurrentCamera.CFrame
local Seat_CFrame = Seat.CFrame
local Angles2 = Seat_CFrame - Seat_CFrame.Position
local rX2, rY2, rZ2 = Angles2:ToEulerAnglesYXZ()

local NewCFrame = (Cam_CFrame
* CFrame.Angles(0,0, rZ2)
)

CurrentCamera.CFrame = NewCFrame
end)
2 Likes

Hi, im so sorry for replying to a 3 year old post, idk how im supposed to reply other than like this.

Personally I was able to do this by using a “scriptable” cameratype and welding a part (using the deprecated weld, I know, but it was the only way I was able to think of to do this easily) that substitutes as the camera to the plane/ship.
From there you can mess with the C0 and C1 properties of the weld and updating said properties when the mouse moves, cancelling out the Z rotation from the CFrames so that the camera cannot roll on the z axis relative to the ship.

With some changes you can use this same method with the weld to make a 3rd person camera that does the same thing.