AI SYSTEMS • WAYPOINTS
HOW TO CREATE A SIMPLE TRAFFIC CAR SYSTEM IN UNITY
Build an ambient road traffic system where autonomous AI cars follow waypoints, brake for obstacles using Raycasts, and pool efficiently for mobile 60 FPS.
Quick Architecture Overview
An efficient traffic car uses a lightweight script that navigates between an array of Transform waypoints with Vector3.MoveTowards() and Quaternion.RotateTowards(), while casting a forward Physics.Raycast() to automatically brake when approaching other cars or player vehicles.
1
The Traffic Car Controller C# Script
TrafficCarAI.cs (C#)
using System.Collections.Generic;
using UnityEngine;
public class TrafficCarAI : MonoBehaviour
{
[Header("Speed & Navigation")]
[SerializeField] private float topSpeed = 12f; // m/s
[SerializeField] private float turnSpeed = 90f; // deg/s
[SerializeField] private float reachThreshold = 1.5f;
[Header("Obstacle Detection")]
[SerializeField] private float sensorLength = 8f;
[SerializeField] private LayerMask obstacleLayer;
[Header("Waypoints")]
[SerializeField] private List<Transform> waypoints = new List<Transform>();
private int currentWaypointIndex = 0;
private float currentSpeed;
private void Start()
{
currentSpeed = topSpeed;
}
private void Update()
{
if (waypoints == null || waypoints.Count == 0) return;
bool isBlocked = CheckForwardObstacle();
// Smoothly accelerate or brake
float targetSpeed = isBlocked ? 0f : topSpeed;
currentSpeed = Mathf.MoveTowards(currentSpeed, targetSpeed, (isBlocked ? 25f : 8f) * Time.deltaTime);
NavigateTowardsWaypoint();
}
private void NavigateTowardsWaypoint()
{
Transform targetNode = waypoints[currentWaypointIndex];
Vector3 targetPosition = new Vector3(targetNode.position.x, transform.position.y, targetNode.position.z);
Vector3 direction = (targetPosition - transform.position).normalized;
if (direction != Vector3.zero)
{
// Rotate smoothly towards waypoint
Quaternion targetRotation = Quaternion.LookRotation(direction);
transform.rotation = Quaternion.RotateTowards(transform.rotation, targetRotation, turnSpeed * Time.deltaTime);
}
// Move forward
transform.position += transform.forward * (currentSpeed * Time.deltaTime);
// Check if reached current waypoint
if (Vector3.Distance(transform.position, targetPosition) < reachThreshold)
{
currentWaypointIndex = (currentWaypointIndex + 1) % waypoints.Count;
}
}
private bool CheckForwardObstacle()
{
Vector3 rayOrigin = transform.position + Vector3.up * 0.5f;
return Physics.Raycast(rayOrigin, transform.forward, sensorLength, obstacleLayer);
}
public void SetPath(List<Transform> pathNodes)
{
waypoints = pathNodes;
currentWaypointIndex = 0;
}
}
Mobile Optimization Pro Tip:
Never instantiate and destroy traffic cars dynamically during gameplay. Use an Object Pool to recycle inactive cars when they move beyond the camera view frustum.
Never instantiate and destroy traffic cars dynamically during gameplay. Use an Object Pool to recycle inactive cars when they move beyond the camera view frustum.