Hello people, so i have been trying to fix my car spawning scripts for some time now and havent been able to, i keep running into bugs where for example: Car spawns in the wrong place, UI doesnt open or the car just does not spawn. Here is my code
Serverscript:
local SpawnCarEvent = game:GetService("ReplicatedStorage"):WaitForChild("Remotes").SpawnCar
local CarsInGame = workspace.CarsIngame
local Spawner = nil
for i, spawner in pairs(workspace:GetDescendants()) do
if spawner:IsA("Model") and spawner.Name == "Spawner" then
local PClone = script.SpawnPrompt:Clone()
PClone.Parent = spawner:FindFirstChild("Select")
Spawner = spawner
end
end
local function SpawnVehicle(Player, Vehicle)
if Vehicle then
--If the player has any old cars
for i, oldcar in pairs(CarsInGame:GetChildren()) do
if oldcar:IsA("Model") then
if oldcar.Name == Player.Name then
oldcar:Destroy()
end
end
end
--Wait a nanosecond so if the player has more than 1 car, the script deletes them when they try to spawn a new one
task.wait()
local ClonedVehicle = Vehicle:Clone()
ClonedVehicle.Name = Player.Name
ClonedVehicle.Parent = CarsInGame
ClonedVehicle:MoveTo(Spawner.SpawnPos.Position)
end
end
local function OnPlayerLeave(Player)
if CarsInGame:FindFirstChild(Player.Name) then
CarsInGame:FindFirstChild(Player.Name):Destroy()
else
return
end
end
game.Players.PlayerRemoving:Connect(OnPlayerLeave)
SpawnCarEvent.OnServerEvent:Connect(SpawnVehicle)
Local script:
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local SpawnCarEvent = ReplicatedStorage.Remotes.SpawnCar
local Vehicles = ReplicatedStorage:WaitForChild("Cars")
local SelectionFrame = script.Parent.Selection
local UITemplate = ReplicatedStorage:WaitForChild("Templates").Template
-- Add a button for every spawnable vehicle
for i, vehicleModel in pairs(Vehicles:GetChildren()) do
if vehicleModel:IsA("Model") and vehicleModel:FindFirstChildOfClass("VehicleSeat") then
local NewUI = UITemplate:Clone()
NewUI.Parent = SelectionFrame
NewUI.Name = vehicleModel.Name
NewUI.Text = vehicleModel.Name
NewUI.MouseButton1Up:Connect(function()
local chosenVehicle = Vehicles:FindFirstChild(NewUI.Name)
SpawnCarEvent:FireServer(chosenVehicle)
script.Parent.Enabled = false
end)
end
end
-- Make vehicle selection UI visible when the player triggers the prompt
for i, spawner in pairs(workspace:GetDescendants()) do
if spawner:IsA("Model") and spawner.Name == "Spawner" then
local selectFolder = spawner:FindFirstChild("Select") or spawner:WaitForChild("Select")
if selectFolder and selectFolder:FindFirstChildOfClass("ProximityPrompt") then
local prompt = selectFolder:FindFirstChildOfClass("ProximityPrompt")
prompt.Triggered:Connect(function(plr)
if script.Parent.Enabled == false then
script.Parent.Enabled = true
else
script.Parent.Enabled = false
end
end)
end
end
end
When referencing instances in ReplicatedStorage, ServerStorage, etc. from a server side Script you do not need to use :WaitForChild() because the replication is done from server to clients and not server to server which means that when the server starts it will already have all assets ready.
This is inefficient, consider using CollectionService and retrieve all spawners by using CollectionService:GetTagged("CarSpawner") and tag all car spawners CarSpawner through the properties window. Anyway why would this be necessary if you are setting the Spawner variable which can only hold one spawner?
Avoid using so similar variable names.
This is unsafe, you are cloning whatever the player is passing as argument to the RemoteEvent, which if the player is using exploits will cause errors.
If SpawnVehicle() is the only function that spawns vehicles, this is redundant since you can just use
local oldCar = CarsInGame:FindFirstChild(player.Name)
if oldCar then
oldCar:Destroy()
end
This is redundant
Corrected server script:
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local CarsInGame: Folder -- Looks like you are using a folder
local Spawner -- Set a reference to the vehicles spawner
local function SpawnVehicle(player: Player, vehicleName: string)
-- Check if the server received a the name of a valid vehicle
local targetVehicle = ReplicatedStorage.Cars:FindFirstChild(vehicleName)
if not targetVehicle then
-- Server received invalid vehicle name, player might be exploiting or there is a bug on the client side
return
end
-- Destroy the player's previous vehicle
local oldVehicle = CarsInGame:FindFirstChild(player.Name)
if oldVehicle then
oldVehicle:Destroy()
end
-- Spawn the new car
local newVehicle: Model = targetVehicle:Clone()
newVehicle.Name = player.Name
newVehicle.Parent = CarsInGame
newVehicle:PivotTo(CFrame.new(Spawner.SpawnPos.Position))
end
local function OnPlayerLeave(player)
local playerVehicle = CarsInGame:FindFirstChild(player.Name)
if playerVehicle then
playerVehicle:Destroy()
end
end
SpawnCarEvent.OnServerEvent:Connect(SpawnVehicle)
Players.PlayerRemoving:Connect(OnPlayerLeave)
It seems the issue is in the LocalScript. Are there any errors in the output?
How should i go about making the Clone() part safer? And also using the collectionservice correctly? So my problem which i actually managed to fix a few minutes ago was that, i had 3 spawners, and when i spawned a car on one of them, it spawned, but when i walked to another spawner and spawned a car, it spawned in the previous spawner.
Heres my updated code, tell me what to change if needed:
Serverscript:
local CollectionService = game:GetService("CollectionService")
local SpawnCarEvent = game.ReplicatedStorage.Remotes.SpawnCar
local CarsInGame = workspace.CarsIngame
local Spawner = nil
for i, spawner in pairs(workspace:GetDescendants()) do
if spawner:IsA("Model") and spawner.Name == "Spawner" then
local PClone = script.SpawnPrompt:Clone()
PClone.Parent = spawner:FindFirstChild("Select")
Spawner = spawner
end
end
local function SpawnVehicle(Player, Vehicle)
if Vehicle then
--If the player has any old cars
local oldCar = CarsInGame:FindFirstChild(Player.Name)
if oldCar then
oldCar:Destroy()
end
--Wait a nanosecond so if the player has more than 1 car, the script deletes them when they try to spawn a new one
task.wait()
local ClonedVehicle = Vehicle:Clone()
ClonedVehicle.Name = Player.Name
ClonedVehicle.Parent = CarsInGame
--This part is in progress, gonna make it so that the car is a bit farther away from the spawner and is also facing it with its side
--Rotate the model to face the spawner with its left side
end
end
local function OnPlayerLeave(Player)
if CarsInGame:FindFirstChild(Player.Name) then
CarsInGame:FindFirstChild(Player.Name):Destroy()
end
end
game.Players.PlayerRemoving:Connect(OnPlayerLeave)
SpawnCarEvent.OnServerEvent:Connect(SpawnVehicle)
Localscript:
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local SpawnCarEvent = ReplicatedStorage:WaitForChild("Remotes"):WaitForChild("SpawnCar")
local Vehicles = ReplicatedStorage:WaitForChild("Cars")
local SelectionFrame = script.Parent:WaitForChild("Selection")
local UITemplate = ReplicatedStorage:WaitForChild("Templates"):WaitForChild("Template")
-- Make vehicle selection UI visible when the player triggers the prompt
for i, spawner in pairs(workspace:GetDescendants()) do
if spawner:IsA("Model") and spawner.Name == "Spawner" then
local selectFolder = spawner:FindFirstChild("Select") or spawner:WaitForChild("Select")
if selectFolder and selectFolder:FindFirstChildOfClass("ProximityPrompt") then
local prompt = selectFolder:FindFirstChildOfClass("ProximityPrompt")
prompt.Triggered:Connect(function(plr)
if script.Parent.Enabled == false then
script.Parent.Enabled = true
else
script.Parent.Enabled = false
end
end)
end
end
end
-- Add a button for every spawnable vehicle
for i, vehicleModel in pairs(Vehicles:GetChildren()) do
if vehicleModel:IsA("Model") and vehicleModel:FindFirstChildOfClass("VehicleSeat") then
local NewUI = UITemplate:Clone()
NewUI.Parent = SelectionFrame
NewUI.Name = vehicleModel.Name
NewUI.Text = vehicleModel.Name
NewUI.MouseButton1Up:Connect(function()
local chosenVehicle = Vehicles:FindFirstChild(NewUI.Name)
SpawnCarEvent:FireServer(chosenVehicle)
script.Parent.Enabled = false
end)
end
end
Collection service helps you organize your instances by grouping them with tags. Think of it like a sorting function on a website that has blog articles and help articles listed together. CollectionService would group the articles in Blog and Help.
By using CollectionService you don’t have to use for loops to find specific instances among mixed ones to filter out those that don’t meet a condition. If you tag all your car spawners CarSpawner, in your script you can then do
local spawners = CollectionService:GetTagged("CarSpawner")
and when a player spawns a car you can loop through the spawners array, find the one closest to the player and spawn the car there.
Also one last question, how do i make it so that when the car is spawned, it always is about 15 studs away from the spawner and is facing it with its left side no matter the position or orientation of the spawner?
edit: forgot to say that i removed the spawnpos part too
What you want to do is first make the car look with its front face at the spawner so that then you will know how much to rotate it to make it look at the spawner with its left face.
Here’s a link to a documentation section that explain specifically that: