Scripting Helpers is winding down operations and is now read-only. More info→
Ad
Log in to vote
2

How would I set Camera recoil and then return back to its last position?

Asked by 6 years ago

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!

1 answer

Log in to vote
0
Answered by
EgoMoose 802 Moderation Voter
6 years ago

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!

0
Man, gotta wait 2 years to get in Calculus but your answer seems right so I'll accept it. Thank you. Mr_MilkysButler 47 — 6y
Ad

Answer this question