How would you manipulate the camera so that the camera looks over your shoulder and aims?

Hello everyone!

So recently, I’ve been trying to make a custom camera system and have used @vsnry’s script retrieved from here. Although this is efficient and does work, I am trying to make it so the camera offsets to the right shoulder and points your character in that direction, similar to how GTA V works. I’ve tried doing this myself, but usually it doesn’t end out that well. The ways I have tried this was by changing the camera position and making the camera position tween to the specified position but it would normally end up like this. I’m trying to make it tween so it can be smooth, but like I said before, I’ve tried other ways and I am not sure how to do this.

Here’s the code I used:

local AIM_XOFFSET = 1.25
local AIM_SENS = 0.25
local aimInfo = TweenInfo.new(0.5)
local aiming = false

function API:GetCFrameFromPos(pos)
	local rootPart = currentChar:FindFirstChild("Head")
	if rootPart then
		local startCFrame = CFrame.new((rootPart.CFrame.p + Vector3.new(0,0,0)))*CFrame.Angles(0, math.rad(xAngle), 0)*CFrame.Angles(math.rad(yAngle), 0, 0)
		local cameraCFrame = startCFrame + startCFrame:vectorToWorldSpace(Vector3.new(pos.X,pos.Y,pos.Z))
		local cameraFocus = startCFrame + startCFrame:vectorToWorldSpace(Vector3.new(pos.X,pos.Y,-50000))
		return CFrame.new(cameraCFrame.p, cameraFocus.p)
	end
end

function API:UpdatePos(pos, tween, ...)
	local tweenTable = {...}
	local tweenInfo
	tween = tween or false
	
	local duration = tweenTable[1] or 1
	local easingStyle = tweenTable[2] or Enum.EasingStyle.Quad
	local easingDirection = tweenTable[3] or Enum.EasingDirection.Out
	if not pos or tween and not tweenTable then
		return
	elseif tween and tweenTable then
		tweenInfo = TweenInfo.new(duration, easingStyle, easingDirection)
	end
	if not tween then
		cameraPos = pos
	else
		local newPos = API:GetCFrameFromPos(pos)
		Camera.Tweening.Duration = duration
		Camera.Tweening.EasingStyle = easingStyle
		Camera.Tweening.EasingDirection = easingDirection
		Camera.Tweening.Enabled = true
		cameraPos = pos
		delay(duration, function()
			if tween[2] then
				Camera.Tweening.Enabled = false
			end
		end)
	end
end

function API:UpdateFOV(FOV, tween, ...)
	local tweenTable = {...}
	local tweenInfo
	tween[1] = tween[1] or false
	tween[2] = tween[2] or false
	
	local duration = tweenTable[1] or 1
	local easingStyle = tweenTable[2] or Enum.EasingStyle.Quad
	local easingDirection = tweenTable[3] or Enum.EasingDirection.Out
	if not FOV or tween and not tweenTable then
		return
	elseif tween and tweenTable then
		tweenInfo = TweenInfo.new(duration, easingStyle, easingDirection)
	end
	if not tween then
		currentCamera.FieldOfView = FOV
	else
		TweenService:Create(currentCamera, tweenInfo, {FieldOfView = FOV}):Play()
	end
end

function API.ToggleAim()
	if not enabled or not currentCamera then
		return
	end
	if not aiming then
		aiming = true
		tweened = true
		Camera.Sensitivity = AIM_SENS
		TweenService:Create(currentCamera, aimInfo, {FieldOfView = 50}):Play()
		API:UpdatePos(Vector3.new(AIM_XOFFSET, 0, 7.5), {true, true}, .325)
	else
		Camera.Sensitivity = DEFAULT_SENS
		TweenService:Create(currentCamera, aimInfo, {FieldOfView = DEFAULT_FOV}):Play()
		API:UpdatePos(Vector3.new(0, 0, 7.5), {true, true}, .325)

		aiming = false
	end
end

function API.IsAiming()
	if enabled then
		if aiming then
			return true
		else
			return false
		end
	end
end

function API:GetCurrentPos()
	return cameraPos
end

UserInputService.InputBegan:Connect(function(input, gameProcessed)
	if not gameProcessed then
		if input.UserInputType == Enum.UserInputType.MouseButton2 then
			if not aiming then
				API.ToggleAim()
			end
		elseif input.UserInputType == Enum.UserInputType.Keyboard then
			local keyCode = input.KeyCode
			if keyCode == Enum.KeyCode.Q then
				API.ToggleAim()
			end
		end
	end
end)

UserInputService.InputChanged:Connect(function(input)
	if input.UserInputType == Enum.UserInputType.MouseMovement then
		xAngle = xAngle - input.Delta.x * 0.4
		yAngle = math.clamp(yAngle - input.Delta.y * 0.4, -80, 80)
	elseif input.UserInputType == Enum.UserInputType.MouseWheel then
		local newPos = input.Position.Z * 4
		local newCameraPos = cameraPos - Vector3.new(0, 0, newPos)
		if newCameraPos.Z < 2 or newCameraPos.Z > 50 or aiming then
			return
		end
		--cameraPos = newCameraPos
		API:UpdatePos(newCameraPos, {true, true}, 0.1)
	end
end)

UserInputService.InputEnded:Connect(function(input, gameProcessed)
	if not gameProcessed then
		if input.UserInputType == Enum.UserInputType.MouseButton2 then
			if aiming then
				API.ToggleAim()
			end
		end
	end
end)

RunService.RenderStepped:Connect(function()
	if not currentChar or not currentCamera then
		return
	end
	local Tween = Camera.Tweening
	local rootPart = currentChar:FindFirstChild("Head")
	local finalCFrame
	if rootPart and enabled then
		local startCFrame = CFrame.new((rootPart.CFrame.p + Vector3.new(0,0,0)))*CFrame.Angles(0, math.rad(xAngle), 0)*CFrame.Angles(math.rad(yAngle), 0, 0)
		local cameraCFrame = startCFrame + startCFrame:vectorToWorldSpace(Vector3.new(cameraPos.X,cameraPos.Y,cameraPos.Z))
		local cameraFocus = startCFrame + startCFrame:vectorToWorldSpace(Vector3.new(cameraPos.X,cameraPos.Y,-50000))
		
		UserInputService.MouseDeltaSensitivity = Camera.Sensitivity
		finalCFrame = CFrame.new(cameraCFrame.p, cameraFocus.p)
		if not Tween.Enabled then
			currentCamera.CFrame = finalCFrame
		else
			currentCamera.CFrame = finalCFrame
			TweenService:Create(currentCamera, TweenInfo.new(Tween.Duration, Tween.EasingStyle, Tween.EasingDirection), {CFrame = finalCFrame}):Play()
		end
	end
end)

Help is very appreciated.

5 Likes

Are you trying to make it so the camera zooms in when you right click?

If so, just create a bool for the camera zoom like “cameraZoom = false”. When the player right clicks, set it to true and when the player lets go set it to false.

To make the actual smooth zoom, in the RenderStepped loop check if cameraZoom is true and lerp cameraPos so that cameraPos.Z is closer to the player. If it’s false lerp it back to its original value.

2 Likes

I already have done that, but the problem I’m having here, if you saw the video, is that everytime I try to change the camera’s CFrame using TweenService to smoothly transition it to the right of the shoulder, it goes out of line of the character. I am mainly trying to do this so that the camera transitions to the right shoulder whenever you equip a gun then zooms in when you right click or press “Q” to aim.

Read my post, this is very simple and doesn’t require any of that fancy API: stuff you did, I’d post some code but can’t at the moment as I’m on my phone.

Ah alright, thank you for your solution. And to clarify the API stuff, it’s a module used under a client script with other modules which are basically the core scripts for the player. This is mainly for other modules to use the camera controller module if needed. But your idea makes more sense, thanks again.