How do I create a camera recoil effect without using a Scriptable camera?

I’m trying to make a recoil effect for a weapon I’m making, here’s what I tried so far:

  • Using Camera:Interpolate
  • Using TweenService to tween the Camera

What I want it to do is go up a little bit and then return to its original position. However, when I want to use Camera:Interpolate or TweenService, I have to change the camera type to scriptable. However, whenever I change it to scriptable, the camera unattaches from the character.

I want it so it makes the camera go up a little bit, then returns to its original state, without changing the camera type to Scriptable or at least changing it, but somehow keeping it attached to the player.

Check this out.

1 Like

this is a script that makes the camera bounce.
i use it in a lot of my projects and it works perfectly fine

local CurrentSpread = 20
local CurrentRecoil = 1.3
local Stance = 0
local StanceSway = 1
local CameraSway = 1
local ABS, HUGE, FLOOR, CEIL = math.abs, math.huge, math.floor, math.ceil
local RAD, SIN, ATAN, COS = math.rad, math.sin, math.atan2, math.cos
local VEC3 = Vector3.new
local CF, CFANG = CFrame.new, CFrame.Angles
local INSERT = table.insert
local Camera = game.Workspace.CurrentCamera
function RAND(Min, Max, Accuracy)
	local Inverse = 1 / (Accuracy or 1)
	return (math.random(Min * Inverse, Max * Inverse) / Inverse)
end
local RecoilX = RAD(CurrentRecoil * RAND(1, 1.5, 0.1)) * StanceSway
local RecoilY = RAD(CurrentRecoil * RAND(-2, 2, 0.1)) * StanceSway
local RS = game:GetService("RunService").RenderStepped
local Selected = true
function RotCamera(RotX, RotY, SmoothRot, Duration)
	spawn(function()
		if SmoothRot then
			local TweenIndicator = nil
			local NewCode = math.random(-1e9, 1e9)
			if (not Camera:FindFirstChild("TweenCode")) then
				TweenIndicator = Instance.new("IntValue")
				TweenIndicator.Name = "TweenCode"
				TweenIndicator.Value = NewCode
				TweenIndicator.Parent = Camera
			else
				TweenIndicator = Camera.TweenCode
				TweenIndicator.Value = NewCode
			end
			
			local Step = math.min(1.5 / math.max(Duration, 0), 90)
			local X = 0
			while true do
				local NewX = X + Step
				X = (NewX > 90 and 90 or NewX)
				if TweenIndicator.Value ~= NewCode then break end
				if (not Selected) then break end
				
				local CamRot = Camera.CoordinateFrame - Camera.CoordinateFrame.p
				local CamDist = (Camera.CoordinateFrame.p - Camera.Focus.p).magnitude
				local NewCamCF = CF(Camera.Focus.p) * CamRot * CFANG(RotX / (90 / Step), RotY / (90 / Step), 0)
				Camera.CoordinateFrame = CF(NewCamCF.p, NewCamCF.p + NewCamCF.lookVector) * CF(0, 0, CamDist)
				
				if X == 90 then break end
				RS:wait()
			end
			
			if TweenIndicator.Value == NewCode then
				TweenIndicator:Destroy()
			end
		else
			local CamRot = Camera.CoordinateFrame - Camera.CoordinateFrame.p
			local CamDist = (Camera.CoordinateFrame.p - Camera.Focus.p).magnitude
			local NewCamCF = CF(Camera.Focus.p) * CamRot * CFANG(RotX, RotY, 0)
			Camera.CoordinateFrame = CF(NewCamCF.p, NewCamCF.p + NewCamCF.lookVector) * CF(0, 0, CamDist)
		end
	end)
end

use this to bounce the camera:

RotCamera(RecoilX, RecoilY, true, 0.06)
5 Likes

If you use RunService:BindToRenderStep() to bind a function to run after Camera, you can easily modify the CFrame of the camera for that frame only without using Scriptable. Combine that with some simple harmonic motion (think glorified math.sin) and you should be good :slight_smile:

3 Likes