Functions Overlap Due to Wait()

i am currently trying tp fix my dialogue system and this specific problem has been bugging me for awhile. Whenever the player presses the space bar or clicks the dialogue box during the typewriting animation. It skips the animation. But since it runs on a seperate function, The wait() in the animation handler still runs. And if you skip quickly to the next dialogue, it causes it to stop randomly.

local function typewriterEffect(text, textBox, sound, speed, stopMultiplier, choiceCooldown, gradient)
	if animationActive.Value == true then return end
	animationActive.Value = true
	skippingEnabled.Value = true
	for _, a in pairs(script.Parent:GetDescendants()) do
		if a:IsA('UIGradient') and not a:IsAncestorOf(OptionsCG) then
			a.Color = gradient.Color
		end
	end
	local currentText = ""
	for character in text:gmatch(".") do
		if animationActive.Value == true then
			currentText = currentText .. character
			textBox.Text = currentText

			if sound ~= nil then
				sfx:FindFirstChild(sound):Play()
			end
			if character == "." then
				wait(speed * 10 * stopMultiplier)
			elseif character == "," then
				wait(speed * 8 * stopMultiplier)
			else
				wait(speed)
			end
		end

	end

	skippingEnabled.Value = false
	task.wait(choiceCooldown)
	script.Parent.DialogueCG.DialogueBorder.DialogueFrame.Continue.Visible = true
	player.PlayerGui.SFX["switch.wav"]:Play()
	animationActive.Value = false
	canProgress.Value = true
	print('finishedanimation')
end



dialogueEvent.Event:Connect(function(dialogue, choices)
	if dialogueHappening.Value == false then
		canChooseResponse.Value = false
		dialogueHappening.Value = true

		currentDialogue = dialogue
		currentChoices = choices

		canProgress.Value = false
		currentLine = 1
		tweenService:Create(dialogueCG, tweenFadeIn, {Position = UDim2.new(0.5,0,0.5,0)}):Play()
		tweenService:Create(dialogueCG, tweenFadeIn, {GroupTransparency = 0}):Play()
		if connection ~= nil then
			connection:Disconnect()
			touchConnection:Disconnect()
		end

		player.Character:FindFirstChild('Humanoid').WalkSpeed = 0
		player.Character:FindFirstChild('Humanoid').JumpPower = 0


		task.spawn(dialogueHandler, currentDialogue, currentChoices)
		connection = uis.InputBegan:Connect(function(input,gameProcessedEvent)
			if gameProcessedEvent then return end
			if input.KeyCode == Enum.KeyCode.Space or input.KeyCode == Enum.KeyCode.ButtonX then
				if canSkip.Value == true then
					coroutine.wrap(function()
						canSkip.Value = false
						task.wait(0.25)
						canSkip.Value = true
					end)()
					print(tostring(animationActive.Value).." "..tostring(skippingEnabled.Value).." "..tostring(canProgress.Value == true).." "..tostring(canChooseResponse.Value == false))
					if animationActive.Value == true and skippingEnabled.Value == true and canProgress.Value == false and canChooseResponse.Value == false then

						animationActive.Value = false
						script.Parent.DialogueCG.DialogueBorder.DialogueFrame.DialogueBorder.TextLabel.Text = currentDialogue[currentLine].Text
						task.wait(currentDialogue[currentLine].Cooldown)
						script.Parent.DialogueCG.DialogueBorder.DialogueFrame.Continue.Visible = true
						player.PlayerGui.SFX["switch.wav"]:Play()
						skippingEnabled.Value = false
						canProgress.Value = true

					elseif animationActive.Value == false and skippingEnabled.Value == false and canProgress.Value == true and canChooseResponse.Value == false then
						currentLine += 1
						canProgress.Value = false
						script.Parent.DialogueCG.DialogueBorder.DialogueFrame.Continue.Visible = false
						task.spawn(dialogueHandler, currentDialogue, currentChoices)
					else
						print('wait')
					end
				end
			end
		end)
		touchConnection = script.Parent.DialogueCG.DialogueBorder.DialogueFrame.InputBegan:Connect(function(input)
			if input.UserInputType == Enum.UserInputType.MouseButton1 or input.UserInputType == Enum.UserInputType.Touch then
				if canSkip.Value == true then
					coroutine.wrap(function()
						canSkip.Value = false
						task.wait(0.25)
						canSkip.Value = true
					end)()
					print(tostring(animationActive.Value).." "..tostring(skippingEnabled.Value).." "..tostring(canProgress.Value == true).." "..tostring(canChooseResponse.Value == false))
					if animationActive.Value == true and skippingEnabled.Value == true and canProgress.Value == false and canChooseResponse.Value == false then

						animationActive.Value = false
						script.Parent.DialogueCG.DialogueBorder.DialogueFrame.DialogueBorder.TextLabel.Text = currentDialogue[currentLine].Text
						task.wait(currentDialogue[currentLine].Cooldown)
						script.Parent.DialogueCG.DialogueBorder.DialogueFrame.Continue.Visible = true
						player.PlayerGui.SFX["switch.wav"]:Play()
						skippingEnabled.Value = false
						canProgress.Value = true

					elseif animationActive.Value == false and skippingEnabled.Value == false and canProgress.Value == true and canChooseResponse.Value == false then
						currentLine += 1
						canProgress.Value = false
						script.Parent.DialogueCG.DialogueBorder.DialogueFrame.Continue.Visible = false
						task.spawn(dialogueHandler, currentDialogue, currentChoices)
					else
						print('wait')
					end
				end
			end
		end)
	end
end)

Please do not ask people to write entire scripts or design entire systems for you. If you can’t answer the three questions above, you should probably pick a different category.

Seems like when you pressing space repeatedly it wraps several coroutines which affect canSkip later. Try killing previous thread or use check when making new thread.

-- Outside function:
local previousThread = nil

-- Inside function:
if previousThread then
    coroutine.close(previousThread)
end
local routine = coroutine.wrap(function()
    canSkip.Value = false
    task.wait(0.25)
    canSkip.Value = true
end)
previousThread = routine()

or:

-- Outside function:
local previousRoutineTime = nil

-- Inside function:
local routine = coroutine.wrap(function()
    local currentRoutineTime = tick()
    previousRoutineTime = currentRoutineTime
    canSkip.Value = false
    task.wait(0.25)
    if currentRoutineTime == previousRoutineTime then
       canSkip.Value = true
    end
end)
1 Like

sorry for the late response, but would i put this in the function where you skip or in the typewriter dialogue function?

It may be better to have something indicating in the code that the text’s still scrolling and to immediately set it to the text if it’s still in that process. Then upon completion it moves onto the next line.

local textCurrentlyScrolling = false
local textFinishedScrolling = false
local stopTextScrolling = false

...

moveOn.Button1Click:Connect(function()
	if not textCurrentlyScrolling then
		textCurrentlyScrolling = true
		textFinishedScrolling  = false
		GUI.Text = ""
		local n = 0
		while GUI.Text ~= str and not stopTextScrolling and n < #str do
			n = n + 1
			GUI.Text = GUI.Text .. str:sub(i, i)
			task.wait(0.1)
		end
		GUI.Text = str
		stopTextScrolling = false
		textCurrentlyScrolling = false
		textFinishedScrolling = true
	else
		stopTextScrolling = true
	end
end)

This is a rough example of how it could be accomplished.

does this replace the typewriterEffect function or is it just an updated verison of it?

Yeah it’s a typewriter-type of text scrolling. It was written as an example of how it could be accomplished.

If the code I’d written were to be used it would need to be edited and fleshed out for practical use rather than just being an example.