Move Camera Using WASD

Hey there, :wave:

I’m wanting to manipulate the camera so that when you use WASD, just as you would when you’re moving your character, the camera moves. But, in my game, the character doesn’t get loaded in so the camera is the players’ entire view of the game. Sorry if that was a bit complicated, but I’d be grateful if you guys could help me.

1 Like

You can create your own custom camera controller by making a script in StarterPlayerScripts and naming it CameraScript. Here’ an example from a project I’m working on:


local RunS = game:GetService("RunService")
local TagS = game:GetService("CollectionService")
local InputS = game:GetService("UserInputService")

local camera = game.Workspace.CurrentCamera
local player = game.Players.LocalPlayer
local mouse = player:GetMouse()

local screen = Instance.new("ScreenGui", player.PlayerGui)

local CAMERA_MOVE_SPEED_MAX = 30
local CAMERA_MOVE_FORCE = 150
local cameraVelocity = Vector3.zero

function getCameraMoveDirInput(): Vector3
	local dir = Vector3.zero
	
	if InputS:IsKeyDown(Enum.KeyCode.D) then dir += Vector3.xAxis end
	if InputS:IsKeyDown(Enum.KeyCode.A) then dir -= Vector3.xAxis end
	if InputS:IsKeyDown(Enum.KeyCode.S) then dir += Vector3.zAxis end
	if InputS:IsKeyDown(Enum.KeyCode.W) then dir -= Vector3.zAxis end
	
	if dir ~= Vector3.zero then
		dir = dir.Unit
	end
	
	return dir	
end

function clampV3Magnitude(v: Vector3, min: number, max:number): Vector3
	return v.Unit * math.clamp(v.Magnitude, min,  max)
end

function updateCameraMovement(dt)
	local accelDir = getCameraMoveDirInput()

	if accelDir ~= Vector3.zero then
		cameraVelocity += CAMERA_MOVE_FORCE * accelDir * dt
		cameraVelocity = clampV3Magnitude(cameraVelocity, 0, CAMERA_MOVE_SPEED_MAX)
	else
		cameraVelocity *= math.clamp(1 - (15 * dt), 0, 1)
	end

	camera.CFrame += cameraVelocity * dt 
end

function updateCamera(dt)
	updateCameraMovement(dt)
end

camera.CFrame = CFrame.new(0, 300, 0) * CFrame.Angles(-math.rad(90), 0, 0)
camera.FieldOfView = 5

camera.CameraType = Enum.CameraType.Scriptable
camera:GetPropertyChangedSignal("CameraType"):Connect(function()
	camera.CameraType = Enum.CameraType.Scriptable
end)

RunS.RenderStepped:Connect(updateCamera)
4 Likes

Thanks! I’ll try this out tomorrow when I get the chance, looks great though!

Edit: Yeah this works, thanks a bunch! Just one thing though, are you able to angle the camera?

1 Like

Yeah, just change the number in this part of the code:

Try something like 45 or 60 degrees.

1 Like

Neither 45 nor 60 really work, 45 goes under the map and 60 makes the camera move somewhere else. And if I try something like 80 it works pretty well but the angle change is really small. I’ll give you a screenshot of the angle I’m trying to reproduce.

1 Like

Sorry, forgot it was really zoomed in. You should probably remove the FieldOfView to keep it at the default, or try experimenting with it. To get the angle you want, try

camera.CFrame = CFrame.new(0, 300, 0) * CFrame.Angles(0, math.rad(-45), 0) * CFrame.Angles(-math.rad(45), 0, 0)

Although now you’ll have to update the movement too:

local accelDir = (camera.CFrame:VectorToWorldSpace(getCameraMoveDirInput()) * Vector3.yAxis).Unit
1 Like

Great! The first bit of code worked and the angle did change but the second bit of code didn’t, now using the WASD keys doesn’t work… :confused:

same thing for me, im trying to make a camera system similar to this too and can’t find any solution :confused:

Sorry for the necroposting. The solution for the WASD problem script can be changed by making accelDir to this:

local accelDir = getCameraMoveDirInput()
accelDir = Vector3.new(accelDir.X, 0, accelDir.Z)

The reason why the last code didn’t work is because accelDir was constantly nan, nan, nan, since the yAxis is 0 and multiplying by Vector3.yAxis makes the vector becomes 0, 0, 0, which’s unit becomes nan, nan, nan. Easiest solution should be constantly setting the y axis to 0 though, and not doing complicated mathematics lol.