How to CFrame a Overhead camera correctly?

I have a system for building that requires I have the camera overhead of the in game building area. I can use right click and drag to rotate the camera, but as I use the A,W,D,S keys , can’t find any examples on how to make sure pressing w then keeps the camera going “forward” or “Up” in relation to the top of the camera, as its looking straight down at times 60 degrees. I think I need to somehow follow the LookVector of the camera, but can someone give me a quick tip on this?

You need to first disable the default camera script and set the camera type to Scriptable. Then you can define an offset height from the ground. You can do a RayCast from the camera position each time its updated to get the height of the ground beneath the camera. Then you can offset the camera from the ground to the desired height.

Your camera lookVector can be Vector3.fromNormalId(Enum.NormalId.Bottom)

Simply add the lookVector to the position component for your look component of the CFrame to get a CFrame with that lookVector: CFrame.new(pos, pos+lookVector)

Finally for your dragging feature you can simply set your camera CFrame to offset up from the mouse position while the player holds their mouse down.

Oh thanks, this sounds good. I’m going to try that now. Thanks.

By the way I have most of it already built… dragging etc… including all the building features… I just can’t seem to get this camera to work well, and I’ve left it for last.

This is what I’m currently doing…
–[[

https://stackoverflow.com/questions/54013176/how-do-you-go-about-making-an-rts-camera-city-builder-camera-in-roblox-studio
]]

local UT2 = require(game.ReplicatedStorage:WaitForChild(“UTILITY_CLASS”)).new()
local cam = game.Workspace.CurrentCamera

– place the camera high in the air, looking down at the ground
local startingPos = Vector3.new(0, 30, 0)
local downwardLookAngle = CFrame.Angles(-math.rad(60), 0, 0)
cam.CFrame = CFrame.new(startingPos) * downwardLookAngle

– create a function that moves the camera around
local moveDir = Vector3.new(0, 0, 0) – we’ll use this vector to control our movement
local moveSpeed = 0.5
local Zrot = 0
local start_click_time = nil
local end_click_time = nil
spawn(function()
while true and script.UnBind.Value==false do
– animate the camera movement
local c = game.Workspace.CurrentCamera.CFrame
game.Workspace.CurrentCamera.CFrame = CFrame.new(c.Position) * CFrame.new(moveDir) * downwardLookAngle
wait(0.01)
end
game.ContextActionService:UnbindAction(“MouseMovement”)
game.ContextActionService:UnbindAction(“MouseRightClick”)
game.ContextActionService:UnbindAction(“mouseWheel”)
game.ContextActionService:UnbindAction(“moveCameraForward”)
game.ContextActionService:UnbindAction(“moveCameraLeft”)
game.ContextActionService:UnbindAction(“moveCameraBackward”)
game.ContextActionService:UnbindAction(“moveCameraRight”)
end)
local delta = nil
local blank = Vector3.new()
local rightclicked=false
local UserInputService = game:GetService(“UserInputService”)
– create a function to handle keyboard inputs
local function onKeyPress(actionName, userInputState, inputObject)
– when a key is pressed, modify our moveDir vector so our camera moves

-- W key input
if actionName == "moveCameraForward" then
    if userInputState == Enum.UserInputState.Begin then
        moveDir = Vector3.new(moveDir.X, moveDir.Y, -moveSpeed)
    elseif userInputState == Enum.UserInputState.End then
        moveDir = Vector3.new(moveDir.X, moveDir.Y, 0)
    end

-- A key input
elseif actionName == "moveCameraLeft" then
    if userInputState == Enum.UserInputState.Begin then
        moveDir = Vector3.new(-moveSpeed, moveDir.Y, moveDir.Z)
    elseif userInputState == Enum.UserInputState.End then
        moveDir = Vector3.new(0, moveDir.Y, moveDir.Z)
    end

-- S key input
elseif actionName == "moveCameraBackward" then
    if userInputState == Enum.UserInputState.Begin then
        moveDir = Vector3.new(moveDir.X, moveDir.Y, moveSpeed)
    elseif userInputState == Enum.UserInputState.End then
        moveDir = Vector3.new(moveDir.X, moveDir.Y, 0)
    end

-- D key input
elseif actionName == "moveCameraRight" then
    if userInputState == Enum.UserInputState.Begin then
        moveDir = Vector3.new(moveSpeed, moveDir.Y, moveDir.Z)
    elseif userInputState == Enum.UserInputState.End then
        moveDir = Vector3.new(0, moveDir.Y, moveDir.Z)
    end
elseif actionName =="MouseMovement" then

   delta = inputObject.Delta
	if rightclicked then
		--print(delta)
		if delta.X>0 then
			Zrot = Zrot + 1
			
		elseif delta.X<0 then
			Zrot = Zrot - 1
		end
			if Zrot<0 then 
				Zrot = 350
			end
			if Zrot>360 then 
				Zrot = 0
			end
		downwardLookAngle =  CFrame.Angles(-math.rad(90), 0, math.rad(Zrot))
		
		
	end
	
	

elseif actionName =="MouseRightClick" then
	 if userInputState ==  Enum.UserInputState.Begin  then
    	UserInputService.MouseBehavior = Enum.MouseBehavior.LockCurrentPosition
		rightclicked = true
		start_click_time = UT2:gettime()
		while (UT2:gettime() - start_click_time)<=.4 and rightclicked==true do
			wait(.1)
			end_click_time =  (UT2:gettime() - start_click_time)
		end
		
    elseif userInputState == Enum.UserInputState.End or userInputState == Enum.UserInputState.Cancel then
        UserInputService.MouseBehavior = Enum.MouseBehavior.Default
		rightclicked = false
		if end_click_time<=.3 then
			local BUILDING_MOD = require(game.ReplicatedStorage.GUI_Building_Mod).new()
			BUILDING_MOD:clearAllSelections(game.Players.LocalPlayer)
		end
    end
elseif actionName =="mouseWheel" then

	local dir = 0
	if inputObject.Position.Z>0 then
		dir = -1
	else
		dir = 1
	end

	 if userInputState == Enum.UserInputState.Change then
        moveDir = Vector3.new(moveDir.X, (moveSpeed)*dir, moveDir.Z)
		wait(1)
		 moveDir = Vector3.new(moveDir.X, 0, moveDir.Z)
    else
        moveDir = Vector3.new(moveDir.X, 0, moveDir.Z)
    end
elseif actionName=="blah" then
	
end

end

– listen for keyboard input that moves the camera
game.ContextActionService:BindAction(“MouseMovement”,onKeyPress,false,Enum.UserInputType.MouseMovement)
game.ContextActionService:BindAction(“MouseRightClick”, onKeyPress,false,Enum.UserInputType.MouseButton2)
game.ContextActionService:BindAction(“mouseWheel”, onKeyPress,false,Enum.UserInputType.MouseWheel )
game.ContextActionService:BindAction(“moveCameraForward”, onKeyPress, false, Enum.KeyCode.W)
game.ContextActionService:BindAction(“moveCameraLeft”, onKeyPress, false, Enum.KeyCode.A)
game.ContextActionService:BindAction(“moveCameraBackward”, onKeyPress, false, Enum.KeyCode.S)
game.ContextActionService:BindAction(“moveCameraRight”, onKeyPress, false, Enum.KeyCode.D)

@Hexcede Okay i solved the problem using the following function I found in a free model script for an RTS_Camerea that takes in account all possible directions to move provided by input, and then provides a directional vector for movement for the camera. I’ve seen similar scripts in the past but couldn’t find them.

function getMovement()
    local look = CFrame.Angles(0, math.rad(rotation), 0)
    local forwardUnit = (look.lookVector * Vector3.new(1, 0, 1)).unit
    local strafeUnit = ((look * CFrame.Angles(0, math.rad(90), 0)).lookVector * Vector3.new(1, 0, 1)).unit
    local forward = (input.forward and 1 or 0) - (input.backwards and 1 or 0)
    local strafe = (input.left and 1 or 0) - (input.right and 1 or 0)
    local mv = (forward * forwardUnit + strafe * strafeUnit)
    if math.abs(mv.X) + math.abs(mv.Y) + math.abs(mv.Z) > 0 then moving = true mv = mv.unit else moving = false end
    return mv
end
2 Likes