My friend asked me if I could create a simple feature where upon a player’s death, their hats…
- become
CanCollide = true
so they don’t fall through the map, - linger on the map for a little bit even after the died player respawns, and
- are able to be picked up by other players during this lingering time.
Well that’s pretty easy to do. But there’s a bug when parenting the hats to workspace. For some reason, one hat will necessarily stay in the character.
https://gyazo.com/c4f0c42ea19047d7abf227e34a4d6561
In this gif, pay close attention to the selected hats in the Explorer when the character dies. You’ll see that one appears to stay behind. If you look at the output, however, it doesn’t seem to show an issue. It’s printing the GetFullName()
immediately after parenting each hat to workspace.
This makes me think there’s some sort of bug where one hat is immediately re-parented to the character. It also seems that the collision property gets reverted as well. I tested doing this while the humanoid was alive as well, and the bug was NOT there.
Here's the code if you think that's where the issue lies.
I made a server-side script in StarterCharacterScripts
that has a listener for the humanoid’s death. It gets all the accessories, makes their Handles CanCollide = true
, parents the accessories themselves to workspace
, and copies a pickup/debris script into them.
Path in DataModel:
DropHats
code:
print("--- New character ---")
local Character = script.Parent
Character:WaitForChild("Humanoid").Died:Connect(
function()
local List = Character:GetChildren()
for i = 1, #List do
local Item = List[i]
if Item and Item:IsA("Accessory") then
Item.Parent = workspace
print(Item:GetFullName(),"- attempted parent change")
Item.Handle.CanCollide = true
local Pickup_Debris = script.Pickup:Clone() -- Allows a dropped hat to be picked up, and also cleans up the dropped hat after 20 seconds if not picked up
Pickup_Debris.Parent = Item
Pickup_Debris.Disabled = false
end
end
end
)
I put the pickup/debris code in a separate script because the above script is deleted when the character respawns. This makes it so the touch connection and cleanup wait
don’t terminate then.
Pickup
code:
local Accessory = script.Parent
Accessory.Handle.Touched:Connect(
function(OtherPart)
local HitHumanoid = OtherPart.Parent:FindFirstChildOfClass("Humanoid")
if HitHumanoid and HitHumanoid.Health > 0 then
print(Accessory:GetFullName(), "picked up")
HitHumanoid:AddAccessory(Accessory)
Accessory.Handle.CanCollide = false
script:Destroy() -- Delete this script when the hat is picked up
end
end
)
wait(20)
if script.Parent then -- If the script hasn't been deleted after twenty seconds (how could this ever be nil?)...
script.Parent:Destroy() -- ... then delete the hat
end
I also have a LocalScript in StarterPlayerScripts
that kills the LocalPlayer when E
is pressed and deletes the LocalPlayer’s hats when =
is pressed. This is purely for testing purposes however.
game:GetService("UserInputService").InputBegan:Connect(
function(InputItem)
if InputItem.UserInputType == Enum.UserInputType.Keyboard then
if InputItem.KeyCode == Enum.KeyCode.E then
print("LocalPlayer died")
game.Players.LocalPlayer.Character.Humanoid.Health=0
elseif InputItem.KeyCode == Enum.KeyCode.Equals then
print("LocalPlayer deleted worn hats")
for _,Hat in pairs(game.Players.LocalPlayer.Character.Humanoid:GetAccessories()) do
Hat:Destroy()
end
end
end
end
)
And a .rbxl file to test with for yourself:
PickupDiedPlayersHats.rbxl (22.3 KB)
I even tried having the script just clone each hat and delete the original. The issue didn’t change.