The custom Interaction system behaving strangely

I’ve been trying to script an Interaction system for weeks but the most common result is that it’s behaving strangely and doesn’t work as it’s scripted

  1. What do i want to achieve? I need to code run smoothly and do what is should.

  2. What is the issue? I use coroutine functions to check if player holds a special key, but as i try the second time, coroutine just runs else part of code then ignoring coroutine.

  3. What solutions have you tried so far? I haven’t seen any solution about this theme

There is a local script for system that i use
Expect for some variables to be not used due i tried many ways to solve problem.

local Inter = game:GetService("ReplicatedStorage").Inter
local OnCoroutine = false
local timeawait = 0
local done = false
local UserInputService = game:GetService("UserInputService")
local CanInteract = true
local target
local TS = game:GetService("TweenService")
local maingui = script.Parent
local UpTitle = maingui.objectcontent:FindFirstChild("TextLabel")
local DownTitle = maingui.Interactcontent:FindFirstChild("TextLabel")
local Interacting = false
local CanResume = true
local ET
local still
local EstimatedTime = 1
local wastedtime = 0
local looking = false
local Progress = maingui.Progress
local Progressbar = Progress.Progressbar
local RunService = game:GetService("RunService")
local Info = TweenInfo.new(EstimatedTime, Enum.EasingStyle.Linear, Enum.EasingDirection.InOut, 0, false, 0)
local Tween = TS:Create(Progressbar, Info, {
	Size = UDim2.new(1,0,1,0)
})
local function showup()
	UpTitle.TextTransparency = 0
	DownTitle.TextTransparency = 0
	Progress.BackgroundTransparency = 0
	Progressbar.BackgroundTransparency = 0
end
local function hide()
	Tween:Cancel()
	Progressbar.Size = UDim2.new(0, 0, 1, 0)
	UpTitle.TextTransparency = 1
	DownTitle.TextTransparency = 1
	Progress.BackgroundTransparency = 1
	Progressbar.BackgroundTransparency = 1
end
local function GetOrigin()
	local Mousepos = UserInputService:GetMouseLocation()
	local start = workspace.CurrentCamera:ViewportPointToRay(Mousepos.X, Mousepos.Y)
	return start
end
local function getDirection()
	local Direction = GetOrigin().Direction * 3
	return Direction
end
local function raycasting()
	local rcresult = workspace:Raycast(GetOrigin().Origin, getDirection())
	if rcresult then
		print("success")
		local testvar = rcresult.Instance.Parent.Setup
		if testvar then
			showup()
			looking = true
			if Interacting == false and looking == true then
				still = true
			else
				still = false
			end
			EstimatedTime = testvar.Hold.Value
			target = rcresult
			return rcresult
		else
			hide()
			print("not found")
			looking = false
		end
	else
		
		print("not found2")
		hide()
		looking = false
	end
end
local KeyHold = coroutine.create(function()
	while UserInputService:IsKeyDown(Enum.KeyCode.F) do
		if Interacting == true then
			if looking == false then
				wastedtime = 0
				Tween:Cancel()
				break
			end
			if wastedtime == EstimatedTime and Interacting == true then
				Inter:FireServer(target.Instance)
				Tween:Cancel()
				break
			elseif wastedtime ~= EstimatedTime and Interacting == true then
				wait(1)
				print("Iteration")
				wastedtime += 1
			else
				print("case")
				wastedtime = 0
				Tween:Cancel()
				break
			end
		end
	end
end)
UserInputService.InputBegan:Connect(function(InputObject, gameProcessedEvent)
	if gameProcessedEvent then return end
	if InputObject.KeyCode == Enum.KeyCode.F and CanInteract == true then
		CanInteract = false
		Interacting = true
		Info = TweenInfo.new(EstimatedTime, Enum.EasingStyle.Linear, Enum.EasingDirection.InOut, 0, false, 0)
		Tween = TS:Create(Progressbar, Info, {Size = UDim2.new(1, 0, 1, 0)})
		Tween:Play()
		print(CanInteract, Interacting, looking)
		coroutine.resume(KeyHold)
		print("Inp start")
	end
end)
UserInputService.InputEnded:Connect(function(InputObject, gameProcessedEvent)
	if gameProcessedEvent then return end
	if InputObject.KeyCode == Enum.KeyCode.F then
		hide()
		wastedtime = 0
		if looking == true then
			still = true
		end
		CanInteract = true
		Interacting = false
		print("Inp end successfully")
		coroutine.yield(KeyHold)
	end
end)
RunService.RenderStepped:Connect(function()
	if Interacting == false then
		if still == true or looking == false then
			GetOrigin()
			getDirection()
			raycasting()
		end
	end
end)

The problem haven’t been solved in my post before and ignored. :face_exhaling:
Thanks for anyone who will help me.

If I understand your code correctly your coroutine are already out of the loop when you tried to yield it result in when you resume coroutine again it will continue after the loop which there is no code past that point

there are 2 solutions about this

1st Solution

Immediately yield coroutine after Key released like this

UserInputService.InputEnded:Connect(function(InputObject, gameProcessedEvent)
	if gameProcessedEvent then return end
	if InputObject.KeyCode == Enum.KeyCode.F then
		coroutine.yield(KeyHold)
		hide()
		wastedtime = 0
		if looking == true then
			still = true
		end
		CanInteract = true
		Interacting = false
		print("Inp end successfully")
		
	end
end)

However do keep in mind that this will likely cause condition race which may cause the coroutine to still out of the loop sometime which I recommend second solution instead

2nd Solution

Close old coroutine and Make new coroutine whenever player released Key like this


local function MakeCoroutine()
	return coroutine.create(function()
		while UserInputService:IsKeyDown(Enum.KeyCode.F) do
			print(Interacting)
			if Interacting == true then
				if looking == false then
					wastedtime = 0

					break
				end
				if wastedtime == EstimatedTime and Interacting == true then
					Inter:FireServer(target.Instance)
					wastedtime = 0
					break
				elseif wastedtime ~= EstimatedTime and Interacting == true then
					wait(1)
					print("Iteration")
					wastedtime += 1
				else
					print("case")
					wastedtime = 0

					break
				end
			end
		end

	end)
end

local KeyHold = MakeCoroutine()

UserInputService.InputBegan:Connect(function(InputObject, gameProcessedEvent)
	if gameProcessedEvent then return end
	if InputObject.KeyCode == Enum.KeyCode.F and CanInteract == true then
		CanInteract = false
		Interacting = true
		Info = TweenInfo.new(EstimatedTime, Enum.EasingStyle.Linear, Enum.EasingDirection.InOut, 0, false, 0)
	
		print(CanInteract, Interacting, looking)
		coroutine.resume(KeyHold)
		print("Inp start")
	end
end)
UserInputService.InputEnded:Connect(function(InputObject, gameProcessedEvent)
	if gameProcessedEvent then return end
	if InputObject.KeyCode == Enum.KeyCode.F then
		hide()
		wastedtime = 0
		if looking == true then
			still = true
		end
		CanInteract = true
		Interacting = false
		print("Inp end successfully")
		--coroutine.yield(KeyHold)
		coroutine.close(KeyHold)
		KeyHold = MakeCoroutine()
	end
end)

This will ensure that player will get new fresh coroutine from start without having to worry about condition race

I am not sure myself if this is what you are looking for but if I misunderstood your question feel free to correct me

Thank you ill try this. Hope this will work : )

Thank you so much you helped me solving this problem! : D

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.