I found this open sourced module which creates a spring effect on the camera, everything works fine until I have few concerns:
You might want to check out the file with the module that I’ve modified for a clearer picture: SpringPhysicsCamera.rbxl (19.4 KB)
Or copy the code and create this structure if you don’t want to download files:
Code
Local Script:
local SpringCam = require(script.Parent:WaitForChild("CameraHandler"))
wait(5)
SpringCam:accelerate(0.25, 20, math.rad(5), 0, math.rad(130)) -- Damper, Speed, X,Y,Z
CameraHandler:
local physics = require(script.PhysicsModule)
local cam = {}
cam.current = workspace.CurrentCamera
cam.recoil = {}
cam.recoil.x = nil
cam.recoil.y = nil
cam.recoil.z = nil
function cam:accelerate(damper,speed,x,y,z)
if x then
cam.recoil.x = physics.new{d=damper;s=speed;}
cam.recoil.x.impulse(x)
end
if y then
cam.recoil.y = physics.new{d=damper;s=speed;}
cam.recoil.y.impulse(y)
end
if z then
cam.recoil.z = physics.new{d=damper;s=speed;}
cam.recoil.z.impulse(z)
end
end
local function updatecam()
if cam.recoil.x and cam.recoil.y and cam.recoil.z then
cam.current.CoordinateFrame = cam.current.CoordinateFrame*CFrame.Angles(cam.recoil.x.p(),cam.recoil.y.p(),cam.recoil.z.p())
end
end
game:GetService("RunService"):BindToRenderStep("RecoilCam",2000,function()
updatecam()
end)
return cam
Physics Module:
local physics = {}
local tick = tick
local setmt = setmetatable
local sin = math.sin
local cos = math.cos
local atan2 = math.atan2
local tan = math.tan
local e = 2.718281828459045
function physics.new(data)
local c0,c1
local t0
local d,s
local target
local cd
if data then
c0,c1=0,0
t0=tick()
d,s=data.d,data.s
target=0
cd=0
else
c0,c1=0,0
t0=tick()
d,s=1,1
target=0
cd=0
end
local function position()
local t=tick()
local sx=s*(t-t0)
if d==1 then
return (c0+c1*sx)/e^sx+target
else
return (c0*cos(cd*sx)+c1*sin(cd*sx))/e^(d*sx)+target
end
end
local function velocity()
local t=tick()
local sx=s*(t-t0)
if d==1 then
return (c1*(s-sx)-c0)/e^sx
else
return s*((cd*c1-c0*d)*cos(cd*sx)-(cd*c0+c1*d)*sin(cd*sx))/e^(d*sx)
end
end
return {
impulse=function(v)
local p0,v0=position(),(velocity()+v)/s
t0=tick()
c0=p0-target
if d==1 then
c1=v0+c0
else
cd=(1-d*d)^0.5
c1=(v0+c0*d)/cd
end
end;
p=position;
}
end
return physics
Play it in studio and the camera will shake after 5 seconds
It includes 3 scripts:
- Local Script > The one who trigger the camera module
- CameraHandler Module Script > Receives the signal from Local script and trigger the physics module script for calculations which returns a function and it will be stored in a table
cam.recoil
. Then call the returned function will return the actual camera angle. A render step will check is the angle presents and set the camera’s cframe. - PhysicsModule Module Script > For all the mathematical calculations (I didn’t modify it much)
My concern is how do I detect when the shake is done? It’s a complicated strucutre which doesn’t yield or return anything when the shake is called (unlike TweenService with Tween.Completed).
I tried methods like comparing values but it doesn’t work. Maybe there’s a way to get the shake total time and apply wait(time) to it but I can’t really figure it out.
Basicially I want the function updatecam()
(which set the camera’s cframe) to stop running after the shake, any ideas?