Camera "tweak" strength varies based on look direction AND doesn't stick to the head

i hate camera manipulation i hate camera manipulation

okay so, this is the first issue;


and this is the second


i’m actually losing my mind with this somebody PLEASE help me :sob:

-- Tables;
local cameraOffsets = {
	MELEE = CFrame.Angles(math.rad(40), math.rad(-60), 0),
	GUN = CFrame.Angles(math.rad(60), math.rad(40), 0),
	CONSUMABLE = CFrame.Angles(math.rad(50), math.rad(30), 0)
}

-- Functions;

local function SetCollisionGroup(children, group)
	for i = 1, #children do
		local child = children[i]

		if child:IsA("BasePart") then
			child.CollisionGroup = group
		end

		SetCollisionGroup(child:GetChildren(), group)
	end
end

local function CameraTwitchOnEquip(weapon: Tool)
	local goalPosition = mouse.Hit.Position 
	local cameraOffset = cameraOffsets[weapon.WeaponType.Value]
	
	local currentCamPos = camera.CFrame.Position
	local newLookVector = (cameraOffset).LookVector
	
	camera.CFrame = CFrame.new(currentCamPos, currentCamPos + newLookVector)
	
	local tweenParams = TweenInfo.new(
		0.3,
		Enum.EasingStyle.Back,
		Enum.EasingDirection.Out
	)
	
	local tweenGoal = {
		CFrame = CFrame.lookAt(camera.CFrame.Position, goalPosition)
	}
	
	local tweenBack = tService:Create(camera, tweenParams, tweenGoal)	
	tweenBack:Play()
	
	rService:BindToRenderStep("WeldCamera", Enum.RenderPriority.Camera.Value, function()
		camera.CFrame = char.Head.CFrame
	end)
	
	tweenBack.Completed:Wait()
	rService:UnbindFromRenderStep("WeldCamera")
end
1 Like

I would do this using this offset method which keeps the original default player scripts CFrame.

Tweenservice should be used with a CFvalue if you only want to modify the rotation and not the position of the CFrame which causes the disconnect.


local TweenService = game:GetService("TweenService")
local cam = workspace.CurrentCamera

--cam.CameraType = Enum.CameraType.Scriptable

local oldOffset = CFrame.new() -- Don't edit this!
local offset = CFrame.new()

-- (Optional): Will accumulate the time in seconds since the script started
local t = 0

game:GetService("RunService"):BindToRenderStep("Camera", 205, function(delta)
	-- (Optional): Accumulate the time in seconds
	t += delta
	-- Cancel out the offset we applied in the previous frame
	cam.CFrame *= oldOffset:Inverse()
	-- Apply the new offset
	cam.CFrame *= offset
	-- Store the offset we have applied so we cancel it in the next frame
	oldOffset = offset
	-- Update the offset that will applied!
	--offset = CFrame.fromOrientation(math.sin(0), math.sin(0), math.rad(45))  --You can change this however you want!
	-- Proof (Optional): You can update the original cframe without affecting the offset
	
	local _,_, z = offset:ToOrientation()
	cam.CFrame *= CFrame.fromOrientation(0, 0, z) --Z offset applied directly since default camera overides
end)


local cfValue = Instance.new("CFrameValue")
cfValue.Changed:Connect(function()
	offset = cfValue.Value
end)

local tweenParams = TweenInfo.new(
	1,
	Enum.EasingStyle.Back,
	Enum.EasingDirection.InOut
)

--You can adjust the tween settings here, this one is going for a bump offset then resets to 0
while true do
	local tweenGoal = {
		Value = CFrame.new()
	}

	local tweenBack = TweenService:Create(cfValue, tweenParams, tweenGoal)	
	cfValue.Value = CFrame.Angles(math.rad(20), math.rad(-30), 0)
	tweenBack:Play()
	tweenBack.Completed:Wait()
	task.wait()--emergency wait not needed
end
1 Like

okay… just one little question

what exactly is 205??

1 Like

205 is there to make the script run after the default camera script so you can add something cool like camera roll on the Z axis since camera control is at 200.

Either way it will still set the Z roll to 0 every frame as thats the default.

2 Likes

okay uh, the camera does stick to the head now, but it kind of flings the camera upwards;


i tried my best to “import” the code you gave me into mine, but let me know if there are any issues

-- Tables;
local cameraOffsets = {
	MELEE = CFrame.Angles(math.rad(10), math.rad(-10), 0),
	GUN = CFrame.Angles(math.rad(20), math.rad(10), 0),
	CONSUMABLE = CFrame.Angles(math.rad(15), math.rad(10), 0)
}

-- Values crucial for those camera tweaks;
local oldOffset = CFrame.new()
local offset = CFrame.new()

local cfValue = Instance.new("CFrameValue")

-- Functions;

local function SetCollisionGroup(children, group)
	for i = 1, #children do
		local child = children[i]

		if child:IsA("BasePart") then
			child.CollisionGroup = group
		end

		SetCollisionGroup(child:GetChildren(), group)
	end
end

local function CameraTwitchOnEquip(weapon: Tool)
	local cameraOffset = cameraOffsets[weapon.WeaponType.Value]
	
	camera.CFrame = camera.CFrame * cameraOffset -- Apply the offset before tweening;
	
	local tweenParams = TweenInfo.new(
		0.25,
		Enum.EasingStyle.Back,
		Enum.EasingDirection.Out
	)
	
	local tweenGoal = {
		Value = cameraOffset
	}
	
	local tweenBack = tService:Create(cfValue, tweenParams, tweenGoal)	
	
	cfValue.Changed:Connect(function()
		offset = cfValue.Value
	end)
	
	tweenBack:Play()
	
	rService:BindToRenderStep("WeldCamera", 205, function()
		camera.CFrame *= oldOffset:Inverse()
		camera.CFrame *= offset
		oldOffset = offset
		
		camera.CFrame = camera.CFrame * offset
	end)
	
	tweenBack.Completed:Wait()
	rService:UnbindFromRenderStep("WeldCamera")
end
1 Like

Second line should be the issue since you are applying offset CFrame twice doubling all the CFrame.

Try removing the second *offset. I did a weird thing that is not needed for Z axis I believe.

		camera.CFrame = camera.CFrame * offset
1 Like

now the “offset” is always random (i think? idk this is really confusing), and the camera never goes back to its original position despite me tweening it that way :((((


local function CameraTwitchOnEquip(weapon: Tool)
	local cameraOffset = cameraOffsets[weapon.WeaponType.Value]
	local startingCamPos = camera.CFrame
	
	camera.CFrame = camera.CFrame * cameraOffset -- Apply the offset before tweening;
	
	local tweenParams = TweenInfo.new(
		0.25,
		Enum.EasingStyle.Back,
		Enum.EasingDirection.Out
	)
	
	local tweenGoal = {
		Value = startingCamPos
	}
	
	local tweenBack = tService:Create(cfValue, tweenParams, tweenGoal)	
	
	cfValue.Changed:Connect(function()
		offset = cfValue.Value
	end)
	
	tweenBack:Play()
	
	rService:BindToRenderStep("WeldCamera", 205, function()
		camera.CFrame *= oldOffset:Inverse()
		camera.CFrame *= offset
		oldOffset = offset
		
	end)
	
	tweenBack.Completed:Wait()
	rService:UnbindFromRenderStep("WeldCamera")
end


i also assume this is the line you wanted me to delete D:

1 Like

okay i wasn’t home for like half the day but i managed to semi-fix it

right now, the camera does NOT tween back to its original position, idk why :((

-- Tables;
local cameraOffsets = {
	MELEE = CFrame.Angles(math.rad(3), math.rad(-3), 0),
	GUN = CFrame.Angles(math.rad(5), math.rad(5), 0),
	CONSUMABLE = CFrame.Angles(math.rad(2), math.rad(2), 0)
}

-- Values crucial for those damn camera tweaks;
local oldOffset = CFrame.new()
local offset = CFrame.new()

local cfValue = Instance.new("CFrameValue")

-- Functions;

local function SetCollisionGroup(children, group) -- Ignore this function!!!
	for i = 1, #children do
		local child = children[i]

		if child:IsA("BasePart") then
			child.CollisionGroup = group
		end

		SetCollisionGroup(child:GetChildren(), group)
	end
end

local function CameraTwitchOnEquip(weapon: Tool)
	local cameraOffset = cameraOffsets[weapon.WeaponType.Value]
	local startCamCFrame = camera.CFrame
	
	camera.CFrame = camera.CFrame * cameraOffset -- Apply the offset before tweening;
	
	local tweenParams = TweenInfo.new(
		0.25,
		Enum.EasingStyle.Back,
		Enum.EasingDirection.Out
	)
	
	local tweenGoal = {
		Value = CFrame.new()
	}
	
	local tweenBack = tService:Create(cfValue, tweenParams, tweenGoal)	
	
	cfValue.Changed:Connect(function()
		offset = cfValue.Value
	end)
	
	tweenBack:Play()
	
	rService:BindToRenderStep("WeldCamera", 205, function()
		camera.CFrame *= oldOffset:Inverse()
		camera.CFrame *= offset
		oldOffset = offset		
	end)
	
	tweenBack.Completed:Wait()
	rService:UnbindFromRenderStep("WeldCamera")
end
1 Like