Animation not working properly when player nearby npc and not nearby npc

How do I make this script so that it play the animation for the npc when the player is nearby and stop to play the animation of the npc when the player is not nearby and out of range. I tried to debug this for hours now and the animations is either bugging, not playing, and very weird. The animation is an emote from Roblox.

Distance checker function:

local function CheckPlayerDistance(ObjectsToGet: {BasePart})
	if #ObjectsToGet == 0 then
		return false, nil
	end

	local minDistance = math.huge

	for _, ObjectToGet in ipairs(ObjectsToGet) do
		if ObjectToGet and ObjectToGet.Parent:IsA('Model') and ObjectToGet.Parent:FindFirstChildWhichIsA('Humanoid') then
			local Config = NPCsQuestConfigs[ObjectToGet.Parent.Parent.Name]

			if Config then
				local distance = (Hrp.Position - ObjectToGet.Position).Magnitude
				if distance <= Config.Trigger.ActivateRange then
					return true, ObjectToGet
				elseif distance < minDistance then
					minDistance = distance
					CurrentTarget = ObjectToGet
				end
			end
		end
	end

	return false, CurrentTarget
end

Animation playing function:

local function PlayNearbyAnim(Status: boolean, TargetHrp: BasePart)
	assert(typeof(TargetHrp) == 'Instance' and TargetHrp:IsA('BasePart'), 'Hrp expect to be a BasePart!!')
	assert(typeof(Status) == 'boolean', 'Status expect to be a boolean but got '..typeof(Status)..' instead!!')
	
	local TargetChar: Model = TargetHrp.Parent
	local TargetHum: Humanoid = TargetHrp.Parent:FindFirstChild('Humanoid')
	local Animator: Animator = TargetHum:FindFirstChild(Player.UserId)
	
	if not (TargetHum or Animator) then
		warn('Something went wrong with TargetHum or Animator. Please check again! ->', TargetHum, Animator)
		return
	end
	
	local TargetConfig = NPCsQuestConfigs[TargetChar.Parent.Name]
	
	if not TargetConfig then
		warn('Something went wrong with TargetConfig. Please check again! -> ', TargetConfig)
		return
	end
	
	if Status then
		if not PlayDebounces[TargetHrp] then
			PlayDebounces[TargetHrp] = true
			NearbyAnim.AnimationId = TargetConfig.NPC.Animations.OnNearbyAnimation
			local LoadedAnim = Animator:LoadAnimation(NearbyAnim)
			if not CurrentTrackList[TargetChar.Parent.Name] then
				CurrentTrackList[TargetChar.Parent.Name] = LoadedAnim
			end
			LoadedAnim:Play()
			task.delay(LoadedAnim.Length, function()
				PlayDebounces[TargetHrp] = false
			end)
		end
	else
		if CurrentTrackList[TargetChar.Parent.Name] then
			CurrentTrackList[TargetChar.Parent.Name]:Stop()
		end
	end
end

Code block where I call the function:

while task.wait() do
	local MouseTarget = PlayerMouse.Target

	if MouseTarget and CanHover and MouseTarget.Parent:IsA('Model') and MouseTarget.Parent:FindFirstChildWhichIsA('Humanoid') and MouseTarget.Parent.Parent.Parent.Name == 'Quests' then
		local Config = NPCsQuestConfigs[MouseTarget.Parent.Parent.Name]

		if Config.NPC.HighlightOnHover.Enabled and not MouseTarget.Parent:FindFirstChildWhichIsA('Highlight') then
			NewHighlight = Instance.new('Highlight', MouseTarget.Parent)
			NewHighlight.Name = 'NPCHighlight'
			NewHighlight.DepthMode = Config.NPC.HighlightOnHover.DepthMode
			NewHighlight.FillColor = Config.NPC.HighlightOnHover.FillColor
			NewHighlight.OutlineColor = Config.NPC.HighlightOnHover.OutlineColor
			NewHighlight.OutlineTransparency = Config.NPC.HighlightOnHover.OutlineTransparency
			NewHighlight.FillTransparency = Config.NPC.HighlightOnHover.FillTransparency
		end
	else
		if NewHighlight then
			NewHighlight:Destroy()
		end
	end

	for _, NPC in QuestsNPCFolder:GetDescendants() do
		if NPC:IsA('Model') and NPC:FindFirstChildWhichIsA('Humanoid') then

			local NPC_Config = NPCsQuestConfigs[NPC.Parent.Name]
			local NPC_Hrp = NPC:WaitForChild('HumanoidRootPart') or NPC.PrimaryPart
			local NPC_Hum = NPC:WaitForChild('Humanoid')

			if NPC_Hrp and NPC_Hum then
				local CurrentNPCCFrame = NPC_Hrp.CFrame
				local NPC_Prompt = NPC_Hrp:FindFirstChildWhichIsA('ProximityPrompt')
				local NPC_Camera = QuestsNPCFolder:WaitForChild(NPC_Config.Name):FindFirstChild('DialogCamera')
				
				if not table.find(NpcHrpList, NPC_Hrp) then
					table.insert(NpcHrpList, NPC_Hrp)
				end
				
				if NPC_Prompt and NPC_Config and NPC_Camera and not PromptDebounces[NPC_Prompt] then
					PromptDebounces[NPC_Prompt] = NPC_Prompt

					if NPC_Prompt:IsA('ProximityPrompt') == false or NPC_Camera:IsA('BasePart') == false then
						warn('Something went wrong with the NPC prompt and camera part.')
						return
					end

					NPC_Prompt.ActionText = NPC_Config.Trigger.ActionText
					NPC_Prompt.ObjectText = NPC_Config.Trigger.ObjectText
					NPC_Prompt.HoldDuration = NPC_Config.Trigger.ActivateCooldown
					NPC_Prompt.MaxActivationDistance = NPC_Config.Trigger.ActivateRange

					NPC_Prompt.Triggered:Connect(function(PlayerWhoTriggered: Player)
						print(NPC_Config.Name)
						local PlrGui = PlayerWhoTriggered.PlayerGui

						if not PlrGui then
							warn('Cannot find PlayerGui in player when starting dialog.')
							return
						end

						local DialogUI = PlrGui:WaitForChild('DialogUI')
						local DialogMain = DialogUI:WaitForChild('Main')
						local DialogTextHolder = DialogMain:WaitForChild('DialogTextHolder')

						local NameLabel = DialogTextHolder:WaitForChild('NameLabel')
						local DialogText = DialogTextHolder:WaitForChild('DialogText')

						local RotateInfo = TweenInfo.new(NPC_Config.NPC.RotateInfo[1], NPC_Config.NPC.RotateInfo[2], NPC_Config.NPC.RotateInfo[3], NPC_Config.NPC.RotateInfo[4], NPC_Config.NPC.RotateInfo[5], NPC_Config.NPC.RotateInfo[6])

						local RotateOpen = TweenService:Create(NPC_Hrp, RotateInfo, {CFrame = CFrame.lookAt(NPC_Hrp.Position, Vector3.new(NPC_Camera.Position.X, NPC_Hrp.Position.Y, NPC_Camera.Position.Z))})
						local RotateClose = TweenService:Create(NPC_Hrp, RotateInfo, {CFrame = CurrentNPCCFrame})

						QuestStatusSignal:FireServer(true)
						Hum.WalkSpeed = 0
						StarterGui:SetCoreGuiEnabled(Enum.CoreGuiType.All, false)
						NameLabel.Text = NPC_Config.Name
						CanHover = false
						NPC_Prompt.Enabled = false
						for _, PlrInGame in Players:GetPlayers() do
							if PlrInGame then
								local AllPlrChar = PlrInGame.Character or PlrInGame.CharacterAdded:Wait()
								if AllPlrChar then
									ToggleCharInvisibility(AllPlrChar, true)
								end
							end
						end
						Utils.Transition.Run(PlayerWhoTriggered, true, NPC_Config)
						RotateOpen:Play()
						QuestController.ToggleDialogFrame(PlayerWhoTriggered, NPC_Config, true)
						task.delay(RotateOpen.TweenInfo.Time, function()
							Utils.Typewriter.typeWrite(DialogText, 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', 0)
							QuestController.AddOption(PlayerWhoTriggered, 'TestOption', 'Click to end quest!!', function()
								CompleteQuest(PlayerWhoTriggered, NPC_Config)
								RotateClose:Play()
							end)
						end)
					end)
				end
				
				if NPC_Config.NPC.PlayAnimOnNearby and not IsInQuest.Value then
					task.spawn(function()
						local DistanceResult, PartResult = CheckPlayerDistance(NpcHrpList)
						if PartResult then
							--print(PartResult.Parent.Parent)
							PlayNearbyAnim(DistanceResult, PartResult)
						end
					end)
				end
			end
		end
	end
end
1 Like

Any help below is appreciated. I really need it to fix my quest dialog system. Here is the video of the animation getting buggy.

2 Likes