Itâs not a problem!
From what youâre describing, you essentially want a system that can let a player teleport to a crate that theyâve collected. Iâm sorry if I misunderstood this in advance, I do have a way to implement this system, but there are numerous ways this system can be implemented. This system is how I would go about this.
The system Iâve devised in a nutshell, crates are contained in a seperate folder in the workspace called âCratesâ, I bind a .Touched event to each object by using a for each loop so that when the player touches the crate, it creates a Vector3Value named the same as the crate (in my project, itâs â1â, â2â etcâŠ) providing that the value doesnât already exist. If the player hasnât touched the crate before, it creates the Vector3Value, setting the .Value property of this value equal to the crate position and parents it to a folder in ServerStorage containing the players data. Itâs good practice to contain data you donât want modified by any client in ServerStorage, since only the server can directly modify the objects contained within it.
With a basic summary of this system out of the way, I can provide you with the code. Iâve commented each script to give you a understanding of what the code does, along with a reason as to why Iâve done it. In advance, I apologise for the amount of comments in the code.
Firstly, Iâve created a script called âDataCreationâ in ServerScriptService, which creates the folder structure for the player and their data:
local PS = game:GetService("Players")
local SS = game:GetService("ServerStorage")
-- Wait for the 'Data' folder in ServerStorage, yielding until the folder exists.
local dataFolder = SS:WaitForChild("Data")
-- We create the required folders for the player upon their player being added into the game, hence the .PlayerAdded event.
PS.PlayerAdded:Connect(function(player)
-- Create a new instance of a player folder, being a child of dataFolder.
local plrFolder = Instance.new("Folder")
-- Name the folder to the tostring() of the plr.UserId, tostring() converts whatever you pass into the parameters to a string.
plrFolder.Name = tostring(player.UserId)
plrFolder.Parent = dataFolder
-- Depending on whether you're having seperate data other than the crates touched by the player, we can create a sub-folder to contain crate data specifically.
local crateFolder = Instance.new("Folder")
crateFolder.Name = "CrateData"
crateFolder.Parent = plrFolder
end)
-- When the player is removed from the game, we also need to make sure the player's data in ServerStorage goes with it, which is where a .PlayerRemoving event comes in.
PS.PlayerRemoving:Connect(function(player)
local plrFolder = dataFolder:FindFirstChild(tostring(player.UserId))
if plrFolder then
plrFolder:Destroy()
end
end)
In another script called âCrateTouchedBindingâ which is in ServerScriptService, this binds the .Touched events for the crates so when a specific one is touched, it creates a Vector3Value and stores it into the âCrateDataâ folder we created in the .PlayerAdded above. For demonstration of the teleporting working as your idea intends, I bind .Touched events to some teleport parts, which basically check whether the Vector3Value for the specific crate exists in the playerâs crate data and if it does, will teleport to the Vector3Value.Value.
local WS = game:GetService("Workspace")
local PS = game:GetService("Players")
local SS = game:GetService("ServerStorage")
local RS = game:GetService("ReplicatedStorage")
-- Wait for the 'Data' folder in ServerStorage, yielding until the folder exists.
local dataFolder = SS:WaitForChild("Data")
-- Wait for the 'Crates' folder in Workspace, yielding until the folder exists.
local cratesFolder = WS:WaitForChild("Crates")
-- Loop through the parts/crates contained in cratesFolder and bind a .Touched event to each part. Ensure to check whether crateObject is a BasePart, since we need it to be to be able to access the .Touched event.
for _, crateObject in ipairs(cratesFolder:GetChildren()) do
if crateObject:IsA("BasePart") then
-- We now have a .Touched event and used :Connect() to connect a function upon the .Touched event being triggered.
crateObject.Touched:Connect(function(hit)
-- We use :GetPlayerFromCharacter(hit.Parent) to ensure that hit.Parent (assuming hit.Parent is the character) that it can find a player object from that.
local player = PS:GetPlayerFromCharacter(hit.Parent)
if player then
-- We now find the player's data folder specifically here (as shown in the data creation, would be the player's userid as a string).
local playerFolder = dataFolder:FindFirstChild(tostring(player.UserId))
if playerFolder then
-- If you plan on having other pieces of data other than the crates collected, we can categorise this data in a sub-folder called "CrateData".
local crateData = playerFolder:FindFirstChild("CrateData")
if crateData then
-- Now we have the crateData folder, we can create a Vector3Value object, naming the object the same as the crate collected and changing the value to the crate's position.
-- We do however need to ensure that the value for the specific crate hasn't been created yet.
local cratePositionValue = crateData:FindFirstChild(crateObject.Name)
if not cratePositionValue then
-- Create the Vector3Value object and assign its value to the crate's position, I've added 3 onto the Y so that the player teleports above the part.
local cratePositionValue = Instance.new("Vector3Value")
cratePositionValue.Name = crateObject.Name
cratePositionValue.Value = crateObject.CFrame.p + Vector3.new(0,3,0)
cratePositionValue.Parent = crateData
-- This isn't needed, but I had to create a way to signify whether the player has touched a specific crate. I just :FireClient to the player which changes the 'TouchToTeleport' part specifically.
RS:WaitForChild("ChangeCrateTouchedPartColour"):FireClient(player, crateObject.Name)
end
end
end
end
end)
end
end
-- You don't have to do this bit, this is just for me to create a way to teleport to crates the player has touched.
local touchToTeleportFolder = WS:WaitForChild("TouchToTeleport")
for _, touchTeleportPart in ipairs(touchToTeleportFolder:GetChildren()) do
touchTeleportPart.Touched:Connect(function(hit)
local plr = PS:GetPlayerFromCharacter(hit.Parent)
if plr then
local playerDataFolder = dataFolder:FindFirstChild(tostring(plr.UserId))
if playerDataFolder then
local playerCrateFolder = playerDataFolder:FindFirstChild("CrateData")
if playerCrateFolder then
local vector3Value = playerCrateFolder:FindFirstChild(touchTeleportPart.Name)
if vector3Value then
local HRP = hit.Parent:FindFirstChild("HumanoidRootPart")
if HRP then
HRP.CFrame = CFrame.new(vector3Value.Value)
end
end
end
end
end
end)
end
Regarding this line of code:
RS:WaitForChild("ChangeCrateTouchedPartColour"):FireClient(player, crateObject.Name)
I just created a LocalScript in ReplicatedFirst called âChangePartColourâ that contains code so that when the .OnClientEvent event (triggered by :FireClient() from the server) runs, it executes the function which we :Connect() to the event, as we pass through within the :FireClient() parameter the player along with the crate name, we know that we should only perform this code for the player specifically, along with what part we need the change to happen to. In this case, I just change the part colour to green.
local RS = game:GetService("ReplicatedStorage")
local WS = game:GetService("Workspace")
local touchToTeleportFolder = WS:WaitForChild("TouchToTeleport")
RS:WaitForChild("ChangeCrateTouchedPartColour").OnClientEvent:Connect(function(crateName)
local teleportPart = touchToTeleportFolder:FindFirstChild(crateName)
if teleportPart then
teleportPart.Color = Color3.fromRGB(0,255,0)
end
end)
Although this part isnât needed (as I donât know how you plan on having people teleport to specific crates theyâve collected, whether it be via a GUI, teleporters like in my demonstration etcâŠ), I have showed you anyway in the event it helps any.
I also forgot to mention, I have a RemoteEvent stored in ReplicatedStorage called âChangeCrateTouchedPartColourâ. In fact, Iâll provide an image as to how my explorer looks, along with the workspace right now:
In the event you want to look more into the project, Iâve provided an example Roblox place file so you can look into how it works.
CrateCollectionSystem.rbxl (31.3 KB)
I hope this helps again, or whether I even understood you correctly. Apologies for the long answer as well, I just wanted to ensure I explained everything. If you have any question, feel free to ask.