How to reference player character through server script for a tool

hey guys im making a water propulsion device for my game, and how it works is quite simple. All i do is just check the current state of the humanoid and then change the player speed if its “swimming”. Did this using a while loop, however now came the issue of adding animations (im still very new to working with animations).

Since animations need to be loaded through the animator, i needed to reference the character, however the character cannot be referenced outside of the function since the script will think im referencing the backpack. So what do you guys suggest i do?

Heres the code:

local handle = script.Parent.Handle

local idleland = script.Parent.IdleLand
local idlewater = script.Parent.Idlewater 
local character = script.Parent.Parent

local animator = character:WaitForChild("Humanoid").Animator

local IdleLandTrack = animator:LoadAnimation(idleland)
local IdleWaterTrack = animator:LoadAnimation(idlewater)
IdleLandTrack.Looped = true
IdleWaterTrack.Looped = true
IdleLandTrack.Priority = Enum.AnimationPriority.Idle
IdleWaterTrack.Priority = Enum.AnimationPriority.Idle



script.Parent.Equipped:Connect(function()
	while true do
		wait(0.5)
	if character:FindFirstChild("Humanoid"):GetState() == Enum.HumanoidStateType.Swimming then
		character:WaitForChild("Humanoid").WalkSpeed = 60
		handle.Sound.Playing = true
	else
		handle.Sound.Playing = false
		character:WaitForChild("Humanoid").WalkSpeed = 16
	end
end

	
script.Parent.Unequipped:Connect(function()
			IdleLandTrack:Stop()
			IdleWaterTrack:Stop()
			character:WaitForChild("Humanoid").WalkSpeed = 16
	end)
end)


4 Likes

quick little note, dont use wait, its deprecated, use task.wait() which is better/way more accurate

you can use the :GetPlayerFromChracter() function which is in the player service

ex (for getting player):

local plrservice = game:GetService("Players")

local tool = script.Parent
local plr

connection = tool.Equipped:Connect(function()
   plr = plrservice:GetPlayerFromChracter(tool.Parent)
   connection:Disconnect()
end)

for getting the player while its in the backpack all you would need to do is this:

local tool = script.Parent
local plr = tool:FindFirstAncestorOfClass('Player')
--plr.Character references the character of the player 
3 Likes

Here’s how Ill do it: I’ll set the character variable to nil.

Now, just hear me out for a sec. When the tool is equipped, the character becomes the tool’s parent (you can see this in the studio). So, I’ll change the character variable from nil to tool.Parent when it’s equipped.

To keep things smooth and avoid any errors, I always check if the character is nil before using it.

3 Likes

:+1:
this would work completely fine too


but the problem with this is memory optimization (just make sure you disconnect the connection and it would be all good)

many people don’t disconnect defined connections which lead to memory leaks, which can lead to bad performance and make your game genuinely unplayable to players on a weaker device (ex: a phone), which makes you lose out on players who could love the concept of the game, but never really get to enjoy the game due to performance issues.

1 Like

You can use :Once instead of :Connect, which will automatically disconnect the connection for you after the event is fired once (hence its name):

local tool = script.Parent


local character


tool.Equipped:Once(function() -- Use "Once" if you otherwise don't need to detect when the Tool is equipped
	character = tool.Parent
	print(character) -- For debugging purposes
end)

@heromahdi

2 Likes

i have never seen the :Once connection, ill look into it, thanks a lot.
this will save me so much time and effort :grin:

1 Like

question, why are you doing

local plr

connection = tool.Equipped:Connect(function()

instead of

local plrconnection = tool.Equipped:Connect(function()

Thats actually a good idea, but what about the animation i have to load?

not the same thing, the first one sets a variable named plr to nil, second one doesnt.

1 Like

i see that makes sense, so its basically the same as doing

local character = nil

correct?

yeah, not giving it a value means its nothing (nil)

also you cannot locally define a connection im pretty sure

2 Likes

yea i was confused at first, cuz i thought you were locally defining the connection lol

i tried this out, and yea it works like a charm, idk if its optimized tho, heres the code:

local tool = script.Parent

local character = nil

tool.Equipped:Connect(function()
	
if character == nil then
	character = tool.Parent
end

	local animator = character:WaitForChild("Humanoid").Animator

	local idleland = script.Parent.IdleLand
	local idlewater = script.Parent.Idlewater

	local IdleLandTrack = animator:LoadAnimation(idleland)
	local IdleWaterTrack = animator:LoadAnimation(idlewater)
	IdleLandTrack.Looped = true
	IdleWaterTrack.Looped = true
	IdleLandTrack.Priority = Enum.AnimationPriority.Idle
	IdleWaterTrack.Priority = Enum.AnimationPriority.Idle
	
	if character:FindFirstChild("Humanoid"):GetState() == Enum.HumanoidStateType.Swimming then
		IdleWaterTrack:Play()
	elseif character:FindFirstChild("Humanoid"):GetState() ~= Enum.HumanoidStateType.Swimming then
		IdleLandTrack:Play()
	end
	tool.Unequipped:Connect(function()
		if character ~= nil then
			character = nil
end
		IdleLandTrack:Stop()
		IdleWaterTrack:Stop()
	end)
end)

I just made a seperate script for the animation part. I might tweak the whole system later, but for now this works.

Nice (ahhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh ignore the message gotta be 50 characters long yk)

1 Like

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