UserInputService stops working when you reset your character

I making an ability for a game and anytime I use the UserInputservice it works the first time but when I reset my character it just stops working. What do I need to do so this does not happen again. Any Fixes this is my second time posting this?

2 Likes

Your code could be the issue. I feel that if this was a bug, big developers (that have #bug-reports acess) would post about it

1 Like

Can you check my code

local UIS = game:GetService("UserInputService")
local module = {}
local db = false
local ShockClone
local WeldConst

function module:Activate(Plr:Player)
		local Char = Plr.Character or Plr.CharacterAdded:Wait()
		local Keycode = Enum.KeyCode.E
		local Animation = game.ReplicatedStorage.Abilities["Ice Barrage"]
		local Humanoid = Char:FindFirstChildOfClass("Humanoid")
		local Animator = Humanoid:FindFirstChildOfClass("Animator")
		local Track = Animator:LoadAnimation(Animation)
		local ShockNormalSize = Vector3.new(5.989, 0.592, 6.125)
		local TweenService = game:GetService("TweenService")
		local Goals = TweenInfo.new(
			0.1,
			Enum.EasingStyle.Linear,
			Enum.EasingDirection.In
		)
	

		UIS.InputBegan:Connect(function(inp,gpe)
			if gpe then return end
	
			if inp.KeyCode == Enum.KeyCode.E  and not db  then
				print(Keycode)
				db = true
				Track:Play()
				
				Track:GetMarkerReachedSignal("Blast"):Once(function()
					ShockClone = game.ReplicatedStorage.Shock:Clone()
					WeldConst = Instance.new("Weld")
					ShockClone.Parent = workspace
					local ShockTween = TweenService:Create(ShockClone,Goals,{["Size"] = ShockNormalSize})
					local ShockTween2 = TweenService:Create(ShockClone,Goals,{["Transparency"] = 1})
					WeldConst.Parent = Char:WaitForChild("Right Arm")
					WeldConst.Part0 = Char:WaitForChild("Right Arm")
					WeldConst.Part1 = ShockClone
					ShockClone.Anchored = false
					ShockClone.CanCollide = false
					ShockClone.Size = Vector3.new(1,1,1)
					ShockClone.Position = Char:FindFirstChild("Right Arm").Position + Vector3.new(0,1,0)
					ShockTween2:Play()
					ShockTween:Play()
				end)
		

			
			Track.Ended:Connect(function()
				task.wait(1)
				db = false
			end)
				Humanoid.Died:Connect(function()
					Track:Stop()
					WeldConst:Destroy()
					ShockClone:Destroy()
					db = false
				end)
				Track.Stopped:Connect(function()
					print("Sup")
				end)
			end
		end)
end
return module
2 Likes

When and where are you calling your Activate function?

1 Like

In this local script I had my first piece of code in a module script than I accessed it here



local plr = game.Players.LocalPlayer
local Char = plr.Character or plr.CharacterAdded:Wait()
local Hum = Char:FindFirstChild("Humanoid") or Char:WaitForChild("Humanoid")
local IceDaggerModule = require(script.Ice_Barrage_Framework)


IceDaggerModule:Activate(plr)
1 Like

Okay I don’t really see anything wrong. How about you try to add a print statement above the part where you check if the player is typing

1 Like

I have hold on lemme show you a video
https://gyazo.com/6df096a84720f5f0ce3d39bb2fb6b08e

1 Like

I just saw that Enum.KeyCode.E was outputted after you respawned. So what’s going on?

1 Like

There is a variable named keycode and I used that variable in this line

if inp.KeyCode == Enum.KeyCode.E  and not db  then

but I forgot to delete this variable so when I press e it just prints Enum.keycode.E

1 Like

Oh I see. But you said that UIS didn’t work altogether? But here it seems like it’s working fine

1 Like

Yeah I just don’t know why every time I reset during the move it just does not play the animation again

1 Like

I cant really find anything that could not make the animation run.

Uhh maybe in the Died event listener make remove the Track:Stop() line? Idk

1 Like

Would I need to use contextactionservice

1 Like

Sure if you want I guess since you can just bind an action and that’s be better. But userInputService isnt the reason your code ain’t working but you could try if you want

1 Like

I took a look at the code, not completely sure what the issue is, but I might have an idea.

What I’d like you to do is:
In the modulescript, add a couple lines with asserts to break the script if something doesn’t exist, mainly the variables Char, Humanoid and Animator. Those might not exist and therefore stop the animation as a result.

Your modulescript should look something like this with the change I suggested.

local UIS = game:GetService("UserInputService")
local module = {}
local db = false
local ShockClone
local WeldConst

function module:Activate(Plr:Player)
		local Char = Plr.Character or Plr.CharacterAdded:Wait()
		assert(Char, "Could not find Character!")
		local Keycode = Enum.KeyCode.E
		local Animation = game.ReplicatedStorage.Abilities["Ice Barrage"]
		local Humanoid = Char:FindFirstChildOfClass("Humanoid")
		local Animator = Humanoid:FindFirstChildOfClass("Animator")
		assert(Humanoid, "Could not find Humanoid!")
		assert(Animator, "Could not find Animator!")
		local Track = Animator:LoadAnimation(Animation)
		local ShockNormalSize = Vector3.new(5.989, 0.592, 6.125)
		local TweenService = game:GetService("TweenService")
		local Goals = TweenInfo.new(
			0.1,
			Enum.EasingStyle.Linear,
			Enum.EasingDirection.In
		)
	

		UIS.InputBegan:Connect(function(inp,gpe)
			if gpe then return end
	
			if inp.KeyCode == Enum.KeyCode.E  and not db  then
				print(Keycode)
				db = true
				Track:Play()
				
				Track:GetMarkerReachedSignal("Blast"):Once(function()
					ShockClone = game.ReplicatedStorage.Shock:Clone()
					WeldConst = Instance.new("Weld")
					ShockClone.Parent = workspace
					local ShockTween = TweenService:Create(ShockClone,Goals,{["Size"] = ShockNormalSize})
					local ShockTween2 = TweenService:Create(ShockClone,Goals,{["Transparency"] = 1})
					WeldConst.Parent = Char:WaitForChild("Right Arm")
					WeldConst.Part0 = Char:WaitForChild("Right Arm")
					WeldConst.Part1 = ShockClone
					ShockClone.Anchored = false
					ShockClone.CanCollide = false
					ShockClone.Size = Vector3.new(1,1,1)
					ShockClone.Position = Char:FindFirstChild("Right Arm").Position + Vector3.new(0,1,0)
					ShockTween2:Play()
					ShockTween:Play()
				end)
		

			
			Track.Ended:Connect(function()
				task.wait(1)
				db = false
			end)
				Humanoid.Died:Connect(function()
					Track:Stop()
					WeldConst:Destroy()
					ShockClone:Destroy()
					db = false
				end)
				Track.Stopped:Connect(function()
					print("Sup")
				end)
			end
		end)
end
return module

What do you mean asserts are those like breakpoints and if so, what lines should I put these

This is most likely a script lifetime issue. If you run your code from a LocalScript in StarterPlayerScripts, it waits for your character to spawn, and holds onto a reference to that character for the life of the script, which is probably the whole session.

For things to work through respawns, you need to connect to the Player.CharacterAdded event so that you can either update the references your module script holds, or destroy the instance entirely and make a new one for each character spawn.

This makes a lot of sense but I just need to figure out where I need to put this event

You’re calling :Activate() once. At that time, it stores your current character in a variable.

But after you reset, that character gets removed, so future usages of that Char variable (or any variables referencing things inside it e.g. Humanoid, Animator) are pointing to a removed character.

You need to update your variables to point to a new character on spawn, and re-do any connections on outdated objects (like humanoid.Died)

So you probably should be structuring your code something like this:

--!strict

local UserInputService = game:GetService("UserInputService")
local TweenService = game:GetService("TweenService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Workspace = game:GetService("Workspace")

local KEY_CODE = Enum.KeyCode.E
local SHOCK_OFFSET = Vector3.yAxis * 1
local SHOCK_LIFETIME = 0.1
local SHOCK_TWEEN_INFO = TweenInfo.new(SHOCK_LIFETIME, Enum.EasingStyle.Linear, Enum.EasingDirection.In)
local DEBOUNCE_SECONDS = 1
local SHOCK_END_GOALS = {
	Size = Vector3.new(5.989, 0.592, 6.125),
	Transparency = 1,
}

local SHOCK_BEGIN_SIZE = Vector3.one

local animation: Animation = ReplicatedStorage.Abilities["Ice Barrage"]
local shockPrefab: BasePart = ReplicatedStorage.Shock

local module = {}

function module._animateShock(shock: BasePart, spawnAtPart: BasePart)
	local weld = Instance.new("Weld")
	local shockTween = TweenService:Create(shock, SHOCK_TWEEN_INFO, SHOCK_END_GOALS)
	weld.Part0 = spawnAtPart
	weld.Part1 = shock
	weld.Parent = spawnAtPart

	shock.Anchored = false
	shock.CanCollide = false
	shock.Size = SHOCK_BEGIN_SIZE
	shock.Position = spawnAtPart.Position + SHOCK_OFFSET
	shock.Parent = Workspace
	shockTween:Play()

	shockTween.Completed:Once(function()
		shock:Destroy()
	end)
end

function module._canShock(inputObject: InputObject, isProcessed: boolean, debounce: boolean): boolean
	if isProcessed then
		return false
	end

	if debounce then
		return false
	end

	if inputObject.UserInputType ~= Enum.UserInputType.Keyboard then
		return false
	end

	if inputObject.KeyCode ~= KEY_CODE then
		return false
	end

	return true
end

function module._onCharacterAddedAsync(character: Model)
	local rightArm = character:WaitForChild("Right Arm") :: BasePart
	local humanoid = character:WaitForChild("Humanoid") :: Humanoid
	local animator = humanoid:WaitForChild("Animator") :: Animator
	local track: AnimationTrack = animator:LoadAnimation(animation)

	local debounce = false

	local inputConnection = UserInputService.InputBegan:Connect(function(inputObject: InputObject, isProcessed: boolean)
		if not module._canShock(inputObject, isProcessed, debounce) then
			return
		end

		debounce = true

		local newShock = shockPrefab:Clone()
		track:GetMarkerReachedSignal("Blast"):Once(function()
			module._animateShock(newShock, rightArm)
		end)

		local diedConnection = humanoid.Died:Once(function()
			newShock:Destroy()
		end)

		track.Ended:Once(function()
			diedConnection:Disconnect()
			task.wait(DEBOUNCE_SECONDS)
			debounce = false
		end)

		track:Play()
	end)

	humanoid.Died:Once(function()
		track:Stop()
		track:Destroy()
		inputConnection:Disconnect()
	end)
end

function module.activate(player: Player)
	if player.Character then
		task.spawn(module._onCharacterAddedAsync, player.Character)
	end
	player.CharacterAdded:Connect(module._onCharacterAddedAsync)
end

return module

Assert is an error, but it only occurs if the variable given in the first argument is invalid. If it is, it will print out whatever string you put as the second argument.

Documentation for assert

I’m asking you to put assert in front of variables that might change, like the Char, Humanoid, and Animator variables. Since a player’s character gets destroyed once they respawn, the old character that the Char variable points to would no longer exist once you reuse the function, if I understand the function correctly.

(also I know this response is late, but I just logged into the dev forum)

Documentation example of assert

local product = 90 * 4
assert(product == 360, "Oh dear, multiplication is broken")
-- The line above does nothing, because 90 times 4 is 360