I need help with a three axis third person camera... in space

So, here is what I am trying to achieve in human english:

I have a sphere in zero gravity, that can move left-right-forward-backward with ‘WASD’, and tilt around its lookVector axis using ‘Q’ & ‘E’. The sphere has a ‘front’ and ‘top’, just like a spaceship. I want to create a system kind of like the ‘fly’ command found in admin commands, except instead of hitting a vertical look limit, it can rotate upward or downward indefinitely, and to the right and left, like a globe if that makes sense.

In this case, the camera would have full 360 degree rotation on the Y and X axis. The X axis being ‘looking down or up’, which would have the same orientation as the spheres RightVector.

Now, this is just the Y and X axis. Now comes the Z axis, the sphere’s ability to tilt.

I want whatever new orientation the tilting creates to be treated as a normal upright orientation, so that the camera can have the same functionality no matter what the orientation is.

And to add to that, the camera should rotate the sphere with it, like the ‘fly’ command as mentioned above.

Boy, where do I even begin?

2 Likes

There are probably way better ways to do this, but I wrote something for you real quick to try to give you a foundation that you can improve upon.

My script currently has editable variables in the form of:

  • local Target = workspace.Part can be used to modify what the Camera is looking at.
  • local CameraOffset = CFrame.new(0, 0, 5) can be used to change how far away the camera is from the target.

What I basically have done step by step is this:

  • Set the CameraType to Scriptable in order for it to be manipulated.
  • Set the CFrame of the Camera to the part, with an offset added so it is not inside the part.
    Camera.CFrame = CFrame.new(Target.Position) * CFrame.Angles(math.rad(VerticalRotationAngle), 0, 0) * CameraOffset
  • Used UserInputService to get input from the player, i.e W,A,S,D
  • If the key is W or S then we modify the vertical angle, adding if going forward and subtracting if going backwards.
  • Set the CFrame of the Camera based on the calculations provided by the while Held do loop and then have an event to detect when the player stops holding the key at the end of the script.
  • If player tries to use more than one key, the script currently has a debounce, but you can probably add a function to your script to support two axis movement at once.
-- Made by TDK on 9/20/2019
local Player = game.Players.LocalPlayer
local UserInputService = game:GetService("UserInputService")
local RunService = game:GetService("RunService")
local CameraOffset = CFrame.new(0, 0, 5)
local Character = Player.Character
local Target = workspace.Part
local VerticalRotationAngle = 0
local HorizontalRotationAngle = 0
Held = false

-- Set CameraType
repeat wait() until Player.Character
Camera = workspace.CurrentCamera
Camera.CameraType = "Scriptable"
Camera.CameraSubject = Target
Camera.CFrame = CFrame.new(Target.Position) * CFrame.Angles(math.rad(VerticalRotationAngle), 0, 0) * CameraOffset

-- Collect Input from Player
UserInputService.InputBegan:Connect(function(input, gpe)
	if gpe or Held then return end
	if input.KeyCode == Enum.KeyCode.W then
		Held = true
		while Held do
			if Held == false then return end
			Camera.CFrame = CFrame.new(Target.Position) * CFrame.Angles(math.rad(VerticalRotationAngle), math.rad(HorizontalRotationAngle), 0) * CameraOffset
			VerticalRotationAngle = VerticalRotationAngle + 1  
			RunService.Stepped:Wait()
		end
	elseif input.KeyCode == Enum.KeyCode.S then
		Held = true
		while Held do
			if Held == false then return end
			Camera.CFrame = CFrame.new(Target.Position) * CFrame.Angles(math.rad(VerticalRotationAngle), math.rad(HorizontalRotationAngle), 0) * CameraOffset
			VerticalRotationAngle = VerticalRotationAngle - 1  
			RunService.Stepped:Wait()
		end
	elseif input.KeyCode == Enum.KeyCode.A then
		Held = true
		while Held do
			if Held == false then return end
			Camera.CFrame = CFrame.new(Target.Position) * CFrame.Angles(math.rad(VerticalRotationAngle), math.rad(HorizontalRotationAngle), 0) * CameraOffset
			HorizontalRotationAngle = HorizontalRotationAngle - 1  
			RunService.Stepped:Wait()
		end
	elseif input.KeyCode == Enum.KeyCode.D then
		Held = true
		while Held do
			if Held == false then return end
			Camera.CFrame = CFrame.new(Target.Position) * CFrame.Angles(math.rad(VerticalRotationAngle), math.rad(HorizontalRotationAngle), 0) * CameraOffset
			HorizontalRotationAngle = HorizontalRotationAngle + 1  
			RunService.Stepped:Wait()
		end
	end
end)

-- Handle player letting go of input
UserInputService.InputEnded:Connect(function(input, gpe)
	if gpe then return end
	Held = false
end)

With this code we end up with something like this:
https://gyazo.com/8f17ba253ffe80e13fc88f7597df866d

7 Likes

I really appreciate your great response. Unfortunately, that wasn’t what I was looking for exactly. I managed to figure it out on my own eventually. I want to give you the solution for trying so hard to help me out. Thank you.

What did you do to solve it? I’m also trying to allow 360 degree rotation

1 Like