Now I don’t know how to do this since this is annoying, I have waited for 3-4 days without a solution and most solutions keep making me lose my mind every day counting up
local handler = {}
local fpsMT = {__index = handler}
local repS = game:GetService("ReplicatedStorage")
local tweenS = game:GetService("TweenService")
local spring = require(repS.modules.spring)
local function getBobbing(addition,speed,modifier)
return math.sin(tick()*addition*speed)*modifier
end
local function lerpNumber(a, b, t)
return a + (b - a) * t
end
function handler.new(weapons)
local self = {}
self.lerpValues = {}
self.loadAnims = {}
self.servAnims = {}
self.ammo = {}
self.disabled = false
self.equipped = false
self.reload = false
self.canFire = false
self.aiming = false
self.firing = false
self.vm = nil
self.cam = nil
self.char = nil
self.gunHandle = nil
self.lerpValues.aim = Instance.new("NumberValue")
self.lerpValues.equip = Instance.new("NumberValue")
self.lerpValues.run = Instance.new("NumberValue")
self.lerpValues.crouch = Instance.new("NumberValue")
self.lerpValues.numValues = {}
--spring stuff
self.springs = {}
self.springs.fireRecoil = spring.create()
self.springs.move = spring.create()
self.springs.run = spring.create()
self.springs.sway = spring.create()
self.springs.cam = spring.create()
return setmetatable(self,fpsMT)
end
function handler:equip(wepName)
if self.disabled then return end
if self.equipped then self:remove() end
local weapon = repS.weps:FindFirstChild(wepName)
if not weapon then return end
weapon = weapon:Clone()
self.vm = repS.vm:Clone()
for i,v in pairs(weapon:GetChildren()) do
v.Parent = self.vm
if v:IsA("BasePart") then
v.CanCollide = false
end
if v.Name == "GripPart" then
self.gunHandle = v
end
end
self.cam = workspace.CurrentCamera
self.char = game.Players.LocalPlayer.Character
self.vm.PrimaryPart.CFrame = CFrame.new(0,-100,0)
self.vm.PrimaryPart.wepM6d.Part1 = self.gunHandle
self.vm.Parent = self.cam
self.settings = require(self.vm.settings)
for i, v in self.settings.anims.vm do
local animation = Instance.new("Animation")
animation.Name = i
animation.AnimationId = v
self.loadAnims[animation.Name] = self.vm.Humanoid.Animator:LoadAnimation(animation)
end
self.wepName = wepName
self.ammo[wepName] = self.ammo[wepName] or (self.settings.ammo + 1)
self.loadAnims.idle:Play(0)
--[[self.loadAnims.idle = self.vm.Humanoid.Animator:LoadAnimation(self.settings.anims.vm.idle)
self.loadAnims.idle:Play(0)]]--
self.equipped = true
end
function handler:aim(toAim)
if self.disabled then return end
if not self.equipped then return end
self.aiming = toAim
if toAim then
local tweeningInformation = TweenInfo.new(1, Enum.EasingStyle.Quart,Enum.EasingDirection.Out)
local properties = { Value = 1 }
tweenS:Create(self.lerpValues.aim,tweeningInformation,properties):Play()
else
local tweeningInformation = TweenInfo.new(0.5, Enum.EasingStyle.Quart,Enum.EasingDirection.Out)
local properties = { Value = 0 }
tweenS:Create(self.lerpValues.aim,tweeningInformation,properties):Play()
end
end
function handler:reload()
if self.vm then
if self.aiming then self:aim(false) end
if self.canFire then self:fire(false) end
if self.reload then return end
self.reload = true
--self.ammo[self.wepName] = 0
self.loadAnims.reload:Play(0)
--if not self.equipped then return end
self.loadAnims.reload.Ended:Connect(function()
--self.ammo[self.wepName] = self.settings.firing.magCapacity
self.reload = false
end)
end
end
function handler:fire(tofire)
if self.disabled then return end
if not self.equipped then return end
if self.reload then return end
--if self.firing and tofire then return end
--if not self.canFire and tofire then return end
self.firing = tofire
if not tofire then return end
local function fire()
local sound = self.settings.sounds.fire:Clone()
sound.Parent = self.gunHandle.FireAttach
sound.PlayOnRemove = true
game:GetService("Debris"):AddItem(sound, .1)
self.loadAnims.fire:Play(0)
-- basically up recoil sideway shake
self.springs.fireRecoil:shove(Vector3.new(self.settings.fire.recoil, math.random(-.02,.02), -.06) * self.deltaTime * 60)
task.delay(0.15, function() --STILL applies to the metioned above
self.springs.fireRecoil:shove(Vector3.new(-(self.settings.fire.recoil/2), math.random(-.02,.02), .06) * self.deltaTime * 60)
end)
-- Muzzle flash
for _, v in pairs(self.gunHandle.FireAttach:GetChildren()) do
if v:IsA("ParticleEmitter") then
v:Emit(self.settings.fire.lifetime)
end
if v:IsA("SpotLight") then
v.Enabled = true
task.wait(.01)
v.Enabled = false
end
end
task.wait(60/self.settings.fire.rpm)
end
repeat
self.canFire = false
fire()
self.canFire = true
until not self.firing
end
--[[function handler:reload()
--if self.aiming then self:aim(false) end
--if self.firing then self:fire(false) end
--if self.reload then return end
self.reload = true
--self.ammo[self.wepName] = 0
self.loadAnims.reload:Play()
--if not self.equipped then return end
self.loadAnims.reload.Ended:Connect(function()
--self.ammo[self.wepName] = self.settings.firing.magCapacity
self.reload = false
end)
end]]--
function handler:remove()
self.vm:Destroy()
self.vm = nil
self.equipped = false
end
function handler:update(deltaTime)
if self.vm then
self.deltaTime = deltaTime
local idleOffset = self.vm.offset.idle.Value
local aimOffset = idleOffset:lerp(self.vm.offset.aim.Value, self.lerpValues.aim.Value)
local veloc = self.char.HumanoidRootPart.Velocity
local mouseDelta = game:GetService("UserInputService"):GetMouseDelta()
if self.aiming then mouseDelta = mouseDelta * .1 end
self.springs.sway:shove(Vector3.new(mouseDelta.x / 200,mouseDelta.y / 200)) --not sure if this needs deltaTime filtering
-- this makes the bobble faster.
local speed = .5
-- this makes the bobble do more. or something.
local modifier = .09
local movementSway = Vector3.new(getBobbing(10,speed,modifier),getBobbing(5,speed,modifier),getBobbing(5,speed,modifier))
-- if velocity is 0, then so will the walk cycle
self.springs.move:shove((movementSway / 25) * deltaTime * 60 * veloc.Magnitude)
local sway = self.springs.sway:update(deltaTime)
local walkCycle = self.springs.move:update(deltaTime)
local recoil = self.springs.fireRecoil:update(deltaTime)
local finalOffset = aimOffset
self.vm.PrimaryPart.CFrame = self.cam.CFrame
self.cam.CFrame = self.cam.CFrame * CFrame.Angles(recoil.x ,recoil.y ,recoil.z)
self.vm.PrimaryPart.CFrame = self.cam.CFrame:ToWorldSpace(finalOffset)
self.vm.PrimaryPart.CFrame = self.vm.PrimaryPart.CFrame:ToWorldSpace(CFrame.new(walkCycle.x / 2,walkCycle.y / 2,0))
self.vm.PrimaryPart.CFrame = self.vm.PrimaryPart.CFrame * CFrame.Angles(0,-sway.x,sway.y)
if self.aiming then
self.vm.PrimaryPart.CFrame = self.vm.PrimaryPart.CFrame * CFrame.Angles(0,walkCycle.y/8,walkCycle.x/8)
else
self.vm.PrimaryPart.CFrame = self.vm.PrimaryPart.CFrame * CFrame.Angles(0,walkCycle.y,walkCycle.x)
end
end
end
return handler
Local Script
-- input controller
local weaponHandler = require(game.ReplicatedStorage.modules.fps)
local velocity = require(game.ReplicatedStorage.modules.Velocity):Init(true)
local inputs = velocity:GetService("InputService")
local uis = game:GetService("UserInputService")
uis.MouseIconEnabled = false
local curWeapon = nil
local enumBinds = {
[1] = "One";
[2] = "Two";
[3] = "Three";
}
local weps = game.ReplicatedStorage.weps:GetChildren()
local weapon = weaponHandler.new(weps)
local viewmodels = workspace.CurrentCamera:GetChildren()
for i,v in pairs(viewmodels) do
if v.Name == "vm" then
v:Destroy()
end
end
-- equip code
for i,v in pairs(weps) do
local working
local function equip()
if working then return end
working = true
if curWeapon ~= v then
if weapon.equipped then
weapon:remove()
end
weapon:equip(v.Name)
curWeapon = v
else
spawn(function()
weapon:remove()
end)
curWeapon = nil
end
working = false
end
inputs.BindOnBegan(nil,enumBinds[i],equip,"Equip : "..i)
end
local function update(dt)
weapon:update(dt)
end
--[[uis.InputBegan:Connect(function(input, gpe)
if gpe then return end
if input.UserInputType == Enum.UserInputType.MouseButton1 then
weapon:fire(true)
end
if input.UserInputType == Enum.UserInputType.MouseButton2 then
weapon:aim(true)
end
if input.KeyCode == Enum.KeyCode.R then
weapon:reload()
end
end)
uis.InputEnded:Connect(function(input, gpe)
if gpe then return end
if input.UserInputType == Enum.UserInputType.MouseButton1 then
weapon:fire(false)
end
if input.UserInputType == Enum.UserInputType.MouseButton2 then
weapon:aim(false)
end
end)]]--
inputs.BindOnBegan("MouseButton1",nil,function() weapon:fire(true) end,"Fire")
inputs.BindOnEnded("MouseButton1",nil,function() weapon:fire(false) end,"Fire")
inputs.BindOnBegan("MouseButton2",nil,function() weapon:aim(true) end,"Aim")
inputs.BindOnEnded("MouseButton2",nil,function() weapon:aim(false) end,"Aim")
inputs.BindOnBegan(nil, "R",function() weapon:reload() end,"Reload")
game.Players.LocalPlayer.Character:WaitForChild("Humanoid").Died:Connect(function() weapon:remove() weapon.disabled = true end)
game:GetService("RunService").RenderStepped:Connect(update)