How to make a proper drop system

Recently (As of 21/04/2023) I came across and issue that probably nobody had, A proper drop script. One that I mean actually drops an item in-front of you and doesn’t do this.

This irritated me, because I wanted to drop an item in a small confined area but I couldn’t as my drop would just go through the roof and the walls. So I spent hours searching for a solution and I couldn’t find one, Until I kept using trial and error to finally beat this bug.

Here is the final product

Project Setup:

  1. Create LocalScript In “StarterCharacterScripts”. Name it whatever you want.
    Screenshot 2023-04-21 052927

  2. Paste this code into your script

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

local remoteEvent = ReplicatedStorage:WaitForChild("Dropped") -- Wait for RemoteEvent to Load
local player = game.Players.LocalPlayer -- Get local player

UserInputService.InputBegan:Connect(function(input, player) -- InputService
	if input.UserInputType == Enum.UserInputType.Keyboard then
		if input.KeyCode == Enum.KeyCode.Q then -- When Q is pressed do this
			remoteEvent:FireServer() -- Fire Remote Event
		end
	end
end)
  1. Next you must locate to “Replicated Storage”. Now create a “RemoteEvent” and called it “Dropped”. Now create a folder in “Replicated Storage” called “Items”, Place every single one of your items inside this folder for these scripts to work.
    Screenshot 2023-04-21 053543

  2. Now make a “Script” Inside of “ServerScriptService”. Name it whatever you want.
    Then paste this one of two these code boxes provided inside of the script.
    Screenshot 2023-04-21 053846

    SOLUTION 1

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local runService = game:GetService("RunService")

local remoteEvent = ReplicatedStorage:WaitForChild("Dropped")

remoteEvent.OnServerEvent:Connect(function(player)
	local humanoid = player.Character:WaitForChild("HumanoidRootPart") -- Wait for player humanoid to load
	
	if humanoid then
		local cast = workspace:Raycast(humanoid.Position, humanoid.CFrame.LookVector * (4)) --Raycast 4 studs away from players lookVector
		if cast ~= nil then -- If the cast hit something
			local items = game.ReplicatedStorage.Items -- Get Items Folder
			local item = player.Character:FindFirstChildWhichIsA("Tool") -- Get equipped player tool
			if item then -- Make sure an Item is equipped so no errors are thrown
				local tool = item:FindFirstChild("Handle") -- Get the handle of this tool

				item.Parent = game.workspace -- Parent to workspace
				item.Handle.CFrame = CFrame.new(cast.Position) -- Set the CFrame of the part to this raycast hit position
			else
				return -- No Item Equipped
			end
			
		else -- If Raycast Hit Nothing
			local items = game.ReplicatedStorage.Items -- Get Items Folder
			local item = player.Character:FindFirstChildWhichIsA("Tool")-- Get equipped player tool
			if item then -- Make sure an Item is equipped so no errors are thrown
				local tool = item:FindFirstChild("Handle") -- Get the handle of this tool
				
				item.Parent = game.workspace -- Parent to workspace
				item.Handle.CFrame = player.Character.HumanoidRootPart.CFrame * CFrame.new(0,0,-4) -- Set The CFrame position to infront of the player
			else
				return -- No Item Equipped
			end
		end
	end
end)
  1. Thats it, your drop system should now work.

NOTE: If for whatever reason solution 1 doesn’t work with your items, you can use solution 2, and vice versa. If you have any improvements etc. Feel free to comment them and I can repost this with an improved version. A big thanks to @lAmTheGovernment for the first solution and @Bubblebuddy200 for the raycast implementation. Lots of credit to them for the help.

4 Likes

Not related to the topic but damn, I blinked and now it’s already 2024?

PS: It would also be nice to add some comments into your code.

1 Like

Haha Thanks for letting me know! I shall comment it and update it.

This looks like it’ll still go through walls if you really wanted it to so I would add raycasting to prevent something like that from happening

Can you tell how I could do that? Not familiar with raycasts

I would add this piece of code somewhere

local cast = workspace:Raycast(humanoid.Position, humanoid.CFrame.LookVector * (studs), optional raycastparams)

and check if it has hit anything. If the raycast hit then drop the item there and offset it towards the player by like 1 stud so nothing funky happens.

The way I would check if it hit anything is by

if cast ~= nil then
--hit something
else
--didn't hit anything
end

So the final results would look something like

local finalCFrame = humanoid.CFrame + (humanoid.CFrame.LookVector * Vector3.new(2,2,2))

local cast = workspace:Raycast(humanoid.Position, humanoid.CFrame.LookVector * 5) -- check 5 studs infront the player

if cast ~= nil then
   finalCFrame = cast.Position
end

--move item to cframe

If you want to know how to move it towards the player then I would suggest figuring out world space or vector3 units

1 Like

Thank you very much! I will update this thread in a bit but if your curious right now here is what I did.

So I pretty much did exactly what you told me to do. It worked flawlessly and now the player can’t drop through walls.

https://gyazo.com/cb767dccfee112a18c887654a50d4c72

SERVER

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local runService = game:GetService("RunService")

local remoteEvent = ReplicatedStorage:WaitForChild("Dropped")

remoteEvent.OnServerEvent:Connect(function(player)
	local humanoid = player.Character:WaitForChild("HumanoidRootPart") -- Wait for player humanoid to load
	
	if humanoid then
		local cast = workspace:Raycast(humanoid.Position, humanoid.CFrame.LookVector * (4)) --Raycast 4 studs away from players lookVector
		if cast ~= nil then -- If the cast hit something
			local items = game.ReplicatedStorage.Items -- Get Items Folder
			local item = player.Character:FindFirstChildWhichIsA("Tool") -- Get equipped player tool
			local tool = item:FindFirstChild("Handle") -- Get the handle of this tool

			item.Parent = game.workspace -- Parent to workspace
			item.Handle.CFrame = CFrame.new(cast.Position) -- Set the CFrame of the part to this raycast hit position
		else -- If Raycast Hit Nothing
			local items = game.ReplicatedStorage.Items -- Get Items Folder
			local item = player.Character:FindFirstChildWhichIsA("Tool")-- Get equipped player tool
			local tool = item:FindFirstChild("Handle") -- Get the handle of this tool

			item.Parent = game.workspace -- Parent to workspace
			item.Handle.CFrame = player.Character.HumanoidRootPart.CFrame * CFrame.new(0,0,-4) -- Set The CFrame position to infront of the player
		end
	end
end)

Thank you very much for this solution. I have updated a few things clientside to avoid errors being thrown that don’t need to be as well but I wont be posting on this comment thread as its irrelevant as of now.