Tween the orientation of the camera without changing the position

I’m trying to use tweens to create a recoil affect for guns.

I am able to tween the orientation of the camera, but when I do the camera locks in world space and doesn’t follow the player until the tween has completed.

I found a code source that is able to do the opposite, which is, tweening the position of the camera without changing the orientation but I was unable to find a way to invert this.

Here is a my code sample. And provided is a video of what is happening.
robloxapp-20240808-1139437.wmv (473.7 KB)

local tweenInfo = TweenInfo.new(
	0.5,
	Enum.EasingStyle.Linear,
	Enum.EasingDirection.InOut,
	0,
	false,
	0
)
local tween = tweenService:Create(camera,tweenInfo,{CFrame = camera.CFrame * CFrame.Angles(math.rad(5),0,0)})
tween:Play()

Try using CFrame:Lerp instead of tweenservice.

local tweenInfo = TweenInfo.new(
	0.5,
	Enum.EasingStyle.Linear,
	Enum.EasingDirection.InOut,
	0,
	false,
	0
)

local function recoilCamera(tweeninfo, waitTime)
    local oldCameraType = workspace.CurrentCamera.CameraType
    local tween = tweenService:Create(camera,tweenInfo,{CFrame = camera.CFrame * 
    CFrame.Angles(math.rad(5),0,0)})
    workspace.Camera.CameraType = Enum.CameraType.Scriptable
    tween:Play()
    Wait(waitTime)
    workspace.Camera.CameraType = oldCameraType
end

recoilCamera(tweenInfo, 1)

Unfortunately, this code sample has the same issue. I checked to make sure that the camera type was being changed from what is was (fixed) to scriptable. However, the camera still freezes in place.

I am unsure how to use lerp. This was my attempt.

camera.CFrame:Lerp(camera.CFrame * CFrame.Angles(math.rad(5),0,0), 1)

I would create a new CFrameValue and tween its orientation:

local cframeValue = Instance.new("CFrameValue")
local tween = TweenService:Create(cframeValue, TweenInfo.new(), {
    Value = CFrame.Angles(math.rad(5), 0, 0),
})
tween:Play()

Then you can update the Camera:

RunService.RenderStepped:Connect(function()
    camera.CFrame *= cframeValue.Value
end)
1 Like
local tweenInfo = TweenInfo.new(
	0.5,
	Enum.EasingStyle.Linear,
	Enum.EasingDirection.InOut,
	0,
	false,
	0
)

local function recoilCamera(tweeninfo, waitTime)
	local oldCameraType = workspace.CurrentCamera.CameraType
	local oldcf = camera.CFrame
	local oldpos = character.Head.Position
	
	local tween = tweenService:Create(camera,tweenInfo,{CFrame = camera.CFrame * 
		CFrame.Angles(math.rad(5),0,0)})
	workspace.Camera.CameraType = Enum.CameraType.Scriptable
	tween:Play()
	
	wait(waitTime)
	
	local characterDistance:number = (oldpos - oldcf.Position).Magnitude
	local Distance = CFrame.new(0, 0, characterDistance)
	local Rot = oldcf.Rotation -- Copy of the CFrame but without any position
	local Point = CFrame.new(character.Head.Position) 
	local tween2 = tweenService:Create(camera,tweenInfo,{CFrame = Point * Rot * Distance})
	
	tween2:Play()
	tween2.Completed:Wait()
	workspace.Camera.CameraType = oldCameraType
end

recoilCamera(tweenInfo, 3) -- You can adjust this number right here for the time that takes for the camera to go back

I tested it by myself and I think it should work for you too

robloxapp-20240808-1244364.wmv (567.5 KB)
Attached is a video clip using your code sample.
I can see what it was that your trying to do. I will try to modify it to get it to work. I’m not sure if I have other code that might be affecting it. Thank you for the help.

Thank-you for the reply. You were exactly correct for thinking to use the CFrame Value. I have found the solution thanks to you!
I first created a CFrameValue and made it equal to the Camera’s CFrame.
Then I tweened the CFrameValue (orientation only) and used bindToRenderStepped to constantly update the camera’s CFrame to the CFrameValue. Once the tween is completed the unbindToRenderStepped ends the loop.


local tweenInfo = TweenInfo.new(
	0.5,
	Enum.EasingStyle.Linear,
	Enum.EasingDirection.InOut,
	0,
	false,
	0
)
local CFrameValue = Instance.new("CFrameValue")
CFrameValue.Value = camera.CFrame

local tween = tweenService:Create(CFrameValue,tweenInfo,{Value = CFrameValue.Value * CFrame.Angles(math.rad(5),0,0)})
tween:Play()

runService:BindToRenderStep("recoilTween", 1, function()
	camera.CFrame = CFrameValue.Value
end)
tween.Completed:Connect(function()
	runService:UnbindFromRenderStep("recoilTween")
end)
1 Like

Here’s another way

local RunService = game:GetService("RunService")
local TweenService = game:GetService("TweenService")

local elapsed = 0
local duration = 0.5
local maxDistance = 5
local lastDistance = 0
local camera = workspace.CurrentCamera
local connection

connection = RunService.Heartbeat:Connect(function(deltaTime)
	elapsed += deltaTime
	if elapsed >= duration then
		connection:Disconnect()
		camera.CFrame *= CFrame.Angles(math.rad(maxDistance - lastDistance), 0, 0)
	else
		local alpha = TweenService:GetValue(elapsed/duration, Enum.EasingStyle.Back, Enum.EasingDirection.InOut)
		local distance = alpha * maxDistance

		camera.CFrame *= CFrame.Angles(math.rad(distance - lastDistance), 0, 0)
		lastDistance = distance
	end
end)

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.