Tool has a delay after letting go of R2

Hello, I am making a gun for VR and im currently testing the automatic fire and im using Nexus VR character model.
The issue is that after letting go of R2 (the right trigger) there is a bit of delay and the gun still fires a shot or two.

Local Script of the tool

local Tool = script.Parent
local Remote = Tool:WaitForChild("RemoteEvent")
local Input = game:GetService("UserInputService")
local RS = game:GetService("RunService")
local CanShoot = true
local FireRate = Tool:GetAttribute("FireRate")
local VRService = game:GetService("VRService")
local triggers = {
	[Enum.KeyCode.ButtonR2] = 0;
	[Enum.KeyCode.ButtonR1] = 0;
}

local function Fire()
	if triggers[Enum.KeyCode.ButtonR2] > 0 and Tool:GetAttribute("Auto") == true then
		print("AutoFire")
		while true do
			--if CanShoot == true then
			Remote:FireServer("Fire",Tool.FirePoint.Position, script.Parent.FirePoint.CFrame.LookVector, nil, Tool.Parent:WaitForChild("Humanoid"), Tool:GetAttribute("Range"), Tool) --Origin, Direction, FireAnim, OriginHumanoid, Range
			--end
			if triggers[Enum.KeyCode.ButtonR2] < 0.2 or Tool:GetAttribute("CurrentMag") == 0 then
				break
			end
			wait(FireRate)
		end
		print("StoppedFire")
	elseif triggers[Enum.KeyCode.ButtonR2] > 0 and Tool:GetAttribute("Auto") == false then
		if CanShoot == true then
			Remote:FireServer("Fire",Tool.FirePoint.Position, script.Parent.FirePoint.CFrame.LookVector, nil, Tool.Parent:WaitForChild("Humanoid"), Tool:GetAttribute("Range"), Tool) --Origin, Direction, FireAnim, OriginHumanoid, Range
			CanShoot = false
			wait(FireRate)
			CanShoot = true
		end
	end
end

local function inputChanged(inputObject)
	if triggers[inputObject.KeyCode] then
		triggers[inputObject.KeyCode] = inputObject.Position.Z
	end
	print("R2", triggers[Enum.KeyCode.ButtonR2])
end

Tool.Activated:Connect(function(e)
	Fire()
end)

Input.InputBegan:Connect(function(io)
	print("Input")
	if io.KeyCode == Enum.KeyCode.ButtonB then
		print("HitB")
		Remote:FireServer("EjectMag", Tool, Tool.Magazine.CFrame)
	end
end)

--script.Parent.Magazine.Touched:Connect(function(hit)
--	print("hit", hit)
--	if hit.Name == "Magazine" then
		
--	end
--end)

RS.RenderStepped:Connect(function(E)
	local A = Tool.Magazine:GetTouchingParts()
	--print(A)
	for i = 1, #A do
		if Tool:GetAttribute("Mag") == false and A[i]:GetAttribute("Gun") == Tool.Name then
			print("is mag")
			Remote:FireServer("LoadMag", Tool, A[i])
		end
	end
end)



game:GetService("UserInputService").InputBegan:Connect(inputChanged) -- x = 1 values
game:GetService("UserInputService").InputChanged:Connect(inputChanged) -- 0 < x < 1 values
game:GetService("UserInputService").InputEnded:Connect(inputChanged) -- x = 0 values

Tools Server script

local MainModule = require(7881298914)
local VRService = game:GetService("VRService")
print("called mainmodule :)")

script.Parent.RemoteEvent.OnServerEvent:Connect(function(Plr, Key, Val1, Val2, Val3, Val4, Val5, Val6, Val7, Val9, Val10)
	if Key == "Fire" then
		MainModule.Fire(Val1, Val2, Val3, Val4, Val5, Val6)
	elseif Key == "EjectMag" then
		MainModule.EjectMag(Plr, Val1, Val2)
	elseif Key == "LoadMag" then
		MainModule.InsertMag(Plr, Val1, Val2)
	end
end)

Main Module


local MainModule = {}
local physicsService = game:GetService('PhysicsService')
local FireDelay = false

workspace.DescendantAdded:Connect(function(v)
	if v:IsA("BasePart") then
		if v.CanCollide == false and not v.Parent:FindFirstChild("Humanoid") then
			physicsService:SetPartCollisionGroup(v, 'AntiRaycast')
		end
		
		if v.Transparency == 1 and not v.Parent:FindFirstChild("Humanoid") then
			physicsService:SetPartCollisionGroup(v, 'AntiRaycast')
		end	
		
		if v.Name == "Handle" and not v.Parent:FindFirstChild("Humanoid") then
			physicsService:SetPartCollisionGroup(v, 'AntiRaycast')
		end
	end
end)



MainModule.Fire = function(Origin, Direction, FireAnim, OriginHumanoid, Range, Tool)
	print(Origin, Direction, FireAnim, OriginHumanoid, Range, Tool)
	local RaycastParameters = RaycastParams.new()
	--local physicsService = game:GetService('PhysicsService')

	--for _, part in pairs(workspace:GetDescendants()) do
	--	if part:IsA('Accessory') then
	--		physicsService:SetPartCollisionGroup(part.Handle, 'AntiRaycast')
	--		print(part)
	--	end
	--end
	
	RaycastParameters.CollisionGroup = 'RayCast'
	
	if Tool:GetAttribute("OneInChamber") == true then
		if Tool:GetAttribute("CurrentMag") ~= 0 then
			Tool:SetAttribute("CurrentMag", Tool:GetAttribute("CurrentMag") - 1 )
		else
			Tool:SetAttribute("OneInChamber", false)
		end
		local raycastResult = game.Workspace:Raycast(Origin, Direction*Range)
		if raycastResult then
			--print("You actually hit something", raycastResult)
			--print("Raycast hit at:", raycastResult.Position)
			--local DebugClone = game.ReplicatedStorage.Debug:Clone()
			--DebugClone.Parent = game.Workspace
			--DebugClone.Position = raycastResult.Position
			if raycastResult.Instance.Parent:FindFirstChild("Humanoid") then
				if raycastResult.Instance.Name ~= "Head" then
					raycastResult.Instance.Parent:FindFirstChild("Humanoid"):TakeDamage(Tool:GetAttribute("Damage"))
				else
					raycastResult.Instance.Parent:FindFirstChild("Humanoid"):TakeDamage(Tool:GetAttribute("Damage")*Tool:GetAttribute("HeadShotMultiplier"))
				end
			end


			coroutine.wrap(function()
				if Tool:FindFirstChild("Flash") then
					local animator = require(Tool.Animator)
					animator.Shoot:Play()
					Tool:FindFirstChild("Flash").Transparency = 0
					wait(0.05)
					Tool:FindFirstChild("Flash").Transparency = 1
				end
			end)()
			local HitTHing = script.Hit:Clone()
			local Attachment = Instance.new("Attachment")
			Attachment.Parent = Tool.FirePoint
			local BeamClon = script.Beam:Clone()
			HitTHing.Position = raycastResult.Position
			BeamClon.Parent = game.Workspace
			HitTHing.Parent = game.Workspace
			BeamClon.Attachment0 = Attachment
			BeamClon.Attachment1 = HitTHing.Attachment
			wait(0.05)
			HitTHing:Destroy()
			Attachment:Destroy()
			BeamClon:Destroy()
		else
			print("Shot fired but hit nothing.")
			local animator = require(Tool.Animator)
			animator.Shoot:Play()
			if Tool:FindFirstChild("Flash") then
				Tool:FindFirstChild("Flash").Transparency = 0
				wait(0.05)
				Tool:FindFirstChild("Flash").Transparency = 1
			end
		end
	end

	
end

MainModule.EjectMag = function(Player, Tool, MagCFrame)
	local animator = require(Tool.Animator)
	if Tool:GetAttribute("Mag") == true and Player.Character:FindFirstChild(Tool.Name) then
		local DropMag = Tool.Magazine:Clone()
		DropMag.CFrame = MagCFrame
		DropMag:BreakJoints()
		DropMag.Parent = game.Workspace
		DropMag.CanCollide = true
		Tool:SetAttribute("Mag", false)
		Tool:SetAttribute("CurrentMag", 0)
		Tool.Magazine.Transparency = 1
		wait(5)
		DropMag:Destroy()
	end
end

MainModule.InsertMag = function(Player, Tool, Mag)
	print("e")
	local animator = require(Tool.Animator)
	animator.MagIn:Play()
	Tool.Magazine.Transparency = 0
	Tool:SetAttribute("Mag", true)
	Tool:SetAttribute("CurrentMag", Mag:GetAttribute("Ammo"))
	Tool:SetAttribute("OneInChamber", true)
	Mag:Destroy()
end


return MainModule

Any sort of help is appreciated.

edit: I’ve noticed that there is no delay on a Xbox controller.

This has been an issue for a while The definitive list of Roblox VR bugs/issues, broken down by headset

However when I play other VR games on Roblox I don’t experience any trigger input delays so there must be some workaround. I only experience trigger input delays in my own VR games but not others.

3 Likes

the workaround is basing it off of InputObject.Delta, but this will screw over playability on steamVR headsets… so you kinda need both, and debounce to keep from double inputs

3 Likes

This seems to do the trick when trigger is let go but the delay still occurs when the trigger is pressed. Are there any methods outside of InputChanged to retrieve the current InputObject?

function TriggerPressed()
	print("Pressed")
end

function TriggerUnpressed()
	print("Unpressed")
end

local trigggerPosAlpha = 0
local pressedThreshold = .95
local pressed = false

	
UIS.InputChanged:Connect(function(input, gpe)
	if input.KeyCode == Enum.KeyCode.ButtonR2 then
		trigggerPosAlpha = input.Position.Z
		if not pressed and trigggerPosAlpha > pressedThreshold then
			pressed = true
			TriggerPressed()
		elseif pressed and trigggerPosAlpha < pressedThreshold then
			pressed = false
			TriggerUnpressed()
		end
	end
end)

Also I’m not sure what you mean by basing it off InputObject.Delta. Could you elaborate?

3 Likes

@Dued1, for some reason Tool.Activated doesn’t have a delay so the script you wrote will add a delay for starting automatic fire.

Also, @GregTame I don’t know how to use inputobject.Delta. Please show me an example if possible.

Delta is how much the InputObject has moved since the last time InputChanged was fired.
So if you’re basing it off stuff like the triggers, you’re detecting how much the trigger has moved, and which direction it moved in.
So you do something like

MovementThreshold = 0.05
UIS.InputChanged:Connect(function(input, gpe)
	if input.KeyCode == Enum.KeyCode.ButtonR2 then
		DeltaZ = input.Delta.Z
		if not pressed and DeltaZ > MovementThreshold then
			pressed = true
			TriggerPressed()
		elseif pressed and DeltaZ < MovementThreshold then
			pressed = false
			TriggerUnpressed()
		end
	end
end)

this has the upside of not requirng the trigger to be fully unpressed for it to reset, and instead resets as soon as you start to let go.
this is really ideal for systems like throwing, where you want that to be as quick of a reaction as possible.

3 Likes

@GregTame, There seems to be an Issue.

when I get the R2 Trigger quickly into position it will fire a thew bullets in a short burst
also the pressed value stays “true” for a short time and even shorter if pressing R2 slowly.

Actually, I got it working. just had to lower the threshold

Thanks for the help!