So lets say I was shooting my gun and the max recoil of the camera would be moving 3 up so kind of like Camera.CFrame=Camera.CFrame*CFrame.Angles(math.rad(1),0,0)) and everytime you tapped fire it would move 1 up and then the camera would stop going up after it moves up 3. -- How would I detect this?
Then how would I return the Camera's position back to the last position before the person shot his gun?
I tried using for loops, counters that stopped camera movement after it moved up 3, and others, but they all failed at the end. Thank you for answering if you did, really appreciate it!
The common way this is dealt with is through springs. This allow the game coder to set some values regarding how the spring moves and then update the target. This allows you to change the spring target dynamically and not have to worry about the for loop timing or other animations.
There's a wiki article on this topic, that gives a broad overview of the concept that can be read here, but to really understand how I got to the code I'm about to post you'll need to do some calculus.
-- module local spring = {}; local spring_mt = {__index = spring}; function spring.new(position, velocity, zeta, omega) local self = {}; self.position = position; self.velocity = velocity; self.zeta = zeta; self.omega = omega; self.target = position; return setmetatable(self, spring_mt); end; function spring:update(dt) if (self.zeta >= 1) then return; end; if (self.zeta < 0) then self.zeta = 0; end; local x0 = self.position - self.target; local omegaZeta = self.omega*self.zeta; local alpha = self.omega*math.sqrt(1-self.zeta*self.zeta); local exp = math.exp(-dt*omegaZeta); local cos = math.cos(dt*alpha); local sin = math.sin(dt*alpha); local c2 = (self.velocity+x0*omegaZeta) / alpha; self.position = self.target + exp*(x0*cos + c2*sin); self.velocity = -exp*((x0*omegaZeta - c2*alpha)*cos + (x0*alpha + c2*omegaZeta)*sin); end; return spring;
With that we can easily set targets and update them properly with a time step.
Here's a very simple example wherein I use the spring to bring the angle back down, but potentially you also want to use it to go up too.
local mouse = game.Players.LocalPlayer:GetMouse(); local camera = game.Workspace.CurrentCamera; local part = game.Workspace.Part; local spring = require(game.Workspace.Spring); local s = spring.new(0, 0, 0.6, 10); mouse.Button1Down:connect(function() s.position = 10; -- up angle end); game:GetService("RunService").RenderStepped:connect(function(dt) s:update(dt); part.CFrame = camera.CFrame * CFrame.Angles(math.rad(s.position), 0, 0) * CFrame.new(1, -1, -3); end)
Hopefully you get the jist!