local c={}c.__index=c c.__aeroPreventStart=true local K=debug.profilebegin local w=debug.profileend local Z="\067\097\109\101\114\097\083\104\097\107\101\114\085\112\100\097\116\101"local m=Vector3.new local D=CFrame.new local C=CFrame.Angles local P=math.rad local n=m()local N=require(script.CameraShakeInstance)local J=N.CameraShakeState local t=m(.15,.15,.15)local H=m(1,1,1)c.CameraShakeInstance=N c.Presets=require(script.CameraShakePresets)function c.new(K,w)assert(type(K)=="\110\117\109\098\101\114","\082\101\110\100\101\114\080\114\105\111\114\105\116\121 \109\117\115\116 \098\101 \097 \110\117\109\098\101\114 \040\101\046\103\046\058 \069\110\117\109\046\082\101\110\100\101\114\080\114\105\111\114\105\116\121\046\067\097\109\101\114\097\046\086\097\108\117\101\041")assert(type(w)=="\102\117\110\099\116\105\111\110","\067\097\108\108\098\097\099\107 \109\117\115\116 \098\101 \097 \102\117\110\099\116\105\111\110")local Z=setmetatable({_running=false;_renderName="\067\097\109\101\114\097\083\104\097\107\101\114";_renderPriority=K;_posAddShake=n;_rotAddShake=n,_camShakeInstances={},_removeInstances={};_callback=w},c)return Z end function c.Start(c)if c._running then return end c._running=true local m=c._callback;(game:GetService("\082\117\110\083\101\114\118\105\099\101")):BindToRenderStep(c._renderName,c._renderPriority,function(D)K(Z)local C=c:Update(D)w()m(C)end)end function c.Stop(c)if not c._running then return end;(game:GetService("\082\117\110\083\101\114\118\105\099\101")):UnbindFromRenderStep(c._renderName)c._running=false end function c.Update(K,c)local w=n local Z=n local m=K._camShakeInstances for D=1,#m,1 do local C=m[D]local P=C:GetState()if P==J.Inactive and C.DeleteOnInactive then K._removeInstances[#K._removeInstances+1]=D elseif P~=J.Inactive then w=w+C:UpdateShake(c)*C.PositionInfluence Z=Z+C:UpdateShake(c)*C.RotationInfluence end end for c=#K._removeInstances,1,-1 do local w=K._removeInstances[c]table.remove(m,w)K._removeInstances[c]=nil end return(D(w)*C(0,P(Z.Y),0))*C(P(Z.X),0,P(Z.Z))end function c.Shake(K,c)assert(type(c)=="\116\097\098\108\101"and c._camShakeInstance,"\083\104\097\107\101\073\110\115\116\097\110\099\101 \109\117\115\116 \098\101 \111\102 \116\121\112\101 \067\097\109\101\114\097\083\104\097\107\101\073\110\115\116\097\110\099\101")K._camShakeInstances[#K._camShakeInstances+1]=c return c end function c.ShakeSustain(K,c)assert(type(c)=="\116\097\098\108\101"and c._camShakeInstance,"\083\104\097\107\101\073\110\115\116\097\110\099\101 \109\117\115\116 \098\101 \111\102 \116\121\112\101 \067\097\109\101\114\097\083\104\097\107\101\073\110\115\116\097\110\099\101")K._camShakeInstances[#K._camShakeInstances+1]=c c:StartFadeIn(c.fadeInDuration)return c end function c.ShakeOnce(C,c,K,w,Z,m,D)local P=N.new(c,K,w,Z)P.PositionInfluence=typeof(m)=="\086\101\099\116\111\114\051"and m or t P.RotationInfluence=typeof(D)=="\086\101\099\116\111\114\051"and D or H C._camShakeInstances[#C._camShakeInstances+1]=P return P end function c.StartShake(D,c,K,w,Z,m)local C=N.new(c,K,w)C.PositionInfluence=typeof(Z)=="\086\101\099\116\111\114\051"and Z or t C.RotationInfluence=typeof(m)=="\086\101\099\116\111\114\051"and m or H C:StartFadeIn(w)D._camShakeInstances[#D._camShakeInstances+1]=C return C end return c
-- Camera Shaker
-- Crazyman32
-- February 26, 2018

--[[
	
	CameraShaker.CameraShakeInstance
	
	cameraShaker = CameraShaker.new(renderPriority, callbackFunction)
	
	CameraShaker:Start()
	CameraShaker:Stop()
	CameraShaker:Shake(shakeInstance)
	CameraShaker:ShakeSustain(shakeInstance)
	CameraShaker:ShakeOnce(magnitude, roughness [, fadeInTime, fadeOutTime, posInfluence, rotInfluence])
	CameraShaker:StartShake(magnitude, roughness [, fadeInTime, posInfluence, rotInfluence])
	
	
	
	EXAMPLE:
	
		local camShake = CameraShaker.new(Enum.RenderPriority.Camera.Value, function(shakeCFrame)
			camera.CFrame = playerCFrame * shakeCFrame
		end)
		
		camShake:Start()
		
		-- Explosion shake:
		camShake:Shake(CameraShaker.Presets.Explosion)
		
		wait(1)
		
		-- Custom shake:
		camShake:ShakeOnce(3, 1, 0.2, 1.5)

		wait(1)

		-- Sustained shake:
		local swayShakeInstance = CameraShaker.Presets.GentleSway
		camShake:ShakeSustain(swayShakeInstance)
		
		wait(3)

		-- Sustained shake fadeout:
		swayShakeInstance:StartFadeOut(3)

		-- "CameraShaker.Presets.GentleSway" or any other preset
		-- will always return a new ShakeInstance. If you want
		-- to fade out a previously sustained ShakeInstance, you
		-- will need to assign it to a variable before sustaining it.

	
	
	NOTE:
	
		This was based entirely on the EZ Camera Shake asset for Unity3D. I was given written
		permission by the developer, Road Turtle Games, to port this to Roblox.
		
		Original asset link: https://assetstore.unity.com/packages/tools/camera/ez-camera-shake-33148
	
	
--]]



local CameraShaker = {}
CameraShaker.__index = CameraShaker
CameraShaker.__aeroPreventStart = true

local profileBegin = debug.profilebegin
local profileEnd = debug.profileend
local profileTag = "CameraShakerUpdate"

local V3 = Vector3.new
local CF = CFrame.new
local ANG = CFrame.Angles
local RAD = math.rad
local v3Zero = V3()

local CameraShakeInstance = require(script.CameraShakeInstance)
local CameraShakeState = CameraShakeInstance.CameraShakeState

local defaultPosInfluence = V3(0.15, 0.15, 0.15)
local defaultRotInfluence = V3(1, 1, 1)


CameraShaker.CameraShakeInstance = CameraShakeInstance
CameraShaker.Presets = require(script.CameraShakePresets)


function CameraShaker.new(renderPriority, callback)
	
	assert(type(renderPriority) == "number", "RenderPriority must be a number (e.g.: Enum.RenderPriority.Camera.Value)")
	assert(type(callback) == "function", "Callback must be a function")
	
	local self = setmetatable({
		_running = false;
		_renderName = "CameraShaker";
		_renderPriority = renderPriority;
		_posAddShake = v3Zero;
		_rotAddShake = v3Zero;
		_camShakeInstances = {};
		_removeInstances = {};
		_callback = callback;
	}, CameraShaker)
	
	return self
	
end


function CameraShaker:Start()
	if (self._running) then return end
	self._running = true
	local callback = self._callback
	game:GetService("RunService"):BindToRenderStep(self._renderName, self._renderPriority, function(dt)
		profileBegin(profileTag)
		local cf = self:Update(dt)
		profileEnd()
		callback(cf)
	end)
end


function CameraShaker:Stop()
	if (not self._running) then return end
	game:GetService("RunService"):UnbindFromRenderStep(self._renderName)
	self._running = false
end


function CameraShaker:Update(dt)
	
	local posAddShake = v3Zero
	local rotAddShake = v3Zero
	
	local instances = self._camShakeInstances
	
	-- Update all instances:
	for i = 1,#instances do
		
		local c = instances[i]
		local state = c:GetState()
		
		if (state == CameraShakeState.Inactive and c.DeleteOnInactive) then
			self._removeInstances[#self._removeInstances + 1] = i
		elseif (state ~= CameraShakeState.Inactive) then
			posAddShake = posAddShake + (c:UpdateShake(dt) * c.PositionInfluence)
			rotAddShake = rotAddShake + (c:UpdateShake(dt) * c.RotationInfluence)
		end
		
	end
	
	-- Remove dead instances:
	for i = #self._removeInstances,1,-1 do
		local instIndex = self._removeInstances[i]
		table.remove(instances, instIndex)
		self._removeInstances[i] = nil
	end
	
	return CF(posAddShake) *
			ANG(0, RAD(rotAddShake.Y), 0) *
			ANG(RAD(rotAddShake.X), 0, RAD(rotAddShake.Z))
	
end


function CameraShaker:Shake(shakeInstance)
	assert(type(shakeInstance) == "table" and shakeInstance._camShakeInstance, "ShakeInstance must be of type CameraShakeInstance")
	self._camShakeInstances[#self._camShakeInstances + 1] = shakeInstance
	return shakeInstance
end


function CameraShaker:ShakeSustain(shakeInstance)
	assert(type(shakeInstance) == "table" and shakeInstance._camShakeInstance, "ShakeInstance must be of type CameraShakeInstance")
	self._camShakeInstances[#self._camShakeInstances + 1] = shakeInstance
	shakeInstance:StartFadeIn(shakeInstance.fadeInDuration)
	return shakeInstance
end


function CameraShaker:ShakeOnce(magnitude, roughness, fadeInTime, fadeOutTime, posInfluence, rotInfluence)
	local shakeInstance = CameraShakeInstance.new(magnitude, roughness, fadeInTime, fadeOutTime)
	shakeInstance.PositionInfluence = (typeof(posInfluence) == "Vector3" and posInfluence or defaultPosInfluence)
	shakeInstance.RotationInfluence = (typeof(rotInfluence) == "Vector3" and rotInfluence or defaultRotInfluence)
	self._camShakeInstances[#self._camShakeInstances + 1] = shakeInstance
	return shakeInstance
end


function CameraShaker:StartShake(magnitude, roughness, fadeInTime, posInfluence, rotInfluence)
	local shakeInstance = CameraShakeInstance.new(magnitude, roughness, fadeInTime)
	shakeInstance.PositionInfluence = (typeof(posInfluence) == "Vector3" and posInfluence or defaultPosInfluence)
	shakeInstance.RotationInfluence = (typeof(rotInfluence) == "Vector3" and rotInfluence or defaultRotInfluence)
	shakeInstance:StartFadeIn(fadeInTime)
	self._camShakeInstances[#self._camShakeInstances + 1] = shakeInstance
	return shakeInstance
end


return CameraShaker
