How To Make A Traffic System?

How to make a traffic system for cars?

I want to make a car that follows a road automatically, it detects the streets, puts a path through the whole road. I want like the video shown: https://www.youtube.com/watch?v=Qqapt_AbPv4

This is my code:

local car = workspace.Cars.Car4.Item local carPrimaryPart = car["primary part"] local CollectionService = game:GetService("CollectionService") local PathFindingService = game:GetService("PathfindingService") local streets = CollectionService:GetTagged("street") local streetsFinishedDriving = {} local hasFinishedDriving = false local function findCurrentStreet()	local raycastOrigin = carPrimaryPart.Position	local raycastDirection = Vector3.new(0, -10000, 0) -- Straight down	local raycastParams = RaycastParams.new()	raycastParams.FilterDescendantsInstances = {streets} -- Ensure streets are grouped	raycastParams.FilterType = Enum.RaycastFilterType.Include	local raycastResult = workspace:Raycast(raycastOrigin, raycastDirection, raycastParams)	if raycastResult then	local street = raycastResult.Instance	if street then	print("Street found:", street)	table.insert(streetsFinishedDriving, street)	return street	else	print("Hit something else:", raycastResult.Instance.Name)	end	else	print("Raycast did not hit anything.")	end	return nil -- Explicitly return nil if no street is found end local function findNextStreet(currentStreet)	local closestStreet = nil	local shortestDistance = math.huge	for _, street in streets do	if street ~= currentStreet then	print("current street: ", currentStreet,"street found: ", street)	local distance = (street.Position - currentStreet.Position).Magnitude	local displacement = street.Position - carPrimaryPart.Position	local direction = carPrimaryPart.CFrame.LookVector	print(direction)	local dot = displacement:Dot(direction)	if distance < shortestDistance and dot >= 0.2 then	print("dot: ", dot, "closest street: ", closestStreet, "shortest distance: ", shortestDistance)	for i, finishedDrivingstreet in streetsFinishedDriving do	print(finishedDrivingstreet)	if not (finishedDrivingstreet == street) then	print("Already driving this street")	closestStreet = street	shortestDistance = distance	end	end	end	end	end	return closestStreet end local function smoothTurn(carPart, targetPoint)	local currentCFrame = carPart.CFrame	local targetDirection = (targetPoint - carPart.Position).Unit	local targetCFrame = CFrame.lookAt(carPart.Position, carPart.Position + targetDirection)	local deltaRotation = targetCFrame:ToObjectSpace(currentCFrame)	return deltaRotation end local function driveTo(startingPos, endingPos)	local path = PathFindingService:CreatePath()	path:ComputeAsync(startingPos, endingPos)	carPrimaryPart:SetNetworkOwner(nil)	local wayPoints = path:GetWaypoints()	local waypoint = 2	local moveToConnection	local linearVelocity = Instance.new("LinearVelocity")	linearVelocity.MaxForce = math.huge	linearVelocity.RelativeTo = Enum.ActuatorRelativeTo.World	linearVelocity.Enabled = true	local angularVelocity = Instance.new("AngularVelocity")	angularVelocity.MaxTorque = math.huge	local attachment = Instance.new("Attachment")	attachment.Parent = carPrimaryPart	linearVelocity.Attachment0 = attachment	linearVelocity.Parent = carPrimaryPart	angularVelocity.Attachment0 = attachment	for i, waypoint in ipairs(wayPoints) do	hasFinishedDriving = false	--if not hasRun or (carPrimaryPart.Position - waypoint.Position).Magnitude < 1 and 2 < #wayPoints then	local direction = (waypoint.Position - carPrimaryPart.Position).Unit	linearVelocity.VectorVelocity = direction * carPrimaryPart.AssemblyMass * 0.06	--angularVelocity.AngularVelocity = smoothTurn(carPrimaryPart, waypoint.Position).LookVector * 15	--end	end	hasFinishedDriving = true	return hasFinishedDriving end	while true do	local currentStreet = findCurrentStreet()	if currentStreet then	print("Current street detected: ", currentStreet)	local destination = findNextStreet(currentStreet)	if destination then	print("Destination detected: ", destination)	local finishedDriving = driveTo(carPrimaryPart.Position, destination.Position)	if finishedDriving then	driveTo(carPrimaryPart.Position, destination.Position)	end	else	warn("No valid destination found!")	end	else	warn("Failed to detect a current street.")	end	-- Optionally wait before starting again	task.wait(1)	end 

Explanation: I detect the current street(raycasting down from the car) and the closest street to the current street, and then just create a path to that closest street, and attach a linear velocity to the car to go to the waypoints of the path to the street.

It can make the car move along the street but most of the time its just back and forth between current and closest street, it also can’t turn, and its extremely unreliable since it keeps creating pathes in real time while driving.

Any help is appreciated!

6 Likes

Ello!

Does this work?

local car = workspace.Cars.Car4.Item local carPrimaryPart = car["primary part"] local CollectionService = game:GetService("CollectionService") local PathFindingService = game:GetService("PathfindingService") local streets = CollectionService:GetTagged("street") local hasFinishedDriving = false local currentDestination = nil local function findCurrentStreet() local raycastParams = RaycastParams.new() raycastParams.FilterDescendantsInstances = streets raycastParams.FilterType = Enum.RaycastFilterType.Include local raycastResult = workspace:Raycast(carPrimaryPart.Position, Vector3.new(0, -10000, 0), raycastParams) return raycastResult and raycastResult.Instance or nil end local function findNextStreet(currentStreet) local closestStreet = nil local shortestDistance = math.huge for _, street in ipairs(streets) do if street ~= currentStreet then local distance = (street.Position - carPrimaryPart.Position).Magnitude if distance < shortestDistance then closestStreet = street shortestDistance = distance end end end return closestStreet end local function smoothTurn(targetDirection) local currentCFrame = carPrimaryPart.CFrame local targetCFrame = CFrame.lookAt(carPrimaryPart.Position, carPrimaryPart.Position + targetDirection) local rotation = currentCFrame:ToObjectSpace(targetCFrame).Rotation carPrimaryPart.CFrame = carPrimaryPart.CFrame * rotation end local function driveTo(destination) hasFinishedDriving = false local path = PathFindingService:CreatePath() path:ComputeAsync(carPrimaryPart.Position, destination.Position) local waypoints = path:GetWaypoints() if #waypoints == 0 then warn("Pathfinding failed!") return end for _, waypoint in ipairs(waypoints) do local direction = (waypoint.Position - carPrimaryPart.Position).Unit smoothTurn(direction) local linearVelocity = Instance.new("LinearVelocity") linearVelocity.MaxForce = math.huge linearVelocity.RelativeTo = Enum.ActuatorRelativeTo.World linearVelocity.Velocity = direction * 10 -- Adjust speed as needed linearVelocity.Parent = carPrimaryPart while (carPrimaryPart.Position - waypoint.Position).Magnitude > 1 do task.wait() end linearVelocity:Destroy() end hasFinishedDriving = true end while true do if not hasFinishedDriving or not currentDestination then local currentStreet = findCurrentStreet() if currentStreet then local nextStreet = findNextStreet(currentStreet) if nextStreet then currentDestination = nextStreet driveTo(nextStreet) else warn("No next street found!") end else warn("Current street not detected!") end end task.wait(1) -- Prevent infinite loop lockup end 
3 Likes

Doesn’t really work and i don’t see any changes, the car just floats and i’m not sure why.

3 Likes

Have you tried using pathfinding links and attachments?
I think this other forum is more of what you should be looking at to help solve your issue

[Full Release] Introducing the Pathfinding Links for NPCs - Updates / Announcements - Developer Forum | Roblox

2 Likes

how would i go about using pathfinding attachments in order to make the car drive on the road endlessly?

3 Likes

Hi there,

I’ve put together two scripts for you. They’re probably a bit over the top for what you needed, but I’ve tested them, and they work great—very smooth. There are a few optional error checks included to help ensure everything is set up correctly. If you prefer, you can remove those.
For example, these lines will alert you if the waypoints folder is missing or empty:

if not waypointsFolder then	error("Waypoints folder 'selfDrivingWaypoints' not found!")	return end if #waypoints == 0 then	error("No waypoints found in 'selfDrivingWaypoints'!")	return end 

Important Note: Make sure your waypoints are set up properly and that the folder name in the script matches your actual folder name:

local waypointsFolder = workspace:FindFirstChild("selfDrivingWaypoints") 

Here’s an example of how the setup should look. You can use a car from the toolbox, delete all its original scripts, and paste in the two scripts I’ve provided below.

Script 1: Self-Driving Script

This script should be placed inside the car:

---THIS SCRIPT GOES IN THE CAR local PathfindingService = game:GetService("PathfindingService") local RunService = game:GetService("RunService") local Effects = require(script.Effects) -- Import the Effects module local car = script.Parent -- The car model local waypointsFolder = workspace:FindFirstChild("selfDrivingWaypoints") local waypoints = waypointsFolder:GetChildren() -- Check if waypointsFolder exists if not waypointsFolder then	error("Waypoints folder 'selfDrivingWaypoints' not found!")	return end if #waypoints == 0 then	error("No waypoints found in 'selfDrivingWaypoints'!")	return end -- Sort waypoints by name table.sort(waypoints, function(a, b)	return tonumber(a.Name) < tonumber(b.Name) end) local speed = 25 -- Adjust car speed local wheelRotationSpeed = 140 -- Adjust for wheel speed local steeringSpeed = 0.1 -- Adjust for smooth turning local currentWaypoint = 1 -- Initialize the Effects module local effectsHandler = Effects.new(car.Chassis, car.Effects, car) effectsHandler:Enable() -- Function to move the car towards a target waypoint local function moveTowardsTarget(targetPosition)	local reached = false	effectsHandler:SetThrottleEnabled(true) -- Enable throttle (engine and sound effects)	while not reached do	local deltaTime = RunService.Heartbeat:Wait()	-- Flatten the target position to ignore height differences	local carPosition = car.PrimaryPart.Position	local flatTargetPosition = Vector3.new(targetPosition.X, carPosition.Y, targetPosition.Z)	-- Calculate direction and target orientation	local direction = (flatTargetPosition - carPosition).Unit	local targetCFrame = CFrame.lookAt(carPosition, carPosition + direction)	-- Gradually turn the car towards the target	car:SetPrimaryPartCFrame(car.PrimaryPart.CFrame:Lerp(targetCFrame, steeringSpeed))	-- Move the car forward	local forwardVelocity = direction * speed * deltaTime	car:SetPrimaryPartCFrame(car.PrimaryPart.CFrame + forwardVelocity)	-- Spin wheels (simulate rotation)	for _, wheelData in ipairs(effectsHandler.wheels) do	local wheel = wheelData.wheel	local wheelRadius = wheel.Size.Y / 2 -- Assuming the wheel's height is the diameter	local rotationSpeed = (wheelRotationSpeed / wheelRadius) * deltaTime -- Rotation based on speed	wheel.CFrame = wheel.CFrame * CFrame.Angles(math.rad(rotationSpeed), 0, 0)	--IF for some reason your wheels look like they are spining backwards make this -math.rad	end	-- Check if the car is close enough to the target	if (car.PrimaryPart.Position - flatTargetPosition).Magnitude < 5 then	reached = true	end	end	effectsHandler:SetThrottleEnabled(false) -- Disable throttle when target is reached end -- Main loop to navigate between waypoints while true do	local startWaypoint = waypoints[currentWaypoint]	local endWaypoint = waypoints[currentWaypoint % #waypoints + 1]	-- Compute path between waypoints	local path = PathfindingService:CreatePath({	AgentRadius = 4.254,	AgentHeight = 6.298,	AgentCanJump = false,	AgentMaxSlope = 45,	})	path:ComputeAsync(startWaypoint.Position, endWaypoint.Position)	if path.Status == Enum.PathStatus.Success then	-- Follow the path step by step	for _, waypoint in ipairs(path:GetWaypoints()) do	moveTowardsTarget(waypoint.Position)	end	else	moveTowardsTarget(endWaypoint.Position) -- Fallback movement	--Really this just makes it contiune on the path it was going to continue on	end	-- Update to the next waypoint	currentWaypoint = currentWaypoint % #waypoints + 1 end 

Script 2: Effects Module

This module should be a child of the self-driving script:

---Place this module Script as the child of the previous script local RunService = game:GetService("RunService") -- Service used for running logic every frame local Effects = {} -- Table that will act as the Effects module Effects.__index = Effects -- Set the metatable for the Effects table -- Constructor function for creating a new Effects instance function Effects.new(chassis, effectsFolder, topModel)	local self = setmetatable({}, Effects) -- Create a new table for the Effects instance	self.ignore = topModel -- The main model of the vehicle, used to ignore certain interactions	self.base = chassis:FindFirstChild("FloorPanel") -- The main floor part of the chassis	self.attachmentContainer = self.base -- Container for attachments (e.g., tire trails)	self.active = false -- Flag to track whether the effects system is active	self.wheels = {} -- Table to store all the wheels for rotation effects	-- Gather all wheels from the chassis and add them to the `wheels` table	for _, suspension in ipairs(chassis:GetChildren()) do	if suspension:FindFirstChild("Wheel") then	local wheelPart = suspension.Wheel	table.insert(self.wheels, { wheel = wheelPart }) -- Store wheel part for later effects	end	end	-- Load engine sound from the effects folder and attach it to the main model	self.engineSound = effectsFolder:FindFirstChild("Engine")	if self.engineSound then	self.engineSound = self.engineSound:Clone() -- Clone the engine sound to avoid modifying the original	self.engineSound.Parent = topModel -- Attach the sound to the main model	end	return self -- Return the new Effects instance end -- Enable the effects system and connect the OnHeartbeat function function Effects:Enable()	self.active = true -- Mark the effects system as active	if not self.heartbeatConn then	-- Connect the OnHeartbeat function to RunService's Heartbeat event	self.heartbeatConn = RunService.Heartbeat:Connect(function(dt)	self:OnHeartbeat(dt) -- Call the OnHeartbeat function every frame	end)	end end -- Disable the effects system and disconnect the OnHeartbeat function function Effects:Disable()	self.active = false -- Mark the effects system as inactive	if self.heartbeatConn then	self.heartbeatConn:Disconnect() -- Disconnect the Heartbeat event	self.heartbeatConn = nil -- Clear the connection reference	end end -- Toggle the engine sound on or off based on the throttle state function Effects:SetThrottleEnabled(toggle)	if toggle and self.engineSound then	self.engineSound.Playing = true -- Start playing the engine sound	elseif not toggle and self.engineSound then	self.engineSound.Playing = false -- Stop playing the engine sound	end end -- Function called every frame while the effects system is active function Effects:OnHeartbeat(dt)	if not self.active then return end -- Exit if the system is not active	-- Custom logic for effects (e.g., tire trails, wheel effects) can be added here	-- This function is intended to update real-time effects based on the car's state end return Effects -- Return the Effects module for use in other scripts 

Final Notes

  • You can adjust the speed and wheel rotation speed in the self-driving script:
local speed = 25 -- Adjust car speed local wheelRotationSpeed = 140 -- Adjust for wheel speed 

If your wheels appear to rotate backward: (This shouldn’t be an issue but if it is)

wheel.CFrame = wheel.CFrame * CFrame.Angles(math.rad(rotationSpeed), 0, 0)	--IF for some reason your wheels look like they are spining backwards make this -math.rad 

To determine the Agent Height and Agent Radius, you can create a part and scale it to roughly match the size of your vehicle. In this example, the part’s size was 8.508, 6.298, 20.583.

  • The Agent Radius is calculated as half of the first number (8.508 ÷ 2 = 4.254).
  • The Agent Height is simply the second number (6.298).

For the slope:

  • A slope of 45° is usually too steep for most vehicles. Upon testing, a 45° slope caused the bumper to hit the incline, preventing the vehicle from climbing.
  • A slope closer to 30° (e.g., part size 22.802, 25.42, 41.702) requires the car’s speed to be increased to be around 90 to make it up the incline.
  • A more manageable slope, such as 13° (e.g., part size 22.802, 9.837, 41.702), works well without needing to adjust the current car’s speed or the wedge’s incline.
-- Compute path between waypoints	local path = PathfindingService:CreatePath({	AgentRadius = 4.254,	AgentHeight = 6.298,	AgentCanJump = false,	AgentMaxSlope = 45,	}) 
  • I’ve ensured the script doesn’t calculate waypoints by height, so you won’t need to worry about perfect waypoint placement. (The car would potentially shake if you didn’t make them perfect otherwise)

If you need further assistance or modifications beyond making the car move as intended, feel free to DM me.

Good luck! :red_car::dash:

2 Likes

Unfortunately, this is not what i need, i need a car(or an NPC) that detects a street(using pathfinding costs or raycasting) and then puts a path on it to drive somewhere random on the street(a far street)

I see that you edited your post Twice. To me it seems like you realized you actually wanted it to do so much more

Then what was originally requested.
I do not mean any offense, but I refuse to help someone who just going to continue changing what they wanted. It really makes me feel like saying “Well Unfortunately you’re going to have to find someone else to help you”
From my understanding it is frowned upon to evolve a question.
If you want me to do this new method, I easily can but you would have to go back to how you originally asked. Make this one solved and then make a new post.
@yousef_mash1

2 Likes