How could I create a top-down camera movement system?

I am looking to create a top-down camera movement system (as the title implies), which moves on both the X & Z axis (not the Y). I have done a few attempts, all of which failed. The current default camera position is -25, 25, -25, looking at 0, 0, 0.

Image of the top-down area for reference:

Could I get some help? Thanks in advance.

Edit: I’m trying to do this with the mouse, not the keyboard.

Hi there, this may not be the best way to do it, but this would be how I would.

Set your currentcamera type to scriptable
have a vector3 value of where you want it to be (goto)
have a vector3 value of where you want it to look (lookat)
Set your currentcameracframe as CFrame.new(goto,lookat)

^ just have this inside a local script inside starterplayerscripts

Could you show me some code please?

Yeah, but my main issue was detecting the mouse move direction. (as I want to use the mouse to move the camera)

Oh, then you’ll have to use Mouse.Hit (I know it’s depreciated, but I think it’s most useful for new devs)

This might help:
https://developer.roblox.com/en-us/api-reference/class/Mouse

Could you perhaps provide material on how to detect the direction? I can’t find anything myself.

You can set the LookAt to the mouse hit vector, and the camera position to the player’s HumanoidRootPart position vector.

This might help you further:
https://developer.roblox.com/en-us/api-reference/property/Camera/CFrame

Well, I have CharacterAutoLoads off, as the player’s character is not needed in the game, and would only get in the way.

Ah, sorry for the misunderstanding. You want like when you move the mouse to the left of the screen, the camera moves left (and vice versa)?

Well, when the mouse moves left, the camera moves right (as you’d need to hold down RMB to move the camera, and having it inverted feels more natural, and since the default camera has inverted rotation to my understanding).

Will this work? I don’t fully understand what u are trying to achieve but if any of the code in here works for your needs then I’m glad I could help!

wait(2)

local c = workspace.CurrentCamera
local player = game.Players.LocalPlayer
local userInput = game:GetService("UserInputService")
local rs = game:GetService("RunService")
local starterPlayer = game:GetService("StarterPlayer")

local selected = false
local speed = 45
local lastUpdate = 0

local camera = Instance.new('Part', workspace)
camera.CanCollide = false
camera.Anchored = true
camera.Transparency = 1
camera.Name = 'FreeCam'
camera.Position = player.Character.HumanoidRootPart.Position + Vector3.new(0,5,0)

function getNextMovement(deltaTime)
	local nextMove = Vector3.new()
	if userInput:IsKeyDown("A") or userInput:IsKeyDown("Left") then
		nextMove += Vector3.new(-1,0,0) end
	if userInput:IsKeyDown("D") or userInput:IsKeyDown("Right") then
		nextMove += Vector3.new(1,0,0) end
	if userInput:IsKeyDown("W") or userInput:IsKeyDown("Up") then
		nextMove += Vector3.new(0,0,-1) end
	if userInput:IsKeyDown("S") or userInput:IsKeyDown("Down") then
		nextMove += Vector3.new(0,0,1) end
	if userInput:IsKeyDown("Space") or userInput:IsKeyDown("Q") then
		nextMove += Vector3.new(0,1,0) end
	if userInput:IsKeyDown("LeftControl") or userInput:IsKeyDown("E") then
		nextMove += Vector3.new(0,-1,0) end
	return CFrame.new( nextMove * (speed * deltaTime)) end

function onSelected()
	local char = player.Character
	if char then
		local root = camera
		local currentPos = root.Position
		selected = true
		lastUpdate = tick()
		c.CameraSubject = root
		player.Character.HumanoidRootPart.Anchored = true
		while selected do
			local delta = tick()-lastUpdate
			local look = (c.Focus.p-c.CoordinateFrame.p).unit
			local move = getNextMovement(delta)
			local pos = root.Position
			root.CFrame = CFrame.new(pos,pos+look) * move
			lastUpdate = tick()
			wait(0.01) end
		player.Character.HumanoidRootPart.Anchored = false
		c.CameraSubject = player.Character.Humanoid
		root.Velocity = Vector3.new() end end

function onDeselected()
	selected = false end

local isOn = false

function onKeyPressed(_,state)
	if state == Enum.UserInputState.Begin then
		isOn = not isOn
		if isOn then
			onSelected() else onDeselected() end end end

function ResetCamera()
	camera.Position = player.Character.HumanoidRootPart.Position + Vector3.new(0,5,0) end

game:GetService("ContextActionService"):BindAction("r",onKeyPressed,false,"r")
game:GetService("ContextActionService"):BindAction("z",ResetCamera,false,"z")