How would you go about making a holdable/chargeable skill?

I’m trying to get familiar with UserInputService as I’m still a beginner however I couldn’t find anyone that had made a useful video or post about charging/holding skills before releasing them.

2 Likes

Alright, I don’t know if this is how people do it conventionally, but I’m almost positive that this is the most efficient way how to do it.

local RunService = game:GetService("RunService")

local function TrackTime()
	local counter = 0
	local tracker = RunService.Heartbeat:Connect(function(deltaTime) -- Uses deltaTime so that the time is always accurate, no matter the framerate
		counter += deltaTime
	end)
	local function endTracking()
		tracker:Disconnect()
		return counter
	end
	return endTracking -- returns this so that when the user stops holding, we can call this
end

Basically, when the function is called, it will begin a counter. The reason why we use delta time is so that the time is the same across framerates.
If we updated it using task.wait(), somebody with a higher framerate would have a much faster counter.

The reason why are returning a function, is because we are going to use UserInputService to see when the user has stopped clicking, and when that happens, we will stop the counter.

Now we can use UserInputService

function UIS.KeyPressed(input : InputObject)
	if input.KeyCode == Enum.KeyCode.E then
		local EndTracking = TrackTime() -- Remember that returned function that I was talking about
		local keyReleased -- declaring outside of scope so that we can disconnect inside of the function
		keyReleased = UserInputService.InputEnded:Connect(function(endedInput)
			if endedInput == input then
				local timeHeld = EndTracking() -- Now we have how long the user held for and you could use it for anything you want.
				keyReleased:Disconnect() -- Just for memory concerns
			end
		end)
	end
end

UserInputService.InputBegan:Connect(UIS.KeyPressed) -- Calling it separately

So now basically, when the key is initially pressed, we will receive a function that allows us to stop the counter. We will then call that function when the key is released, and you could use the time for whatever you want.
If you wanted something to happen if the counter was > 5, then you could do that.

Also, if you wanted like some sort of animation to play while they player was holding down the key or something of that nature, then you could just do this:

local function TrackTime()
	local counter = 0
	local tracker = RunService.Heartbeat:Connect(function(deltaTime) -- Uses deltaTime so that the time is always accurate, no matter the framerate
		counter += deltaTime
	end)
	local animation : AnimationTrack = game.Players.LocalPlayer.Character.Humanoid.Animator:LoadAnimation(game.ReplicatedStorage.Animation) -- Wherever you store it
	animation:Play()
	local function endTracking()
		animation:Stop()
		tracker:Disconnect()
		return counter
	end
	return endTracking -- returns this so that when the user stops holding, we can call this
end

Basically, the point is, you could do anything you want with it.

1 Like

Thanks so much for the help aswell as the explanation!

1 Like

Also it gave me an error when the function was named UIS.KeyPressed so I just removed the period and re-named it to “UISKeyPressed” to fix it. :+1:

1 Like

Also (sorry to bother), what if I wanted, for example, the player to jump when the counter hits 5 seconds without releasing the key?

Server Script

local RS = game:GetService("ReplicatedStorage")
local manaShieldRE = game.ReplicatedStorage.Remotes.manaShield


manaShieldRE.OnServerEvent:Connect(function(plr, timeHeld)
	
	local hum =  plr.Character:WaitForChild("Humanoid")
	local humRP = plr.Character:WaitForChild("HumanoidRootPart")
	
	print(timeHeld)
	if timeHeld >= 5 then
		hum.Jump = true
	end
	
end)

Local Script is the same

Just fire the remote event after calling EndTracking

local timeheld = EndTracking()
manashieldRe:FireServer(timeheld)

Since the input already ended, you do not need to account for when the key was stopped being held down and fire away

I meant like a way to get the time held during the input instead of after the player releases the key

I believe you are talking in reference to this question:

Also (sorry to bother), what if I wanted, for example, the player to jump when the counter hits 5 seconds without releasing the key?

You could simply just check the time every time the counter increases. So inside of the RunService Hearbeat connection, you could do this:

local tracker = RunService.Heartbeat:Connect(function(deltaTime) -- Uses deltaTime so that the time is always accurate, no matter the framerate
	counter += deltaTime
	if counter >= 5 then
		-- Do whatever you want here
		return counter -- This would automatically stop the timer, if you want the timer to still go on, then don't include this line
	end
end)
1 Like

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