I’m trying to set up a sniper scope, but I have three scripts in my game that are required for the custom camera manipulation, all of which that have stopped me in the past from making it through regular methods. However, I recently thought it would be better if the camera just zoomed in when the scope is active (holding down the right mouse button), and returned to normal when the scope isn’t (releasing the right mouse button).
How would I go about doing this?
TL;DR: I want to make a script that zooms in the camera when an input begins, and zooms out when it ends.
Yes, however last time I ran into a problem in which activating the scope in certain ways causes the camera to be forever zoomed in, or the controls to be inverted (holding rmb zooms out, releasing zooms in)
Activating the scope multiple times in quick succession (sometimes)
Activating the scope, unequipping the tool, re-equipping the tool and activating the scope again (always)
The video below will demonstrate what I mean (done in a test place, not in-game)
This could either be a result of the tweening of the FOV, or something to do with the RunService connection. I’m not sure though
I have managed to create a fixed version, that doesn’t have any issues (that I know of)
However I still want to make a smooth animation between aiming and not aiming
Here’s the code for the gun:
-- SERVICES --
local Players = game:GetService('Players')
local RuS = game:GetService('RunService')
local UIS = game:GetService('UserInputService')
local camera = workspace.CurrentCamera
-- PLAYER VARIABLES --
local Player = Players.LocalPlayer
local hum = Player.Character:WaitForChild('Humanoid')
local mouse = Player:GetMouse()
-- VALUES --
local Holdable, Holding = true, false -- if holdable is true, the weapon will be (semi)automatic
local Aimable, Aiming = true, false
local debounce = false
-- ANIMATIONS --
local tool = script.Parent
local shoot = script.Parent:WaitForChild('Shoot')
local ShootAnims = tool.ShootAnims
local Hold = tool:WaitForChild('Hold')
local Shoot1 = ShootAnims:WaitForChild('Shoot1')
local Shoot2 = ShootAnims:WaitForChild('Shoot2')
local Shoot3 = ShootAnims:WaitForChild('Shoot3')
local holdanim = hum:LoadAnimation(Hold)
local shootanim1 = hum:LoadAnimation(Shoot1)
local shootanim2 = hum:LoadAnimation(Shoot2)
local shootanim3 = hum:LoadAnimation(Shoot3)
function Send()
shoot:FireServer({Position = mouse.Hit.Position})
end
tool.Activated:Connect(function()
Holding = true
if Holdable then
local Run
Run = RuS.Heartbeat:Connect(function()
if not Holding then
Run:Disconnect()
end
Send()
end)
else
Send()
end
end)
tool.Deactivated:Connect(function()
Holding = false
end)
tool.Equipped:Connect(function()
InputBeganRun = nil
InputEndedRun = nil
holdanim:Play()
if Aimable then
InputBeganRun = UIS.InputBegan:Connect(function(input, gameprocess)
if not gameprocess then
if input.UserInputType == Enum.UserInputType.MouseButton2 then
Aiming = true
if Aimable then
ScopeRun = nil
ScopeRun = RuS.Heartbeat:Connect(function()
if not Aiming then
ScopeRun:Disconnect()
end
camera.FieldOfView = 40
end)
end
end
end
end)
end
if Aimable then
InputEndedRun = UIS.InputEnded:Connect(function(input, gameprocess)
if not gameprocess then
if input.UserInputType == Enum.UserInputType.MouseButton2 then
Aiming = false
task.wait(.05)
camera.FieldOfView = 86
end
end
end)
end
end)
tool.Unequipped:Connect(function()
Holding = false
Aiming = false
camera.FieldOfView = 86
InputBeganRun:Disconnect()
InputEndedRun:Disconnect()
ScopeRun:Disconnect()
holdanim:Stop()
shootanim1:Stop()
shootanim2:Stop()
shootanim3:Stop()
end)
And here’s the snippet of code that makes the scoping work:
tool.Equipped:Connect(function()
InputBeganRun = nil
InputEndedRun = nil
holdanim:Play()
if Aimable then
InputBeganRun = UIS.InputBegan:Connect(function(input, gameprocess)
if not gameprocess then
if input.UserInputType == Enum.UserInputType.MouseButton2 then
Aiming = true
if Aimable then
ScopeRun = nil
ScopeRun = RuS.Heartbeat:Connect(function()
if not Aiming then
ScopeRun:Disconnect()
end
camera.FieldOfView = 40
end)
end
end
end
end)
end
if Aimable then
InputEndedRun = UIS.InputEnded:Connect(function(input, gameprocess)
if not gameprocess then
if input.UserInputType == Enum.UserInputType.MouseButton2 then
Aiming = false
task.wait(.05)
camera.FieldOfView = 86
end
end
end)
end
end)
tool.Unequipped:Connect(function()
Holding = false
Aiming = false
camera.FieldOfView = 86
InputBeganRun:Disconnect()
InputEndedRun:Disconnect()
ScopeRun:Disconnect()
holdanim:Stop()
shootanim1:Stop()
shootanim2:Stop()
shootanim3:Stop()
end)
Right now, it instantly zooms in and out by setting the camera FOV to whatever it needs to be, without any transition, but how would I go about making it so that it tweens the camera’s FOV, rather than having it instantly zoom in?
UPDATE 2:
I fixed it by just swapping out the ‘camera.FieldOfView’ with a tween that sets the field of view. Guess I didn’t need to overthink it
Thanks for your help anyway!
Full code if anyone’s interested (in local script):
-- SERVICES --
local Players = game:GetService('Players')
local RuS = game:GetService('RunService')
local UIS = game:GetService('UserInputService')
local TS = game:GetService('TweenService')
local camera = workspace.CurrentCamera
-- PLAYER VARIABLES --
local Player = Players.LocalPlayer
local char = Player.Character or Player.CharacterAdded:Wait()
local hum = char:WaitForChild('Humanoid')
local mouse = Player:GetMouse()
-- VALUES/CONFIG --
local Holding = false
local Aiming = false
local debounce = false
local tool = script.Parent
config = {
Holdable = script:GetAttribute('Holdable'), -- if holdable is true, the weapon will be (semi)automatic
Aimable = script:GetAttribute('Aimable'), -- if aimable is true, the weapon will have a scope
zoomFOV = script:GetAttribute('zoomFOV')
}
local TInfo = TweenInfo.new(
0.3,
Enum.EasingStyle.Exponential,
Enum.EasingDirection.Out,
0,
false,
0
)
-- ANIMATIONS --
local shoot = script.Parent:WaitForChild('Shoot')
local ShootAnims = tool.ShootAnims
local Hold = tool:WaitForChild('Hold')
local Shoot1 = ShootAnims:WaitForChild('Shoot1')
local Shoot2 = ShootAnims:WaitForChild('Shoot2')
local Shoot3 = ShootAnims:WaitForChild('Shoot3')
local holdanim = hum:LoadAnimation(Hold)
local shootanim1 = hum:LoadAnimation(Shoot1)
local shootanim2 = hum:LoadAnimation(Shoot2)
local shootanim3 = hum:LoadAnimation(Shoot3)
function Send()
shoot:FireServer({Position = mouse.Hit.Position})
end
tool.Activated:Connect(function()
Holding = true
if config.Holdable then
local Run
Run = RuS.Heartbeat:Connect(function()
if not Holding then
Run:Disconnect()
end
Send()
end)
else
Send()
end
end)
tool.Deactivated:Connect(function()
Holding = false
end)
tool.Equipped:Connect(function()
InputBeganRun = nil
InputEndedRun = nil
holdanim:Play()
if config.Aimable then
InputBeganRun = UIS.InputBegan:Connect(function(input, gameprocess)
if not gameprocess then
if input.UserInputType == Enum.UserInputType.MouseButton2 then
Aiming = true
if config.Aimable then
ScopeRun = nil
TS:Create(camera, TInfo, {FieldOfView = config.zoomFOV}):Play()
ScopeRun = RuS.Heartbeat:Connect(function()
if not Aiming then
ScopeRun:Disconnect()
end
camera.FieldOfView = config.zoomFOV
end)
end
end
end
end)
end
if config.Aimable then
InputEndedRun = UIS.InputEnded:Connect(function(input, gameprocess)
if not gameprocess then
if input.UserInputType == Enum.UserInputType.MouseButton2 then
Aiming = false
task.wait(.05)
TS:Create(camera, TInfo, {FieldOfView = 86}):Play()
end
end
end)
end
end)
tool.Unequipped:Connect(function()
Holding = false
Aiming = false
TS:Create(camera, TInfo, {FieldOfView = 86}):Play()
if InputBeganRun ~= nil then
InputBeganRun:Disconnect()
end
if InputEndedRun ~= nil then
InputEndedRun:Disconnect()
end
if ScopeRun ~= nil then
ScopeRun:Disconnect()
end
holdanim:Stop()
shootanim1:Stop()
shootanim2:Stop()
shootanim3:Stop()
end)
UIS.InputBegan:Connect(function(input, gameprocess)
if not gameprocess then
if input.UserInputType == Enum.UserInputType.Keyboard then
if input.KeyCode == Enum.KeyCode.E and debounce == false then
debounce = true
tool.Grip = CFrame.Angles(0, math.rad(90), 0)
task.wait(1)
tool.Grip = CFrame.new(Vector3.new(0.039, 0, -0.295)) * CFrame.Angles(0, math.rad(126), 0)
task.wait(1.1)
debounce = false
end
end
end
end)