car AI is an user-friendly, open source and OOP module that allows roblox’s cars to do lots of thing, such as chasing players/targets, pathfinding your car through a maze and much more! Here you will find examples, templates, instructions and more.
TRAILER
- (animation by @asadfai )
INSTRUCTIONS
-
Import your working car model and place it in the
workspace
; this means that the model must have a driver seat, and everything must be welded correctly. I suggest editing the car in the template file.
-
Insert an attachment onto the driver seat and position it near the bumper, as shown in the photo.
-
Then add a server script into the car model. The script should first require the module, then create a new AI car object (
local newAI = mod.new(carModel, bumperAttachment)
). Then you only need to choose one of the 3 methods i made to choose how your AI car will drive itself. The code is going to look like this.
EXAMPLES
-
Pathfinding car chasing another car. Here we can see how the car can easily reverse to continue the chase.
-
AI car directly chasing directly a target withouth using pathfinding resulting in a more performance friendly result (good for open maps).
LINKS & DOWNLOAD
Here is the download links of the template model .
And also our discord server if you need any support or help.
Finally here is the link of the full module.
source here
local signal = require(script.Signal)
local carAI = {}
function carAI.new(car : Model, bumper : Attachment)
local new = setmetatable({}, carAI)
new.car = car
new.seat = car:FindFirstChildOfClass("VehicleSeat")
new.pathfindingFailed = signal.new()
new.pathfindingCompleted = signal.new()
new.bumper = new.seat:FindFirstChildOfClass("Attachment") or bumper
local seat = new.seat
local bumper = new.bumper
function new.checkForward()
local rayParams = RaycastParams.new()
rayParams.FilterDescendantsInstances = { seat.Parent}
local vehicleLength = seat.Parent:GetExtentsSize().Z
local vehicleWidth = math.ceil( seat.Parent:GetExtentsSize().X/2)
for i = -vehicleWidth, vehicleWidth do
local result = workspace:Raycast( seat.Position + Vector3.new(i,0,0), seat.CFrame.LookVector*vehicleLength/2,rayParams)
if result and result.Instance and result.Instance:IsGrounded() then
return result.Instance
end
end
end
function new.steerToTarget(target : Vector3)
local rot = math.atan2(target.Z-bumper.WorldPosition.Z,target.X-bumper.WorldPosition.X)
local desiredAngle = math.deg(rot)+seat.Orientation.Y+90
if desiredAngle > 180 then
desiredAngle = -(360-desiredAngle)
elseif desiredAngle <-180 then
desiredAngle = 360+desiredAngle
end
local turndir = desiredAngle/15
local speed = math.abs(20/desiredAngle)
if desiredAngle > 100 or desiredAngle < -100 and (bumper.WorldPosition - target).Magnitude < 10 then
turndir = -turndir
speed = -0.2
end
seat.ThrottleFloat = speed
seat.SteerFloat = turndir
seat.Torque = 6
end
function new.pathToTarget(target : Part)
local path = game:GetService("PathfindingService"):FindPathAsync(bumper.WorldPosition, target.Position)
if path.Status == Enum.PathStatus.Success then
local normalWaypoints = path:GetWaypoints()
local keyWaypoints = {}
local diff1 = Vector2.new(0,0)
for i, v in pairs(normalWaypoints) do
if i ~= #normalWaypoints then
local difference = (Vector2.new(v.Position.X,v.Position.Z) - Vector2.new(normalWaypoints[i+1].Position.X,normalWaypoints[i+1].Position.Z))
local isTrue = workspace:Raycast(v.Position,Vector3.new(0,-5,0))
if ((diff1 - difference).Magnitude) > 0.5 then
table.insert(keyWaypoints,v)
end
diff1 = difference
end
end
table.insert(keyWaypoints, normalWaypoints[#normalWaypoints])
for i, v in pairs(keyWaypoints) do
local currentDist = math.huge
while (v.Position - bumper.WorldPosition ).Magnitude > 6 do
if (bumper.WorldPosition - v.Position).Magnitude >= currentDist and seat.Velocity.Magnitude < 5 then
if new.checkForward() then
local turn = 0.5
if math.random(2) == 1 then turn = -0.5 end
seat.ThrottleFloat = -0.2
seat.SteerFloat = turn
wait(1)
seat.ThrottleFloat = 0
seat.SteerFloat = 0
end
end
if car == nil then
break
end
currentDist = (bumper.WorldPosition - v.Position).Magnitude
new.steerToTarget(v.Position)
wait()
end
end
new.pathfindingCompleted:Fire(true)
else
new.pathfindingFailed:Fire(true)
end
end
function new.advancedPath(target)
local params = RaycastParams.new(); params.FilterType = Enum.RaycastFilterType.Exclude; params.FilterDescendantsInstances = {seat.Parent, target}
local obstacles = workspace:Raycast(seat.Position, target.Position, params)
if obstacles ~= nil then
new.pathToTarget(target)
else
new.steerToTarget(target.Position)
end
end
return new
end
return carAI
This module development started just a couple of days ago and our ai cars are able to go pretty much everywhere. Please help me keep this project alive, and let me down in the comments of the post if you found bugs or any feedback.
Created by @gianfragolo , @asadfai